블로그

빠타박스

[인프런 워밍업클럽 2기] CS전공지식_발자국_1주차

1. 개요이름: 인프런 워밍업 클럽 2기 - CS 전공지식 빠타박스 [신충식]기간: 2024.09.30 - 2024.10.04  2. 목표 및 성과설정한 목표: 자료구조와 알고리즘, 운영체제에 대한 이해 직접 말하며 학습 및 노션 기록달성한 성과: 대부분 말로 하지 못하는 몇가지 운영체제 및 알고리즘 자료구조에 대한 이해를 할 수 있었다. 3. 잘된 점 (Keep)성공적인 요소: CS 전공지식에 대한 부분을 조금더 말로써 표현할 수 있는 부분 긍정적인 : CS 전공지식 과정이 10월 18일날 종료되는 시점에서 확실히 면접 부분에서 얻어 갈 수 있는 지식 부분들이 있음.4. 개선할 점 (Problem)문제점 : 현재 정보처리기사 실기 시험이 올해 마지막인데. 이 스터디가 좀 빡세다... ; 구현 부분에서 javascript를 C++로 구현해보고 공부해야 하니까..; 일단 넘어가고 다음에 해야 할련지.. 휴.. 너무 힘들다 하면 그냥 보고 넘어갔다가 다음에 시험 끝나고 하는 방식으로 진행해보는 것도 좋을거 같다..개선이 필요한 프로세스 : 기록을 하려다 보니 시간을 너무 많이 잡는다. 또 구현부분에서 C++로 변환하는 과정에서 4시간 이상을 쏟아 붓는다.. 개선되어야 한다..  5. 다음 단계 (Try)향후 계획: 2주차 때는 좀 가볍게 보고 이후 기록을 진행하는 편으로 해야 겠다... 정보처리기사 실기가 더 중요하다 현재로써 나의 우선순위는 그것이다... 다음 2주차에서 시도할 사항: 기록은 가볍게, 구현 부분 가볍게 C++과 비교하기 (다른 사람의 코드)머릿속으로 그림그리기말로 직접 풀이 해보면서 강의해보기 역할 및 책임: 2주차 3주차 까지 마지막 하는 부분 최대한 간단히 하는 부분과 말로 직접 하면서 내것으로 만들 필요가 있을것 같다. 현재로써는.. 정처기 실기를 1트만에 합격해야 하는 의무가 있다..; 내년 까지 또 기다릴 순 없다.. 6. 기타 의견일주일 동안 학습하며이번 1주차에는 자료구조와 알고리즘 기본,LinkedList, DoubleLinkedList, Stack, Queue, Deque, Hash, 운영체제, 프로세스, 스레드, PCB, 컨텍스트스위칭, 인터럽트 등 처음부터 게임회사 취업시 필요한 면접 내용에 대해 간단히 배울 수 있었다.  -> 연결리스트를 통해 계속해서 이어나가는 점에서 인상깊었다. 아 연결리스트로 스택과 큐, 덱, 해쉬에 응용할 수 있구나 ? 라는 것을 알 수 있었다. 확실히 처음 보는 CS전공지식인데. 감자님의 강의는 정말 간단하고 보기 편하다. 1주차 미션에 대해처음 미션을 보고서 간단한 단답형 또는 서술형을 작성 할 수 있게 되어있었다. 배운 내용에 대한 이해를 위해서 말로써 해본 것들이 떠올랐고, 발표하는 느낌으로 진행했다. 가장 어려웠던 알고리즘 구현부분에서 javascript 작성한 것을 최대한 비슷하게 만들기 위해 노력했었다.미션부분에서 인터럽트에 대해 전에 들어본적은 있었으나. 세부적인 내용에 접근하려고 해보았다. 어떤 알고리즘 자료구조를 사용해봐야할지 고민을 했다. 나는 주력 언어가 C++이라서 C++로 최대한 구현하고자 했는데. STL을 활용하여 , vector 및 구조체 사용을 통해 하거나 STL로 기본적으로 구현할 수 있는 queue가 어떤식으로 사용할 수 있는지 접근해보려고 했다. 하지만. STL로 부족한 부분은 활용만 하고 직접 구현해야 하는 부분도 있었는데. 원리 참고만하고 다른사람의 구현목록을 보고 가져와서 사용하려고 했었던거 같다.그리고 Chatgpt, 뤼튼, Gemini를 사용하여 거짓된 정보를 제거하고 정말 간단한 구현에 초점을 맞췄던거 같다 이후 최적화된 구현방법이 무엇인지 풀이해볼려고 했었다.미션을 좀 이렇게 해볼걸...미션을 하면서 조금 조급한 마음이 들었다. 왜냐하면 지금 정처기 준비에 온 신경이 쏟아져있는데.이 스터디 클럽 때문에,,, 사실... 너무 오랜 시간을 쏟고 있었다...다음 주차 부터는 좀 가볍게 해야겠다. 다시 보는 한이 있더라도 중요한 것 먼저 끝내야 겠다. 하지만 미션 풀이하면서 다시한번더 되새김질 하여서 좋았다. 마음이 조급해지는 것만 조금.. 뭔가 미션에 목숨을 걸게 된다..책임감 때문에,,..?흠... 모르겠다...일단 지금 집중해야 할 것을 집중하자...

알고리즘 · 자료구조알고리즘자료구조워밍업클럽2기발자국CS-발자국cs-발자국감자

[워밍업 클럽 2기 - Clean Code & Test Code] 4주차 발자국

