블로그

ykm8864

[인프런 워밍업 클럽 백엔드 스터디 2기] 4주차 발자국

마지막 4주차 발자국을 작성하는 시간이다. Mockito로 Stubbing 하기mock에 대한 원하는 행위(return)을 정의한 다음 내가 테스트하고자하는 서비스에만 집중. ⇒ stubbing이라고 일컷는다.Mockito에서 Stubbing은 모의 객체(Mock)의 메서드가 호출될 때 반환할 값을 미리 설정해 두는 작업을 말한다. 테스트할 때 실제 객체 대신 Mockito로 생성한 모의 객체를 사용하는데, 이때 필요한 메서드의 동작을 미리 정의해 주는 것을 Stubbing이라고 한다. 이렇게 설정하면 실제 메서드가 호출되지 않고, 지정된 값이나 행동을 반환하므로 독립적인 테스트가 가능한 이점이 있다..Stubbing을 설정하려면 when과 thenReturn 또는 thenThrow 메서드를 사용하여 원하는 값을 정의한다. Test Double단위 테스트에서 사용되는 용어로, 테스트하려는 코드의 의존성이나 협력 객체를 대신하여 사용하는 객체를 말한다. 크게 아래 5가지가 있다.Dummy : 아무 것도 하지 않는 깡통 객체Fake : 단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체 ex) FakeRepository (메모리에 휘발성으로 관리)Stub : 텟트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체.Spy : Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체다. 일부는 실제 객체처럼 동작시키고 일부만 Stubbing 할 수 있다.Mock : 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체Mock ≠ Stub공통점은 가짜객체. 차이점 : Stub 은 상태에 대한 검증, Mock은 행위에 대한 검증이다. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이테스트 객체를 생성해주는 다양한 어노테이션이 있다. 크게 Spring 기반 테스트인지 Mockito 기반 테스트인지 구분을 하고 spy 인지 아닌지로 나눌 수 있다.Mokito사용해서 mock만들려면 클래스 상단@ExtendWith(MockitoExtension.class) 를 붙여줘야한다.@Mock:Mockito에서 사용하는 애노테이션으로, 인터페이스나 클래스를 Mock 객체로 생성한다.해당 객체는 실제 동작 없이 사전 설정된 행동만 수행하도록 설정된다.주로 단위 테스트에서 사용@MockBean:Spring Boot에서 사용하는 애노테이션으로, 스프링 컨텍스트에 Mock 객체를 등록한다.스프링 빈으로 주입이 필요한 경우 사용하며, 실제 빈을 Mock 객체로 대체하여 통합 테스트에 적합.@Spy:Mockito에서 사용하는 애노테이션으로, 실제 객체를 기반으로 스파이 객체를 생성한다.원래 메서드를 호출하면서도, 필요한 경우 특정 메서드만 Mocking하여 동작을 변경할 수 있다.@SpyBean:Spring Boot에서 사용하는 애노테이션으로, 스프링 컨텍스트에 실제 객체를 스파이 객체로 등록한다.기존 스프링 빈의 동작을 유지하면서, 특정 메서드만 Stub 처리하여 통합 테스트에서 부분적으로 변경하고 싶을 때 유용하다.@InjectMocks:Mockito에서 사용하는 애노테이션으로, @Mock이나 @Spy로 생성된 객체를 주입해주는 역할을 한다. BDDMockito어? given 절인데 문법이 when이네?Mockito를 감싸고있는 BDD(GIVEN, WHEN, THEN)스타일로 작성만 할 수 있게 이름만 바꾼 상태!! 그래서 그냥 BDDMockito 사용하면 된다. 앞으로는 Classicist VS. Mockist테스트코드를 전적으로 믿냐 아니냐에 대한 견해 차이로 보인다.Mockist : 단위테스트할떄 이미 모든걸 mocking으로 테스트했으니까, 통합테스트할떄는 다 mocking처리해서 기능 보장된 애들은 다 쳐내고 해야하는 것만 짤라서 하자. vs.Classicist : mocking을 다 해버리면 실제 production에서 실 객체가 움직일때의 올바른 동작을 어떻게 보장할 수 있어? 개인적으로 나도 우빈님처럼 Classicist에 더 가까운 편인 거 같다. 테스트 코드는 아무리 완벽하게 하려고 해도 프로덕션 코드에 따라가지 못한다고 생각하고 결국 테스트를 작성하는 사람도 나 자신이기 때문에 허점은 존재할 거 같다. Clean 테스트 코드테스트 코드도 한 문단에 한 주제테스트는 문서다! 글쓰기란 관점에서 봤을때, 한 문단에 하나의 주제를 가지고 있는 게 좋다.완벽하게 제어하기테스트하기 위한 환경을 조성할 때, 모든 조건을 완벽하게 제어할 수 있어야한다.테스트 “환경”의 독립성을 보장하자따라서 given절은 일반적인 생성자만 기입되는게 좋다.테스트 “간”의 독립성을 보장하자두개 이상 테스트 간의 독립성을 보장하자.Test FixtureFixture : given절에 쓰이는 객체들(내가 원하는 결과를 얻기위해 고정해둔 조건들) 이떄 when절에 given절 내용이 들어가는 경우가 많은데 이런 실수를 범하지 말자. 99%의 when절은 한줄이다. (메서드실행) @ParameterizedTest하나의 테스트 메서드를 다양한 매개변수로 반복 실행할 수 있도록 하는 어노테이션사용 예: 여러 입력값에 대해 동일한 로직을 테스트할 때 활용주요 기능:@ValueSource: 간단한 값 배열을 전달(e.g., int, String).@CsvSource / @CsvFileSource: CSV 형식의 데이터나 파일을 통해 여러 매개변수를 전달@MethodSource: 메서드를 통해 테스트 데이터를 전달 @DynamicTest런타임에 테스트 케이스를 생성한다. 정적인 테스트 메서드로 정의되는 것이 아닌 Stream<DynamicTest> 형식으로 생성한다.사용 예: 테스트 시나리오가 복잡하고 실행할 테스트 케이스의 수나 조건이 실행 중 결정되는 경우에 유용하다.주요 기능:동적 테스트를 생성하려면 @TestFactory 어노테이션 필수!Stream<DynamicTest>를 반환한다.메서드 내부에서 테스트 케이스와 이름을 동적으로 정의할 수 있습니다. Spring REST DocsAPI의 구조, 기능, 요청 및 응답 형식 등을 문서화AsciiDoc의 도움을 받아 MarkDown문법으로 작성하고 라이브러리를 의존성 주입받아 html로의 변환도 쉽게 할 수 있다.Swagger vs. REST DocsSwagger적용이 쉽다.문서에서 바로 api호출을 수행할 수 있다.프로덕션 코드에 침투적이다.신뢰도가 떨어진다.REST Docs테스트를 통과해야 문서가 만들어지므로 신뢰도가 높다.프로덕션 코드에 비침투적이다.코드의 양이 많고 설정이 어렵다.강의에서 여러 설정을 잡고 최종적으로 REST Docs문서를 생성하여 브라우저를 통해 확인해보았다. 테스트 과정을 거치며 각각의 문서 조각들이 모여 하나의 문서가 되는 것이 재밌었다. 4주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)테스트 코드를 짤 때 어떤 점이 문서화를 할 때 좋을지 다시 한번 생각해볼 수 있으며, 각종 어노테이션을 습득할 수 있었다. 더불어 api를 많이 짤 일이 생길 텐데 이렇게 REST Docs를 통해 문서 규격을 자동화하여 관리할 수 있다는 점이 너무 유용하고 값진 경험이였다. 앞으로 토이프로젝트를 하면서도 많이 사용해볼 예정이다..Problem (아쉬웠던 점)전반적으로 이번 강의를 마치면서 강사님의 생각을 내가 완전히 따라가지는 못했다는 생각이 많이 든다. 정말 훌륭한 강의를 펼쳐주시지만 내가 모든 것을 내꺼로 체화시키는 과정은 별도로 필요해보인다. 남이 하는걸 봤을때 쉬워보이면 그 사람이 정말 잘하는 거라고 하던데 나도 그런 경지가 되고 싶다는 생각이 들었다. Try (다음에 시도해볼 점)전반적으로 배운 내용을 적용해본 토이프로젝트를 진행할 예정이다. 클린코드와 테스트코드 원칙을 기반으로 서비스를 런칭시켜볼 예정이다. 너무 많은 것을 배워 행복한 일주일이였다. 

