Yeon's Frame
  • Intro
  • Project
    • 미소웨더
      • 기획 - 아이디어 및 유스케이스 정리
      • DB 설계 - JPA 활용 중심
  • Study
    • Spring
      • Spring Feature
      • N+1
      • OSIV
      • @Valid
      • Spring Boot Feature
      • Spring 5 Feature
      • JPA vs MyBatis
      • Filter, Interceptor
      • Persistence Context
      • @Transactional
      • @Controlleradvice, @ExceptionHandler
      • Spring Security
      • Dispatcher Servlet
      • @EnableWebMvc
      • Stereo Type
      • AOP
      • JPA Repository
    • Infrastructure
      • Git
      • DNS
      • JWT
      • DevOps
      • Docker
      • Jenkins
      • Cloud Computing
      • MSA
    • Clean Code
      • 깨끗한 코드
      • 의미있는 이름
      • 함수
      • 주석
      • 형식 맞추기
      • 객체와 자료구조
      • 오류 처리
      • 경계
      • 단위테스트
      • 클래스
      • 시스템
  • Basic
    • Java
      • OOP
      • OOL Features
      • Class & Objects
      • Instance & Heap Memory
      • Constructor
      • Reference Type Uses
      • Access Modifier & Hiding
      • This
      • Collaboration
      • Static
      • Inheritance
      • Polimorphism & Casting
      • Abstract Class
      • Interface
      • Object Class
    • Java Coding
      • JVM
      • String, StringBuffer, StringBuilder
      • SOF
      • Blockcing/NonBlocking
      • Enum
      • Static
      • Thread
      • hashCode() | equals()
      • JDK8
      • Stream
      • Optional
      • Lambda & Closure
      • Exception
      • Garbage Collecter
      • Collection
      • Call by Value & Call by Reference
      • Generic
    • Java_Advance
      • Inner Class
      • Lambda Expression
      • Functional Interface
      • OOP vs Lambda Expression
      • Stream
      • Reduce()
      • Exception Handling
      • Custom Exception
      • Error Log
      • IO Stream
      • IO Stream - Serialization
      • File Class
      • Decorator Pattern
      • Thread
    • Data Structure
      • Intro
      • Generic(1)
      • Generic(2) T extends
      • Generic(3) Method
      • Collection Frameworks
      • List
      • Iterator
      • Set
      • Comparable & Comparator
      • Map
  • Practice
    • Algorithm
      • Strategy
        • Primitive, Reference, Generic
        • Number Data Types
        • For-Each
        • Array, Queue, ArrayDeque
        • Array vs ArrayList
Powered by GitBook
On this page
  • 📃 시스템 제작과 시스템 사용을 분리하라
  • 📃 관심사 분리
  • 📃 Main 분리
  • 📃 팩토리
  • 📃 의존성 주입
  • 📃 확장
  • 📃 횡단(cross-cutting) 관심사
  • 📃 자바 프록시 API
  1. Study
  2. Clean Code

시스템

깨끗한 코드를 구현하면 낮은 추상화 수준에서 관심사를 분리하기 쉬워진다. 높은 추상화 수준, 즉 시스템 수준에서도 깨끗함을 유지하는 방법을 살펴본다.

📃 시스템 제작과 시스템 사용을 분리하라

SW 시스템은 애플리케이션 객체를 제작하고 의존성을 서로 '연결'하는 준비 과정과 준비 과정 이후에 이어지는 런타임 로직을 분리해야 한다.

  • 제작(Construction): 어플리케이션 객체를 제작하고 의존성을 서로 연결하는 과정

  • 사용(Use): 제작 과정 이후 이어지는 런타임 과정

📃 관심사 분리

애플리케이션을 서로 겹치지 않는 개별 단위로 나누는 과정 → 한 영역이 다른 영역과 격리되기 때문에 다른 영역에 영향을 주지 않고도 변경할 수 있으며, 애플리케이션의 전체적인 유지보수가 용이해진다.

가장 흔히 쓰이는 초기화 지연(Lazy Initialization)의 한계

public Service getService() {
  if (service == null)
    service = new MyServiceImpl(...);
  return service;
}

장점

  • 실제로 필요할 때까지 객체를 생성하지 않으므로 불필요한 부하가 걸리지 않는다. → 애플리케이션을 시작하는 시간이 그만큼 빨라진다.

  • 어떤 경우에도 null 포인터를 반환하지 않는다.

단점

  • getService 메서드가 MyServiceImpl 과 생성자 인수에 명시적으로 의존한다.

  • MyServiceImpl이 무거운 객체라면 단위 테스트 시 적절한 테스트 전용 객체를 할당해야 한다.

  • 일반 런타임 로직에 객체 생성 로직을 섞어놓은 탓에 모든 실행 경로(service가 null이 아닌 경로)도 테스트 해야 한다.

  • 메서드가 작업을 두 가지 이상 수행한다 = 책임이 둘이다. → 단일 책임 원칙(SRP)을 깬다.

많은 애플리케이션이 초기화 지연 기법을 수시로 사용한다. 그래서 전반적인 설정 방식이 곳곳에 흩어져 있다. 모듈성은 저조하며 대개 중복이 심각하다.