워밍업 클럽 2기: Clean Code & Test Code의 4주차 발자국 작성입니다.3주차 발자국 보러가기 📝 학습 내용Presentation Layer 테스트 작성Mock더 나은 테스트를 작성하기 위한 여러 팁REST Docs ✍ 학습 내용 복습Q. Presentation Layer의 특징은?클라이언트로 부터 입력을 받아서 비즈니스 계층으로 해당 요청을 보내는 계층요청을 제일 먼저 받는 계층입력 데이터에 대한 기본적인 검증을 수행한다Presentation 계층에서의 검증과 Business 계층에서의 검증을 분리해서 생각해야 한다Presentation 계층에서는 보통 형식적인 검증을 한다예시: 필수 입력 값 검사, 데이터 타입 검사, null 검사, 빈 문자열 검사Business 계층에서는 비즈니스 로직에 따른 도메인 유효성 검사가 이루어진다Business 계층으로 부터 결과를 받아서 클라이언트로 반환한다컨트롤러에서 사용하는 요청 DTO가 서비스 계층으로 침투하지 못하도록 컨트롤러 계층에서 서비스 전용 DTO로 변환하는 것을 권장한다(상황에 따라 다를 수 있을것 같다. 만약 받는 포맷이 변할 가능성이 거의 없다면, 그냥 컨트롤러의 DTO를 쭉 사용해도 괜찮지 않을까 생각이 된다.)Q. Presentation Layer의 테스트 방법은?Business, Persistence 계층을 모킹해서 테스트한다MockMvc 같은 도구를 사용해서 HTTP요청과 응답을 시뮬레이션 한다모킹을 위해서 Mockito 같은 프레임워크를 사용할 수 있다 Q. Test Double의 종류를 정리해보자면?Dummy: 아루런 동작도 하지 않는 객체. 잘 사용되진 않지만, 보통 파라미터 전달용으로 사용된다.Fake: 실체 객체와 동일한 기능은 수행하지만, 프로덕션 용도로 사용하기에는 적합하지 않은 객체.예시: 인메모리로 맵을 사용해서 가짜 레포지토리를 구현하는 경우Stubs: 테스트에서의 요청에 대해 미리 준비된 결과를 제공하는 객체. 미리 반환할 데이터가 정의되어 있고, 호출하는 경우 해당 데이터를 반환한다. 미리 정의되어 있지 않은 것들은 응답하지 않는다.Spies: Stub이지만 정복 기록도 함께하는 객체. 호출 여부, 호출 횟수 등의 정보를 기록할 수 있다. 일부는 실제 객체 처럼 동작하고, 일부는 Stubbing할 수 있다.Mocks: 행위에 대한 기대를 명세하고, 그 명세에 따라 동작되도록 설계 된 객체. 그러니깐 개발자가 직접 그 객체의 행동을 관리하는 객체이다.Q. Stub과 Mock을 구분하는 기준은?Stub : 상태 검증(State Verification)Mock : 행동 검증(Behavior Verification) TIP. 테스트 작성을 위한 여러 팁을 정리해보면Mockito 프레임워크를 한번 래핑하는 BDD Mockito 프레임워크를 사용해서 조금 더 자연스러운 API 네이밍으로 프레임워크를 사용할 수 있다테스트 간의 독립성을 보장하자 테스트에서 전역 변수를 정의해서 사용하는 것은 권장하지 않는다@BeforeEach또는 @AfterEach 메서드를 사용한 레포지토리 클렌징@Transactional사용 Test Fixture용 클래스를 따로 분리해서 사용하는 것은 권장하지 않는다Test Fixture를 @BeforeEach를 사용한 셋업 메서드에서 사용하는 경우, 중복 제거보다 해당 테스트에 해당 내용을 알아야하는지 고려해보고 적용하자테스트 내용은 동일한데 입력값만 변경해보면서 테스트 해보고 싶으면 @ParameterizedTest 사용private메서드에 대한 테스트가 필요하다면 해당 메서드의 책임을 분리할지 고민해본다단순히 테스트하기 위해서 public으로 열어두는 것은 권장하지 않는다 Q. REST Docs vs Swagger의 차이는?REST Docs테스트를 통과해야 문서가 만들어지기 때문에 신뢰도가 높다프로덕션 코드에 비침투적이다코드의 양이 많고 설정이 상대적으로 어렵다Swagger적용이 쉽다문서에서 바로 API 호출이 가능하다애노테이션을 달아줘야 하기 때문에 프로덕션 코드에 침투적이다🤔 회고워밍업 클럽의 마지막 주차가 되었다. 강의 양이 많아도 내가 정말 필요한 내용을 담아서 만들어져있어서, 시간 가는 줄 모르고 시청했다.강의와 미션을 따라가면서 학습에 많은 도움을 받았다. 만약 워밍업 클럽 3기가 있다면 다시 참가할 예정이다.지금까지 학습 내용을 다시 복습해보고 더 나아가서 프로젝트에 적용하는 것이 목표이다. 🔍 참고Practical Testing: 실용적인 테스트 가이드

백엔드테스트코드워밍업클럽2기백엔드발자국4주차회고

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 발자국 4주차

강의 : Practical Testing: 실용적인 테스트 가이드@Mock객체가 기대하는 행위와 리턴 값을 지정하여 테스트에서 기대하는 동작만 테스트가 가능하다주로 외부 네트워크를 사용하는 객체에 사용하면 좋다 @MockBean스프링 컨테이너에서 사용하기 위한 @Mock 객체@Spy일부는 Mock 객체처럼 동작만 그 이외에는 실제 객체처럼 동작한다내가 지정한 동작을 기대하는 행위, 반환에 대한 mocking 할 수 있다실제로 많이 쓰이지는 않는다@SpyBean스프링 컨테이너에서 사용하기 위한 @Spy 객체@InjectMocksMock, MockBean 객체를 주입 받는 대상 객체에 사용된다ex) OrderService에 UserService, ProductService 주입이 필요한 경우 BDDMockitogiven, when, then 3단계로 테스트 작성이 가능하다Classicist vs Mockist클래스를 직접 사용하여 테스트할지? Classicist 관심사 외엔 다 목킹하여 테스트할지? Mockist정답은 없지만 개인적인 내 생각으로는 객체간의 협력에 따른 결과가어떤 결과가 나올지 예상 불가하기에 최대한 실제 객체를 사용하는 Classicist가 좀 더 좋아보인다뭐가 정답이라기 보다는 관심사에는 Classicist, 관심사가 아닌 부분엔 Mockist을 적절하게 배치하는게 좋아보인다한 문단에 한 주제테스트 또한 문서의 성격을 띄기 때문에 하나의 테스트에 한 가지 기능만 테스트해야 가독성 좋다테스트 환경/테스트간의 독립성 을 보장하자어떤 환경이던, 어떤 순서로 실행하던 반복가능하며, 테스트가 성공으로 떠야 한다테스트 환경 통합테스트 환경을 빠르게 하기 위해서는 ApplicationContext가 띄우는 횟수를 줄여야 한다layer별로 상위 클래스를 만들고 그 상위 클래스를 상속하는 방식으로 ApplicationContext를 재사용하자private 메서드의 테스트?public 함수 호출 시 내부 private 메소드도 호출되기에 따로 작성 필요없다private 메서드의 테스트가 강력하게 필요하다 느끼면 그건 클래스 분리의 신호!! 

백엔드워밍업클럽2기BE클린코드&테스트

Groot

<워밍업 클럽 2기 - 백엔드 클린 코드, 테스트 코드> 4주차 발자국

강의 수강수강한 강의: Practical Testing: 실용적인 테스트 가이드학습 내용 요약Mocking에 관해 배웠다. 여러 stub과 mocking 기법에 관해서 배우며 정리하는 시간을 가졌다.노트 중 일부말고도 private method에 관한 테스트나 Classicist VS. Mockist 부분에서는 어떤 것이 어떤 상황에 어울리는지 등을 배웠다. 회고이번에 Mock과 Stub애 관해 개념을 제대로 잡으면서 잘못하고 있었던 부분들을 점검할 수 있었다.이번 주를 마지막으로 강의를 모두 완강하게 되었는데 테스트 부분은 수강하며 여러모로 반상하게 되는 시간이기도 했다. 왜 테스트를 하는지, 어떤 관점에서 바라보는지가 매우 중요했고 직접 짜는 것을 보며 배우니 추상적인 부분도 코드로 풀어내는 것을 볼 수 있어서 실전 감각을 익히기 좋았다.미션해결 과정Mock, Stub에 관한 어노테이션들을 정리하고 수도코드로 된 테스트 케이스를 직접 어떻게 짤 것인지 제시해보는 미션을 받았다.모든 테스트 케이스 모두 사용자 하나와 게시글이 필요해서 이러한 공통된 부분은 @BeforeAll에 배치했다. 나머지는 늘하던대로 Given, When, Then 형식으로 작성했다. 실제 코드 작성은 없어서 금방 끝났었다.회고Spy를 사용해본적이 아직 없는데 Spy를 사용해서 테스트 코드를 더 짜봐야겠다는 생각이 들었다. 실제 사용 사례를 좀 더 찾아봐야겠다!그리고 뭔가 마지막 미션이 너무 무난해서 제대로 한건지 궁금하다. 다른 사람의 수행한 결과물도 보며 복습해봐야겠다.