백엔드워밍업클럽백엔드2기발자국몰입하는개발자테스트코드

ykm8864

[인프런 워밍업 클럽 2기] Layered Architecture에서의 Testing 정리

Layered Architecture의 레이어별 특징 및 테스팅 방법 정리예시: 음식 배달 서비스각 레이어를 음식 배달 서비스의 역할로 설명한다. 음식 배달 서비스를 통해 사용자가 음식을 주문하고, 음식점에서 음식을 준비하고, 배달원이 고객에게 음식을 전달하는 과정을 생각해 본다. Persistence Layer특징비지니스 가공 로직이 포함되어서는 안 된다.이 레이어는 데이터베이스와 상호작용하여 음식점의 메뉴, 고객 정보, 주문 기록 등을 저장하고 관리한다. 마치 식당의 재료 창고처럼, 데이터의 상태를 정확히 관리하고 필요한 정보를 보관한다. 창고에서는 식당의 주방장이 재료를 요청하면, 정확한 재료를 꺼내주는 역할을 한다. 데이터의 가공은 하지 않고, 필요한 데이터만 정확하게 주고받는 것이 이 레이어의 역할이다.테스트 방법- 단위 테스트: 재료 창고에서 특정 재료를 꺼내거나, 새로운 재료를 추가할 때 그 과정이 제대로 이루어지는지 검증한다. Mocking을 통해 창고에 직접 접근하지 않고, 데이터가 올바르게 반환되는지 확인한다.- 통합 테스트: 실제 창고에서 재료를 꺼내고 추가하는 테스트를 진행한다. 예를 들어, '김치 찌개 재료'를 창고에 추가하고, 해당 재료를 제대로 꺼낼 수 있는지를 확인한다. Business Layer특징트랜잭션을 보장해야 한다.이 레이어는 주방에서 음식의 조리 과정을 담당한다. 사용자 주문에 따라 어떤 메뉴를 어떻게 조리할지 결정하고, 레시피에 따라 재료를 가공하거나 조리 과정을 관리한다. 주방장은 여러 재료를 받아서 맛있는 요리를 만들어내는 역할을 한다. 마치 식당 주방장이 음식의 맛과 품질을 관리하듯, 비즈니스 로직을 통해 데이터와 요구사항을 처리한다.테스트 방법- 단위 테스트: 주방장이 다양한 재료로 요리를 만들 때 레시피에 따라 올바르게 조리하는지 검증한다. Mocking을 통해 창고에서 직접 재료를 받지 않고, 주방에서의 조리 과정 자체에 집중한다.- 통합 테스트: 주방과 창고가 함께 작동하며 올바른 음식을 내놓는지를 확인한다. 예를 들어, '된장찌개' 주문이 들어왔을 때 창고에서 된장과 야채를 받아, 조리 과정을 거쳐 최종 요리가 완성되는지를 검증한다. Presentation Layer특징MockMvc를 통해 내가 테스트하고자하는 부분에 집중한다.상위레이어가 하위 레이어를 알고 있는 것은 당연하지만, 하위레이어가 상위레이어를 알고 있는 것은 의존성이 강한 구조이다.이 레이어는 완성된 음식을 고객에게 전달하는 역할을 한다. 주로 배달원이 주문한 음식을 정확하게 고객에게 전달하며, 사용자가 원하는 방식대로 음식이 전달되는지 책임진다. 고객의 요구사항을 주방에 전달하고, 그 결과를 받아 다시 고객에게 전달하는 역할을 한다. 배달원이 고객에게 주문한 음식을 가져다주는 것처럼, 이 레이어는 사용자와 가장 가까운 곳에서 상호작용을 수행한다.테스트 방법- 단위 테스트: 배달원이 주문한 음식과 고객의 요청을 제대로 처리하는지 검증한다. Mocking을 통해 주방이나 창고에 접근하지 않고, 배달원과 사용자의 상호작용에 집중한다.- 통합 테스트: 배달원, 주방, 창고가 함께 작동하면서 사용자의 주문을 제대로 처리하는지 검증한다. 예를 들어, 고객이 '비빔밥'을 주문했을 때, 주방과 창고의 도움을 받아 배달원이 정확하게 비빔밥을 전달하는지를 확인한다. 흐름도사용자 <-> Presentation Layer (배달원 역할) <-> Business Layer (주방 역할) <-> Persistence Layer (재료 창고 역할)- 사용자(고객)는 Presentation Layer를 통해 주문을 요청한다.- Presentation Layer는 Business Layer에 주문 내용을 전달한다.- Business Layer는 Persistence Layer에서 필요한 데이터를 가져와 주문에 따라 데이터를 가공한다.- 최종적으로 Presentation Layer는 사용자가 원하는 형식으로 결과를 전달한다. - 각 레이어는 역할을 명확히 나누어, 서로에게 필요한 정보를 정확하게 전달하는 데 집중한다.

