LostCatBox

자바 주니어 개발자를 위한 강의

Word count: 1.2kReading time: 7 min
2024/05/30 Share

왜?

간단하게 자바 주니어가 가르침 받아야할 목록 정리(요약)

출처

섹션1

컨벤션

  • Get 은 인스턴스 반환, Find는 Optional 반환

  • isExist -> exist활용하기 (동사는 하나만)

  • Getter, setter 객체에 난발하지마라

    • 객체는 자율적이고 객체지향적으로 코딩하자
    • user.setUserStatus(UserStatus.ACTIVE) -> user.login() 객체에 일을 시키자
  • Optional 사용하자 -> NPE 줄어듬

  • Collection.Map 남발하지마라 -> 가급적이면 일급 클래스로 만들고, 사용하더라도, {scope}밖으로 가지마라

  • 검증 필요할때

    • verify -> 동작 확인, 실패시 Exception
    • validate -> 검증 void반환, 실패시 Exception
    • check -> check만 진행, 수정에 대한 행동은 하지않는다.
    • Is -> boolean 반환
  • 구글 코드 스타일 찾아보기

  • 클래스이름은 단어 조합 3개 이하로

객체 지향적인 코드짜기

vo, dto, entity

  • vo

    • 불변 객체로만 유지
    • 생성자 역할
      • 생성전 값 검증
      • 불변값 할당
  • dto

    • 상태를 보호하지 않으며, 모든 속성을 노출한다
    • 데이터 전송에 사용
  • 엔티티

    • 유일한 식별자 가짐
    • 수명 주기 존재
    • 쓰기 모델에 저장 지속성가짐 (보통 db에저장)

어떤 값을 불변, 어떤값을 메서드 노출시킬것인지 중요

디미터법칙

  • 디미터법칙은 객체의 내부 구조를 외부로 드러내지 않는 것이 중요

행동 위주의 사고로 클래스 설계

순환 참조 하지않기

  • 결합도 높음
  • 직렬화 불가능 순환참조가 일어나므로

순환 참조 해결

  • 간접 참조로 해결 -> foreignkey로 푸는것이 아닌 간접적으로 id값만 객체에 넣기
  • 컴포넌트 분리 검토 -> 기존 A <-> 기존 B 가 아니라 -> A -> C <- B 로 별로의 클래스 분리가능한지 생각
  • mappedBy 생각안해도됨 -> 단방향 참조를 할것이므로

Final, 메서드 먼저 생각

VO의 변경자는 구현가능 -> return new VO 형태

설계

SOLID

의존성

  • 의존성 역전: 추상화와 관련된 개념. 상위 모듈은 하위모듈의 구현체에 의지하지않고, 상위 모듈, 하위 모듈은 공통의 인터페이스에 의존해아함
  • 의존성 주입: Springboot가 해주는것, 의존성이 있는 클래스들을 생성자 등에서 주입해준다
    • Ioc

의존성 조언

  • 의존성 주입과 책임
    • 생성자 의존성 주입이 7개 이상넘어가거나
    • 파라미터 의존성 주입이 4개 이상 넘어간다면
    • 분리 고려대상
  • 의존성을 드러내라
    • 테스트를 짜기 쉬운 구조로 변경해야한다
    • 시간, 랜덤에 대한 의존성을 사용함 -> 변하는값 -> 외부에서 의존하는게 테스트하기 쉽고, 외부에 주입형태를 사용하자.
    • 변하는 값에 대한 의존성 처리는 의존성 역전을 통해 -> 추상화 후 런타입 의존성과 컴파일 타임 의존성을 다르게하는것
    • image-20240602125250572

CQRS(명령과 질의의 책임 분리 이론)

  • 명령
    • 명령 메소드는 객체의 상태를 변경시킴 , return 값을 갖지않는다.
  • 질의
    • 상태를 물어보는 메소드 -> 객체의 상태를 변경시키면 안됨

image-20240602125728127

기타 팁

500 응답(=장애성 에러 -> 알맞는 에러코드 필요)

좋은 프로그램

  • 돌아가야한다
  • 유지보수가 가능해야한다.

디자인 패턴에 매몰되지 않는다

OOP

  • 객체 지향 프로그래밍! (클래스 지향)
  • TDD, DDD, FP
  • DDD -> 도메인 이라는 객체 모델을 어떻게하면 잘 정의할수있을까?