백엔드클린코드자바워밍업클럽2기워밍업2기

[워밍업 클럽 2기] Day 18 - 모킹 애노테이션의 종류, 테스트 내용 배치

워밍업 클럽 2기: Clean Code & Test Code의 Day 18 미션입니다. 🎯 미션 11. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다. @MockMockito의 기본 모킹 애너테이션Mock 객체를 만들어 해당 객체의 메서드 호출에 대해 미리 정의된 값을 반환하도록 설정 가능(stub)Mock 객체는 실제 메서드를 호출하지 않고 동작만 시뮬레이션 한다@MockBeanMock 객체를 빈으로 등록합니다. 이는 테스트 대상 클래스가 의존성 주입을 통해 해당 Mock 빈을 받을 수 있도록한다.보통 @SpringBootTest나 @WebMvcTest와 같은 Spring 컨텍스트와 함께 사용되는 경우에 적합하다 @SpyMockito에서 객체의 일부 메서드만 모킹하고 나머지는 실제 메서드를 호출할 수 있다객체의 일부 기능만 변경하여 테스트하고 싶은 경우 사용한다실제 객체가 만들어져서 사용된다doReturn().when.() 사용SpyBean부분 모킹을 위해 스프링 컨텍스트에 등록된 실제 빈을 Spy로 대체한다실제 빈의 일부 메서드만 모킹하고, 나머지는 실제 메서드를 호출하게 할 때 유용하다@InjectMocks테스트 클래스에 정의된 @Mock 또는 @Spy로 선언된 객체를 주입하여, 대상 클래스의 의존성을 자동으로 설정한다  🎯 미션 22. 아래 3개의 테스트가 있습니다. 내용을 살펴보고, 각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치하고 싶으신가요? (@BeforeEach에 올라간 내용은 공통 항목으로 합칠 수 있습니다. ex. 1-1과 2-1을 하나로 합쳐서 @BeforeEach에 배치) As-Is@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when // then - 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then - 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then - 검증 } 다음은 미션을 수행한 To-Be 입니다.To-Be@BeforeEach void setUp() { 1-1. 사용자 생성에 필요한 내용 준비, 2-1. 사용자 생성에 필요한 내용 준비, 3-1. 사용자1 생성에 필요한 내용 준비 3-3. 사용자2 생성에 필요한 내용 준비 1-3. 게시물 생성에 필요한 내용 준비, 2-3. 게시물 생성에 필요한 내용 준비, 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-2. 사용자 생성 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then - 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { // given 2-2. 사용자 생성 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then - 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-2. 사용자1 생성 3-4. 사용자2 생성 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then - 검증 }고려한 내용@BeforeEach()에는 각 테스트에서 반복되지만, 검증하는 대상과는 직접적인 관련이 없는 공통 준비 사항을 처리하려고 했다. 여기서 준비하는 내용은 없어도 각 테스트를 이해할 수 있어야 하고, 각 내용이 변경되어도 각 테스트는 정상적으로 수행될 수 있어야 한다.when에는 각 테스트에서 검증하는 행위만을 배치시켰다  🔍 참고Practical Testing: 실용적인 테스트 가이드

백엔드워밍업클럽2기테스트코드Day18모킹

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 day18 과제

강의 : Practical Testing: 실용적인 테스트 가이드@Mock 객체가 기대하는 행위와 리턴 값을 지정하여 테스트에서 기대하는 동작만 테스트가 가능하다주로 외부 네트워크를 사용하는 객체에 사용하면 좋다 @MockBean스프링 컨테이너에서 사용하기 위한 @Mock 객체@Spy 일부는 Mock 객체처럼 동작만 그 이외에는 실제 객체처럼 동작한다내가 지정한 동작을 기대하는 행위, 반환에 대한 mocking 할 수 있다실제로 많이 쓰이지는 않는다 @SpyBean 스프링 컨테이너에서 사용하기 위한 @Spy 객체@InjectMocksMock, MockBean 객체를 주입 받는 대상 객체에 사용된다ex) OrderService에 UserService, ProductService 주입이 필요한 경우 @MockBean private UserService userService; @MockBean private ProductService productService @InjectMocks private OrderService orderService;각 항목을 @BeforeEach, given절, when절에 배치한다면 어떻게 배치할지?@BeforeEach void setUp() { 사용자 생성에 필요한 내용 준비 게시물 생성에 필요한 내용 준비 댓글 생성에 필요한 내용 준비 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-2. 사용자 생성 1-4. 게시물 생성 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-2. 사용자 생성 2-4. 게시물 생성 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-2. 사용자1 생성 3-4. 사용자2 생성 3-6. 사용자1의 게시물 생성 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }

백엔드워밍업클럽2기클린코드&테스트

[워밍업 클럽 2기] Day 15 - 레이어 별 특징과 테스트 방법

워밍업 클럽 2기: Clean Code & Test Code의 Day 15 미션입니다. 🗄 Persistence(Data Access) 계층특징데이터 소스와의 상호작용을 담당한다데이터를 저장하고, 읽고, 업데이트하고 삭제하는 CRUD 작업을 수행한다데이터 JPA, JPQL, JDBC, 등의 여러 기술이 사용될 수 있다비즈니스 로직이 포함되면 안된다테스트 방법어느 기술을 사용하든, 신뢰성있는 테스트를 위해서 레포지토리의 테스트를 하는 것을 권장한다@SpringBootTest 또는 @DataJpaTest를 사용해서 데이터베이스에 CRUD 작업이 제대로 수행 되는지 테스트 한다@SpringBootTest와 @DataJpaTest의 차이를 알자 🚀 Business 계층특징핵심 비즈니스 로직을 처리하는 계층Persistence(Data Access)와의 상호작용을 통해 비즈니스 로직을 수행한다트랜잭션이 보장되어야 한다읽기 전용 트랜잭션과 CUD 트랜잭션(Command)을 적재적소에 적용하면 좋다트랜잭션의 종류에 따라 추후에 서비스를 나누는 것도 생각할 수 있다테스트 방법Persistence 계층까지 묶어서 통합 테스트를 하는 방식으로 테스트하거나, Persistence 계층을 모킹해서 단위 테스트 방식으로 테스트 한다.테스트 간 격리를 위해서 레포지토리를 초기화하는 로직이 필요하다@BeforeEach, @AfterEach, 등을 사용한 setUp이나 tearDown 메서드를 만들어서 레포지토리를 비운다@Transactional을 사용한다(서비스에 @Transactional이 붙어있지 않아도 동작한다. @Transactional의 효과에 대해 잘 파악하고 있어야 한다.) 💻 Presentation 계층특징클라이언트로 부터 입력을 받아서 비즈니스 계층으로 해당 요청을 보내는 계층요청을 제일 먼저 받는 계층입력 데이터에 대한 기본적인 검증을 수행한다Presentation 계층에서의 검증과 Business 계층에서의 검증을 분리해서 생각해야 한다Presentation 계층에서는 보통 형식적인 검증을 한다(예시: 필수 입력 값 검사, 데이터 타입 검사, null 검사, 빈 문자열 검사, 등...)Business 계층에서는 비즈니스 로직에 따른 도메인 유효성 검사가 이루어진다Business 계층으로 부터 결과를 받아서 클라이언트로 반환한다컨트롤러에서 사용하는 요청 DTO가 서비스 계층으로 침투하지 못하도록 컨트롤러 계층에서 서비스 전용 DTO로 변환하는 것을 권장한다(상황에 따라 다를 수 있을것 같다. 만약 받는 포맷이 변할 가능성이 거의 없다면, 그냥 컨트롤러의 DTO를 쭉 사용해도 괜찮지 않을까 생각이 된다.)테스트 방법Business, Persistence 계층을 모킹해서 테스트한다MockMvc 같은 도구를 사용해서 HTTP요청과 응답을 시뮬레이션 한다모킹을 위해서 Mockito 같은 프레임워크를 사용할 수 있다 🔍 참고Readable Code: 읽기 좋은 코드를 작성하는 사고법

