성규
수강평 작성수
6
평균평점
4.8
블로그
전체 5#카테고리
- 백엔드
![[인프런 워밍업 스터디 클럽 2기 백엔드(클린코드, 테스트코드)] 후기](https://cdn.inflearn.com/public/files/blogs/f9f2e106-a9d4-493f-bf15-4a059f1c0b83/334820.png?w=260)
2024. 11. 05.
0
[인프런 워밍업 스터디 클럽 2기 백엔드(클린코드, 테스트코드)] 후기
강의 후기!!.Net 을 개발을 하다가 Java 업무를 접하게 되면서 부족한 부분이 많다는 것을 느끼고 클린코드에 대한 필요하다는 것을 알게되었는데 책으로만 배우기에는 아쉬움을 느끼던 와중 클린코드, 테스트코드 스터디클럽이 개설되어 고민 없이 신청을 하였습니다. 그러나 업무와 학습을 병행하여 빡빡한 스케줄을 마추기는 힘들어서 열정적으로 듣지는 못했던 부분이 매우 아쉬웠지만 강의에서 말하는 포인트들이 마음에 와닿은 말들이 많아서 이후 조금이라도 좋은 코드를 생성할 수 있다는 확신이 들었습니다. 아직은 수준이 낮아서 덜 공감 되는 부분도 없지 않았지만 이후 계속 생각을 해서 어떤 부분이 더 나을지 계속적인 확인 작업이 필요할꺼 같습니다. 실무에 적용하기에는 아직 부족하지만 강의를 통해 배운 내용을 되새기면서 업무를 하다 보면 좋은 코드를 작성을 위해 강의와 라이브에서 알려준 부분들도 추가로 학습을 하여 좋은 개발자가 되도록 노력을 할 예정입니다. 다음기회에 또 뵈요~!!!
백엔드
![[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 4주차 발자국](https://cdn.inflearn.com/public/files/blogs/ed9d6766-14af-4c52-a65d-47800300968d/334820.png?w=260)
2024. 10. 21.
0
[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 4주차 발자국
MockMvcMock(가짜) 객체를 사용해 스프링 MVC 동작을 재현할 수 있는 테스트 프레임워크 Test DoubleDummy아무 것도 하지 않는 깡통 객체Fake단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체Stub (상태검증)테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체 그 외에는 응답하지 않는다.SpyStub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체 일부는 실제 객체처럼 동작 시키고 일부만 Stubbing 할 수 있다.Mock (행위검증)행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체BDDMockitoBDD : 행동 주도 개발Mockito 를 한번 감싸서 호출하는 것 뿐한 문단에 한 주제!완벽하게 제어하기DateTime.Now 처럼 제어하지 못하는 것 보다는 제어 할 수 있는 부분으로 변경외부 시스템을 이용해야하는 경우는 Mock 을 활용하여 처리테스트 환경의 독립성을 보장하자테스트는 given 에서 문제가 발생하지 않도록, 문제는 when, then 에서 나게 유도 생성자를 활용하여 처리하는 걸 추천테스트 간 독립성을 보장하자공유자원을 활용하여 처리를 하는 경우 서로에게 영향이 갈 수가 있음한 눈에 들어오는 Test Fixture 구성하기Fixture : 고정물, 고정되어 있는 물체테스트를 위해 원하는 상태로 고정시킨 일련의 객체@BeforeAll, @BeforeEach 는 아래 질문에 부합할 때 사용!! 테스트 내용을 히애하는데 문제가 없는가? 수정해도 모든 테스트에 영향을 주지 않는가??테스트에 필요한 것만 생성을 할 수 있도록 간편하게 적용테스트에서 중복으로 사용하게 되는 함수나 클래스등을 모아서 처리 하는 방식은 모아둔 곳이 거대해져서 더 안 좋아 질 수도 있음deleteAllInBatch연관관계와 다르게 순서를 안 지키면 삭제 안됨DELETE 만 발생deleteAll전체 조회 후 외래키와 관계된 데이터를 건마다 삭제ALL select → EACH delete다수의 쿼리로 인해 많은 비용이 발생@Parameterized Test단 하나의 테스트 인데 값을 바꿔가면서 테스트 하고 싶을 떄@DynamicTest시나리오 작성하듯이 순차적으로 테스트 발생 시킬 수 있음테스트 수행도 비용이다!통합테스트를 하게 되면 스프링부트가 중복으로 많이 호출 되게 됨같은 @SpringBootTest 라도 조금이라도 다르면 다시 호출 됨새롭게 스캔해야하는 경우에도 다시 호출 ex) MockBeanMockBean 을 사용하는 것과 안하는 것 두개를 나눠서 처리 해도 됨서버를 뜨는 시간을 줄이는 것이 테스트 양이 많아 질수록 이득Private 메서드의 테스트는 어떻게 하나요??테스트를 할 필요가 없다(?)객체를 분리할 시점인가?? 확인Public Method 를 테스트 하다보면 Private Method 는 자연스럽게 검증이 됨테스트에서만 필요한 메서드가 생겼는데 프로덕션 코드에서는 필요 없다면??만들어도 된다. 하지만 보수적으로 접근하기
백엔드
![[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 3주차 발자국](https://cdn.inflearn.com/public/files/blogs/84c131ef-276b-462f-895b-5b575d69a4a6/334840.png?w=260)
2024. 10. 20.
0
[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 3주차 발자국
통합 테스트일반적으로 작은 범위의 단위 테스트만으로는 기능 전체의 신뢰성을 보장할 수 없다.풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트SpringLibrary내 코드가 주체!!외부에 있는 기능을 끌어 옴Framework이미 동작 할 수 있는 환경내 코드가 수동적SpringIOCDIAOPJPAORM : Object-Relational Mapping객체 지향 패러다임과 관계형 DB 패러다임의 불일치단순 작업을 줄이고 비지니스 로직에 집중 할 수 있다.JPA인터페이스 이고 여러 구현체가 있지만 보통 Hibernate를 많이 사용한다.편리하지만 어떤 식으로 쿼리가 만들어지고 실행되는지 명확하게 이해하고 있어야 한다.Sping Data JPAJPA 를 한번 더 추상화한 Spring Data JPA 제공QueryDSL과 조합하여 많이 사용한다. (타입체크, 동적 쿼리)※ @AllArgsConstructor 를 지양하시는 이유빌더 패턴은 빌더 패턴의 장점이 별도로 있기 때문에 사용하는 것이고, @AllArgsConstructor 를 사용하지 않는 이유는 별개의 이유입니다.@AllArgsConstructor는 편리하게 모든 필드를 가진 생성자를 만들어 주지만, 필드의 순서가 변경되는 경우 치명적일 수 있습니다.예를 들어 어떤 객체가 2개의 String 타입을 필드로 가지고 있고, 이에 대한 생성자를 외부에서 사용하고 있다고 가정해 봅시다.해당 객체의 필드 순서가 실수로 변경되어도 컴파일 에러가 발생하지 않고, 추후 인지하지 못한 치명적인 버그가 발생할 수 있는 여지가 됩니다.그럼 @RequiredArgsConstructor를 사용해도 final 키워드만 붙었지 마찬가지 아닌가, 싶으실텐데요. 맞습니다. AllArgs~와 동일한 문제를 안고 있지만, 저는 그래도 편의성을 위해 @RequiredArgsConstructor정도는 인지하고 사용하자는 편입니다.이유는 다음과 같은데요.사용자가 final 키워드를 붙이면서 필수 파라미터에 대한 인지를 하고 필드를 선언한다는 점스프링에서는 객체의 생성자만 만들어두면 스프링에서 알맞은 타입과 이름의 빈을 찾아서 주입해주기 때문에, 필드 순서가 바뀌거나 해도 타입+이름 기반으로 동작하니 @RequiredArgsConstructor 를 사용해도 큰 무리가 없음다만 스프링의 Bean이 아닌 사용자가 직접 만들고 사용하는 일반 객체라면, 위 문제를 방지하기 위해 @RequiredArgsConstructor 대신 그냥 생성자를 사용해보는 것을 고려해볼 수 있습니다.※ 패키지 구성애그리거트(Aggregate) 기준으로 패키지를 나누고 하위에 domain, sub-domain, service, repository 등을 위치시켜 컨텍스트를 나누는 방식으로도 사용할 수 있습니다. Persistence LayerData Access 의 역할비지니스 가공 로직이 포함되어서는 안된다. Data에 대한 CRUD에만 집중한 레이어데이터를 담당하는 부분으로서 꼼꼼하게 확인을 해둬야하는 부분Business Layer비지니스 로직을 구현하는 역할Persistence Layer와의 상호작용을 통해 비지니스 로직을 전개시킨다트랜잭션을 보장해야 한다.트랜잭션에 대한 이해를 해야 운영에서 문제 없이 돌아 갈 수가 있다.Presetation Layer외부 세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행한다.
![[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 2주차 발자국](https://cdn.inflearn.com/public/files/blogs/73102a70-d4cd-4cee-a119-8e4b975453c0/334840.png?w=260)
2024. 10. 12.
0
[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 2주차 발자국
주석의사 결정의 히스토리를 코드로 표현할 수 없을 때, 주석으로 상세하게 설명자주 변하는 정보는 지양코드도 변경되면 주석도 함께 변경좋은 주석?우리가 가진 모든 표현 방법을 동원해 코드에 의도를 녹여내고그럼에도 불구하고 전달해야 할 정보가 남았을 때 사용하는 주석변수와 메서드의 나열 순서정답은 없지만 중복이 없을 수 있게 정렬변수사용하는 순서대로사용하는 곳 근처메서드공개 메서드를 상단에중요도, 종류별로 그룹화상태 변경 >> 판별 ≥ 조회나열 순서로도 의도와 정보를 전달 할 수 있는 것!!!코드를 보는 사람이 인지하기 쉽게!!패키지 나누기패키지는 문맥으로써의 정보를 제공할 수 있다.패키지는 적당(?)하게 나눠야 좋다리펙토링null 을 반환하는 것은 nullPointException 을 발생시키기 때문에 안티패턴파라미터로 Optional 을 보내는 것도 안티 패턴Optional 이 자체가 nullOptional 에 들어있는 객체가 nullOptional 에 들어있는 객체가 존재 한다 받는 입장에서는 위 3가지 처리를 해야함Optional.ifPresentOrElse 앞에는 값이 있을 때, 뒤에는 값이 없을 때 액션을 지정할 수 있음optionalLockerPass.ifPresentOrElse( lockerPass -> outputHandler.showPassOrderSummary(selectedPass, lockerPass), () -> outputHandler.showPassOrderSummary(selectedPass) ); Git Commit 은 짧게 짧게작업을 쪼개서 유지 관리에 용이 해짐IO 통합세트로 묶여서 작업되는 부분들을 합쳐서 관리하는 것일급 컬렉션일급 컬렉션은 리스트를 감싸서 컬렉션 내부에서 리스트를 추상화(제어.. 등등)을 할 수 있음display 책임Order 추가헥사고날 아키텍쳐포트와 어댑터포트 : 인터페이스, 스펙!어댑터 : 포트에 맞는 구현체능동적 읽기목표 : 우리의 도메인 지식을 늘리는 것!!오버 엔지니어링필요한 수준보다 더 높은 수준의 엔지니어링!구현체가 하나인 인터페이스구현체를 수정할 때마다 인터페이스도 수정해야함코드 탐색에 영향, 어플리케이션이 비대해 짐너무 이른 추상화정보가 숨겨지기 때문에 복잡도가 높아진다다른 개발자들이 의도를 파악하기 어렵다.클린코드는 절대적인 것이 아니다.미래에 잘 고치도록 할 수 있는 코드 센스가 필요!결국 클린코드의 사고법을 기반으로 결정!지속가능한 소프트웨어의 품질 vs 기술부채를 안고 가는 빠른 결과물
백엔드
![[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 1주차 발자국](https://cdn.inflearn.com/public/files/blogs/17eff55c-db65-40ba-8c05-8956208bdf73/334820.png?w=260)
2024. 10. 06.
0
[워밍업 클럽 스터디 2기 :: BE 클린코드 & 테스트] 1주차 발자국
뇌 메모리 적게 쓰기프로그램 = 데이터 + 코드정리하는 뇌정리 시스템에서 중요한 과제는 최소의 인지적 노력으로 최대의 정보를 제공하는 것이다.도둑맞은 집중력뇌는 한 번에 한 가지 일 밖에 하지 못한다.인지적 경제성을 추가하자Early returnEarly return 으로 else의 사용을 지양하자Early return 을 통해서 끊어서 볼 수 있도록 하여 이후 불필요한 로직을 수행하지 않도록 처리사고의 depth 줄이기중첩 분기분, 중첩 반복문‘무조건 1 depth로 만들어라’ 가 아니다. → 보이는 depth를 줄이는 데에 급급한 것이 아니라, 추상화를 통한 사고 과정의 depth를 줄이는 것이 중요 → 2중 중첩 구조로 표현하는 것이 사고하는 데에 더 도움이 된다고 판단한다면, 메서드 분리보다 그대로 놔두는 것이 더 나은 선택일 수 있다. 때로는 메서드를 분리하는 것이 더 혼선을 줄 수도 있다.무조건 strame 이 인지하기 좋은 것은 아니다. for i, foreach 가 더 좋은 경우도 있으니 상황에 맞게 사용하자사용할 변수는 가깝게 선언하기Beforeint i = 10; // 코드 20줄..... int j = i + 10; After// 코드 20줄..... int i = 10; int j = i + 10; 파라미터를 줄일 수 있다면 줄이는게 좋다.공백 라인을 대하는 자세공백 라인도 의미를 가진다. → 복잡한 로직의 의미 단위를 나우어 보여줌으로써 읽는 사람에게 추가적인 정보를 전달할 수 있다.부정어를 대하는 자세부정어구를 쓰지 않아도 되는 상황인지 체크부정의 의미를 담은 다른 단어가 존재하는지 고민 or 부정어구로 메서드명 구성※ 부정 연산자(!)의 가동성 ↓if(!isLeftDirection()){ } // 반대대는 상황이 있다면 if(!isRightirection()){ } // 메서드명에 Not 을 추가하는 방법 if(isNotLeftDirection()){ } 해피 케이스와 예외 처리사람은 해피 케이스에 몰두하는 경향이 있다.예외가 발생할 가능성 낮추기어떤 값의 검증이 필요한 부분은 주로 외부 세계와의 접점의도한 예외와 예상하지 못한 예외를 구분하기Null을 대하는 자세항상 NullPointException을 방지하는 방향으로 경각심 가지기메서드 설계 시 return null을 자제한다. → 만약 어렵다면, Optional 사용을 고민해 본다.Optional에 관해Optional은 비싼 객체다. 꼭 필요한 상황에서 반환 타입에 사용한다.Optional을 파라미터로 받지 않도록 한다. 분기 케이스가 3개나 된다. (Optional이 가진 데이터가 null인지 아닌지 + Optional 그 자체가 null인지)Optional을 반환받았다면 최대한 빠르게 해소한다.잘못 사용된 Optional은 안티패턴이다. (JPA에서의 Optional 은 잘 사용된 패턴)Optional을 해소하는 방법분기문을 만드는 isPresent()-get() 대신 풍부한 API 사용orElse(), orElseGet(), orElseThrow()의 차이 숙지orElseThrow() : 그냥 쓰면 됨orElse() : 항상 실행, 괄호안의 값이 확정된 값일때 활용orElseGet() : null인 경우 실행, 값을 제공하는 동작(Supplier) 저의public T orElse(T other){ return value != null ? value : other; } Intger result = somethingOptional.orElse(methodHeavy()); // 호출할 필요가 없는 경우에도 항상 실행 Intger result3 = somethingOptional.orElse(0); // 정해진 값일 때 사 public T orElseGet(Supplier supplier){ return value != null ? value : supplier.get(); } integer result = somethingOptional.orElseGet(() -> methodHeavy()); // null인 경우에만 실행 예외를 던지고 그 안에 메세지를 넣어서 무슨 오류인지 인지할 수 있게 도와주자비교를 할 때 상수와 변수를 비교해야 한다면 상수를 앞에 넣어서 NullPointException 이 안 일어나게 할 수도 있다추상의 관점으로 바라보는 객체 지향객체 : 추상화된 데이터 + 코드관심사의 분리유지 보수가 원활해진다.높은 응집도, 낮은 결합도객체 설계하기객체 : 데이터 + 코드객체(Object)로 추상화 하기비공개 필드(데이터), 비공개 로직(코드, 기능 구현부)공개 메서드 선언부를 통해 외부 세계와 소통 → 각 메서드의 기능은 객체의 책임을 드러내는 창구객체의 책임이 나뉨에 따라 객체 간의 협력이 발생객체가 제공하는 것절차 지향에서 잘 보이지 않았던 개념을 가시화관심사가 한 군데로 모이기 때문에, 유지보수성 ↑ → ex) 객체 내부에서 객체가 가진 데이터의 유효성 검증 책임을 가질 수 있다.여러 객체를 사용하는 입장에서는 구체적인 구현에 신경 쓰지 않고 보다 높은 추상화레벨에서 도메인 로직을 다룰 수 있다.새로운 객체를 만들때 주의할 점1개의 관심사로 명확하게 책임이 정의되었는지 확인하기 → 메서드를 추상화 할 때와 비슷하다. → 객체를 만듦으로써 외부 세계와 어떤 소통을 하려고 하는지 생각해보자.생성자, 정적 팩토리 메서드에서 유효성 검증이 가능하다. → 도메인에 특화된 검증 로직이 들어갈 수 있다.Setter 사용 자제→ 데이터는 불변이 최고다. 변하는 데이터라도 객체가 핸들링 할 수 있어야 한다.→ 객체 내부에서 외부 세계의 개입 없이 자체적인 변경/가공으로 처리할 수 있는지를 확인→ 만약 외부에서 가지고 있는 데이터로 변경 요청을 해야하는 경우, ‘set~’이라는 단순한 이름 보다는 ‘update~’ 같이 의도를 드러내는 네이밍을 고려하자.Getter도 처음에는 사용 자제. 반드시 필요한 경우에 추가하기→ 외부에서 객체 내 데이터가 필요하다고 getter를 남발하는 것은 무례한 행동이다.객체에 메시지를 보내라단일 책임의 원칙 :SRP : Single Responsibility Principle하나의 객체는 각자 맞는 책임을 가지게OCP : Open-Closed Principle추상화와 다형성을 이용!객체 자체는 무엇이 들어와도 처리가능 하게인터페이스를 통해 다양한 값이 들어 올 수 있도록 처리LSP : Liskov Subsitution Principle부모에서의 기능을 자식에서도 동일하게ISP : Interface Segregation Principle클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안된다. → 인터페이스를 잘게 쪼개라ISP를 위반하면, 불필요한 의존성으로 인해 결합도가 높아지고, 특정 기능의 변경이 여러 클래스에 영향을 미칠 수 있다.※ 기능단위로 인터페이스를 작게 사용해라! DIP : Dependency Inversion Principle의존성 : 하나의 모듈이 다른 하나의 모듈을 생성하거나 사용하는 모든 것, 참조하는 것의존성 순방향 : 고수준 모듈이 저수준 모듈을 참조
백엔드