OOP -> 역할, 책임, 협력

상속을 지양하고 Composition을 지향할것

테스트를 먼저 생각하기( 테스트 쉬움 -> 좋은 코드)

블락 과 tab in tab(=if else 등의연속)

  • 코드에 각 블록(띄어쓰기로 용도 구분) -> 메서드로 분리하기
  • tab in tab 반복 시 메서드 분리

색센2: OOP스럽게 스프링 사용

안티패턴(Transaction script)

안티패턴1(Smart UI -> controller가 너무 스마트해.. 비즈니스로직까지 포함함)

image-20240602135752682

안티패턴 2 (서비스가 신이 되어있는 절차지향적코드)

image-20240602140328759

개선된 레이어 아키택처

  • controller, service, domain,repository 로 분리함

  • Service 계층은 소프트웨어가 수행할 작업을 정의하고 표현력 있는 도메인 객체가 문제를 해결하게 하는 레이어, (service)응용 계층은 최대한 얇게 유지되어야한다. 오직 작업을 조정하고 아래에 위치한 계층에 도메인(domain) 객체의 협력자에게 작업을 위임한다

image-20240602135947673

  • 서비스에 있는 책임을 각 도메인 layer에 분산시켜 책임분리 -> 도메인은 능동적으로 변할수있게 일을 시켜야함

개선된 로직

  • 해당 로직은 어떤 도메인 객체 하나에 책임위임하기 힘듬.-> 새로운 객체를 만들어 책임분리

image-20240602140834487

  • priceCalcurate -> 테스트도 용이, 또는 Cashier 도메인으로 분리해도 적합해보인다.
  • 보통은 Manager 또는 도메인 서비스 라고 한다. 도메인 계층에 포함된다.
    • Application Service 계층은 단순히 domain 계층에 일을 위임할 뿐이다.

image-20240602141009782

image-20240602141231859

도메인과 도메인 서비스

  • 도메인 영역의 애그리거트나 밸류(Entity, VO)와 같은 구성요소와 도메인 서비스의 차이점은 도메인 서비스는 상태 없이 로직만 구현한다는 점이다.

  • 도메인 서비스를 구현하는 데 필요한 상태는 다른 방법으로 전달받는다.

  • 도메인 서비스는 반드시 주입받아서 해결한다.

    도메인 서비스 객체를 애그리거트(Entity, VO)에 주입하지 않기
    애그리거트의 메서드를 실행할 때 도메인 서비스 객체를 파라미터로 전달한다는 것은 애그리거트가 도메인 서비스에 의존한다는 것을 의미한다. 스프링 DI와 AOP를 공부하다보면 애그리거트가 의존하는 도메인 서비스를 의존 주입으로 처리하고 싶을 수 있다. 하지만 개인적으로 이것은 좋은 방법이 아니라고 생각한다. 도메인 객체는 필드로 구성된 데이터와 메서드를 이용해 개념적으로 하나인 모델을 표현한다. 모델의 데이터를 담는 필드는 모델에서 중요한 구성요소다. 그런데 discountCalculateService(도메인 서비스) 필드는 데이터 자체와 관련이 없으며, 다른 필드와 달리 저장 대상도 아니다. 또한 Order가 제공하는 모든 기능에서 필요로 하는 것도 아니다. 일부 기능을 위해 굳이 도메인 서비스 객체를 애그리거트에 의존 주입할 이유는 없다.

    응용 서비스 vs 도메인 서비스

    특정 기능이 응용 서비스인지 도메인 서비스인지 감을 잡기 어려울 때는 해당 로직이 애그리거트의 상태를 변경하거나 상태 값을 계산하는지 검사해보자. 계좌 이체 로직은 계좌 애그리거트의 상태를 변경한다. 결제 금액 로직은 주문 애그리거트의 주문 금액을 계산한다. 이 로직들은 각각 애그리거트를 변경하고 값을 계산하는 도메인 로직이다. 도메인 로직이면서 한 애그리거트에 넣기 적합하지 않으므로 도메인 서비스로 구현하게 된다.

결국 객체 지향 프로그램을 활용하고. 객체간 책임, 협력, 역할이 명확해야한다.

어디까지 추상화 해야하는가?