백엔드워밍업클럽2기테스트코드Day15미션

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

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 발자국 3주차

강의 : Practical Testing: 실용적인 테스트 가이드테스트의 필요성잘 만든 테스트로 인하여 신뢰성 있는 소프트웨어를 만들 수 있다잘 만든 테스트로 인하여 과감한 수정 및 리팩토링이 가능하다테스트 코드 자체가 문서가 된다자동화 테스트와 JUnit테스트를 만드는 것 자체도 비용이 들기에 사람이 수동으로 하기 보다는 자동화 테스트가 필요함테스트를 빠르고 여러번 실행 가능하도록 하도록 JUnit이 돕는다 테스트 어려운 영역을 분리테스트는 반복가능하며 항상 성공하는 테스트여야 한다시간, 랜덤 등의 성격의 경우 매개변수로 주입하여서 테스트 힘든 부분을 분리하여 테스트가 가능하다TDD실패하는 테스트를 만든다테스트를 성공 시킨다리팩토링아래의 3단계를 짧은 사이클로 가져가면서 점차적으로 개발이 가능하다DisplayName테스트는 요구사항을 잘 드러내는 문서의 역할도 겸하기 때문에 Display name을 잘 지어야 한다~ 테스트가 아닌 문장으로 끝내며 주어, 목적, 결과가 다 드러나도록 기재해야 한다BDDgiven, when, then 3단계에 나눠거의 : Practical Testing: 실용적인 테스트 가이드 테스트의 필요성잘 만든 테스트로 인하여 신뢰성 있는 소프트웨어를 만들 수 있다잘 만든 테스트로 인하여 과감한 수정 및 리팩토링이 가능하다테스트 코드 자체가 문서가 된다자동화 테스트와 JUnit테스트를 만드는 것 자체도 비용이 들기에 사람이 수동으로 하기 보다는 자동화 테스트가 필요함테스트를 빠르고 여러번 실행 가능하도록 하도록 JUnit이 돕는다테스트 어려운 영역을 분리테스트는 반복가능하며 항상 성공하는 테스트여야 한다시간, 랜덤 등의 성격의 경우 매개변수로 주입하여서 테스트 힘든 부분을 분리하여 테스트가 가능하다TDD실패하는 테스트를 만든다테스트를 성공 시킨다리팩토링아래의 3단계를 짧은 사이클로 가져가면서 점차적으로 개발이 가능하다 DisplayName테스트는 요구사항을 잘 드러내는 문서의 역할도 겸하기 때문에 Display name을 잘 지어야 한다~ 테스트가 아닌 문장으로 끝내며 주어, 목적, 결과가 다 드러나도록 기재해야 한다BDDgiven, when, then 3단계에 나눠서 테스트를 작성하도록 한다given테스트에 필요한 객체 및 데이터를 생성한다when테스트하고자 하는 내용을 실행한다thenassertj 단언문을 이용하여 테스트하고자 하는 내용을 확인한다 

백엔드클린코드테스트워밍업클럽2기

[워밍업 클럽 2기 - Clean Code & Test Code] 3주차 발자국

워밍업 클럽 2기: Clean Code & Test Code의 3주차 발자국 작성입니다.2주차 발자국 보러가기<br>✍ 학습 내용 복습Q. 자동화된 테스트가 필요한 이유는?값을 직접 출력해서 확인하는 수동 테스트는 사람이 개입해서 확인해야 한다. 검증을 사람이 하기 때문에, 값을 확인하는 과정에서 휴먼 에러가 발생할 확률이 높다.자동화된 테스트를 도입하면 검증을 기계에 맡길 수 있기 때문에 사람이 직접 검증하는 것 보다 신뢰할 수 있다.사람이 일일이 확인하는 것보다 빠르다. Q. 단위(Unit) 테스트란?단위 테스트(Unit Test)라는 것은 코드의 가장 작은 기능적 단위를 독립적으로 검증하는 테스트를 일컫는다.여기서 작은 기능적 단위(Unit)는 보통 내가 작성한 클래스 또는 메서드를 의미한다.Q. 테스트할 때 신경 써야하는 부분들은?예외 케이스를 고민한다경계값에 대한 테스트는 중요하다(예시: 범위, 구간, 날짜, 등의 경계값에 대한 테스트) Q. TDD(테스트 주도 개발)란?프로덕션 코드보다 테스트 코드를 먼저 작성해서 테스트가 코드의 구현 과정을 주도하도록 하는 개발 방법론Red, Green, Blue의 3단계 과정으로 이루어진다Red제일 먼저 실패하는 테스트 코드를 작성한다이때 테스트 코드는 컴파일 조차 안돼도 괜찮다Green테스트를 통과하도록 위해 실제(프로덕션) 코드를 작성한다이때 작성하는 코드는 테스트를 통과할 정도로만 최소한의 코드를 작성하도록 한다최대한 빠르게 작성하려고 노력한다Blue코드를 리팩토링한다설계나 구현을 개선한다이때 테스트의 통과 상태는 유지되어야 한다 Q. 좋은 Display Name(테스트 네이밍)은?행위에 대한 결과까지 담는다도메인 용어를 사용한다코드의 단위를 검증하는 것이 아닌 동작(기능)의 단위를 검증하려고 노력한다 🤔 회고중간에 1, 2주차에서 활용했던 StudyCafe 애플리케이션에 대한 단위 테스트를 작성해보는 미션을 수행 했지만, 잘 작성하지 못했던 것 같다.코드를 따라 쳐보면서 학습 해야겠다  🔍 참고Practical Testing: 실용적인 테스트 가이드

백엔드발자국3주차테스트코드워밍업클럽2기백엔드

Groot

<워밍업 클럽 2기 - 백엔드 클린 코드, 테스트 코드> 3주차 발자국