웹 개발워밍업클럼2기몰입하는개발자테스트코드TDD

ykm8864

[인프런 워밍업 클럽 백엔드 스터디 2기] 3주차 발자국

워밍업 클럽 백엔드 스터디 2기 3주차 발자국 입니다.본격적인 TDD 가이드에 대하여 배우기 시작했습니다.테스트는 왜 필요할까?테스트 = 귀찮다?프로그램이 커지면 수동테스트의 정확도가 어떨까?사람이 할거야?변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야한다면 소프트웨어의 신뢰도가 낮아질 가능성이 높다. 올바른 테스트 코드자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있고, 수동 테스트에 드는 비용을 크게 절약할 수 있다.소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.가까이 보면 느리지만, 멀리 보면 가장 빠르다.단위테스트란작은 코드(클래그 or 메서드) 단위를 독립적으로 검증하는 테스트단위테스트는 검증속도가 빠르고 안정적이다.우리는 JUnit5 와 AssertJ 를 사용하여 테스트 코드를 작성해보았다. 테스트 케이스 세분화하기질문하기 : 암묵적이거나 아지 드러나지 않은 요구사항이 있는가? 해피케이스와 예외케이스에 대하여 테스트 케이스를 세분화 해야한다.-> 경계값 테스트라는 개념을 배웠다.어떠한 정수가 있는데 정수가 3이상일 때, A라는 조건이 성립한다면?⇒ 테스트를 4나 5로 테스트 하는게 야니고 3에 대하여 테스트를 작성하는게 맞다.⇒ 예외 케이스는 2나 1이나 -1과 같은 경계값보다 아래의 경우의 수로 예외케이스를 짜는게 맞다. 테스트하기 어려운 영역 분리하기외부세계에 관련된 도메인은 테스트하기 어려우니 분리하여 가능한 것에 집중한다.input 과 output이 외부세계에 영향을 주거나, 외부세계에 영향을 받는 경우에는 테스트하기 어렵다.ex) 표준출력, 메시지발송, 데이터베이스에 기록하기 등.. 강의에서는 "현재시간" 은 테스트를 돌리는 시간이 바뀜에 따라 매번 결과값이 달라질 수 있으므로 정확한 테스트가 어려워 프로덕트 코드에는 현재시간을 매개변수로 넣고, 테스트할 때는 테스트 하고자 하는 시간을 매개변수로 세팅하여 분리한다. 즉, 테스트 어려운 조건이 생기면 테스트 어려운 영역을 외부로 분리하여 조치한다.TDD프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론RED - GREEN - REFACTOR위 과정으로 TDD가 이루어진다. 실패케이스를 먼저 짜고, 통과를 위한 통과 케이스를 짜고, 리팩토링하고 이를 반복한다.선기능 구현, 후 테스트의 문제점테스트 자체의 누락 가능성(아 테스트 짤 시가니 없네)특정 테스트 케이스만 검증할 가능성(해피케이스만 생각)잘못된 구현을 다소 늦게 발견할 가능성 테스트는 [문서]다.언어가 사고를 제한한다.프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보안해피케이스와 예외케이스를 생각하여 더 깊게 이해할 수 있다.어느 한 사람이 과거에 경험했던 고민의 결과물을 팀차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.테스트케이스를 통해 고민의 결과를 공유하여 소스코드를 관리할 수 있다.  DisplayName을 섬세하게테스트 하고자 하는 내용을 명확하게 기술하자문장형태로 작성하자!테스트 행위에 대한 결과까지 기술한다.도메인 용어를 사용하여 한층 추상화된 내용을 담기테스트의 현상 중점 기술: "특정 시간 이전에 주문을 생성하면 실패한다."여기서는 "실패한다"는 구체적인 현상을 강조한다. 테스트가 어떤 상황에서 실패하는지를 중심으로 표현한 것이다. 하지만 이 표현은 테스트가 도메인의 규칙이나 의도를 명확하게 설명해주지 못할 수 있다. 실제 비즈니스 로직의 핵심 규칙보다는 실패 여부에 집중하게 되는 문제가 있게된다.도메인 관점에서의 기술: "영업 시작 시간 이전에는 주문을 생성할 수 없다."이 표현은 현상보다는 도메인의 규칙을 명확하게 기술. "영업 시작 시간 이전에는 주문을 생성할 수 없다"는 표현은, 해당 비즈니스 로직이 적용되는 이유나 규칙을 이해하는 데 도움이 되며, 비즈니스 도메인에서의 규칙을 중심으로 설명하는 방식이다. 레이어드 아키텍쳐와 테스트Presentation Layer - Business Layer - Persistence Layer관심사의 분리를 위해 레이어를 분리한다.기본적인 JPA 엔티티를 설계하고 테스트하고자하는 레이어를 분리하였다.Persistence Layer 테스트기본적인 CRUD를 구성한 후 데이터베이스와의 연동테스트를 하였다.EnableJpaAuditing을 통하여 테이블의 상태를 트랙킹하고 H2 테이버베이스 콘솔과 비지니스 구현 로직이 정상 작동하는지 확인하였다.Business Layer 테스트비지니스 로직을 구현하는 역할 Persistence Layer와의 상호작용(data를 읽고 쓰는 행위)를 통해 비지니스 로직을 전개시킨다. 트랜잭션을 보장해야한다.도메인 로직에 대한 테스트 코드를 작성하였다. 이때 트랜잭션에 대한 관리가 중요했다.상품을 주문할 때, 제고차감에 대한 로직에서 트랜잭션 관리의 중요성을 느꼈는데 기본적인 테스트코드에서의 @Transactional 개념은 이러하다.트랜잭션 관리: @Transactional을 사용하면, 해당 테스트 메서드가 실행될 때 자동으로 트랜잭션이 시작된다. 그리고 테스트가 완료되면, 해당 트랜잭션은 롤백처리.데이터 정리: 트랜잭션이 롤백되므로, 테스트 중 데이터베이스에 삽입되거나 수정된 데이터는 테스트가 끝나면 모두 사라집니다. 따라서, 별도의 정리 작업이 필요 없게된다.. 테스트 격리성: 트랜잭션 범위 내에서 테스트가 실행되고, 롤백을 통해 테스트 이전 상태로 되돌아가므로, 테스트 간의 데이터 격리성이 자연스럽게 유지된다.이렇게 보면 무조건 트랜잭션 어노테이션을 사용하는 것이, AfterEach를 통한 수동 삭제보다 이점이 크다는 생각이 들지만, 테스트코드에만 트랜잭션이 잡혀있고 실제 프로덕션 코드에는 트랜잭션이 안 잡혀있을 수 있는 위험성이 있으므로 팀원 내부적인 공지나 개발자의 인지가 필요하다.이런 점을 놓치면 심각한 상황이 발생할 수 있다. 테스트코드는 통과했지만 실제 운영에는 버그가 생기는 것이다. 예를 들어, 주문을 생성하고 주문에 포함된 상품이나 재고를 업데이트하는 작업이 순차적으로 실행될 때, 중간에 예외가 발생하면 앞서 실행된 작업은 롤백되지 않아 장애가 있을 것이다. 3주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)테스트 코드의 기본적인 Given When Then 방식이 익숙해짐을 느꼈다. 더불어 JPA와 Spring Data JPA에 대한 개념을 다시 한번 다지는 기회도 갖을 수 있었다. 또한, 단위테스트와 통합테스트에 대한 개념이 실무에서는 어떻게 적용되어야 하는지 인지할 수 있었다..Problem (아쉬웠던 점)기본적으로 JUnit 과 AssertJ의 메서드에 아직 친숙한 느낌은 아닌 거 같다. 그러다보니 강의를 들으며 도메인을 따라가면서 코드까지 신경쓰는 것이 어려운 부분이 있었다. 천천히 다시 한번 강의를 들으며 다시 학습하는 과정이 필요해보인다. Try (다음에 시도해볼 점)세부적으로 여러가지를 알려주셔서 좋았다. 다음에는 개인프로젝트로 동시성문제에 대해서 좀 더 고찰해보는 시간을 가지고 싶다. 지나가면서 말씀해주신 ptimistic lock / pessimistic lock 에 대해서도 공부해보고 싶다.

