블로그
전체 4#카테고리
- 백엔드
#태그
- 워밍업클럽
- 테스트
- 클린코드
2024. 10. 16.
0
워밍업 클럽 2기 BE 클린코드&테스트 발자국 4주차
Day 15. Spring & JPA 기반 테스트: Presentation LayerPresentation Layer외부 세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행한다.MockMvcMock(가짜) 객체를 사용해 스프링 MVC 동작을 재현할 수 있는 테스트 프레임워크미션 - 생각하는 레이어별 특징과 테스트 방법Persistence Layer데이터 저장 및 조회를 담당데이터베이스에 연결하여 데이터 저장 및 조회가 잘 되는지 테스트Business Layer비즈니스 로직을 담당비즈니스 규칙에 맞게 올바르게 동작하는지 테스트Presentation Layer사용자와 상호작용을 담당사용자가 보낸 요청의 유효성 체크와 응답이 제대로 가는지 테스트Day 16. Mock을 마주하는 자세Test Double상태 검증 -> Stub행위 검증 -> Mock@Mock, @Spy, @InjectMocks@Mock : Mock 객체로 만듬@InjectMocks : Mock 객체를 주입해줌@Spy : 일부만 Mock 객체로 만듬BDDMockitoMockito와 동일하다.BDD 스타일로 이름만 변환.Mockito.when().thenReturn(); BDDMockito.given().willReturn();Day 17. 더 나은 테스트를 작성하기 위한 구체적 조언한 문단에 한 주제!: 하나의 테스트 코드에서 하나의 테스트만!완벽하게 제어하기: 제어 불가능한 영역은 상위 계층으로!테스트 환경의 독립성을 보장하자테스트 간 독립성을 보장하자한 눈에 들어오는 Test Fixture 구성하기: given 절을 구성할 때의 주의사항Test Fixture 클렌징테스트 수행도 비용이다. 환경 통합하기Q. private 메서드의 테스트는 어떻게 하나요?해서도 안 되고 할 필요가 없다.Q. 테스트에서만 필요한 메서드가 생겼는데 프로덕션 코드에서는 필요 없다면?만들어도 되지만 보수적으로 접근하기!Day 18. 학습 테스트 | REST Docs학습 테스트잘 모르는 기능, 라이브러리, 프레임워크를 학습하기 위해 작성하는 테스트Spring REST Docs테스트 코드를 통한 API 문서 자동화 도구Spring REST Docs : https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/Asciidoctor : https://asciidoctor.org/Swagger : https://swagger.io/미션 - @Mock, @MockBean, @Spy, @InjectMocks의 차이 정리@Mock: 해당 객체를 Mock 객체로 만든다.@MockBean: Spring의 ApplicationContext에 Mock 객체로 만들어 빈으로 등록한다.@Spy: 일부분만 Mock 객체로 만들어준다.@InjectMockes: Mock 객체로 만들어 주입해준다.미션 - 각 항목을 @BeforeEach, given절, when절 배치@BeforeEach void setUp() { 1-1., 2-1., 3-1. 사용자 생성에 필요한 내용 준비 1-2., 2-2., 3-2. 사용자 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }회고아기다리 고기다리던 금요일 특강을 회사일때문에 참가하지 못했다.하필 저번주도 다음주도 아닌 이번주 금요일에 하필...아쉽지만 지금까지 공부하고 배운 내용을 내것으로 만들어 가야겠다.출처https://inf.run/zgJk5https://inf.run/kHiWM
백엔드
・
워밍업클럽
・
테스트
2024. 10. 10.
0
워밍업 클럽 2기 BE 클린코드&테스트 발자국 3주차
Day 10. 단위 테스트테스트는 왜 필요할까?빠른 피드백자동화안정감단위 테스트작은 코드 단위(클래스 or 메서드)를 독립적으로 검증하는 테스트검증 속도가 빠르고, 안정적이다.테스트 케이스 세분화하기해피 케이스예외 케이스경계값 테스트테스트하기 어려운 영역을 분리하기테스트하기 어려운 영역관측할 때마다 다른 값에 의존하는 코드외부 세계에 영향을 주는 코드순수 함수같은 입력에는 항상 같은 결과외부 세상과 단절된 형태테스트하기 쉬운 코드Day 11. TDD | 테스트는 [ ] 다TDD: Test Driven Development프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론테스트와 상호작용하며 발전하는 구현부클라이언트 관점에서의 피드백을 주는 Test Driven애자일 성명서 : http://agilemanifesto.org/테스트는 [ ] 다[ ]는 강의에서😀우리는 항상 팀으로 일한다DisplayName을 섬세하게도메인 용어를 사용하여 한층 추상화된 내용을 담기테스트의 현상을 중점으로 기술하지 말 것BDD 스타일로 작성하기TDD에서 파생된 개발 방법 Given : 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)When : 시나리오 행동 진행Then : 시나리오 진행에 대한 결과 명시, 검증Day 12. 테스트 코드 적용 미션 https://github.com/japygo/readable-code/commits/mission7-1/회고이름 짓기처럼 DisplayName을 짓는 것도 역시나 고민되고 어렵다.테스트 코드를 굳이 작성해야하나 싶은 테스트를 작성해야 하는지 의문이다.테스트 커버리지 보다는 다양한 예외 케이스들을 제대로 했는지가 중요한 것 같다.Day 13. Spring & JPA 기반 테스트: Persistence Layer레이어드 아키텍처(Layered Architecture)와 테스트풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트Library vs FrameworkLibrary: 내 코드가 주체Framework: 이미 동작할 수 있는 환경이 있어 내 코드가 수동적Persistence LayerData Access의 역할비즈니스 가공 로직이 포함되어서는 안 된다. Data에 대한 CRUD에만 집중한 레이어Day 14. Spring & JPA 기반 테스트: Business LayerBusiness Layer비즈니스 로직을 구현하는 역할Persistence Layer와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.트랜잭션을 보장해야 한다.회고테스트 코드 강의 역시 상상 속의 있던 유니콘을 만나는 기분이었다.중요한 걸 알지만 현업에서 만나볼 수 없어서 감이 전혀 오지 않았는데 어떤 느낌인지 알 수 있었다.열심히 해서 다양한 테스트 케이스를 만나 볼 수 있으면 좋겠다.출처https://inf.run/zgJk5https://inf.run/kHiWM
백엔드
・
워밍업클럽
・
테스트
2024. 10. 05.
0
워밍업 클럽 2기 BE 클린코드&테스트 발자국 2주차
Day 6. 리팩토링: 코드 다듬기주석의 양면성좋은 주석우리가 가진 모든 표현 방법을 총동원해 코드에 의도를 녹여내고, 그럼에도 불구하고 전달해야 할 정보가 남았을 때 사용하는 주석변수와 메서드의 나열 순서중요한 것은, 나열 순서로도 의도와 정보를 전달할 수 있다는 것패키지 나누기패키지는, 문맥으로써의 정보를 제공할 수 있다.처음 만들 때부터 잘 고민해서 패키지를 나눠놓는 것이 제일 좋다. IDE의 도움 받기코드 포맷 정렬 : Option + Cmd + L | Ctrl + Alt + L코드 품질 : Sonarlint (https://www.sonarsource.com/products/sonarlint)포맷 규칙 : .editorconfig (https://editorconfig.org/)Day 7. 클린코드 리팩토링 실습미션 - 스터디 카페 이용권 선택 시스템 리팩토링 https://github.com/japygo/readable-code/tree/mission6-1회고강의를 통해 배운 것을 생각하며 리팩토링하려 했지만 생각보다 쉽지 않다.변수명, 메서드명이 잘 떠오르지 않았다. Day 8. 리팩토링 연습 | 기억하면 좋은 조언들리팩토링 연습추상화 레벨중복 제거, 메서드 추출객체에 메세지 보내기 객체의 책임과 응집도IO 통합일급 컬렉션display()의 책임Order 객체관점의 차이로 달라지는 추상화FileHandler를 바라보는 관점 어떤 데이터를 필요로 하는가데이터를 어디로부터 어떻게 가져올 것인가기억하면 좋은 조언들능동적 읽기능동적으로 리팩토링하면서 물고 뜯고 맛보면서 읽기오버 엔지니어링필요한 적정 수준보다 더 높은 수준의 엔지니어링오버 엔지니어링을 경계하고 꼭 필요한 곳에 알맞게 사용은탄환은 없다한번은 개발자와 체스를 구현하는 방법에 대해 논의한 적이 있습니다.나는 그가 어떻게 할 것인지 물었습니다.객체 지향 프로그래밍에 정통한 그는 “인터페이스와 클래스를 사용한다”고 답했습니다.나는 “하드코딩하는 편이 더 쉽지 않을까요?” 라고 운을 띄웠습니다.그는 “물론이죠. 하지만 잘 유지보수 하시기 바랍니다.” 라고 말하면서 내가 농담을 한 것처럼 씩 웃었습니다.“체스는 지난 500년 동안 변하지 않았습니다.”내 말에 그의 눈이 커졌습니다.- 크리스찬 클라우젠, 「파이브 라인스 오브 코드」, 위키북스, 2023, 302p항상 정답인 기술은 없다.마무리하며전문가는 언제나 탑다운(top-down)으로 깔끔하게 생각할 것이다.라는 미신.- 김창준, 「함께 자라기」, 인사이트, 2018, 153p추상과 구체를 넘나드는 것Day 9. 중간 점검헥사고날 아키텍쳐 - 만들면서 배우는 클린 아키텍처(https://www.yes24.com/Product/Goods/105138479)클린 코드, 테스트 코드, 더 나아가서 소프트웨어 개발은 팀 게임, 혼자는 한계가 있다.아주 작은 단위, 메서드 분리부터 시작 -> 책임을 정의하고 객체로도 분리잘 만들어진 라이브러리, 프레임워크에서 배우는 것도 좋은 방법 - https://github.com/spring-projects파라미터 수가 많을 경우 의도에 따라 줄일 수 있으면 좋다.도메인따라 다르지만 NPE 방지를 위해 empty 객체 반환회고1주차도 그렇고 2주차때도 꼭 강의를 들으려 하면 일이 생긴다.일을 다니며 하는건 쉽지 않다.그동안 궁금하고 답답한 부분을 시원하게 긁을 수 있는 강의라서 매우 좋았다.출처https://inf.run/zgJk5 https://inf.run/kHiWM
백엔드
・
워밍업클럽
・
클린코드
2024. 09. 29.
0
워밍업 클럽 2기 BE 클린코드&테스트 발자국 1주차
Day 2. 추상과 구체추상과 구체추상 (抽象)사물을 정확하게 이해하기 위해서 사물이 지니고 있는 여러 가지 측면 가운데서 특정한 측면만을 가려내어 포착하는 것이다. 어떤 일면만을 추상하는 것은 다른 측면을 버린다는 것과 같다. (위키백과)추상은 항상 구체적인 실재에서 시작해야 한다. - Pablo Picasso추상화의 가장 대표적인 행위이름을 짓는다. 이름 짓기단수와 복수 구분하기이름을 줄이지 않기은어/방언 사용하지 않기좋은 코드를 보고 습득하기 메서드와 추상화잘 쓰여진 코드라면, 한 메서드의 주제는 반드시 하나다.메서드 선언부반환타입 메서드명 (파라미터) {}메서드 선언부: 반환타입 메서드명 (파라미터)메서드 구현부: {}메서드 시그니처: 메서드명 (파라미터)추상화 레벨하나의 세계 안에서는, 추상화 레벨이 동등해야 한다.매직 넘버, 매직 스트링의미를 갖고 있으나, 상수로 추출되지 않은 숫자, 문자열 등미션 - 생각나는 추상과 구체의 예시Winter is coming지구가 태양을 공전하여 태양의 고도가 점차 낮아진다.이로인해 햇빛의 강도가 약해져 기온이 감소한다.북쪽의 차가운 공기가 내려오고 습한 공기와 만나게 되면 눈이 내린다.Day 3. 논리, 사고의 흐름 | 객체 지향 패러다임뇌 메모리 적게 쓰기“정리 시스템에서 중요한 과제는 최소의 인지적 노력으로 최대의 정보를 제공하는 것이다.”- 대니얼 J. 레비틴, 「정리하는 뇌」, 와이즈베리, 2015, 134p뇌는 한 번에 한 가지 일 밖에 하지 못한다. 멀티태스킹? 그건 저글링일 뿐.- 요한 하리, 「도둑맞은 집중력」, 어크로스, 2023, 60pEarly returnEarly return으로 else의 사용을 지양사고의 depth 줄이기중첩 분기문, 중첩 반복문‘무조건 1 depth로 만들어라’가 아니다!사용할 변수는 가깝게 선언하기공백 라인을 대하는 자세공백 라인도 의미를 가진다.부정어를 대하는 자세부정 연산자(!)의 가독성은 낮다.해피 케이스와 예외 처리사람은, 해피 케이스에 몰두하는 경향이 있다.Null을 대하는 자세항상 NullPointException을 방지하는 방향으로 경각심 가지기Optional에 대해 orElse(), orElseGet(), orElseThrow()의 차이 숙지추상의 관점으로 바라보는 객체 지향객체 = 데이터 + 코드협력과 책임캡추상다관심사의 분리객체 설계하기새로운 객체를 만들 때 주의할 점1개의 관심사로 명확하게 책임이 정의되었는지 확인하기생성자, 정적 팩토리 메서드에서 유효성 검증이 가능하다.setter 사용 자제getter도 처음에는 사용 자제. 반드시 필요한 경우에 추가하기필드의 수는 적을수록 좋다.도메인 지식은 만드는 것이 아니라 발견하는 것미션 - 읽기 좋은 코드로 리팩토링public boolean validateOrder(Order order) { if (order.hasNotItem()) { log.info("주문 항목이 없습니다."); return false; } if (order.hasNotTotalPrice()) { log.info("올바르지 않은 총 가격입니다."); return false; } if (order.hasNotCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } return true; } class Order { private List items = new ArrayList(); private Long totalPrice; private String customerInfo; public boolean hasCustomerInfo() { return customerInfo != null && !customerInfo.isEmpty(); } public boolean hasNotCustomerInfo() { return !hasCustomerInfo(); } public boolean hasNotItem() { return !items.isEmpty(); } public boolean hasTotalPrice() { return totalPrice != null && totalPrice > 0; } public boolean hasNotTotalPrice() { return !hasTotalPrice(); } }Day 4. SOLID미션 - 자기만의 언어로 정리한 SOLIDSRP: Single Responsibility Principle클래스는 하나의 책임, 즉 변경 이유를 한 가지만 가져야 한다. 한 가지 일을 잘 처리하도록 해야 유지보수가 쉬워진다.OCP: Open-Closed Principle새로운 기능이 추가할 때 기존 코드를 변경하지 않고 확장이 가능해야 한다.LSP: Liskov Substitution Principle부모 클래스의 기능을 자식 클래스에서도 사용할 수 있어야 한다.ISP: Interface Segregation Principle하나의 책임이 있는 인터페이스 여러 개로 나눈다. 그래야 필요한 인터페이스에 대해서만 구현할 수 있다.DIP: Dependency Inversion Principle하나의 모듈이 다른 모듈은 참조하지 말고 추상화에 의존해야 하고, 구체적인 사항은 나중에 정의해야 한다.Day 5. 객체 지향 적용하기상속과 조합조합과 인터페이스를 활용하는 것이 유연한 구조상속을 통한 코드의 중복 제거가 주는 이점보다, 중복이 생기더라도 유연한 구조 설계가 주는 이점이 더 크다.Value Object도메인의 어떤 개념을 추상화하여 표현한 값 객체불변성동등성유효성 검증일급 컬렉션일급 시민의 조건을 만족하는 컬렉션컬렉션을 포장하고 유일한 필드로 가지는 객체Enum의 특성과 활용Enum은 상수의 집합이며, 상수와 관련된 로직을 담을 수 있는 공간이다.만약 변경이 정말 잦은 개념은, Enum보다 DB로 관리하는 것이 나을 수 있다.다형성 활용하기변하는 것과 변하지 않는 것을 분리하여 추상화하고, OCP를 지키는 구조숨겨져 있는 도메인 개념 도출하기완벽한 설계는 없다. 그 당시의 최선이 있을 뿐.출처https://inf.run/zgJk5 https://inf.run/kHiWM
백엔드
・
워밍업클럽
・
클린코드