강의 수강수강한 강의s: Readable Code: 읽기 좋은 코드를 작성하는 사고법, Practical Testing: 실용적인 테스트 가이드학습 내용 요약이번주는 클린코드를 완료하고 테스트에 관한 강의로 넘어갔다.Test 필요성, TDD, BDD 등을 배우고 실제 클린코드에서 리팩터링한 코드를 짜보는 시간을 가졌다.회고개인적인 사정(코테, 면접, 스터디, ...)으로 미션 7 이후로 진도 조절에 실패해서 강의자료를 보면서 이해 안 되는 것 위주로 빠르게 수강하고 있다. 뭔가 정신 없이 밤이나 새벽에 하다보니 되게 힘들었다. 오늘 몰아서 진도를 정상화시키고 월요일 과제는 좀 더 여유롭게 할 수 있도록 해야겠다...미션해결 과정스터디카페를 잡고 테스트를 짜보았다. 대충 개념이나 어떻게 짜면 되는지는 이해가 됐는데 막상 시작하려니깐 되게 막막했다. 일단 특수한 모델 객체부터 검증해나가며 테스트를 점진적으로 추가해가다 보니 풀리기 시작했다.하다가 내가 원한 모든 테스트케이스를 완성하지는 못했다. 외부에 의존하는 사이드 이펙트를 다루는게 좀 어려웠다. Scanner나 이상한 데이터를 주입했을 때도 테스트하고 싶었는데 실패했다.회고Scanner 같은 부분을 테스트하려고 하는데 stdin까지 원하는대로 컨트롤하려니깐 이상했다. 외부에 의존하는 부분을 만들려다 그 코드가 엄청 길어지니깐 굳이 Class를 직접 갖다 않고 Mock으로 원하는 방향으로 만들어 주는게 자연스러워보이기 시작했다.한번 Application, PassMachine 코드를 Mock으로 외부 디펜던시를 만들고 검증해보려했는데 한참 삽질하다가 실패했다. 마침 아직 못 본 섹션 7의 Mock이다. 얼른 섹션 7을 수강하고 내가 생각하는 방향이 맞는 점검해보고 다시 시도해볼 예정이다!

백엔드클린코드워밍업클럽2기자바워밍업2기

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 발자국 2주차

강의 : Readable Code: 읽기 좋은 코드를 작성하는 사고법섹션 6 코드 다듬기주석의 양면성코드는 유지보수 되나 주석은 유지보수 되지 않는다코드의 설명을 위한 주석은 좋지 않다주석을 사용한다면 코드로 파악이 힘든 내용들을 담도록 하자히스토리 파악이 힘든 코드에 대한 히스토리 설명패키지 나누기의미있는 단위로 패키지를 나누자 섹션 7 리팩토링 연습코드 레벨에서의 추상화가 아닌 도메인을 잘 이해하여 높은 레벨로 추상화하여 가독성을 높이자  ex) 고정석이 아니면 return 관점을 고정석이 아닌 경우라 생각하면 doesNotFixed라 메소드 이름을 짓게 된다고정석이 아니라는 건 락커를 사용할 수 없다는 의미로 더 높은 추상화 레벨로 메소드 이름을 지으면 canNotUserLocker로 메소드 이름을 지을 수 있다클래스명에 대한 추상화 ex) 파일을 읽어 어떠한 정보를 가져오는 클래스클라이언트 입장에선 어떤 정보를 가져오는지에 대한 관심만 있음정보를 가져오는 수단에 대한 관심을 지우고 어떠한 정보를 가져올지에 포커스를 맞추다~Provider, ~Generator 등의 이름을 활용하도록 하자더 좋은 네이밍은 스프링에서 찾아보도록 하자 섹션 8 기억하면 좋은 조언들객체지향이 무조건 좋은 건 아니다과한 객체 지향은 오버엔지니어링이 될 수 있고 가독성을 해친다요구사항에 따라 절차적 프로그래밍이 어울릴 수 있고 객체지향 프로그래밍이 어울릴 수 있다내가 짠 코드에 근거를 가지고 상황에 맞게 리팩토링 기법이나 객체 지향을 잘 적용하도록 하자 

백엔드워밍업클럽2기BE클린코드&테스트

[워밍업 클럽 2기 - Clean Code & Test Code] 2주차 발자국

워밍업 클럽 2기: Clean Code & Test Code의 2주차 발자국 작성입니다.1주차 발자국 보러가기 ✍ 학습 내용 복습이전의 클린 코드에 대해 학습한 내용을 직접 코드에 적용해서 리팩토링하는 시간을 가졌습니다.메서드 추출 시 고려할 점중복 제거무조건적인 중복 제거 보다는 상황에 맞춰서(어설픈 중복 제거 보다는 사람들이 이해하기 쉬운 코드가 더 좋음!)주변의 추상화 레벨과 동떨어져 있는지 항상 확인 객체의 책임 파악 시 고려할 점책임은 상황에 따라서 변할 수 있음예시특정 주문의 할인 금액과 총 가격을 출력하는 기능이 있다고 가정하자. 할인 금액과 총 가격이 단순히 출력 용도로만 사용된다면 해당 가격 계산을 출력을 담당하는 클래스에서 정의할 수 있겠지만, 보통은 추후에 다른 곳에서도 사용될 가능성이 있기 때문에 주문 클래스의 책임으로 만드는 것이 더 좋은 설계일 가능성이 높다(물론 이것은 상황에 따라 언제든지 변할 수 있다) 🤔 회고처음부터 내가 설계한 코드를 리팩토링 하는 것과 남의 코드를 리팩토링 하는 것은 굉장히 다르다는 것을 체감했다남의 코드 리팩토링 하는 것이 더 어렵다 😭그냥 강의만 듣고 넘어가는 것 보다, 코드를 작성하고 강사님의 코드와 비교하는 것이 학습에 훨씬 도움이 된다!🔍 참고Readable Code: 읽기 좋은 코드를 작성하는 사고법

백엔드워밍업클럽2기백엔드클린코드-테스트코드발자국2주차

99ekdus