백엔드워밍업클럽2기몰입하는개발자백엔드테스트코드TDD

ykm8864

[인프런 워밍업 클럽 백엔드 스터디 2기] 2주차 발자국

워밍업 클럽 백엔드 스터디 2기 2주차 발자국 입니다.우선 객체의 책임과 추상화레벨에 근거한 코드다듬기에 대하여 배웠습니다.주석의 양면성주석이 많다는 것은, 그만큼 비지니스 요구사항을 코드에 잘 못 녹였다는 이야기좋은 주석이란 → 우리가 가진 모든 코딩 표현 방법을 총동원해 코드에 의도를 녹여내고, 그럼에도 불구하고 전달해야 할 정보가 남았을 때 사용하는 주석 변수와 메서드의 나열 순서변수는 사용하는 순서대로 나열한다. (인지적 경제성을 위해)메서드의 순서는 공개메서드를 상단에 배치하고 private 메서드를 후순위로 둔다. 이때 각 메서드 그룹(public, private) 안에서는 상태변경 > 판별 >= 조회 메서드 순으로 배치시키는 것이 좋다.메서드를 만들거나 추출할 때마다 2가지 생각을 할 줄 알아야한다. 1. 어? 이 메서드를 어디쯤 둬야하지 2. 어?이게 private 인가 public인가? 외부에서 내부로 쓰임새가 변경되었는지까지 한번 더 확인 패키지 나누기패키지는 문맥으로써의 정보를 제공할 수 있다.하지만 멋대로 바꾸면 안된다. 협업 안에서의 안정성과 팀원을 배려함을 확보하면서 작업해야한다. 알고리즘 최적화스택오버플로우? 재귀? dfs? 스택 ? 데큐? 더 좋은 성능이 무엇일까특정 알고리즘의 성격을 띄는 비지니스 로직이 있을 수 있다. 이는 기본적인 자료구조와 알고리즘에 대한 이해를 기반으로 최적화 해나갈 수 있다. 강의에서는 dfs라는 배경지식을 기반으로 재귀를 스택자료구조로 표현했고 이후 데큐를 통해 성능을 최적화했다. ide의 도움받기코드 포맷 정렬, Sonarlint, editorconfig발전하는 it의 특성상 여러가지 툴도 동시에 발전해나가고 있다. 툴의 도움을 꺼려하지말자. 더 많은 것을 배울 수 있다. 능동적 읽기뒤가 있어 우리에겐 " git reset --hard"코드를 읽고 이해하려고 할 때, 공백으로 단락을 구분하고 의미와 책임으로 추상화를 해보고, 주석을 직접 달아가면서 해석을 해보자. 도메인의 지식을 늘리면 코드의 추상화가 더 쉬워진다. 도전을 두려워하지마 우리게엔 git reset --hard가 있다.오버엔지니어링정말 필요한 코드 구조인가?도메인의 지식에 벗어난 과한 추상화, 과한 인터페이스는 오히려 오버엔지니어링일 수 있다. 은탄환은 없다.정답은 없다.클린코드는 모든 방법의 핵심이 아니다. 클린코드는 미래의 일어날 수 있는 변화에 대하여 잘 대응할 능력을 제공해준다. 이러한 사고법을 기반으로 언제 적재적소에 알맞게 클린코드가 필요한지 파악할 수 있다. 모든 기술의 방법록은 정적 기술의 범위 내에서 적용되어야 좋은 기술이다. 1주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)추상화와 조금 더 친해질 수 있었다. 클린코드를 배우다보면 초창기에는 모든 코드가 불편하게 보이게 되는 경향이 있다. 하지만 이번 차수를 마치면서 은탄환은 없다. 적재적소에 맞는 기술과 코드를 쓰는 것이 중요하다라고 느꼈고 이 점을 회사에 적용해보니 더 많은 사람들이 나의 생각을 이해하고 따라와주는 것에 고마움과 만족감을 느꼈다. 앞으로 더 넓은 객체의 세계를 배워 더 좋은 설계를 해보고 싶다. .Problem (아쉬웠던 점)알고리즘과 자료구조에 대한 깊은 이해가 부족하다는 생각이 들었다. 알고리즘을 겉햝기 식으로 풀어는 왔지만 막상 코딩테스트 문제를 통해 접근하는 알고리즘과 실제 비지니스 도메인로직에 알고리즘을 녹이는 것은 차원이 다르다는 생각이 들었다. 우선 원초적인 기본부터 지켜나가면서 공부를 더 해야함을 느꼈다.  Try (다음에 시도해볼 점)주석을 쓴다는 것은, 내 코드를 다른 사람들이 읽기 쉽게 해준다고 생각했었다. 예를 들어 회사에서 잘 쓰지 않는 신규 api나 메서드를 가지고 코딩을 하면 그 코드에 대한 해석이 어려운 부분이 있을 거라 생각해서 그랬던 거 같다. 하지만 이번 강의를 통해 더 친절한 코딩을 하면 주석따위는 필요없다고 생각이 들었다. 앞으로 코딩을 할 때 과연 내가 후손에게 친절한 코드를 작성하고 있는가 에 데한 고민을 수시로 해봐야겠다.

