블로그
전체 42024. 10. 26.
0
백엔드 클린코드, 테스트코드 회고 4주차 마지막
해당 회고는 'Practical Testing: 실용적인 테스트 가이드' 강의에 대한 회고입니다.마지막 주벌써 4주 동안의 스터디가 끝났습니다. 그래도 무언가 마무리된다는 것은 보람차면서도 아쉽네요.이번주에 한 것들을 정리하면서 마지막 회고를 작성해보겠습니다! 배운 것들4주차에서는 Mockito와 관련된 사용과 stubbing하는 방법, 더 나은 테스트 작성하기, 학습 테스트와 Spring REST docs를 공부했습니다. Mockito로 Stubbing하기추가 기능으로 날짜와 이메일을 받고 일 총 매출 이메일로 전송해주는 것을 구현외부 네트워크를 타는 로직의 경우 실제 메일을 전송하는 것까지 테스트에 포함시켜야 할까?할 필요가 없다 시간과 비용적인 낭비다적절한 mocking으로 원활한 테스트를 가능하게 해보자! @MockBean private MailSendClient mailSendClient; @DisplayName("결제 완료 주문들을 조회하여 매출 통계 메일을 전송한다.") @Test void sendOrderStatisticsMail() { //given ... when(mailSendClient.sendEmail(any(String.class), any(String.class), any(String.class), any(String.class))) .thenReturn(true); //when ... }Test Doublestub과 Mock이 헷갈렸는데 바로 알게되었다.둘의 공통점은 어떤 행위에 대한 결과를 정해두고 그것을 리턴해주는 것차이점은 검증 목적이다. Stub은 테스트를 함에 따라 변한 상태를 검증하는 것, 테스트 후에 Stub의 상태가 어떻게 변했는지 주목Mock은 테스트를 함에 따라 동작하는 행위를 검증하는 것, 테스트를 하면 어떤 동작이 실행될 것인지에 대해서 주목순수 Mokito Extension으로 사용해보기, 어노테이션 사용해보기Mock과 Spy의 차이를 명확하게 공부하고 직접 함수를 이용해봤다. 외에도 @MockBean, @SpyBean, @InjectMocks도 학습했다. BDDMokitoMock을 사용할 때 when 함수의 경우 표기상 when절에 있는 것이 맞을 것 같은데 given절에 있어서 뭔가 표현이 매끄럽지 않은 것 같다.따라서 나온 것이 BDDMockito.모든 동작은 Mockito와 동일하다 BDD스타일로 이름만 변경한 것.앞으로 Mockito를 작성할 때는 given절에서 BDDMockito를 적극적으로 이용하자!given절에 구현되는 when절을 BDDMockito.given()으로 사용할 수 있도록 해줘서 매끄러운 표현을 할 수 있도록 해준다.@DisplayName("메일 전송 테스트") @Test void sendMail() { //given BDDMockito.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .willReturn(true); //when boolean result = mailService.sendMail("", "", "", ""); Classicist vs MockistMockist는Mock으로 모든 테스트를 커버하고 보장이 된 부분에 대해서는 Mocking처리를 해서 빠른 테스트를 진행하자는 주의Classicist는 실제 프로덕션 코드에서 잘 돌아간다는 보장을 하기 위해서 실제 객체로 최대한 테스트를 진행해야 하고 꼭 필요한 경우에만 Mocking을 진행하자는 주의만약 프로덕션 레벨에서 테스트의 유효성이 Mockist가 낮다면 Classicist를 따르는 것이 맞을 것 같은데 규모가 작거나 커버리지 퍼센트를 어느정도 유지하고 싶다면 Mockist 방법을 택해서 할 수도 있을 것 같다. 나은 테스트를 위한 조언하나의 문단에 하나의 주제를 가지는 것이 좋은 글쓰기인 것처럼 각 테스트메서드는 하나의 주제만 가지는 것이 바람직테스트 환경을 조성할 때 모든 환경을 제어할 수 있어야 한다.given절에서 테스트 기반 환경을 세팅할 때 다른 테스트와 결합이 생기지 않도록 독립적으로 작성하자두가지 이상의 테스트가 하나의 공유변수를 이용할 때 한 테스트가 변수의 상태를 바꾼다면 다른 테스트의 결과를 보장할 수 없다.여러가지 테스트 메서드를 정의했을 때 given에 겹치는 데이터가 생각보다 많다.문서로써의 테스트 기능을 잘 수행하도록 잘 분배해보자성능과 시간적으로 효율적이고 일괄 삭제를 해주는 deleteAllInBatch를 사용하자파라미터에 여러값을 적용해서 테스트할 수 있는 @ParameterizedTest와 공유변수로 다수의 테스트를 수행할 수 있는 @DynamicTest테스트 환경도 상위에서 관리할 수 있게 해서 환경을 통합 관리하자private 메서드 테스트를 하고 싶다면 객체 분리의 시점으로 보자. 하나의 퍼블릭 메서드에서 하는일이 너무 많은지 확인해보고 프라이빗 메서드의 기능을 별도의 객체에 위임하는 방법을 고려하자프로덕션 코드에서는 필요없는 테스트 코드에서만 사용하는 최소의 생성자나 빌더는 필요에 의한 최소범위로 만들고 무분별한 생성을 지양하자 학습테스트학습테스트는 테스트를 학습의 용도로 이용하는 것이다.Guava라는 라이브러리를 테스트메서드로 학습해보았다. 실제 동작적인 확인을 하기에 매우 좋은 것 같고 뭔가 나만의 동적인 Docs를 남기고 공유하고 싶을 때 이용하기 좋은 방법인 것 같다. Spring REST Docs프로젝트 때 비슷한 swagger를 사용해봤다. 제대로 잘 익혀놓으면 다음 개발때 잘 이용해 볼 수 있을 것 같다. 진짜 마무리 회고많은 분들에게 동기부여받고 학습했던 한 달이었습니다. 배움에는 끝이 없다는 것을 늘 느끼고 앞으로도 꾸준히 열심히 도전하고 학습하고 싶습니다. 인프런 워밍업 클럽 짱
웹 개발
・
백엔드
・
클린코드
・
테스트코드
・
워밍업클럽
2024. 10. 20.
0
백엔드 클린코드, 테스트코드 회고 3주차
해당 회고는 'Practical Testing: 실용적인 테스트 가이드' 강의에 대한 회고입니다.시작이번주부터는 본격적으로 테스트 코드에 대한 강의를 듣게 되었습니다. 테스트 코드에 대해서 적용은 하고 싶지만 접근 방법에 대해서 몰랐던 저에게 한줄기 희망이 된 강의입니다. 배운 것들3주차에서는 테스트가 왜 필요한지, 사용한다면 어떤 이점이 있는지에 대한 학습을 위주로 했습니다. 테스트 필요성테스트 코드가 없는 경우production code가 커짐에 따라 커버할 수 없는 영역 발생변화가 생기는 순간마다 발생가능한 케이스를 모두 고려해야 한다그에 따른 피드백은 느려지고 이는 유지보수의 어려움으로 이어진다, 소프트웨어의 안정성을 보장할 수 없다 따라서 테스트코드를 작성하는 것이 좋다테스트 코드를 작성할 경우개발 코드에 대한 빠른 피드백을 얻을 수 있으며 자동화를 통해 시스템이 코드를 검증할 수 있도록 할 수 있다이를 통해 서비스의 안정성을 보장할 수 있다 이런 이유에서 테스트 코드를 잘 작성하는 것은 매우 중요하다무엇을 검증하는지 모호하고 혹은 너무 복잡한 테스트 코드라면 무용지물이 될 수 있다. 혹은 잘못된 검증이 이루어질 수 있다 좋은 테스트 코드는 다음과 같다테스트 코드가 자동화되어 빠른 시간에 버그를 발견할 수 있어 사람이 수동 테스트하는 비용을 줄여준다내가 남긴 코드와 테스트에 대해 다른 팀원에게도 공유되어 팀 전체의 공유 자산으로 활용된다짤 때는 귀찮은데 사실 이것이 가장 빠르고 확실하고 좋은 길이다 문서로써 테스트프로덕션 기능을 설명다양한 테스트 코드를 통해 프로덕션 코드를 이해하는 시각과 관점 보완과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서 모두의 자산으로 공유 가능! @Test void add() { CafeKiosk cafeKiosk = new CafeKiosk(); cafeKiosk.add(new Americano()); System.out.println("담긴 음료 수 : " + cafeKiosk.getBeverages().size()); System.out.println("음료 상세 : " + cafeKiosk.getBeverages().get(0).getName() + ": " + cafeKiosk.getBeverages().get(0).getPrice()); } 이런 테스트 코드의 경우 문제가 있다어쨋든 마지막에 사람이 직접 확인해야한다다른 사람이 봤을 때 어떤 것이 맞는 테스트인지 틀린 테스트인지 알기 힘들다심지어 이 코드는 틀릴 일이 없다… 단순한 콘솔 찍기이므로..이런 수동 테스트는 효율적이지도 못하고 테스트의 역할조차 제대로 하지 못한다자동화된 테스트로 코드 검증을 자동으로 해주어 개발자의 코드검증 개입을 최소화 해보자 단위테스트단위테스트란클래스나 메서드와 같이 작은 단위를 독립적으로 테스트테스트 속도가 빠르고 안정적테스트를 위한 프레임워크와 라이브러리 이용 테스트 세분화하기암묵적인 요구사항이 있는지 먼저 확인최대한 많은 상황을 커버하기 위해 테스트 세분화는 중요 세분화해피 케이스 → 생각한대로 잘 작동하는지 (ex. 아메리카노를 2잔 주문했다면 주문내역에 2잔이 들어갔는지)예외 케이스 → 작동하지 않는 경우 (ex. 아메리카노 105잔 주문은 불가능)경계 테스트 → 범위, 구간, 날짜에 대해서 정상동작 범위를 명확히 하면 해피 케이스와 예외 케이스의 테스트 생성을 올바르게 할 수 있다.(ex. 3이상까지 정상 동작하는 코드라면 해피케이스로 3, 예외 케이스로 1을 두어 테스트)경계값에서 테스트하는 것이 중요하다경계값에서 설정한 예외와 설정한 메시지가 잘 던져지는지 확인하자 테스트하기 어려운 영역을 구분하고 분리하자테스트 가능한 코드에 테스트가 불가능한 부분이 들어온다면 전체 코드가 테스트 불가능하게 된다. 따라서 테스트하고자 하는 영역을 잘 생각해야 한다. 테스트 영역을 어디까지 분리하는 것이 좋을까?기본적으로는 모호하고 어려운 부분을 외부로 분리할 수록 테스트를 할 수 있는 범위는 늘어난다. 하지만 당연히 적당한 멈추는 선이 있을 것이다.정확하게 어려운 영역이 무엇인지 체크해보고 분리범위에 대해서 알아보자. 테스트 어려운 영역테스트마다 다른 값에 의존하는 코드날짜, 시간, 랜덤 값, 전역 변수나 함수, 사용자 입력외부 세계에 영향을 주는 코드표준 출력, 메시지 발송, DB기록 등 테스트 쉬운 영역 (순수 함수)같은 입력에 항상 같은 결과외부 세상과 단절된 형태테스트하기 쉬운 코드 TDDTest Driven Development테스트 코드를 먼저 작성하고 이후에 프로덕션 코드를 작성해서 테스트 코드를 중심으로 서비스가 구현되는 방법론cf. 애자일 소프트웨어 개발 선언에서 켄트 백이 소프트웨어 개발 방법으로 XP(extream programming)을 제안했고 이것을 실천할 수 있는 방법 중 하나가 TDD TDD과정실패할 수밖에 없는 테스트 작성 (RED)테스트를 통과하기 위한 최소한의 코드 작성 (돌아가기만 하면된다. GREEN)테스트 통과를 유지하면서 작성한 코드를 개선해 나감 (REFACTOR) TDD의 핵심내가 작성하는 프로덕션 코드에 대해서 빠르고 자주 피드백을 받을 수 있다결국 테스트를 잘하기 위한 구조를 고민하게 된다. 시간을 분리했던 코드와 같이 시간이 테스트하기 어려운 부분이라는 것을 먼저 캐치하고 미리 외부로 분리하는 구조를 선택! 선 테스트 작성 후 기능 구현테스트 가능한 코드로 구현하면서 복잡도가 낮고 유지보수가 쉬운 구현이 가능해진다발견하기 어려운 엣지 케이스를 놓치지 않게 해준다구현에 대한 빠른 피드백 가능과감한 리팩토링 가능TDD는 구현부가 테스트와 상호작용하며 발전한다TDD는 클라이언트 관점에서 피드백을 준다 DisplayName과 BDD@DisplayNamejunit5에서 추가된 어노테이션해당 테스트가 어떤 역할을 하는지 명시해줄 수 있다 명사의 나열보다 문장으로 쓰자“~테스트” 형식은 지양하자테스트에 대한 결과까지 써주는 것이 좋다 BDDTDD에서 파생함수 단위 테스트가 아닌 시나리오 기반 테스트케이스에 집중해서 테스트한다개발자가 아니어도 이해할 수 있을 정도의 추상화 수준 권장 작성 방법Given 어떤 환경에서When 어떤 행동을 진행했을 때Then 어떤 상태가 일어난다 Persistence Layer 테스트Persistence Layer?Data Access 역할을 한다비즈니스 관련 작업을 하는 로직이 포함되어서는 안된다data에 대한 CRUD에만 집중한 레이어 Repository Layer에 대한 테스트JpaRepository를 상속하는 경우 쿼리 메서드명을 잘 지을 경우 틀릴 일이 없는데 왜 테스트를 진행할까?→ 간단한 쿼리라면 가시적으로 충분히 확인할 수 있지만 where절의 조건 때문에 메서드명이 길어지거나 파라미터를 잘못 작성할 수도 있다. 날 것 그대로 쿼리를 작성하는 JPQL이나 QueryDSL을 사용하는 경우도 있다따라서 현재 내가 작성한 쿼리가 잘 동작하는지 테스트하는 것도 있지만 이후 다른 방법으로 사용될 쿼리를 미리 검증하기 위해서도 필요하다.Repository 테스트의 경우 서버를 띄워서 하지만 DB에 엑세스하는 부분만 보기 때문에 기능 별로 테스트하는 단위 테스트의 느낌이 있다 cf. 테스트가 통과할거라고 예상하고 테스트했지만 에러 발생java.lang.AssertionError: Expected size: 2 but was: 4 in: [sample.cafekiosk.spring.domain.product.Product@7bb996e0, sample.cafekiosk.spring.domain.product.Product@589cc8eb, sample.cafekiosk.spring.domain.product.Product@44233014, sample.cafekiosk.spring.domain.product.Product@6888a33] 아마 설정파일이 디폴트가 local로 되어 있는데 local 설정은 디비 초기화 후 data.sql이 자동실행되어 이미 저장된 데이터들 때문에 에러가 발생하는 것 같다해당 테스트를 실행할 설정 프로파일을 data.sql이 적용되지 않는 다른 프로파일로 지정해주자!테스트 클래스에 @ActiveProfiles(”적용할 설정 프로파일이름”)만 해주면 된다 마무리 회고이것저것 할 것이 많은 한 주였습니다. 잘 마무리하고 마지막주인 다음주까지 열심히 달리고 싶습니다.워밍업 클럽뿐만 아니라 배운 것들을 정리하면서 기록하는 것이 중요하다는 것을 크게 느낍니다. 앞으로도 차곡차곡 쌓아갈 수 있었으면 좋겠습니다. 앞으로도 화이팅!
웹 개발
・
백엔드
・
클린코드
・
테스트코드
・
워밍업클럽
2024. 10. 13.
0
백엔드 클린코드, 테스트코드 회고 2주차
해당 회고는 'Readable Code : 읽기 좋은 코드를 작성하는 사고법' 강의에 대한 회고입니다.2주차 동안..강의 완강은 하지 못했지만 한 것들을 정리하고자 합니다.강의를 따라 리팩토링 해보면서 가장 느낀 점은 리팩토링은 정해진 답이 있지 않고 상황에 따라 유연한 생각이 뒷받침되어야 한다는 것이었습니다. 따라서 앞으로 코드를 칠 때 고려할 수 있는 아이템을 많이 만든다는 생각으로 수강했습니다. 배운 것들 객체와 고려할 점추상화된 객체의 구성비공개 필드 (데이터)비공개 로직 (기능 구현부)공개 메서드 선언부 → 외부에서 어떤 기능을 제공하는지 알 수 있게 해줌 고려할 점객체 생성 시 1개의 관심사로 책임이 정의되어 있는지 확인하자 메서드 추상화랑 비슷시간이 지나면서 객체의 요구사항이 변경되면서 책임이 변경될 수 있음.. 잘 변경해야 함 생성자, 정적 팩토리 메서드에서 유효성 검증이 가능 검증 로직도 같은 관심사로 취급될 수 있는지 확인 필요 setter 사용은 자제하고 getter는 웬만하면 자제데이터는 불변이 최고, 변해도 객체가 핸들링 가능해야 함외부에서 데이터 변경 요청을 해야 하는 경우 set같은 남용될만한 단어가 아닌 update와 같이 의도를 명확하게 드러내는 단어를 선택!getter는 반드시 필요한 경우에 추가Don't Tell, Ask 필드 수는 적을 수록 좋다필드 계산 기능이 있다면 메서드의 기능으로써 제공하자미리 가공하는 것이 성능 상 이점이 있다면 필드로 빼도 무방 객체 설계하기지뢰 찾기 게임을 객체 지향적으로 리팩토링!String 배열을 사용해서 구현하고 있던 지뢰 보드를 Cell이라는 객체를 만들어 지뢰 보드의 각 셀의 상태를 물어보는 방식으로 바꾸었다.리팩토링 중 몇가지...Cell 객체 생성정적 팩토리 메서드를 사용 모든 셀에 대해서 sign 확인하기Cell 객체에 대해 getSign을 해서 가져오고 싶지만 객체에 물어볼 수 있는지 확인 후 메서드를 만들었다보드 그리기반대로 보드를 그릴 때는 객체에게 부탁하는게 이상하다. 내가 그리면서 객체에게 부탁하는 것은 맞지 않다.이때는 과감하게 getter를 사용해서 객체에게 데이터를 받아서 그릴 때인 것이다. 지뢰 수 board와 지뢰 여부 board 적용Cell에 근처 지뢰 수 필드와 지뢰 여부 필드 추가한다, 생성자도 변경한다.그러면 팩토리 메서드도 변경되고.. 나머지 Cell을 리턴하는 메서드들은 어떻게 값을 주어야 할까??? Cell의 필드와 필드들이 가질 수 있는 상태에 대해 생각해 보았을 때Cell의 필드 : nearbyLandMineCount, isLandMineCell이 가질 수 있는 상태 : 깃발 있음/없음, 셀 열림/닫힘, 사용자가 확인함 여기서 깃발이 꽂힌 셀은 사용자가 지뢰가 있을 것을 예상해 닫힘과 동시에 확인한 셀이다.깃발을 꽂는 것을 생각했을 때 셀이 열렸다, 닫혔다와 사용자가 확인했다는 서로 개념이 다르다!깃발을 꽂는 경우 셀은 닫혀있지만 사용자가 확인한 셀이다.현재 게임종료 조건에 모든 셀이 열렸을 경우 끝내는 것이었지만 사실은 닫혀있어도 이미 확인된 셀이 존재했다. 따라서 현재 게임종료조건은 부적절하다!강의에서는 이런 고려들을 새롭게 알게된 도메인 지식이라고 했다.결론은..주변 지뢰 개수나 지뢰 여부 같은 경우 별도의 String기반 배열로 관리했기 때문에 해당 기능이 가능했다.(별도의 BOARD를 확인해 원래 BOARD에 값을 넣는 식)Cell이라는 데이터와 기능을 가지는 객체를 생성함으로써 사용자의 입력에 따라 Cell의 상태를 변화하는 로직으로 바꿔야 한다!!Cell로 인해 관련 데이터들이 캡슐화되어서 Cell 자체를 변경하는 것이 아닌 상태를 변경시켜 달라고 Cell 내부의 상태를 변경하는 식으로 변경해야 한다원래 Cell의 상태변경 후 Cell의 상태 board의 Cell객체가 가지는 정보에 따라 Cell의 sign 상태를 리턴하기Cell 객체는 상태를 보여주는 필드들을 관리했다. 이들에 기반해서 현재 Cell의 sign은 무엇인지 리턴해준다. 중간 점검스케줄 상 readable code 강의를 완강한 주에 다같이 모여 중간점검을 진행했습니다.전체적인 리뷰와 미션 피드백을 해주셨는데요, 좋은 질문과 답을 들을 수 있었습니다.들으면서 작성한 메모입니다.코드 짤 때 사용자와의 구체적인 인터렉션이 도메인에 직접적으로 영향을 미치는 것은 좋지 않다static메서드를 인스턴스 메서드로 대체할 수 없는 경우..는 인스턴스 메서드로 할 수 없는지 충분히 고려하자객체지향에서는 내부에 있는 객체의 상태를 확인하기 위해 bypass되는 메서드가 있을 수 밖에 없다충분한 설계에 대한 고민을 하다가 도메인을 새로 배우게 되는 계기가되고 그에 맞게 리팩토링을 하면된다totalPrice라는 변수는 view일까 domain일까.. 3:7로 domain 왜냐하면 totalPrice라는 변수가 단순 결과를 내는 것 외에도 여러 곳에서 쓰일 수 있다. 예를 들어 그 후에 합계금액에 대한 결제 로직을 진행할 때 도메인안에서 해당 변수가 쓰인다면? 도메인의 발전 방향을 예측했을 때 어디 두는 것이 쓰임이 편할지 고려하자중복을 정말 꼭 고려하자 유지보수 시 중복되는 만큼 작업을 해줘야 한다!다르게 처리해줘야 하는 부분이 있으면 왜 다르게 처리해주는지를 명확하게 보일 수 있는 것이 좋다!enum(정적)이나 config(동적)를 적용할 때 어디까지 적용하는 것이 좋을지 고려해보자null대신 NPE를 방지할 수 있는 emtpy 개념을 고려해볼 수 있다.. 만약 여러 군데에서 디비나 API를 통해 데이터를 가져와야 한다면 NPE는 절대 나면 안된다 마무리 회고앞으로 코드를 짤 때 유용한 자원이 되어줄 리소스를 모은 듯한 한 주였습니다.다음 주도 이런저런 준비로 할 일이 산더미지만 커리큘럼을 조금씩 잘 따라갔으면 좋겠습니다.다음 주도 화이팅!!
백엔드
・
워밍업
・
클린코드
・
테스트코드
2024. 10. 06.
0
백엔드 클린코드, 테스트코드 회고 1주차
해당 회고는 'Readable Code : 읽기 좋은 코드를 작성하는 사고법' 강의에 대한 회고입니다.시작팀프로젝트를 진행하면서 완성도 있는 코드를 짜고 싶다는 생각과 함께 여기저기서 들었던 코드 잘 짜는 방법에 대한 정리가 필요했습니다. 이런 모호한 생각들을 정리해보았고 결론적으로 이 강의를 듣게 되었습니다.제가 이 강의를 찾은 이유는 다음 3가지 이유에서였는데요,지금까지 프로젝트를 진행하면서 기능구현을 위한 개발은 했지만 같이 개발하는 팀원들을 위한 개발은 하지 못한 것 같다팀원들과 코드 컨벤션을 정하면서 서로 알고 있는 리소스 자체가 적어 방향성을 잡기 힘들었다팀원들에게서 괜찮았던 구현방식을 배우면서 나도 나만의 좋은 코드짜는법을 익혀 주변 사람들에게 공유하고 싶은 마음읽기 좋은 코드라는 의미를 작은 수준에서부터 자연스럽게 확장시켜가는 강의라고 느껴져 작은 부분에서부터 빠른 적용을 하고 싶은 저에게 좋은 선택이었다고 생각합니다. 배운 것들1주차에서 학습한 것은 추상에 관한 것들과 코드를 읽을 때의 생각을 배우고 이들을 기반한 객체 지향을 학습했습니다.읽기 좋은 코드를 쓰기에 앞서 시작을 추상으로 한 것이 좋았습니다. 구체적인 코드 작성법을 배우기 전 모든 것의 기반은 적절한 추상화라는 것을 느꼈습니다.다음은 코드를 읽을 때 어떤 사고가 이루어지는지와 이를 기반한 코드적 습관(?)을 배웠습니다. 뭔가 코드를 짤 때하는 행동들에 생명력을 주는 듯한 느낌이었습니다. 배운 것은 다음과 같습니다. 추상추상은 중요한 정보를 가려내고 덜 중요한 정보는 버리는 것반대로 추상에서 구체적인 것을 유연하게 찾을 수 있어야 한다!다음과 같은 이유로 추상에서 구체로 돌아가지 못할 수 있다..추상화 과정에서 중요한 정보를 부각시키지 못함해석자가 동일하게 공유하는 컨텍스트가 없음잘못된 추상화는 후폭풍이 매우 심하기 때문에 잘 고려해서 해야 한다. 이름 짓기이름 짓기는 추상화의 대표적인 예라고 할 수 있다.중요한 점은 표현하고자 하는 구체에서 중요한 개념만 추출해서 드러내고 우리 도메인 컨텍스트 안에서 이해되어야 한다는 것이다.다음과 같은 tip이 있다.단수와 복수를 비교하기만약 리스트나 컬렉션 타입이라면 복수형태로 표현해서 이해를 도울 수 있다이름 줄이지 않기줄임말은 얻는 것보다 잃는 것이 많다(가독성 > 효율성?)관용어처럼 사용되는 것 제외 (col, lat, lon, cnt는 비추천)줄임말이 이해되는 것은 컨텍스트 때문인 것을 늘 상기은어/방언 사용하지 않기농담, 일부 팀원만 아는 용어 금지도메인 용어 사용하기 (도메인 용어 사전을 먼저 구축해야 할 수도, 방대하거나 필요하다면)좋은 코드를 보고 습득하기비슷한 상황에서 자주 사용되는 단어나 개념 습득하기pool(한정된 자원을 가지는 것), candidate(후보), threshold(문지방, 한계점, 임계값) 등 메서드 추상화잘 짜여진 메서드는 메서드 안에 주제(하는 일)가 하나만 존재한다.메서드명을 생각해보면 메서드명은 내부의 구체적인 동작을 유추할 수 있어야 한다. 반대로 생각해보면 하나의 메서드명이 나오기 힘든 로직을 가진다면 2개 이상의 동작이 있을 확률이 크다. 메서드명, 파라미터, 반환타입은 추상화된 구체를 쉽게 유추할 수 있거나 실행할 때 필요한 변수들을 쉽게 캐치할 수 있도록 하는 것이 좋다. 반환 타입은 필요한 의미를 충분히 가지도록 하고 void 대신 반환할만 한 값이 있는지 고민해보자. 추상화 레벨메서드 안과 밖은 서로 추상화 레벨이 다르다.밖은 상대적으로 추상화 레벨이 높고 안은 낮다고 할 수 있다. 메서드 안팎은 서로 파라미터와 반환타입으로 교류한다.하나의 메서드 안에서 추상화 레벨을 맞춰주기 위해 구체적인 레벨의 것이 있는지 확인하고 있다면 메서드화하는 등의 방법으로 바꿔주면 좋다. 매직 넘버, 매직 스트링상수로 추출하는 것은 이름을 주어 추상화하는 것이라고 볼 수 있다.특정한 의미를 가지는 (보드의 가로, 세로 길이 등) 숫자나 문자열같은 경우에 상수로 추출해준다면 가독성과 유지보수성이 올라간다.또한 중요한 숫자나 문자를 강조하면서 읽는 사람이 더 주의깊게 볼 수 있도록 해준다. 사고의 depth 줄이기사고 과정의 depth를 줄이기 위한 메서드 추출을 고려하자.사용할 변수는 가깝게 선언하는 것이 좋다. 공백 라인, 부정어, 예외처리의미 단위로 적절하게 공백 라인을 사용하는 것이 좋다.연산자로 부정하기 보다는 메서드명으로 구성하는 것이 더 나을지 고민하자.해피 케이스 외의 예외들이 생길 부분을 고려하고 의도한 예외(사용자에게 보여줄 예외)와 그렇지 않은 예외(개발자가 보고 처리해야 할 예외)를 구분하자. Nullnull반환은 웬만하면 하지 않는다. Optional도 처리할 분기가 3개나 되기 때문에 꼭 필요한지 생각해본다.stream API를 적용하자. orElse(), orElseGet(), orElseThrow()의 차이를 알고 적절하게 사용하자. 마무리 회고어렴풋이 아는 것들을 확실하게 체득할 수 있었던 한 주였습니다.새롭게 기록되는 학습들을 보니까 기분이 좋습니다. 이번주에는 불규칙하게 들었지만 다음주에는 정해진 시간에 정해진 양만큼 들어야겠습니다. 다음주도 화이팅!
웹 개발
・
백엔드
・
클린코드
・
테스트코드
・
워밍업클럽