워밍업 클럽 2기 BE 클린코드 & 테스트코드 🐾1주차 발자국

 📃 학습 내용 요약학습 내용추상과 구체 좋은 추상화란 해당 도메인의 문맥 안에서 중요한 핵심만 남겨서 표현하는 것이다.추상화의 핵심은 '이름 짓기'!잘 쓰여진 코드의 메서드는 오직 하나의 주제만 갖고 있다.코드를 작성할 때, 동등한 추상화 레벨로 맞추는 것이 좋다.논리, 사고의 흐름 뇌의 메모리에 적은 정보를 올리도록 코드를 작성하자.Early return을 통해 else의 사용을 지양하자.중첩된 분기문, 중첩된 반복문에서 메서드를 추출해 사고의 depth를 줄여보자.공백 라인을 통해 상대방이 이해해줬으면 하는 단락이 무엇인지 강조하기객체 지향 패러다임SOLID  ✏ 회고Liked (좋았던 점) : 추상화의 개념, 추상과 구체의 관계를 명확히 이해하게 되었고, 코드를 작성에 대한 자신감이 생겼습니다.Lacked (아쉬웠던 점) : 다른 분들의 코드를 읽으면서 느낀 건데, Day 4 미션에서 리팩토링을 할 때, 추상화 레벨을 동등하게 맞추지 않은 것이 아쉬움이 남습니다..!Learned (배운 점) : 추상화의 의미를 다시 한번 깨달았습니다! 추상화는 단순히 코드를 짧게 만드는 것이 아니라, 개발자가 더 효율적으로 코드를 작성하고 유지 보수할 수 있도록 돕는 중요한 역할을 한다는 것을 알게 되었습니다.  📌 Day 2 미션추상 : 아이유 콘서트 티켓팅을 한다.구체 :제일 먼저 티켓팅을 하기 전에 콘서트 정보를 확인하고, 가고 싶은 날짜와 좋은 좌석을 미리 정한다. 티켓팅 날, 컴퓨터 또는 스마트폰을 준비해서 원하는 웹 브라우저에 접속해 멜론 티켓 홈페이지에 들어가 로그인을 한다.아이유 콘서트 예매 페이지에 들어가 정각이 될 때까지 긴장을 풀며 기다린다.정확한 시간에 예매 버튼을 클릭하고, 본인의 예매 대기 순서를 기다린 다음에 날짜를 선택한다.좌석을 선택하고, 티켓 가격과 할인 수단 확인 후 마지막으로 결제를 한다.마이페이지에 들어가 예매 내역을 확인한다.두근거리는 마음으로 콘서트 날까지 기다린다.😄 추상 : 아이유 콘서트를 봤다.구체 :신나게 즐기기 위해 체력 단련을 하고, 아이유 노래의 응원법을 외운다.콘서트 당일 날 보조배터리와 물, 간식 등을 챙겨서 편한 옷을 입고 집을 나선다.목적지인 상암월드컵경기장까지 지하철을 타고 간다.여유 있게 콘서트 시작 2~3시간 전에 도착해 티켓 부스에 가서 티켓을 수령하고, 아이유 응원봉인 아이크를 구매한다.공연장 주변에서 시간을 보내다가, 콘서트 시작 시간에 맞춰 들어간다.아이유 콘서트가 시작되는 순간부터 끝날 때까지 현장의 열기를 느끼며, 행복한 시간을 만끽한다.새로운 추억을 간직하며, 다음 콘서트를 기대한다.  📌 Day 4 미션public boolean validateOrder (Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } if (order.getTotalPrice() <= 0) { log.info("올바르지 않은 총 가격입니다."); return false; } return true; }불필요한 if (order.getTotalPrice() > 0) 조건을 제거했다.주문 항목이 없거나 총 주문 가격이 0보다 작은 경우 false를 반환하고 있으므로, 추가적으로 검사할 필요가 없다.else연산을 지양하기 위해서 각 if문에서 false 를 일찍 return 한다.!(order.getTotalPrice() > 0) 에서 부정 연산자(!)를 없애고, order.getTotalPrice() <= 0 으로 변경하여 코드의 가독성을 높였다. 단일 책임의 원칙 SRP (Single Responsibility Principle)한 클래스는 하나의 책임만 가져야 한다. 한 사람이 여러 가지 일을 동시에 해서 효율성이 떨어지는 것보다 여러 사람이 각자 맡은 일에 최선을 다하는 게 더 좋다. 레스토랑에서 주문 받는 사람, 요리 하는 사람, 계산 하는 사람 따로 있듯이 클래스도 각자의 역할에 집중해야 코드가 복잡해지지 않고 유지 보수 하기 쉽다.개방-폐쇄 원칙 OCP (Open-Closed Principle)확장에는 열려 있지만, 수정에는 닫혀 있어야 한다. 새로운 기능을 추가할 때 기존 코드를 수정하지 않고 새로운 코드를 추가하여 시스템을 확장하는 것이다.리스코프 치환 원칙 LSP (Liskov Substitution Principle)자식 클래스는 언제든지 부모 클래스를 대체할 수 있어야 한다. 자식 클래스는 부모 클래스가 사용되는 모든 곳에서 사용될 수 있어야 한다.인터페이스 분리 원칙 ISP (Interface Segregation Principle)하나의 거대한 인터페이스보다는 여러 개의 작은, 특정한 클라이언트를 위한 인터페이스를 사용해야 한다. 레스토랑 메뉴판에서 너무 많은 메뉴를 한꺼번에 보여주는 것보다 종류별로 메뉴를 분리하여 보여주는 것이 고객들이 원하는 음식을 쉽게 찾을 수 있어 편하다. 인터페이스도 특정 기능에 맞게 분리해야 클라이언트가 필요한 기능만 사용할 수 있다.의존성 역전 원칙 DIP (Dependency Inversion Principle)고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화된 인터페이스에 의존해야 한다. 레스토랑에서 요리를 할 때, 특정 브랜드의 재료만 의존하지 않게 해야 한다. 하나의 브랜드만 사용하지 않고, 다양한 브랜드의 재료를 사용함으로써 맛을 더 업그레이드 시킬 수 있다. 

워밍업클럽2기

Groot

<워밍업 클럽 2기 - 백엔드 클린 코드, 테스트 코드> 1주차 발자국

강의 수강수강한 강의: Readable Code: 읽기 좋은 코드를 작성하는 사고법학습 내용 요약이번주는 가볍게 추상, 인지 부하를 줄여주는 코드 작성법, SOLID 위주로 공부했다.회고이번주는 익숙한 내용이 많아서 쭉쭉 진도를 나갈 수 있었다. 뒤에 가면 어렵지 않을까?역시 매주 미션이 주어지니 목표가 있어서 훨씬 의욕적으로 수강하게 되는 것 같다.계속 인프런 사이트에 접속하다보니 예전에 할인하길래 사두고 방치한 강의도 다시 보게 된다. 문득 이렇게 여유로운 날에 모두 공부해봐야 겠다는 생각이 든다. ㅎㅎ인프런의 노트 기능을 처음 써봤는데 내용을 상기하기 좋았다. 이미지도 첨부되어서 그냥 아무 맥락 없이 내 개인 노트에 남기기 보다 노트 기능으로 남겨두니 더 맥락있게 볼 수 있어서 좋았다. 앞으로도 활용해볼 것 같다.미션해결 과정이번주는 간단한 미션이라 큰 무리없이 진행할 수 있었다.회고간단한 코드도 직접 고쳐보고 내용을 적용해볼 수 있어서 좋았다. 원칙들을 내 언어로 풀이하는 것도 재밌었고 이해도를 높여주는 것 같다.앞으로도 아직 나에게 생소한 원칙/개념이 있다면 나만에 언어로 풀이해보면 좋을 것 같다. 

백엔드클린코드워밍업클럽2기자바

[워밍업 클럽 2기 - Clean Code & Test Code] 1주차 발자국

워밍업 클럽 2기: Clean Code & Test Code의 1주차 발자국 작성입니다. ✍ 학습 내용 복습 Q. 클린 코드를 작성하는 이유?미래의 나, 미래의 동료가 더러운 코드로 인해 고통 받지 않도록 하기 위해서 클린 코드를 작성한다.코드를 작성하는 순간부터 그 코드는 사실상 기술 부채를 가지게 된다. 기술 부채를 최대한 줄이기 위해서 클린 코드를 작성한다. Q. 클린 코드를 작성하기 위해서 사용하는 가장 핵심적인 개념은?추상화라고 생각한다. 추상화의 본질은 핵심 개념만 드러내고, 불필요한 정보는 감추는 것이다.추상화 레벨이 높아질수록 더 함축적인 개념을 다루고, 낮아질수록 구체적인 동작과 세부 구현에 집중한다.추상화 레벨이 높아지면 높아질수록 정보의 함축 수준이 높아지고 이해하기 쉬워진다. 그렇다고 너무 함축시키면 실제 구체(정보)의 재현이 어렵기 때문에 적절한 추상화가 필요하다. Q. 적절한 추상화란?적절한 추상화란 해당 도메인 내에서 핵심적인 부분만 드러내면서 구체적인 구현은 필요에 따라 숨기는 것이다핵심적인 부분과 불필요한 정보의 구분은 문맥에 따라 언제든지 달라질 수 있다도메인을 파악하는 것이 중요하다 Q. 효과적인 네이밍은?네이밍(이름짓기)을 통해서 의도를 드러낼 수 있다. 높은 추상화 레벨에서는 세부 사항을 숨기고, 큰 개념을 드러내는 네이밍을 사용한다. 낮은 추상화 레벨에서는 더 구체적인 동작을 설명하는 이름을 사용한다.대부분의 경우 내부로 들어갈수록 추상화 레벨이 낮아진다주변 코드와의 추상화 레벨이 동떨어져 있는지 지속적으로 확인하는 것이 좋다 Q. 가독성이 좋은 코드는?가독성이 좋은 코드는 불필요한 정보를 덜 인지 해도 되면서 이해하기 수월한 코드라고 생각한다. Q. 가독성이 좋은 코드를 작성하는 방법들은?early return 사용하기이중 반복문, 분기문의 depth를 줄일 수 있는지 고민하기부정어 표현 !을 제거할 수 있는 방법이 있는지 고민하기 Q. 객체란?캡슐화비공개 데이터(필드), 비공개 로직(프라이빗 메서드)을 가질 수 있다공개 메서드를 통해서 외부와 소통한다객체 간 상호작용(협력)을 한다하나의 객체로 관심사가 모이기 때문에 유지보수하기 쉬워진다 Tip. 객체 사용시 주의점하나의 관심사를 가지는지 확인하자웬만하면 setter의 사용을 자제하고, 값의 변경은 updateXxx, addXxx 같은 명확한 네이밍을 사용하자 Q. SOLID(객체 지향 설계의 5개 원칙)는 무엇인가?https://www.inflearn.com/blogs/8391 에 정리 Q. 상속 보다 조합을 권장하는 이유는?상속 관계에서 자식과 부모간의 결합은 매우 강하다. 이는 부모 클래스의 변경은 자식 클래스에도 영향을 준다는 의미이다. 변경의 가능성이 매우 적고, 상위 클래스의 활용이 필요한 경우가 아니라면 조합과 인터페이스의 사용이 훨씬 유연한 구조를 제공한다 🤔 회고코드를 같이 따라치면서 학습하는 것이 더 효율적일 것 같다. 주말 동안 코드도 같이 따라 치면서 복습할 생각이다.토이 프로젝트에 배운 내용을 직접 적용해보면서 학습할 예정이다. 참고Readable Code: 읽기 좋은 코드를 작성하는 사고법