추상화

  • 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려내는것
  • 즉, 모듈을 격리하고 인터페이스를 만드는과정(책임을 선별하는 과정 필요)
  • DIP 의 핵심은 고수준 모듈이 저수준 모듈에 의존하지 않도록 하기위함이다.
  • 하지만, Controller, Service는 추상화할필요없다.
    • Controller, serivce, vo, entity 는 구현체로 구현되도상관없다. 한번 생성으로 영원히 같은 일을 할수있는 객체이기때문이다
  • 도메인 계층을 추가하자
    • 도메인 계층은 Service에만 의존하고, 원칙적으로는 Repositroy를 알필요없다
    • image-20240602142533802

추상화 결론

  • 시스템 외부 연동은 추상화한다.(client, repository 등)
  • Controller, serivce, vo, entity 는 추상화할필요없다.
  • 도메인 계층을 만들고, 도메인 영역을 풍부하게한다.
  • 테스트 하기 쉬운 것이 좋은 코드다

서비스란 무엇인가?

  • 서비스는 비즈니스 서비스 퍼사드 이다. 즉, 자기자신의 로직, 도메인, 도메인 서비스에게 일을 시키는 역할을 한다.

  • 하지만 따로 도메인 서비스를 만드는 이유는 객체로 다듬도, 책임을 분리하기 위해서다.

    • 애플리케이션 Service : 스프링의 서비스 컴포넌트에 종속되는 서비스
    • 도메인 Service: 스프링의 서비스 컴포넌트에 종속되지 않는 서비스
  • 결국 서비스는 앏게 만들고, 도메인은 풍부하게

  • 서비스 객체는 한번 생성하면 특정 작업을 하는 작은 기계처럼 영원히 실행한다. 결국 불변해야하며, 이는 생성자 주입을 통해 서비스 객체를 생성해야하는 이유가 된다.

    • final사용
    • 생성자 주입사용
    • Setter 사용 금지
  • image-20240602143136796

기타 꿀팁

JPA

  • 양방향 하지마라

  • n+1 문제와 해결

  • 낙관적 락, 비관적 락

    • 낙관젹 -> version 필드 사용 -> db 락 사용 안함
    • 비관적 락 -> select for update -> db 락 사용
  • Self-invocation : AOP 에너테이션을 사용하는 메소드를 자가 호출할때, 문제발생한다. -> 스프링 컴포넌트에 있는 AOP 에너테이션은 스프링 프록시를 거칠 수 있을 때만 가능하다.

    • 아래 예시에서는 자가 호출을 할때, 스프링 프록시를 거치지 않기때문에 @Transactional은 안먹힌다

    • image-20240602150039063

  • FACK 객체 사용

    • image-20240602150346938
  • CQRS공부

테스트를 왜 해야하나?

레거시 코드란?

  • 테스트 루틴이 없는 코드가. 레거시 코드다.
  • 소형테스트를 하는것이 최우선

테스트 코드의 목적

  • 회귀 버그 방지
  • 유연한 설계

테스트에 필요한 개념

  • sut : 테스트 대상
  • tdd : 실패 , 실패->성공 , 리팩토링
  • bdd : 행동 주의
  • interaction test : 상호작용 테스트
  • dummy : 아무런 동작없이 코드가 정상적으로 돌아가기위한 객체
  • Fake: 자체 로직 있음
  • stub : 미리 준비된 값 반환
  • mockito : 지양해야함. 쓸수록, 테스트 코드 작성이 목적이 되고, 추상화로 유연한 설계를 얻을 기회를 상실함(mockito는 단순히 반환값까지 지정해버리기때문에)

테스트 기법 소개

  • private 메소드는 테스트 하지않는다.
    • 만약, 테스트 하고싶다면, 행위가 중요하므로 클래스를 분리해야함
  • final 메소드 stub해야한다면, 틀린방식
    • 의존석 약하게 하는 방법고려
  • 테스트는 dry < damp
  • 테스트에는 논리(+, for, if)를 넣지말자

테스트

  • 의존성 추상화 (의존성 역전) 생각해보기
  • 이벤트 기록방법

섹션4