웹 개발몰입하는개발자워밍업클럽발자국성장

ykm8864

[인프런 워밍업 클럽 백엔드 스터디 2기] 1주차 발자국

학습 내용리팩토링을 왜할까? 클린코드를 왜 작성할까?우리는 생산을 해냈다고 끝이 아니다. 이후에 조상들이 작성한 코드를 후손들이 유지보수하는 일이 생기기 마련이다. 이에 관련하여 여러가지 방법에 대하여 배워보자추상? 그게 뭔데의미를 담을 수 있는 더 작은 단위, 책임이름짓기단수와 복수의 구분관용어가 아닌 이상 줄임말 자제그 집단만 알 수 있는 은어/방언 사용하지 않기좋은 코드를 많이 보기메서드로의 분리의미를 담을 수 있는 더 작은 단위로 메서드를 분리하기기준 : 추상화되는 의미가 있는가? 이미 이해가 잘 간다면 그대로 두는게 더 나을 수 있다.추상화 레벨 구체에 가깝다 = 추상화 레벨이 낮다. (디테일한 코드 상세) 추상에 가깝다 = 추상화 레벨이 높다. (디테일한 코드를 외부세계로 감싸는 메서드)하나의 세계 안에서는, 추상화 레벨이 동등해야 한다. 내가 너무 주변 레벨에 비해서 구체화시키고 있다면 추상화를 고려해보자매직넘버와 매직스트링의미를 갖고 있으나, 상수로 추출되지 않은 숫자상수를 추출하고 이름을 짓고 의미를 부여함으로서 가독성이 향상될 수 있다.상수로 뺀다는건, 이거는 중요한 숫자야~ 유지보수할때 중요깊게 봐야할 필요가 있을거야~ 라는 의미를 줄 수 있다.  논리 사고의 흐름#최소의 인지적 노력으로 최대의 정보를 제공# 뇌는 한번에 한가지 일 밖에 하지 못한다. 멀티태스킹? 그건 저글링일 뿐이다.뇌에 메모리를 적게 쓰게 하기.Early return논리의 흐름을 빠르게 중단시켜 생각 회로를 단순화 한다.코드 흐름을 단순화하고 가독성을 향상중첩분기, 중첩반복문에 대한 최적화depth를 1로 만들 수 있는지 생각해보기때로는 stream에 대한 활용도 고려할 수 있다.2중 중첩구조 안에도 사고에도움이 된다면 중첩 안에 메서드를 분리하여 두어도 좋다.사용할 변수는 가깝게 선언하기공백라인도 의미를 가진다복잡한 로직의 의미 단위를 나누어 보여줌으로써 읽는 사람에게 추가적인 정보를 전달할 수 있다.부정어를 대하는 자세논리를 거꾸로하여 생각하는 과정을 거친다는 것은 가독 저하의 요인일 수 있다.부정어구를 쓰지 않아도 되는 상황인지 체크하기 (무조건 부정조건으로검사해야하는 상황인지)부정의 의미를 담은 다른 단어자체가 존재하는지 고민하기 or 부정어구로 메서드 명 구성해피케이스와 예외 처리예외가 발생할 가능성 낮추기검증로직은 생성자 or 별도의 분리가 필요의도한 예외와 예상하지 못한 예외를 구분하기Null을 대하는 자세equals작성시 상수를 앞에 둔다.Optional은 비싼 객체라 항상 좋은건 아니지만 값이 있을 수도 있고 없을 수도 있는 상황에는 고려할 수 있다. 이때 멤버변수에 Optional은 좋지 않다. 만들어진 목적이 메서드의 반환타입에 쓰게금 설계되어있다.[orElse() : 괄호 안에 값이 항상 실행orElseGet() : 옵셔널안에 원본값이 null인 경우 실행orElseThrow() : 값이 있으면 쓰고 없으면 예외를 던지겠다. 라는 의미라서 그냥 써도된다.StackTrace는 안티패턴이다. 추상의 관점으로 바라보는 객체 지향객체지향 패러다임객체 간의 협력과 객체가 담당하는 책임객체간의 협력과 객체가 담당하는 책임의 관점으로 추상화를 접목시켜 이해하는 것이 중요하다.관심사의 분리관심사끼리 객체를 분리한다.높은 응집도, 낮은 결합도 유지객체 설계하기객체도 추상화와 같이 객체로 나누는 순간 외부와 경계가 발생한다. 이때 외부세계와 소통을 위해서 공개메서드를 활용한다.객체는 외부로 기능을 제공해준다. (개념의 가시화 = 관심사)비공개필드(데이터), 비공개로직(기능 구현부), 공개 메서드 선언부만 외부로 노출하여 이루어진다.여러 객체를 사용하는 입장에서는 구체적인 구현에 신경쓰지 않고 보다 높은 추상화 레벨에서 도메인 로직을 다룰 수 있다.새로운 객체를 만들 때 주의할 점1개의 관심사로 명확하게 책임이 정의되었는지 확인유효성 검증setter 사용 자제(데이터의 불변성)getter가 꼭 필요한지 생각해보기 (객체에 메시지를 보내서 필요한 정보를 메서드로 가져올 수 없는지?)필드의 수는 적을 수록 좋다. 객체지향 패러다임(SOLID)SRP : ”책임을 볼 줄 아는 눈”전문가가 되어야한다. 하나 이상의 일을 책임지게 되면 업무의 효율성이 떨어지게 된다. 이를 어기면 각각의 역할에 집중할 수 없고 공통 업무의 변화가 생기면 모두 바뀌어야한다.OCP : "기존 코드의 변경 없이 , 시슽템의 기능을 확장할 수 있어야한다. (추상화와 다형성의 활용)"전기콘센트 같은것. 허용 전압 규격만 맞으면 냉장고, 가스레인지 등 모든 가전제품을 사용 가능하다. 가전제품이 늘어나도 규격이 맞으면 사용 가능하고 전기콘센트를 교체할 필요 없다.LSP : "자식클래스는 부모클래스의 책임을 준수하며, 부코클래스의 행동을 변경하지 않아야한다."엄마말을 잘 듣자. 상속의 세계에서는 자식은 부모를 이길 수 없다. 따라서, 자식은 부모의 규칙을 어기거나 변경할 수 없이 말을 잘 들어야한다.ISP : "인터페이스를 기능단위로 잘게 쪼개라"덜어냄의 미학. 흑백요리사에서처럼 인터페이스도 많은 기능(책임)을 가진다고 좋은게 아니다. 필요한 만큼만 가지는게 최고다.DIP : "상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다. 둘 모두 추상화에 의존해야 한다."수준에 맞게 놀자. 고수준(추상 : 핵심비지니스 로직) 모듈이 저수준(구체 : 구현세부사항)모듈을 직접적으로 참조하는 것은 저수준모듈의 변경에 민감하게 반응하게된다. 객체지향 적용하기상속과 조합상속보다는 조합을 사용하자상속은 시멘트처럼 굳어진 구조다. (부모와 자식의 결합도가 높다.)조합과 인터페이스를 활용하는 것이 유연한 구조다.상속을 통한 코드의 중복 제거가 주는 이점보다, 중복이 생기더라도 유연한 구조 설계가 주는 이점이 더 크다.상속 : extends → 부모 - 자식 간의 필수 오버라이딩 제약이 없고, 부모의 구현을 자식이 알고있는 관계 → 자식.부모메서드() 로 호출이 가능하여 재사용성이 향상됐다고 볼 수 있지만 객체 지향 관점에서는 캡슐화가 깨진 상태라고도 볼 수 있음조합 : 부모에는 공통 스팩 제공하는 인터페이스를 사용하고, 해당 부모의 구현체들은 부모의 스팩만 유지한 상태라면 부모에 독립적이고 변경이 많아질 수 있는 부분은 부모 클래스에 두지 않고 별도의 클래스로 분리함으로써 캡슐화와 확장성을 지킨다.주입 : 외부에서 부모 클래스나 자식 클래스가 의존하는 객체들을 주입함으로써, 객체 간의 강한 결합을 방지하고, 필요 시 구현체를 쉽게 교체할 수 있게 하여 유지보수와 테스트의 용이성을 높인다.Value Object도메인의 어떤 개념을 추상화하여 표현한 값 객체 값으로 취급하기 위해서, 불변성, 동등성, 유효성 검증 등을 보장해야 한다.엔티티와 vo의 차이(식별자 유무 차이)일급 컬렉션일급시민이란? -> 다른 요소(누군가의 파라미터, 변수, 함수의 결과로 return)에게 사용 가능한 모든 연산을 지원하는 요소일급컬렉션이란?컬렉션을 포장하면서 필드로 무조건 해당 컬렉션 하나만을 가지고 있는 객체컬렉션을 다른 객체와 동등한 레벨로 다루기 위함getter로 컬렉션을 반환할 일이 생긴다면 필드에서 가지고 있는 컬렉션과 같은 참조를 리턴하는 일이 생기지 않도록 new해서 새로운 컬렉션을 반환하자.enum의 특성과 활용상수의 집합변경이 정말 잦은 개념이면 enum보다 db로 관리하는게 좋을 수 있음.다형성 활용하기변하는 것과 변하지 않는 것을 분리하여 추상화하는 것.변하지 않는 것을 지켜야[추상] → 변경에는 닫혀있는 상태를 유지 가능변화하는 것에는 유동적으로 해결이 되어야[구체] → 확장에 열려있는 상태가 된다. 숨겨져 있는 도메인 개념 도출하기완벽한 설계는 없다. 그 당시의 최선이 있을 뿐.도메인 지식은 만드는 것이 아니라 발견하는 것설계할 때는 근시적, 거시적 관점에서 최대한 미래를 예측하려는 시도가 필요하다시간이 지나 만약 틀렸다는 것을 인지하면 언제든 돌아올 수 있도록 코드를 만들어야 한다.미션-> 주어진 코드에 대한 리팩토링얼리리턴추상화레벨 맞추기처리해야할 예외와 그렇지 않은 예외의 분리변수명, 함수명책임의 분리등.. 배운 지식을 활용하여 최적화하는 연습을 해보았다.   1주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)현재 코드를 작성하면서 "조상"과 "후손"이라는 표현을 사용한 점이 인상 깊었다. 이 표현은 코드의 지속성과 유지보수의 중요성을 잘 드러낸다고 생각이 들었다. 실무에서는 생산성과 클린 코드를 상반된 개념으로 보는 경우가 많은데, 이는 조직의 코드 문화에 긍정적이지 않다는 생각도 같이 들곤 했다. 이러한 문화를 개선하기 위한 방법론을 이번 학습을 통해 구체적으로 알게 되어 만족스러웠다..Problem (아쉬웠던 점)처음 보는 코드에 대한 빠른 이해가 부족하다는 점을 느꼈다. 즉, 현재 짜여진 코드를 너무 쉽게 납득해버리는 경향이 있는게 아닌가 싶다. 강사님처럼 코드를 보고 잠재적인 문제와 개선 가능성을 구조적으로 접근하는 시야가 필요하다고 생각한다. 이를 통해 "보는 눈"에 대한 중요성을 느꼈다.Try (다음에 시도해볼 점)구체적인 코드 설계에서 추상과 구체를 명확하게 분리하는 연습을 해보고 싶다. 처음부터 완벽한 설계를 할 수는 없겠지만, 도메인의 책임을 분리하고 리팩토링을 고려한 설계를 시도해봐야겠다. 우선 흐름대로 코드를 작성한 후, 리팩토링을 통해 개선하는 과정을 반복하며 사고력을 기르는 과정을 연습해보아야 할 거 같다.

백엔드워밍업클럽회고자기계발몰입하는개발자BE백엔드

채널톡 아이콘