백엔드워밍업클럽2기백엔드클린코드-테스트코드발자국1주차

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 발자국 1주차

강의 : Readable Code: 읽기 좋은 코드를 작성하는 사고법섹션 2 추상추상화를 코드 레벨에서 어떻게 풀어내는지? 이름 짓기가장 쉬운 추상화 방법이면서 가장 중요하다고 생각한다이름 하나만 잘 짓고 하나의 주제 단위로 메소드 추출만 잘 해도 가독성 좋은 코드가 된다메소드메소드명이 추상화에 중요한 건 알았지만 리턴타입, 파라메터, 파라메터 순서까지 신경쓰지는 않았었다리턴타입, 파라메터의 변수명을 활용하여 가독성 좋은 코드를 어떻게 만드는지 알 수 있었다 섹션 3 논리, 사고의 흐름가독성 좋은 코드를 위해서 사용할 수 있는 여러 기법들을 소개한다early return복잡한 분기가 있을 경우 공백 라인의미 단위로 공백 라인을 사용하면 가독성에 도움을 준다부정어에 대한 자세부정어를 긍정어로 바꿀 수 있다면 변경이름에서 부정을 나타내도록 변경메소드 내에서 같은 레벨로 추상화재사용성은 떨어지더라도 메소드 추출하여 하나의 메소드에서 같은 레벨로 추상화섹션 4 객체지향 패러다임SOLID를 코드 레벨에서 어떻게 구현할 수 있는지?SRP클래스가 변경될 이유는 단 하나다!!클래스 설계 시, 하나의 관심사로 응집하여 구현하도록 하자OCP기존 코드의 변경 없이, 기능 추가하도록 설계가 되어야 한다 다형성을 이용하여 클라이언트 코드의 변경 없이 구현체를 쉽게 변경이 가능하다LSP부모 클래스에서 정의한 스펙을 자식 클래스에서도 지켜야 한다instance of로 타입 체크하여 특정 타입에 대해서만 처리가 필요하다는 건 LSP를 위반한 사례이다!!ISPSRP와 비슷하게 인터페이스 또한 한 가지 책임을 가지도록 분리를 잘해야 한다DIP클래스 참조 시, 추상화 레벨이 높은 인터페이스, 추상클래스, 상위 클래스를 참조하도록 하자코드에 구현체가 드러나게 되면 기능 변경시, 클라이언트 코드의 변경이 생기므로추상화 레벨이 높은 인터페이스 등을 메소드 파라메터, 필드, 리턴타입으로 활용하도록 하자

백엔드워밍업클럽2기BE클린코드&테스트발자국

[워밍업 클럽 2기] Day4 - 논리, 사고의 흐름 & SOLID

