-
[FEPL05 / TIL] Day 09 - 내겐 너무 어려운 클린 아키텍처Study (etc)/멋쟁이사자처럼 FEPL_05 2025. 6. 30. 00:40
나는 아직 진격거를 다 안봤다. ✏️ 오늘 배운 것
클린 아키텍처 (Clean Architecture)
- 제어의 역전
- 클린 아키텍처
🙂↕️ 이미 알고 있던 것
있었으면 부트캠프 안했다. 💡 새로 알게된 것
클린 아키텍처
더보기먼저, 회고에 앞서 강사님께서 대체적으로 블로그에서 클린 아키텍처에서 이야기하는 것의 대부분은 제대로 이해하지 못하고 작성한 것일 가능성이 높다고 말씀해주셔서, 나도 드리는 당부 말씀.
저도 이해하지 못하고 쓰고 있을지도 모릅니다. 그냥 제가 공부했다는 흔적을 남기는 것이니... 이 글을 통해 유의미한 정보취득이 가능할 지는 모르겠습니다만, 최선을 다해 정리해보겠습니다.
클린 아키텍처, 말 그대로 깨끗한 아키텍처.
소프트웨어를 위의 이미지처럼 여러 계층으로 분리하고 핵심 비즈니스 로직을 외부 요소로부터 독립적으로 보호하고, 시스템의 유지보수성과 확장성을 높이기 위한 설계 원칙이다. 부트캠프에서나 각종 개발자 커뮤니티나 책에서 울부짖는 '비즈니스 로직'의 분리에 관한 한 가지의 해답이 될 수도 있어 보인다.
클린 아키텍처는 다음과 같은 특징들을 갖는다.
- 계층 구조
- 의존성 규칙
- 관심사 분리
그리고, 클린 아키텍처의
이것들에 대해서 하나하나 배운대로 정리를 해보자.
클린 아키텍처의 계층 구조를 통한 의존성 규칙과 관심사 분리
위에서 봤던 이미지를 다시 한 번 인용해서.
클린 아키텍처는 시스템을 여러 계층으로 구분하여, 핵심 비즈니스 로직을 UI, DB, 프레임워크 등의 외부 환경으로부터 독립적으로 보호하는 구조를 가진다.
클린 아키텍처의 계층 구조는 엔터티 ➡️ 유스케이스 ➡️ 인터페이스 어댑터 ➡️ 프레임워크 / 드라이버 순서이다.
동심원의 안쪽에 위치할 수록 추상화 수준이 높고 외부 변화에 영향을 받지 않는 서비스의 핵심 로직을 담고 있다.
1. Entities 엔터티 (Domain Layer)
시스템의 핵심 비즈니스 규칙과 엔터프라이즈 수준의 도메인 모델 (객체)를 포함한다. 동심원으로 표현되는 계층 구조의 가장 안쪽 계층에 해당하며, 시스템에서 가장 변화가 적은 계층이다. 잘 설계되고 구현된 엔터티 계층은 여러 애플리케이션에서 재사용 될 수 있을 정도로 외부 UI, DB 등에 영향을 받지 않는다.
2. Use Cases 유스케이스 (Application Layer)
시스템이 제공하는 구체적인 동작을 정의한다. 여기에는 유스케이스, 서비스, 애플리케이션의 비즈니스 로직이 포함된다. 엔터티를 활용하여 사용자의 요구사항을 구현하고, 여전히 외부 시스템의 영향을 받지 않는다.
비즈니스 로직을 구현하는 계층으로 클린 아키텍처의 핵심 계층이라고 할 수 있다.
좋은 아키텍처를 만들어내기 위해서는 이 유스케이스가 안정적으로 잘 구현되어야 한다. 그 외의 도구들 (UI, DB, 프레임워크)은 언제든지 바뀔 수 있기 때문에 약한 결합력 (Loose Couplling)을 갖는 것이 중요하다.
3. Interface Adapters 인터페이스 어댑터 (Interface Adapters Layer)
웹, API, 데이터베이스, 프레임워크 등의 외부 환경과 내부 유스케이스 & 엔터티 계층 간의 데이터 변환 및 연결을 담당한다.
위의 이미지 상에서도 확인할 수 있듯 컨트롤러, 게이트웨이 등이 이 계층에 포함된다.
4. Frameworks & Drivers 프레임워크 및 드라이버 (Infrastructure Layer)
언제든지 교체되거나 변경될 수 있는 UI, DB, 프레임워크 등, 시스템의 가장 바깥쪽에 위치한 요소들로 시스템의 핵심 로직에 영향을 주지 않으며 Interface Adapters 객체를 통해 엔터티와 유스케이스와 소통한다. 구현 세부사항을 포함한다.
의존성 규칙
의존성은 항상 동심원의 바깥에서 안쪽으로만 향해야 한다.
동심원의 안쪽 계층, 즉 핵심 비즈니스 로직을 담당할수록 구현 세부사항에 대한 바깥 계층에 대해 전혀 알 필요가 없다.관심사의 분리
- 관심사?
- 소프트웨어 내에서 각 영역이 맡은 역할, 해결해야 하는 목표
- 데이터 저장, 화면 렌더링 등
- 소프트웨어 내에서 각 영역이 맡은 역할, 해결해야 하는 목표
💡 각 계층이 특정 역할에만 집중해야 한다.
- 같은 목적을 가진 코드끼리 묶고, 서로 다른 목적을 가진 부분은 분리.
- e.g. 화면을 그리는 로직과 데이터를 저장하는 로직은 서로 독립적으로 분리한다.
- e.g. Next.js에서 작성한 UI 컴포넌트에서 데이터를 다루지 않는 등
- 유지보수성 향상
- 재사용성 증가
- 테스트 용이
- 변경의 영향 최소화
제어의 역전 (IoC ; Inversion of Control)
제어의 역전, 혹은 역제어는 소프트웨어 디자인 패턴으로, 프로그램의 제어 흐름을 개발자가 직접 제어하지 않고, 외부 프레임워크나 컨테이너에게 위임하는 원칙이다.
기존까지는 개발자가 프로그램에 필요한 객체를 직접 생성하고 조작했다면, IoC 원칙을 적용한다면 프레임워크가 객체의 생명주기와 의존성을 관리해주는 것이다.
역제어의 이점
- Loose Coupling
- 유지보수성 향상
- 테스트 용이성 증가
- 모듈 간 독립성 강화
제어의 역전은 일반적으로 의존성 주입 (DI ; Dependency Injection)에 의해서 구현된다.
2년 전, 대학에서 Spring Boot 수업을 들을 때, DI에 곯머리를 썩었던 적이 있다. 그게 도대체 뭔가 싶어가지고..
근데 지금도 잘 모름요 진짜로(이제부터라도 확실히 알아가야겠죠)의존성 주입 (DI ; Dependency Injection)
객체가 직접 의존 대상을 생성하지 않고 외부에서 필요한 의존 객체를 주입받아 사용하는 방법.
* 의존성 주입이 없는 경우
// UserService.java public class UserService { public void join() { System.out.println("회원 가입 로직 실행"); } } // UserController.java public class UserController { private UserService userService; public UserController() { this.userService = new UserService(); // 직접 생성 (강한 결합) } public void joinUser() { userService.join(); } }
위는 Spring에서 의존성 주입이 없는 경우, Controller가 Service 객체를 생성해서 사용하는 예시다.
이렇게 사용하게 되면 UserController는 어느 상황에서나 UserService 클래스에 의존을 하게 된다.
서비스의 규모가 커질수록 양쪽 모두 쉽사리 수정할 수 없게 되어버린다.
Service가 바뀌면 Controller도 바꿔야되거든...
* 생성자를 통한 주입
// UserService.java import org.springframework.stereotype.Service; @Service public class UserService { public void join() { System.out.println("회원 가입 로직 실행"); } } // UserController.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class UserController { private final UserService userService; @Autowired // 생성자가 1개면 생략 가능 public UserController(UserService userService) { this.userService = userService; // 외부에서 주입 (약한 결합) } public void joinUser() { userService.join(); } }
(코드는 모두 퍼플렉시티에게 부탁했다.)
@Autowired 어노테이션이 달린 블럭을 보면, 생성자는 이미 만들어진 UserService의 객체를 파라미터로 주입 받고 있다. 이 경우 Service만 바꿔도 Controller는 바꿀 필요가 없으므로 의존도가 낮고, 재사용성이 높아짐을 알 수 있다.
🤔 아직 모르는 것
그래서, 클린 아키텍처가 뭐고 어떤 장점이 있는지는 알았다.
누가 설명하라 그러면 설명도 할 수 있겠다.
그런데, 문제는 이걸 이제 어떻게 나의 프로젝트에 적용하냐는 것인데,
그건 뭐 차주부터 프로젝트 주간이기 때문에, 프로젝트를 진행해나가면서 조원들과 토의하거나 강사님께 자문을 구하면서
체득되지 않을까 하는 막연한 생각을 가져본다.
💭 느낀 점
클린 아키텍처, 동명의 서적이 있다는 사실은 알고 있었다.
주변 개발자 분들이 클린 코드와 클린 아키텍처를 외칠 때, '난 아직 그럴 단계가 아닌 것 같아' 하고 미뤄놨는데
막상 접해보니 진입 장벽이 좀 높긴 해도 왜 필요한지를 알게 되니 뭔가 친근하게 느껴졌다.
소프트웨어 개발에서 아키텍처는 늘 뜨거운 감자인 것 같다.
언제는 이걸 외치고, 언제는 저걸 외치고, 시대가 변하면서 중요하게 여겨지는 아키텍처들이 점점 달라지는 느낌.
하지만 지금은 클린 아키텍처가 맞다.
'Study (etc) > 멋쟁이사자처럼 FEPL_05' 카테고리의 다른 글
[FEPL05 / TIL] Day 08 (2편) - 밟으실 수...수수수파베이스 (0) 2025.06.29 [FEPL05 / TIL] Day 08 (1편) - 데이터를 정규화하자 (0) 2025.06.29 [FEPL05 / TIL] Day 07 - 데이터를 모델링해보자 (feat. 정처기) (5) 2025.06.26 [FEPL05 / TIL] Day 06 - Next.js 기초 (0) 2025.06.25 [FEPL05 / TIL] Day 05 - TypeScript 기초 (2) 2025.06.23