블로그
전체 12#카테고리
- 백엔드
#태그
- 워밍업클럽
- 백엔드
- 박우빈
- 클린코드
- 테스트코드
- MVC
- 테스트
- backend
- 객체지향
- 인프런
- 워밍업클럽4기백엔드
- ReadableCode
- CleanCode
- Backend
- 인프런워밍업클럽
- 스터티
- 스터디
- 최태현
- 자바와스프링부트로생애최초서버만들기
- SpringBoot
2025. 06. 21.
3
[워밍업 클럽 4기 - 백엔드] 마지막 발자국
마지막 회고[Day 16] Presentation Layer(2)여섯 번째 섹션 중에서 제일 재밌게 학습한 날이 아닌가 싶다. 백엔드 개발자가 아니다보니 혼자 간단한 프로젝트를 만들어보고자.. 챗GPT를 스승삼아 개발했었는데 챗GPT가 항상 그렇듯 한 번에 완벽한 대답을 내주진 않는다. 챗 GPT가 HTTP 응답 메세지를 구조화하라고 알려줬지만, 정확한 답변은 주지 못한 상태에서 혼자 이것저것 찾아보다가 흉내만 내도록 구현했던 것 같은데 이번 챕터에서 ApiResponse를 마주하다니! 뜻밖의 이득이었다. 또한 Exception 처리도 @ControllerAdvice도 나름 혼자 사용해봤는데 만족할만한 결과물이 나오지 않았다. 사실 어떻게 하는지 개념이 잡히지가 않고, 눈으로 관련 코드를 본 적도 없어서 제대로 잘 적용할 수가 없었는데 이번 강의가 마치 나에게는 완벽한 정답처럼 다가왔다. 그래서 이번 강의는 엄청나게 눈을 반짝이면서 봤다.그 외에 제일 기억에 남았던 건 spring-validation이다. Reqeust Dto에서는 해당 필드의 타입이 유효한 값인가를 검증하게하고, 그 외에 도메인과 관련된 유효성 검사들은 좀 더 안쪽 내부에서 진행해야 된다, 즉 책임을 분리해야 한다는 지식이었다. [Day 17] Mock을 마주하는 자세Mock을 처음 접해봤는데 제대로 된 개념이 잡혀있지 않아 Mock과 Stub을 정확히 구분하고, 언제 써야하고, 어떻게 써야하는지 감이 잡히지 않았다. 조금 더 공부해봐야할 것 같은 주제다.그리고 Classicist와 Mockist 얘기를 듣고 나도 내 기준을 생각해 봤는데 Classicist가 맞는 것 같다고 결론을 내렸다. 완벽한 프로그램은 없는 것처럼 완벽한 Mocking도 없을 것이다. 그래서 Mocking 위주로 대부분의 테스트로 짠 프로그램이 진짜 객체를 마주했을때 과연 완벽하게 동작할 수 있을 것인가?를 생각해보면 아닐 확률이 더 크다고 생각한다.아무튼 Mock에 대한 건 좀 더 공부해보자. [Day 18] 더 나은 테스트를 작성하기 위한 구체적 조언되게 많은 주제들을 짤막하게 다루었다. 집중력이 그리 좋지 않은 나로서는 좋은 챕터였다. 그리고 꿀팁과 실무적인 관점을 배울 수 있었다. 이번 강의 전에 테스트 코드를 직접 짜보는 미션을 진행했었는데 직접 코드를 짰었을때 어려운 부분이나 '이게 맞나' 싶은 부분을 긁어주는 강의었다. 여러 개의 타입을 가진 Enum에 관련된 테스트를 진행했는데 한 가지 타입만 테스트하면 안 될 것 같아서.. 타입 검사하는 한 테스트에 모든 타입에 대한 given, when, then을 적었었는데 @ParameterizedTest라는 좋은,, 방법이 있어서 다음에는 고민만 하지말고 더 나은 대안을 찾을 수 있도록 구글에 한 번 검색해보자고 생각했다. 약간 부끄 [Day 19] 학습 테스트 | REST Docs테스트를 학습용으로 쓰다니! 내 입장에서는 놀라운 발상이었다. 앞으로 궁금한 라이브러리들은 마음놓고 테스트하면서 공부할 수 있게 됐다!REST Docs는 처음해봤다. 예전에 한 번 써본건 Swagger였는데 Swagger 쓰다가 REST Docs를 쓰니까 약간 어색하면서, UI가 뭔가 부족한거같으면서, 어렵다는 느낌을 받았다. 그래도 Swagger는 프로덕션 코드에 직접적으로 추가해줘야하는 코드들이 많았던 걸로 기억하는데 REST Docs는 테스트 코드 기반으로 만들어진다니 더 깔끔한 관리가 될 것 같다고 생각했따. [Day 20] 중간 점검마지막 중간 점검이다! 너무 아쉬워. 테스트 코드를 본격적으로 공부해본게 처음이라서 혹시나 내 질문이 이상한 질문일까봐, 너무 쉬울까봐 하지 말까했는데 내가 올리기 전까지 아무도 질문을 안올려서 나라도 일단 냅다 올리자 하고 올렸다. 용기내서 올린 질문은 나에게 100배의 좋은 지식으로 돌아왔다. 다음에는 더 용기가 생긴다면 코드 리뷰도 한 번 받아보고 싶다고 생각했다.다른 분들의 코드리뷰를 보면서 도대체 어떻게 저렇게 생각하고 저렇게 구현하지?라는 생각을 많이했다. 나도 우리 회사에서 나름 잘하는 사람 중에 하난데 여기 오니까 우물 안 개구리라 생각됐다. 더 많이 공부하고 나보다 더 잘난 사람들을 많이 접해야 내가 성장하는 것 같다. 마지막 회고워밍업 클럽은 되게 충동적으로 신청했다. 0기를 수료했었는데도 신청한 이유는 0기와는 전혀 다른 주제여서 뭔가싶어 쓰윽 봤는데 여태 한번도 배우지 않았던 주제지만 궁금은 했었던 주제여서 할인 코드도 주는 김에 신청했던 것 같다. 되게 가벼운 마음으로 신청했지만 무거운 뇌를 갖고 돌아가는 강의다. 추상화도 이렇게 본격적으로 코드에 녹여 본 것도 처음이고 테스트 코드도 작성은 해봤지만 그저 강의의 일부정도라 깊게 배우진 않았다. 게다가 내가 직접 내 머리로 생각해서 작성했던 건 아예 처음이었다. 처음인만큼 난이도가 초급이지만 나에게는 중급 정도의 난이도였으며, 솔직히 워밍업 클럽이 아니었다면 도중에 듣고 탈주했을 것만 같았다. 매일매일 힘내라고 말씀해주시면서 공지사항에 메세지를 보내주신 박우빈님 덕에 완주할 수 있었던 것 같다. 언젠가 백엔드로 직무 전환에 성공한다면 이번에 획득한 지식들을 가지고 실무에 적용해볼 수 있는 날이 왔으면 좋겠다. 그럼 우빈님한테 배웠다고 자랑해야지 ㅎㅎ다들 고생많으셨고 감사합니다!
백엔드
・
워밍업클럽
・
백엔드
・
박우빈
・
클린코드
・
테스트코드
2025. 06. 15.
2
[워밍업 클럽 4기 - 백엔드] Day 18 미션
미션@Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 정리@Mock 순수 자바 환경의 테스트 단위에서도 사용할 수 있다.가짜 객체를 생성한다. 실제 로직은 없다.행위에 대한 기대를 명세하고 그에 따라 동작하도록 한다.보통 테스트 대상 클래스의 의존 객체를 대체할 때 사용한다. @MockBean스프링 부트 환경 같이 Bean을 사용하는 통합 테스트에서 사용할 수 있다.스프링의 올라가있는 실제 Bean을 Mock 객체로 교환한다. @Spy순수 자바 환경의 테스트 단위에서도 사용할 수 있다.stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체다.일부는 실제 객체처럼 동작시키고, 다른 일부만 stubbing할 수 있다. 즉, 선택적 구현과 mocking을 섞어 사용할 수 있다. @SpyBean스프링 부트 환경 같이 Bean을 사용하는 통합 테스트에서 사용할 수 있다.기존 Bean을 Spy 객체로 감싸 실제 로직을 유지하면서 특정 메서드만 moking 한다. @InjectionMock순수 자바 환경의 테스트 단위에서도 사용할 수 있다.mock 객체를 자동으로 주입해준다.테스트 대상 객체에 mock된 의존성 객체들을 자동으로 주입한다. 즉, 스프링의 도움을 받지 않고 의존성을 주입할 때 사용한다. 테스트 코드 리팩토링@BeforeEach void setUp() { 1-1. 댓글 레포지토리.deleteAllInBatch(); 1-2. 게시글 레포지토리.deleteAllInBatch(); 1-3. 사용자 레포지토리.delteAllInBatch(); } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-1. 사용자 생성 - createUser() 호출 1-2. 게시물 생성 - createPost() 호출 // when 1-3. 댓글 생성 - createReply() 호출 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-1. 사용자 생성 - createUser() 호출 2-2. 게시물 생성 - createPost() 호출 2-3. 댓글 생성 - createReply() 호출 // when 2-4. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-1. 사용자1 생성 - createUser() 호출 3-2. 게시물1 생성 - createPost() 호출 3-3. 댓글1 생성 - createReply() 호출 3-4. 사용자2 생성 - createUser() 호출 // when 3-5. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 } private User createUser() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 } private Post createPost() { 1-1. 게시물 생성에 필요한 내용 준비 1-2. 게시물 생성 } private Reply createReply() { 1-1. 댓글 생성에 필요한 내용 준비 1-2. 댓글 생성 } 한마디강의에서 배웠던 내용을 잘 적용해볼 수 있었던 미션같아서 한 번 더 정리하는 느낌이라 좋았다. 마지막 미션까지 달릴 수 있어서 뿌듯함 100배 출처인프런_워밍업_클럽_4기_BEPractical Testing: 실용적인 테스트 가이드
백엔드
・
워밍업클럽
・
박우빈
・
백엔드
・
테스트코드
2025. 06. 15.
2
[워밍업 클럽 4기 - 백엔드] Day 16 미션
미션MVC 기반에서 가장 많이 사용되는 3티어 레이어별로 특징과 테스트 방법을 정리해보자! Layered Architecture 일반적으로 controller(presentation) -> service(business) -> repository(persistence) 구조로 이루어져있다.레이어를 단계적으로 구분하는 이유는 관심사 분리가 목적이다. persistence LayerDB와 직접적인 소통을 하는 계층이며 CRUD 쿼리 작업을 처리한다.Business 계층에서 넘어온 데이터를 처리한다.주로 JPA와 QueryDSL을 사용한다. 테스트 방법클래스 레벨에서 @SpringBootTest, @DataJpaTest 어노테이션을 사용할 수 있다.@SpringBootTest를 사용하는 것을 더 추천한다(다른 테스트와의 환경 통합을 위해)작성한 쿼리가 의도대로 동작하는지 테스트한다. business Layer비즈니스 로직이 메인이다.presentation에서 데이터를 받으며 중요 비스니스 로직을 수행하고 persistence 계층으로 전달하는 중간다리 역할을 한다. 테스트 방법클래스 레벨에 @SpringBootTest를 사용하거나 Mock을 사용하는 경우 @ExtendWith(MockitoExtension.class)를 사용한다. 이 역시 환경의 통합을 위해 되도록이면 SpringBootTest를 사용하는 것이 좋다. 스트 객체를 생성할 때 관련 테스트 메서드에는 꼭 필요한 데이터만 파라미터로 넘겨받아 빌더 패턴을 활용한다.단위 테스트를 작성할 수도, persistence 계층와 통합해서 테스트할 수도 있다. presentation Layer외부 세계를 제일 처음 맞이하는 계층이다. 또한 외부 세계에 응답 데이터를 전달해주는 계층이다. 테스트 방법사용자 요청의 데이터에 최소한의 검증을 해야한다. (validation) 다만, 타입의 유효성 자체에 대한 검증이 아닌 도메인과 관련된 검증들은 presentation 계층이 아닌 더 내부에서 진행한다.클래스 레벨에 @WebMvcTest(className.class)를 사용한다.mock을 사용한다.직렬화, 역직렬화를 위해 ObjectMapper 객체가 필요하다. 출처인프런_워밍업_클럽_4기_BEPractical Testing: 실용적인 테스트 가이드
백엔드
・
워밍업클럽
・
박우빈
・
테스트코드
・
MVC
2025. 06. 15.
3
[워밍업 클럽 4기 - 백엔드] 3주차 발자국
3주차 회고[Day 11] 미션Day 11일에는 테스트 코드를 직접 작성해보는 미션을 진행했다. Readable 강의에서 지뢰찾기와 스터디 카페에 대한 테스트 코드를 3개 이상의 서로 다른 클래스 & 총 7개 이상의 테스트를 작성하는 미션이었다. 객체지향으로 리팩토링 했었던 지난 미션보다는 시간이 적게 걸렸지만, 이번 미션도 여전히 생각할 거리가 너무 많았다.고민을 많이 했던 부분은 전체적으로 테스트를 작성할 수 있는 시간이 물리적으로 부족했기 때문에 선택과 집중을 해서 정말 테스트가 필요할만한 부분에 적용해보고 싶어 어떤 클래스를 선정할지 생각을 많이했다.또, 단위 테스트 위주로 할지 7개만 작성하니까 통합 테스트 격으로 할지도 많이 고민했는데 테스트를 작성하는 실력이 그리 뛰어나진 않아 처음부터 천천히 하기로해서 단위 테스트 위주로 짰던거 같다.이번 미션도 역시 재밌었다! [Day 12] Persistence Layer이번 챕터에서는 전체적인 레이어드 아키텍처 Presentation, Business, Persistence Layer들에 대한 간략한 설명과 통합 테스트의 정의, 그리고 앞으로 개발할 프로젝트의 설계에 대해 배웠다. 강의를 들으면서 느낀 건 강의가 정말 초보자 위주로 짜여져 있다는 것이다(positive). Library와 Framework의 차이점, spring의 대표적인 기술, ORM 등에 대한 설명들을 테스트 강의에서 들을 줄은 몰랐는데 초보자는 아무래도 반복학습이 중요하다보니 이런 기초적인 것들을 하나씩 짚어주셔서 개념을 다시 바로 한 번 더 잡기에 좋았다. 제일 기억에 남는 건 테스트를 작성할 때 클래스 레벨에 @SpringBootTest와 @DataJpaTest 어노테이션이다.SpringBootTest스프링 부트 컨텍스트를 로드한다.웹 환경, 서비스, 레포지토리, 컴포넌트 등 모든 Bean을 실제처럼 사용할 수 있다.DataJpaTestSpringBootTest에서 JPA 관련 컴포넌트만 로드 되게끔 경량화슬라이스 테스트로 빠르게 JPA 레이어만 검증할 때 사용된다.@Service나 @Controller등의 Bean이 로드되지 않는다. [Day 13-14] Business Layer이번 섹션에서는 비즈니스 로직이 메인인 Business Layer에 대해 알아보고, 코드를 구현했다.비즈니스 레이어는 비즈니스 로직을 구현하는 레이어고, Persistence와의 상호작용을 통해 비즈니스 로직을 전개시키며, 트랜잭션을 보장(원자성)해야 한다. 이번 코드 구현에서는 고객이 주문을 할 수 있는 Order, Stock의 전반적인 부분을 개발했다. 코드를 구현하면서 드는 의문점은 여태 다른 강의를 들을 때 상품의 재고 관련한 데이터는 Product에 필드로 관리했는데 이 강의에서는 별도의 엔티티로 따로 빼준게 의아했다. 혼자 생각해봤는데 Stock의 데이터는 최대 품절, 아니면 재고 현황(숫자)만 보여주면 될 것 같았기 때문이다. 그래서 질문을 냅다 올리려다 다른 사람이 비슷한 질문을 한게 있나 찾아봤는데 있어서 읽어봤더니 아하!하게 되었다.관련 질문 : stock을 entity로 분류하는 이유 [Day 15] Presentation Layer(1)이번 섹션에서는 마지막 레이어인 Presentation layer를 구현하고 테스트했다. Presentation Layer는 외부 세계의 요청을 가장 먼저 받아들이는 계층이며, 받은 파라미터에 대해 최소한의 검증을 수행해야한다. 추가적인 요구사항에 대한 테스트를 작성하고 개발을 하면서 @Transaction에 readOnly란 속성에 대해 배웠다.대부분의 서비스는 CRUD 중에 읽기인 'R' 비중이 매우 높다. 그래서 Read와 CUD(command) DB를 슬레이브(R) / 마스터(CUD)로 분리해서 장애를 격리하는 방식을 추천한다고 하셨다.코드 상에서는 일단 클래스 레벨에 무조건 @Transactional을 주는게 아니라 전체적으로 readOnly = true 속성을 먹게끔 작성하고, CUD 작업이 있는 메서드에만 따로 @Transactional을 붙여주는게 성능 상으로도 더 좋다고 말씀해주셨다.@Transactional(readOnly = true) public class service { @Transaction public void save {} } 3주차 회고초보자 입장에서는 TDD로 테스트부터 개발까지 모든 과정을 함께 참여할 수 있어서 나에게 더 좋은 경험으로 다가온 강의였다. 시간은 좀 길었지만 그만큼 얻는 것도 많아 아주 유익했다. 다음에는 강의 없이 혼자서 간단한 프로젝트를 TDD 기반으로 만들어보고싶다! 이번주도 열공😄 출처인프런_워밍업_클럽_4기_BEPractical Testing: 실용적인 테스트 가이드
백엔드
・
워밍업클럽
・
백엔드
・
박우빈
・
테스트
2025. 06. 08.
3
[워밍업 클럽 4기 - 백엔드] 2주차 발자국
2주차 회고[Day 6] 리팩토링: 코드 다듬기이번 챕터에서 제일 기억에 남는 건 '주석'이었다. 주석 사용 법은 배웠지만 좋은 주석은 처음 알게된 개념이라 도움이 많이 됐다. 실무에서도 개발하기 급급해서 기존에 있던 주석까지 신경쓰지 않았었는데 주석과 코드는 한 몸이라 생각하고 앞으로 꼼꼼히 봐야겠다고 생각했다.그리고 키워드 정리 시간에 지뢰찾기에 앞으로 추가해볼 수 있는 기능들을 몇몇개 말해주셨는데 내 힘으로 기능들을 추가해보는 시간을 가져도 좋을 것 같다. [Day 7] 클린코드 리팩토링 실습(미션)이번 챕터는 온전히 미션을 위한 날이었다. studycafe 패키지에 작성된 코드를 읽어보고, 추상화 해보는 미션을 진행했다.고작 조각 코드인 몇 줄 짜리가 아니라 더 어렵긴 했지만 더 생각할 수 있었던 것들이 많아서 좋았다.코드를 다 읽어보고 난 후에 여태 배운 추상화 기법들이 머릿속을 스쳐지나갔다. 이 부분에서 뭘 하면 좋을 것 같은데?! 정도의 생각이 들었다. 다만, 구현으로 실천하기가 매우 어려웠다. 생각과 구현 능력이 절실히 필요하다고 생각했다. 시간 상의 문제로 완벽히 추상화를 하진 못했지만 그래도 백지에서 추상화를 진행해본적이 처음이라 어렵지만 재밌었던 시간이었다. 추후 중간 점검 때 코드 리뷰에서 정말 많은 것을 얻었다. 각자의 실력도 다르지만 각자의 생각도 다르고, 관점도 달랐다. 그래서 배운 게 두 배, 아니 세 배 더 많아진 것 같다! [Day 8] 리팩토링 연습 | 기억하면 좋은 조언들studyCafe를 처음부터 끝까지 우빈님과 함께 진행했다. 순전히 내 뇌로는 닿을 수 없는 부분까지 닿을 수 있었던 거 같았다. 이래서 '나를 이끌어 줄 상사가 중요하구나'를 느꼈다.추상화도 어렵지만 오버 리팩토링이 너무 어려운 것 같다. 오버 리팩토링이 되는 시점을 정확히 캐치할 수 없다보니 그냥 둥둥 뇌 속에 떠도는 구름 같은 개념을 보는 것 같다. 우빈님이 말씀하신대로 오버 리팩토링은 경험에 의해서만 얻을 수 있다고하니 추상화를 많이 도전해보는 것이 중요하다고 느꼈다.실무에서도 추상화를 많이 접할 수 있으면 더 좋았을 것 같은데 그러지 못한 환경에 조금 갈증을 느끼며 오늘도 이직 단단히 다짐한다. Readable Code : 읽기 좋은 코드를 작성하는 사고법 강의가 막을 내렸다. 혼자서 도전했으면 어려움에 어지럼증을 느껴 끝까지 완주하지 못했을 것 같은 강의었다. 워밍업 클럽 덕분에 포기하지 않고 한 강의를 완강할 수 있어서 참으로 감사함을 느낀다. [Day 9] 단위 테스트 | TDD | 테스트는 []다새로운 Practical Testing 테스트 강의를 시작했다!이번 챕터에서는 기본적인 테스트에 대해서 알게 되었고, TDD, BDD에 대해 얘기 나누었다. TDD는 말로만 들어봤었는데 강의에서 TDD 방식으로 코드를 짜나간다고 하시니 약간 생각지도 못한 이득 본 것 같아 엄지를 들었다. 강의를 계속 들으면서 느끼는 점은 코딩 실력도 중요하지만 언어 능력이 중요하다는 걸 엄청나게 많이 깨닫는다. 코딩은 사람이 컴퓨터에게 하는 언어라 컴퓨터가 못 알아 들으면 에러도 내주고 테스트 통과도 시켜주는데 사람이 하는 언어는 내가 뱉은 말을 정말 다양하게 해석할 수 있는 여지가 있어 정확하고 확실한 언어로 내 생각과 코드를 전달해야 정말 실력 있는 개발자인 것 같다.앞으로 그런 개발자가 되도록 노력하자! 출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법Practical Testing: 실용적인 테스트 가이드
백엔드
・
워밍업클럽
・
백엔드
・
박우빈
・
클린코드
・
테스트
2025. 06. 04.
1
[워밍업 클럽 4기 - 백엔드] Day 7 미션
미션[섹션 7. 리팩토링 연습]의 "연습 프로젝트 소개" 강의를 보고, '스터디 카페 이용권 선택 시스템' 프로젝트에서 지금까지 배운 내용을 기반으로 리팩토링을 진행해 봅시다. 브랜치 링크 :https://github.com/techhan/readable-code/tree/day7 나름 해보다가 진도가 더 안나가서 제출합니다!생각은 나름 해봤는데 객체 지향으로 구현하는 능력이 조금 부족하네요!앞으로 구현 부분을 신경써서 들어야할 것 같습니다! 출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법
백엔드
・
워밍업클럽
・
backend
・
박우빈
・
클린코드
・
객체지향
2025. 06. 01.
3
[워밍업 클럽 4기 - 백엔드] 1주차 발자국
1주차 회고[Day 2] 추상과 구체이번 챕터에서 가장 와 닿았던 키워드는 '읽기'다. 사실 코딩을 하면서 '읽기 좋은 코드'를 작성하기 보다는 별 생각 없이 '원하는 요구사항에 맞춰 개발하면 됐지'라는 생각이 커서 내 코드를 읽을 후손들은 생각지도 못한 채 개발을 했었다. 그렇다보니 강의를 듣는 내내 처음 해보는 생각들이라 시간이 많이 더뎌졌다.추상화 레벨 파트를 들으면서 메서드를 이렇게 잘게 쪼개본 적이 없어서 많이 당황스러웠다. 여태 라인 수에 따라 돈을 내는 것도 아닌데 전체적인 라인 수를 줄이려고 노력했지 메서드를 잘게 쪼개는 형식으로 개발한 건 처음이었다.이론적인 공부도 중요하지만, 코드를 가독성 좋게 잘 짜는 사람의 코드를 경험하고, 이해하고 작성해보는 시간이 개발자에게 엄청난 경험을 안겨주는 것을 실감했다. [Day 2] 미션미션 링크처음 만난 미션은 어려웠다(1번 제외). 추상과 구체를 스스로 생각해본 적이 없었기 때문이다. 흔히 아는 붕어빵, 자동차, 동물 이런 예시들을 듣고, 적용하기만 해봤지 추상과 구체를 자세하게, 특히 레벨 별로 나눠서 생각해 본 적은 정말 없어서 꽤 오랫동안 생각에 잠겼다.내용을 적어 내려가면서 '이게 맞나?'싶었다. 왜냐면 내가 나름의 추상 레벨로 구분 해 놓은 것들이 사실 파고들면 파고들 수록 더 깊게 구체화 시킬 수 있었기 때문이다. 어떻게 나눠야 적정 레벨로 나눌 수 있는지가 참 애매했던 것 같다. 정답은 없는 것 같다고 결론 내렸다. 다만, 이 능력을 키워갈 수는 있을 것 같다. 처음 시작이 어렵지 앞으로 추상과 구체를 레벨 별로 잘 나누어보는 연습을 해야겠다. [Day 3] 논리 사고의 흐름 | 객체 지향 패러다임나에게는 이 챕터가 제일 곤욕이었다. 재직자라 수업을 들을 수 있는 시간은 한정적인데다 다음 날에 미션까지 있어 마음이 너무 조급했다. 퇴근하고 듣는 수업은 눈이 감기기 일쑤였다. 그래서 복습이 매우매우 필요한 챕터라고 생각한다.그래도 기억 나는 것들을 적어보자면 '평소에 내가 생각하지 못했던 것들'이었다. 나는 대단한 개발자가 아니다. 그래서 스스로 'Early return'이나 'depth 줄이기' 등과 같은 내용을 생각하지 못한다. 이번 챕터에서 가장 많이 배웠다고 해도 무리가 없다.객체 지향 패러다임도 많이 배웠다. 단순히 이론만이 아닌 리팩토링하는 실습까지 같이해서 많이 배운 것 같다. 물론 혼자 스스로 적용해보기엔 아직 무리지만. 객체 지향 패러다임에서는 'getter'와 'setter'를 자제하란 내용이 신기했다. Setter의 지양은 너무 많이 알려져있는 내용이라 그러려니 했지만 Getter의 경우는 처음 듣는 얘기었다. Entity를 생성할 때 Lombok으로 @Getter를 만들고 보는 내 입장에선 배울 게 정말 많았다.이번 챕터는 배워서 바로 쓰기에는 조금 어려운 내용이지 않았나 싶다. 앞으로 배운 내용들을 복습하고, 새로운 곳에 적용해보는 연습이 필요할 것 같다. [Day 4] SOLID그 유명한 SOLID에 대해 공부했다. 내용들은 워낙 유명하니 굳이 적진 않겠다. SOLID는 유명하지만 코드에 적용하기는 매우 어려운 내용이다. 각종 블로그에서 보이는 짤막한 코드 조각을 보면 이걸 어떻게 실무에 적용할지 약간 까마득해진다. 우빈님 강의에서는 짧지 않는 코드를 SOLID의 각 내용에 맞춰 점진적으로 리팩토링하니까 더 이해가 잘 됐던 것 같다. 물론 초보가 따라가기엔 어려웠지만 내가 그리 갈망하던 초급 -> 중급으로 넘어갈 수 있는 실력을 좀 갈고 닦은 느낌이 들었다. [Day 4] 미션미션 링크이번 미션도 시간이 오래 걸렸다. 실제로 리팩토링하는 부분이 있어서 많은 고민을 했던 것 같다. 솔직히 다른 분들의 코드를 참고하기도 ㅎ 했다. 뭐.. 그러면서 실력이 느는 것 아닐까?!(뻔뻔) 그래도 양심적으로 조그만 부분만 참고했다. 제시된 메서드만 간단하게 리팩토링해보기엔 내 실력을 믿고 검증할 수가 없어서 코드가 돌아가게끔 최소한으로 class들을 만들고 실행시켜봤더니 마음이 한결 편해졌다.어려웠긴 했지만 코딩을 직접적으로 하는 미션이 너무 재밌어서 시간 가는 줄 모르고 했다.이런 미션이 또 나왔으면 좋겠다. [Day 5] 객체 지향 적용하기나는 '상속' 밖에 몰랐고, '상속'이 객체 지향의 꽃인 줄 알았다. 근데 실무에서는 잘 쓰지 않는다니! 또 충격을 받았다. 충격을 5일째 받으니 머리가 어질어질.. 요즘엔 '상속'보다는 '조합'을 더 많이 쓴다고 한다. 어쩐지 내가 '상속'으로 개발했을 때 조금이라도 변경이 생기면 머리가 아프더라..! 이런 가려운 부분을 잘 긁어주셔서 참으로 감사했다. 종합적인 회고그저 배운게 많았던 한 주였다. 복습이 필요함을 느꼈고, 내가 많이 부족하다는 것도 느꼈다. 이 강의를 통해 좀 더 나은 개발자가 되길 소망한다. 화이팅! 출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법
백엔드
・
워밍업클럽
・
backend
・
박우빈
2025. 05. 30.
2
[워밍업 클럽 4기 - 백엔드] Day 4 미션
미션아래 코드와 설명을 보고, [섹션 3. 논리, 사고의 흐름]에서 이야기하는 내용을 중심으로 읽기 좋은 코드로 리팩토링해 봅시다.[as-is]public 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-be]public class Day4 { public boolean validateOrder(Order order) { try { isOrderItemsEmpty(order); isCustomerInfoEmpty(order); isTotalPricePositive(order); System.out.println("유효성 검사를 통과했습니다."); return true; } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); return false; } } private static void isCustomerInfoEmpty(Order order) { if(!order.hasCustomerInfo()) { throw new IllegalArgumentException("사용자 정보가 없습니다."); } } private static void isTotalPricePositive(Order order) { if(order.getTotalPrice() orderItem = new ArrayList(); private Customer customer; public void setItem(Item item) { orderItem.add(item); } public void setCustomer(Customer customer) { this.customer = customer; } public List getItems() { return orderItem; } public int getTotalPrice() { int totalPrice = 0; for(Item item : orderItem) { totalPrice += item.getPrice(); } return totalPrice; } public boolean hasCustomerInfo() { return customer != null; } } class Customer { private String id; public Customer(String id) { this.id = id; } } class Item { private final int price; public Item(int price) { this.price = price; } public int getPrice() { return price; } }수업에서 배운 내용들을 차분히 적용하도록 노력했다. 다음과 같은 순서로 리팩토링을 진행했다.메인인 validateOrder() 메서드 외엔 추상화를 적용하지 못했다. (시간이 없..어서) Early return복잡하게 얽혀있던 if-else문을 뜯어내 if문을 최소화했다. 메서드 추상화메서드의 경우엔 이름이 정말 고민 많았는데, 일단 세 메서드 다 isXXX로 통일시켰다.예외처리예외 처리를 통해 유효성 검사가 통과되지 않았을 때의 로직을 통일했다. return false를 하나하나 써주지 않아도 됐다. 테스트 결과public void run() { System.out.println("======= 시작 ======="); Order order1 = new Order(); validateOrder(order1); // "주문 항목이 없습니다." Order order2 = new Order(); Item item = new Item(1000); order2.setItem(item); validateOrder(order2); // "사용자 정보가 없습니다." Order order3 = new Order(); Item item2 = new Item(-10); order3.setCustomer(new Customer("id3")); order3.setItem(item2); validateOrder(order3);// "올바르지 않은 총 가격입니다." Order order4 = new Order(); Item item4 = new Item(1000); order4.setCustomer(new Customer("id4")); order4.setItem(item4); validateOrder(order4); // "유효성 검사를 통과했습니다." } SOLID에 대하여 자기만의 언어로 정리해 봅시다.SRP : Single Responsibility Principle / 단일 책임 원칙이상적인 사회 모습. 회사에서 한 사람 당 하나의 책임만 가졌으면 좋겠는 것 처럼, 객체는 단 하나의 책임만 가져야 한다. 하나의 객체가 여러 책임을 가질 경우 변경 시 파급력이 크다. OCP : Open-Closed Principle / 개방-폐쇄 원칙열린교회 닫힘. 새 신도는 환영하면서 문을 열어주지만 나갈때는 아니란다. 소프트웨어 요소는 확장에는 열려있어야 하고 변경에는 닫혀있어야 한다. 추가적인 요구사항에 유연하게 확장할 수 있어야한다. 기능 추가 시 최소한의 코드를 수정해야 함(물론 로직에 직접적인 영향을 주는 코드는 수정 X) LSP : Liskov Substitution Principle / 리스코프 치환 원칙자식은 부모의 거울이다! 자식 클래스는 부모 클래스의 기능을 정확하게 확장해야한다. ISP : Interface Segregation Principle / 인터페이스 분리 원칙객체와 똑같다. 하나의 인터페이스에 너무 많은 기능을 넣으면 원치않는 의존성이 생길 수 있다. DIP : Dependency Inversion Principle / 의존 역전 원칙구현체가 아닌 추상에 의존해야 한다. 구현체에 의존하게 되면 어떠한 인터페이스에 대한 구현체가 바뀔 때마다 다른 코드에 영향을 줄 수 있다 !! 결합도를 낮추고 유연한 구조를 만든다. 출처인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법
백엔드
・
클린코드
・
워밍업클럽
・
박우빈
2025. 05. 27.
2
[워밍업 클럽 4기 - 백엔드] Day 2 미션
미션강의에서 안내하는 것처럼, 프로젝트를 개인 계정으로 fork하고 강의를 수강해 주세요.github 주소 : https://github.com/techhan/readable-code.git 추상과 구체" 강의를 듣고, 생각나는 추상과 구체의 예시가 있다면 한번 3~5문장 정도로 적어봅시다.추상 : 택배를 받았다.구체 과정고객이 주문한다.판매자가 확인 후 택배 송장을 뽑는다.계약된 회사가 택배를 수거하러 방문한다.택배를 수거해서 한 번 이상의 상하차를 거친다.택배 배달원이 고객에게 택배를 전달한다. 짧은 회고두 번째 문제를 처음 맞닥뜨렸을 때는 좀 당황스러웠다. 추상과 구체. 프로그래밍을 배우면서 추상과 구체에 대해 들어본 적은 있었다. 단순히 '동물-강아지' 이런 수준. 들어만 봤지 내가 직접 생각해 본 적은 별로 없었고, 더군다나 3~5문장으로 적어 본 적은 더 없어서 꽤나 생각하는데 애를 먹었다. 그래도 한 번 생각의 물꼬가 터지니, 위에서 도출해 낸 구체 과정에서도 완벽한 구체가 아닌, 그 안에 또 구체, 또 구체, 또 구체...가 있는 걸 알게 됐다. 예를 들면 고객이 주문하는 과정에서도 '핸드폰 켜기 > 사이트 들어가기 > 장바구니에 담기 > 결제하기 > 완료하기' 등등의 구체들이 숨어 있다는 게 별 거 아닌 것 같지만 흥미로웠다. 추상과 구체는 기억에 매우 오래 남을 것 같다. 출처 인프런_워밍업_클럽_4기_BEReadable Code: 읽기 좋은 코드를 작성하는 사고법
백엔드
・
인프런
・
워밍업클럽4기백엔드
・
박우빈
・
ReadableCode
・
CleanCode
・
Backend
2024. 03. 10.
1
[인프런 워밍업 클럽_0기] 3주차, 세 번째 발자국 #3
3주차 요약 : 직장인은 집중하기 힘든 코스인 걸 느꼈다..!강의 요약은 notion에 정리해두었다. https://www.notion.so/d2e9b3e27b3348abbde60994cf627ebd Day 11. 객체지향과 JPA 연관관계기존 코드를 리팩토링하면서 객체지향적인 개발이 무엇인지 조금이나마 체험할 수 있었다.객체지향의 사실과 오해에서 나왔던 '객체의 메시지'를 드디어 체험하게 되었다.JPA 연관관계 및 연관관계의 주인이 되는 기준에 대해서 알게되었다.연관관계에 주인이 아닌 쪽에는 mappedBy 옵션을 줘야한다.개념은 언뜻 알고있었지만 연관관계의 주인을 정하는 기준을 이렇게 정확하게 알게된 건 처음이다.연관관계의 주인은 Table을 보았을 때 관계의 주도권을 쥐고있는 쪽이 연관 계의 주인이 된다.연관관계 주인에 의해서 객체가 연결되는 기준이 된다.연관관계의 주인 객체에서 연결되는 다른 객체의 setter를 만들어 저장하면 데이터 저장이 정상적으로 잘 된다....!연관관계를 setter로 연결 후 Transactional이 아직 끝나지 않은 시점에서 그 반대인 객체에서 주인 객체를 getter로 가져오면 null이 반환된다. -> DB 상에서는 아직 저장이 되지 않아 데이터가 없기 때문해당 문제를 해결하기 위해서는 Setter를 한 번에 둘 다 연결해주면 된다.cascade 옵션과 orphanRemoval 옵션에 대해 알게되었다.도메인 계층에 비즈니스 로직이 들어가도 된다는 걸 알게되었다. 뭔가 도메인 계층은 깨끗한 상태로 getter와 생성자 외에는 추가적인 메서드가 있으면 안될 것 같았는데 그러지 않아도 되는 것 같다.리팩토링 후 Service 계층에서 오만가지 도메인을 불러와 직접 처리해주었던걸 리팩토링 하면서 연관 관계를 사용해 최대한 도메인들끼리 직접 협력할 수 있게 코드를 변경한 진귀한 경험을 했다. -> 객체지향의 사실과 오해..! 짱지연로딩의 개념과 다양한 옵션들에 대해 알게되었다.연관관계 사용이 100% 정답이 아닌 걸 알게되었다.비즈니스 요구사항, 기술적인 요구사항, 도메인 아키텍처 등 여러 부분을 고민해서 연관관계 사용을 선택해야 함.실무에서 경험이 쌓여야 판단이 가능할 것으로 보인다. 과제는 따로 못했다..! 야근이 날 괴롭혀서 강의도 겨우 들었기 때문....ㅜDay12. 기본적인 배포를 위한 준비배포의 개념에 대해서 알게되었다.profile 기능을 사용해서 H2와 Mysql 관련 설정을 분리하였다.git과 github의 개념과 차이점을 알게되었다.git의 기초 사용법을 다시 한 번 리마인드하는 시간이 되었다.git은 사용해봐서 기초 사용법을 알고 있는 상태였다.AWS의 EC2를 난생 처음 사용해봤다. 과제는 따로 하지 못했다.. 이날도 아마 야근했던 거 같다... 😢Day13. AWS와 EC2 배포AWS에서 리눅스 명령어를 다뤄봤다.AWS에 콘솔에 접근하는 방법을 알게되었다.리눅스 명령어 중에 권한 관련 명령어가 좀 어려운 것 같다. 추가적인 공부가 필요한듯.배포를 위한 프로그램 설치는 Java, mysql, git이었는데 mysql을 설치할때 좀 곤욕이었다. 강의 영상과 현재 ec2 리눅스 버전이 달라서 그런건지 강의에 나오는 명령어를 입력하면 에러가 나서 블로그 이것저것을 검색해봤다. 난생 처음 CLI로 빌드를해봤다. 빌드할 때도 영상을 그대로 따라서 하면 에러가 발생했다. 영상에서는 java 11을 설치했는데 내 프로젝트는 java가 17이라 java를 다시 설치해주었더니 정상적으로 빌드가 됐다.foreground와 background의 개념을 알게되었다.난생 처음 도메인을 구입해봤다.Day14. Spring Boot 설정, 버전업 이해하기build.gradle에 대해서 알게되었다.dependency configuration에 대해서 알게되었다.Spring과 Spring boot의 역사에 대해 간략하게 알게되었다.YAML 문법에 대해 알게되었다.Day15. 마무리 및 추가 꿀팁 영상공부 방향성에 대한 얘기 중 spring의 원리 및 클린 코드를 공부해야겠다고 생각했다.코틀린에 대한 관심도가 올라갔다. 조만간 코틀린에 대해서도 공부할지도?스프링 배치가 궁금해서 관련 강의를 사놨었는데 이것도 얼른 수강해야겠다.Spring boot에서 Mybatis를 사용하는 법을 알게되었다. 우리 회사 같은 경우는 옛날 기술들을 많이 쓰고 최신 기술에 대한 거부감이 있는데 이런 걸 보여줌으로써 차근차근 최신 기술로 안내하는 것도 나쁘지 않을 것 같다Client-Side Rendering과 Server-Side Rendering의 개념을 알게되었다. 완강 후기자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]를 완강했다! 🥳🥳🥳🥳뭔가 강의 제목을 딱 봤을때 진짜 엄청난 기초의 강의겠구나 했는데 강의를 들으면 들을수록 어느정도 깊이가 있어 조금 놀랐다. 오히려 기초가 없는 사람은 약간 따라하기 버거울 수도 있다는 생각이 들었다.기존 코드를 객체지향적으로 리팩토리하는 부분에서 많은 인사이트를 얻어서 뭔가 최태현님의 다른 강의들까지 들으면 남들과 조금은 다른 개발자가 될 수 있지 않을까란 생각도 들었다. 아무래도 서적에서 공부하는 것과 실무가 약간 버무러진 코드와 깊이 있는 코드를 경험하는 것은 너무 다르니까..! 아무튼 너무 기초적이지 않는 강의에 만족도가 높았다.직장인이라 잦은 야근과 피로감에 미니 프로젝트의 진도가 더디게 나가서 매우 아쉬웠다. 인프런 워밍업 클럽이 끝나도 미니 프로젝트는 개발을 계속 시도해봐야겠다.정말 유익하고 열정적인 3주였다. 나 포함 참여한 인프러너와 코치님까지!모두 3주 동안 너무 고생하셨습니다!오프라인 수료식에 참여하고 싶었지만 평일인데에다 판교라 참여하지 못하는 것이 너무 아쉽네요.온라인으로라도 참여하겠습니다열정적인 개발자분들 앞으로도 화이팅하세요🥳그리고 하루에 과제가 하나씩 있었을 때는 정말 미리 해놓지 않으면 직장인은 따박따박 당일에 수료하기 어려운 코스인 거 같아 이런 부분만 조금 개선되었으면 좋을 거 같습니다! ex) 과제는 미리 내놓되 완료 체크는 주말에 하기 같은..참고로 미니 프로젝트는 현재진행중입니다! 평일에는 시간이 없어 주말에 후다닥 개발을 하려고 하는 중입니다.https://devhan.tistory.com/327
백엔드
・
인프런워밍업클럽