워밍업 클럽 2기 [Clean Code & Test Code](https://www.inflearn.com/roadmaps/5699) 로드맵의 Day4 미션입니다. 1. 코드 리팩토링As-Ispublic boolean validateOrder(Order order) { if (order.getItems().size() == 0) { log.info("주문 항목이 없습니다."); return false; } else { if (order.getTotalPrice() > 0) { if (!order.hasCustomerInfo()) { log.info("사용자 정보가 없습니다."); return false; } else { return true; } } else if (!(order.getTotalPrice() > 0)) { log.info("올바르지 않은 총 가격입니다."); return false; } } return true; } To-Bepublic boolean validateOrder(Order order) { if (order.itemsIsEmpty()) { log.info("주문 항목이 없습니다."); return false; } if (order.customerInfoIsEmpty()) { log.info("사용자 정보가 없습니다."); return false; } if (order.totalPriceIsNegative()) { log.info("올바르지 않은 총 가격입니다."); return false; } return true; }고려한 내용!를 쓰지 않고 부정어구를 사용해서 처리일찍 return할 수 있는 부분은 return을 해서 이전 내용을 신경 쓰지 않아도 된다else 지양분기문 중첩 depth 줄이기 2. SOLID(객체 지향의 5대 원칙)SRP(단일 책임)SRP는 하나의 클래스 또는 모듈은 하나의 책임을 가져야 한다는 원칙이다. Q. 그럼 책임이라는 것은 무엇일까? 여기서 책임은 "변경의 이유"라고 표현할 수 있다. 만약 하나의 클래스가 여러 가지 이유로 변경되어야 한다면, 그 클래스는 여러 가지 책임을 가지고 있다는 뜻이다. 이렇게 여러가지 책임이 하나의 클래스에 존재한다면, 추후에 유지보수하기 어려워질 가능성이 높다. Q. 그러면 책임의 범위를 어떻게 정하는 것이 좋을까?책임의 범위라는 것은 문맥과 상황에 따라 다를 수 있다. 이런 책임의 범위를 잘 정하는 것은 경험적인 영역이 많이 포함된다. (한마디로 책임을 보는 눈을 기르기 위해서는 경험을 많이 쌓자!)확실한 것은 어떤 변경이 있을 때 파급 효과가 적다면 SRP를 잘 따른 것으로 볼 수 있다. 정리하자면 SRP는 변경의 이유를 하나로 만들어서 코드의 응집성을 높이고, 결합도를 낮추면서 유지보수성을 개선하는 것 이다. 이때 책임(변경의 이유)의 범위를 잘 정할수 있는 능력을 기르는 것이 중요하다. OCP(개방 폐쇄)OCP는 소프트웨어가 확장에는 열려있고, 변경에는 닫혀 있어야 한다는 원칙이다. 쉽게 말해서, 새로운 기능이나 요소를 추가할 때 기존의 코드 변경 없이 추가가 가능해야 한다. Q. OCP는 어떻게 구현할까?인터페이스를 구현한 새로운 클래스를 만들어서 새로운 기능을 구현하거나 추가하는 다형성을 활용해서 구현한다. 조금더 자세히 설명하자면, 구현체가 아닌 인터페이스를 의존하도록 하고, 단순히 구현체를 변경하는 방식으로 기능의 변경이 가능하도록 설계하는 것이다. LSP(리스코프 치환)LSP는 프로그램의 객체는 프로그램을 깨트리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다는 원칙이다. 쉽게 말해서 상속 관계에서 자식 클래스의 객체가 부모 클래스의 객체를 완전히 대체해도 정상적으로 동작해야 한다는 의미다. ISP(인터페이스 분리)ISP는 클라이언트는 자신이 사용하지 않는 인터페이스(메서드)에 의존하면 안된다는 원칙이다. 쉽게 말해서, 인터페이스를 명확한 기준을 가지고 더 작은 인터페이스로 분리하자는 원칙이다. Q. 사용하지 않는 인터페이스에 의존하지 말자는 것이 무슨 의미인가?인터페이스가 너무 광범위하면 인터페이스를 구현하는 클래스들이 사용하지도 않을 메서드를 오버라이딩 해야하는 상황이 발생한다. 이를 방지하기 위해서, 명확한 기준을 가지고 인터페이스를 더 작게 분리하자는 것이 ISP 원칙이다. 불필요한 메서드 오버라이딩 외에도, 변경으로 인한 파급 효과를 줄이기 위해서 ISP를 적용할 수 있다.쉽게 말해서, 특정 클라이언트를 위한 인터페이스(좁은 범위의 책임을 가지는 인터페이스) 여러개가 범용적인 인터페이스 하나보다 낫다는 것이다. DIP(의존 관계 역전)DIP는 구체화에 의존하면 안되고, 추상화에 의존해야 한다는 원칙이다. 더 자세히 말하자면 고수준 모듈과 저수준 모듈 모두 추상화에 의존해야 한다는 뜻이다. 쉽게 말해서, 구현 클래스에 의존하지 말고 인터페이스에 의존하라는 뜻이다. Q. 구체적인 요소의 의존을 피하는 이유는?구체적이라는 것은 변동 가능성이 높다는 것이다. 저수준 모듈의 변경 사항이 있을 때 마다 해당 모듈을 사용하는 모듈도 변경이 필요할 가능성이 높아진다. 반면에, 추상화에 의존하게 되면 저수준 모듈이 변경되어도, 고수준의 모듈에는 영향이 가지 않는다(의존 관계의 역전). DIP는 DI(의존성 주입)과 IoC(제어의 역전)이라는 개념과 자주 다루어진다. IoC(제어의 역전)IoC는 프로그래머가 작성한 코드가 프레임워크의 제어를 받게 되는 패턴을 이야기 한다. 전통적인 프로그램에서의 흐름은 프로그래머가 작성한 프로그램이 라이브러리의 코드를 호출해 이용한다. 하지만 제어의 역전이 적용된 구조에서는 프레임워크의 코드가 프로그래머가 작성한 코드를 호출한다.DI(의존성 주입)DI는 클라이언트의 생성에 대한 의존성을 클라이언트의 행위로부터 분리하는 것이다. 쉽게 말해서, 필요한 의존성을 외부로 주입을 받는 것이라고 생각하면 된다. 의존성이라는 것은 동작하기 위해 필요한 클래스 또는 객체이다. Q. 그러면 주입(의존 관계 연결)은 누가 해주는 것인가?주입 받는 쪽이나 주입하는 의존성이 아닌 제 3자가 해준다. 이를 보통 IoC 컨테이너, DI 컨테이너, 등의 표현을 사용한다.스프링을 예시로 들자면, ApplicationContext가 이를 해준다.  

백엔드ReadableCode워밍업클럽2기Day4

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 day4 과제

Readable Code: 읽기 좋은 코드를 작성하는 사고법(링크)아래 내용은 위의 인프런 강의를 들으면서 과제 및 내용을 정리해봤습니다. 아래 코드 리팩토링 하기public boolean validateOrder(Order order){ if(order.getItems().size() == 0){ log.info("주문 항목이 없습니다"); }else{ if(order.getTotalPrice() > 0){ if(!order.hasCustomerInfo()){ log.info("사용자 정보가 없습니다"); return false; }else{ return true; } }else if(!(order.getTotalPrice() > 0)){ log.info("올바르지 않은 총 가격입니다"); return false; } } return true; }본 코드의 문제는 아래와 같다if, else if, else 그리고 중접 if 등으로 인하여 주문의 유효성 조건이 한 눈에 들어오지 않는다=> early return을 사용해보자 무분별한 getter의 사용(if(order.getItems().size() == 0))=> 주문에 담긴 상품이 있는지 확인하는 내용인데 굳이 getter를 써야할까?=> 오히려 order에 item 항목이 있다고 세부 내용을 노출해버리고 있다=> 의미있는 이름의 메소드를 order에서 그 역할을 책임하도록 해보자 부정어의 사용 if(order.hasCustomerInfo()) / !(order.getTotalPrice() > 0)=> 부정어를 사용하면 코드의 가독성을 해친다 => 1순위 긍정어를 사용하여 메소드 만들 수 있는지 확인=> 2순위 긍정어를 사용할 수 없다면 메소드명으로 부정을 나타내서 만들어보자 위의 내용을 고려한 최종 코드는 아래와 같다public boolean validateOrder(Order order){ if(order.isEmptyOrderItem()){ log.info("주문 항목이 없습니다"); return false; } if(order.isLessThanOrEqualToZero()){ log.info("올바르지 않은 총 가격입니다"); return false; } if(order.isEmptyCustomerInfo()){ log.info("사용자 정보가 없습니다"); return false; } return true; }public class Order{ private List<Item> items; public boolean isEmptyOrderItem(){ return order.getItems().size() == 0; } public boolean isLessThanOrEqualToZero(){ return order.getTotalPrice() <= 0 }; public boolean isEmptyCustomerInfo(){ return !hasCustomerInfo(); } public double getTotalPrice(){...} public boolean hasCustomerInfo(){...} }SOLID에 대하여 자기만의 언어로 정리SRP클래스가 변경될 이유는 단 하나다!!클래스 설계 시, 하나의 관심사로 응집하여 구현하도록 하자OCP기존 코드의 변경 없이, 기능 추가하도록 설계가 되어야 한다 다형성을 이용하여 클라이언트 코드의 변경 없이 구현체를 쉽게 변경이 가능하다LSP부모 클래스에서 정의한 스펙을 자식 클래스에서도 지켜야 한다instance of로 타입 체크하여 특정 타입에 대해서만 처리가 필요하다는 건 LSP를 위반한 사례이다!!ISPSRP와 비슷하게 인터페이스 또한 한 가지 책임을 가지도록 분리를 잘해야 한다DIP클래스 참조 시, 추상화 레벨이 높은 인터페이스, 추상클래스, 상위 클래스를 참조하도록 하자코드에 구현체가 드러나게 되면 기능 변경시, 클라이언트 코드의 변경이 생기므로추상화 레벨이 높은 인터페이스 등을 메소드 파라메터, 필드, 리턴타입으로 활용하도록 하자

백엔드ReadableCode워밍업클럽2기

채널톡 아이콘