체계적이고 탄탄한 시스템을 만들고 싶다면 모듈성을 깨서는 절대로 안 된다. 객체를 생성하거나 의존성을 연결할 때도 마찬가지다. 설정 논리는 일반 실행 논리와 분리해야 모듈성이 높아진다.

📃 Main 분리

시스템 생성과 시스템 사용을 분리하는 방법

  • 생성과 관련한 코드는 모두 main이나 main이 호출하는 모듈로 옮긴다.

  • 모든 의존성이 main에서 애플리케이션으로 향한다.

  • 애플리케이션은 main이나 객체가 생성되는 과정을 모른다.

  • 애플리케이션은 모든 객체가 생성되었고 모든 의존성이 연결되었다고 가정한다.

📃 팩토리

객체가 생성되는 시점을 애플리케이션이 결정할 때 사용하는 방법

  • ABSTRACT FACTORY 패턴 사용

  • 모든 의존성이 main에서 애플리케이션으로 향한다.

  • 애플리케이션은 main이나 객체가 생성되는 과정을 모른다.

  • 객체 생성 시점은 애플리케이션이 결정하지만, 객체 생성 코드는 애플리케이션이 모른다.

  • main 쪽에 있는 FactoryImplementation이 안다.

  • 애플리케이션은 객체 생성 시점을 완벽히 통제하며, 생성자 인수도 넘길 수 있다.

📃 의존성 주입

사용과 제작을 분리하는 강력한 메커니즘

필요한 객체를 직접 생성하는 것이 아닌, 외부로부터 필요한 객체를 받아서 사용 하는 것이다. 이를 통해 객체간의 결합도를 줄이고 코드의 재활용성을 높여준다.

의존성 주입은 제어 역전 기법을 의존성 관리에 적용한 메커니즘이다. 제어 역전에서는 한 객체가 맡은 보저 책임을 새로운 객체에게 전적으로 떠넘긴다. 새로운 객체는 넘겨받은 책임만 맡으므로 단일 책임 원칙을 지키게 된다.

  • DI 컨테이너를 통해 의존성을 관리한다.

  • setter 메소드나 생성자 인수를 통해 의존성을 주입한다.

  • DI 컨테이너는 요청이 들어올 때마다 필요한 객체의 인스턴스를 만든 후 의존성을 설정한다.

📃 확장

'처음부터 올바르게' 시스템을 만들 수 있다는 믿음은 미신이다. 대신에 우리는 오늘 주어진 사용자 스토리에 맞춰 시스템을 구현해야 한다.

테스트 주도 개발 (Test-driven Development), 리팩터링, 그에 따라 얻은 깨끗한 코드는 코드 수준에서 시스템을 조정하고 확장하기 쉽게 만든다.

📃 횡단(cross-cutting) 관심사

로깅, 보안, 트랜잭션 등등 다수의 모듈에서 반복적으로 나타나는 부분 영속성과 같은 관심사는 애플리케이션의 자연스러운 객체 경계를 넘나드는 경향이 있다. 모든 객체가 전반적으로 동일한 방식을 이용하게 만들어야 한다.

  • AOP: Aspect-Oriented Programming

횡단 관심사에 대처해 모듈성을 확보하는 방법론

Aspect: "특정 관심사를 지원하려면 시스템에서 특정 지점들이 동작하는 방식을 일관성 있게 바꿔야 한다."

📃 자바 프록시 API

Step 1: Bank 객체에 프록시 API를 통해 영속성을 추가하는 과정

  • 이제는 사용되지 않는 과정

  • Bank 인터페이스를 만들고, BankImpl이 Bank 인터페이스를 구현한다.

  • Invocation Handler를 구현하고 BankProxyHandler를 생성한다.

  • Java Relection API를 이용해 Bank 인터페이스를 구현하는 객체의 메서드 호출을 가져온다.

  • 데이터베이스에서 데이터를 가져오는 과정을 추가한다.

  • Proxy API를 호출할 때 BankImpl 객체를 통해 생성한 BankProxyHandler와 Bank 인터페이스를 사용한다.

  • 프록시된 인터페이스를 사용하여 모델과 로직이 분리된 코드를 작성할 수 있다.

Step 2: 순수 Java AOP Framework

  • 순수 자바 관점을 구현하는 스프링 AOP, JBoss AOP 프레임워크는 내부적으로 프록시를 사용한다.

  • 설정 파일이나 API를 사용해 객체의 역할을 설정한다. Bank 객체는 DAO로 프록시되었다.

  • 객체를 얻어올 때는 (XML 파일에 설정했던) DI 컨테이너에게 객체를 요청(getBean)한다.

EJB3 - JPA 와 같은 객체 영속성 관리 표준 API

  • 모든 정보가 annotation 속에 있기 때문에 코드 자체가 깔끔하고 가독성이 좋다.

  • annotation에 있는 영속성 정보 전부 또는 일부를 XML 설정으로 옮길 수 있다.

  • (실무에서는 annotation 사용을 선호한다고 함!)

Previous클래스NextJava

Last updated 2 years ago