네트워크

  • Load balancing
  • Global server load balancing
  • ACL : 접근 제어 목록(외부 통신시 필요)
  • Proxy : 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할수있게함.
    • 포워드 프록시
    • 리버스 프록시
  • 온프레미스: 자체 전산실에 직접설치 운영 , 온디맨드: 수요 발생시 바로 서비스 전달방식
  • HA: 고가용성
  • DR : 재난 복구 매뉴얼
  • Failover : 장애 극복 기능 -> 서버, 시스템, 네트워크 등 이상생겼을때, 시스템 자동 전환기능
  • Webhook: 이벤트 발생시 API를 호출하는 콜백 API

Mysql 조언

image-20240603221601265

image-20240603221720442

image-20240603221836250

https://raw.githubusercontent.com/lostcatbox/lostcatbox.github.io-image_repo/uploadimage/img202406032218280.png![image-20240603221846160](https://raw.githubusercontent.com/lostcatbox/lostcatbox.github.io-image_repo/uploadimage/img202406032218188.png)

  • 쿼리를 쪼개는것이 훨씬좋다
  • 서브쿼리 사용하지마세요/
  • image-20240603221915927

image-20240603221927611

image-20240603221952169

image-20240603222007182

image-20240603222017707

image-20240603222032936

CATALOG
  1. 1. 왜?
  2. 2. 출처
  3. 3. 섹션1
    1. 3.1. 컨벤션
    2. 3.2. 객체 지향적인 코드짜기
      1. 3.2.1. vo, dto, entity
      2. 3.2.2. 어떤 값을 불변, 어떤값을 메서드 노출시킬것인지 중요
      3. 3.2.3. 디미터법칙
      4. 3.2.4. 행동 위주의 사고로 클래스 설계
      5. 3.2.5. 순환 참조 하지않기
      6. 3.2.6. 순환 참조 해결
    3. 3.3. 설계
      1. 3.3.1. SOLID
      2. 3.3.2. 의존성
      3. 3.3.3. 의존성 조언
      4. 3.3.4. CQRS(명령과 질의의 책임 분리 이론)
    4. 3.4. 기타 팁
      1. 3.4.1. 500 응답(=장애성 에러 -> 알맞는 에러코드 필요)
      2. 3.4.2. 좋은 프로그램
      3. 3.4.3. 디자인 패턴에 매몰되지 않는다
      4. 3.4.4. OOP
      5. 3.4.5. OOP -> 역할, 책임, 협력
      6. 3.4.6. 상속을 지양하고 Composition을 지향할것
      7. 3.4.7. 테스트를 먼저 생각하기( 테스트 쉬움 -> 좋은 코드)
      8. 3.4.8. 블락 과 tab in tab(=if else 등의연속)
  4. 4. 색센2: OOP스럽게 스프링 사용
    1. 4.1. 안티패턴(Transaction script)
      1. 4.1.1. 안티패턴1(Smart UI -> controller가 너무 스마트해.. 비즈니스로직까지 포함함)
      2. 4.1.2. 안티패턴 2 (서비스가 신이 되어있는 절차지향적코드)
      3. 4.1.3. 개선된 레이어 아키택처
        1. 4.1.3.1. Service 계층은 소프트웨어가 수행할 작업을 정의하고 표현력 있는 도메인 객체가 문제를 해결하게 하는 레이어, (service)응용 계층은 최대한 얇게 유지되어야한다. 오직 작업을 조정하고 아래에 위치한 계층에 도메인(domain) 객체의 협력자에게 작업을 위임한다
      4. 4.1.4. 개선된 로직
      5. 4.1.5. 도메인과 도메인 서비스
      6. 4.1.6. 결국 객체 지향 프로그램을 활용하고. 객체간 책임, 협력, 역할이 명확해야한다.
    2. 4.2. 어디까지 추상화 해야하는가?
      1. 4.2.1. 추상화
      2. 4.2.2. 추상화 결론
    3. 4.3. 서비스란 무엇인가?
    4. 4.4. 기타 꿀팁
      1. 4.4.1. JPA
  5. 5. 테스트를 왜 해야하나?
    1. 5.1. 레거시 코드란?
      1. 5.1.1. 테스트 코드의 목적
    2. 5.2. 테스트에 필요한 개념
      1. 5.2.1. 테스트 기법 소개
      2. 5.2.2. 테스트
  6. 6. 섹션4
    1. 6.1. 네트워크
  7. 7. Mysql 조언