써니쿠키의 IOS 개발일기

클린아키텍쳐(Clean Architecture) 본문

swift, Ios

클린아키텍쳐(Clean Architecture)

sunnyCookie 2023. 3. 2. 21:32

안녕하세요 써니쿠키입니다 🍪

클린아키텍쳐 공부하고, 만들어 둔 프로젝트 하나를 리팩토링 해 볼 계획이라

엉클밥 아저씨가 만든용어 'Clean Architecture' 에 대해 알아보고자 합니다.

 

주관적 견해가 포함되어있으니 잘못된 정보가 있다면 댓글로 알려주시면 감사하겠습니다 🙇🏻‍♀️

 

밥삼촌은 다양한 아키텍처들을 보면서 각각 세세한건 다르지만 공통된 목적은 관심사 분리라고 말씀하셨습니다.
그리고는 통합 정리하셨습니다. 클린아키텍쳐!로 그럼 관심사의 분리부터 개념을 잡고 클린아키텍쳐로 넘어가겠습니다.


   관심사의 분리?  

'관심사의 분리'는 말 그대로 프로그램 내부에서 관심있는 것들끼리 모아서 분리하는 겁니다.

여기서 말하는 '관심사'는 프로그램 내부에서 해결 또는 처리하려는 목표라고 생각하면 좋을 것 같습니다.

 

예를들어, 프로그램에 저장해야할 데이터를 서버 혹은 기기에 저장해야하는 부분이 있고,

유저가 볼 수 있는 화면을 그리는 부분이 있다고 한다면,

전자는 화면이 그려지든 말든 '데이터를 저장'하는게 목표고,

후자는 데이터를 저장하든말든 유저에게 보여줄 '화면 그리기'가 목표입니다.

목표가 다르니 이 둘은 관심사가 다르다고 할 수 있고, '관심사의 분리' 디자인을 적용하면 둘은 각기 분리 될 수 있습니다.

 

즉, '관심사의 분리'는 특정 관심사를 기준으로 프로그램을 분리하고, 각 부분은 하나의 관심사를 해결한다고 할 수 있습니다.

(더 작은 단위로는 함수(혹은 메서드)가 하나의 문제만 해결하도록 구현하는 것도 '관심사의 분리'라고 할 수 있습니다.)

 

그럼 왜 관심사를 분리하냐?? 늘 나오는 말인 유지보수..!가 쉬워지기 때문입니다.
관심사 분리가 잘 되어있으면 프로그램을 설계하고 배치할 때 비교적 자유도가 올라가고,

독립적인 부분의 개발과 업그레이드도 쉬워지고,

각기 분리되어있기 때문에 재사용에 용이하다는 장점들이 있습니다.

 

한마디로 정리하면 관심사의 분리로 모듈, 함수들이 각자 맡은 일을 잘 처리하도록 만들어 유지보수가 좋은 코드가 되게 하기 위함입니다


 

그럼 이제 관심사의 분리를 목표로하는 클린아키텍쳐를 살펴보겠습니다

  클린아키텍쳐  

위에서 말했듯이, 밥 삼촌은 여러 아키텍쳐들 (헥사고날, 어니언, 스크리밍 아키텍처 등) 을 묶어

이들의 공통된 목적은 "관심사의 분리" 라고 말씀하시며 이 분리는 계층으로 나뉜다고 하셨습니다.

 

이 계층에는

1. 비즈니스 규칙을 위한 계층과

2. 인터페이스를위한 다른 계층이

있다고 합니다.

 

그리고 이런 아키텍처들은 모두 다음과 같은 시스템을 생성한다고 하셨습니다.

 

1. 프레임워크에 독립적: 아키텍쳐는 소프트웨어 라이브러리에 의존하지 않음

2. 테스트에 용이함: UI, DB, 웹서버, 외부요인없어도 테스트 가능

3. UI가 독립적인 시스템: 다른부분 수정없이 UI변경이 가능하다

4. 데이터베이스가 독립적인 시스템 : 데이터베이스를 변경하기 쉽다.

5.외부기능으로부터 독립적인 시스템

 

이렇게 공통점을 읊어 주시더니 단일개념으로 통합하시겠다며 '클린 아키텍쳐'를 소개하셨습니다

 

 

그럼 이제 이 그림을 하나씩 이해해보..봅시다!


  의존 규칙 (Dependency Rule)  


그림의 빨간 박스부분이 의존규칙을 보여주는 화살표입니다.

 

각 동심원들은 각각 다른 영역을 나타내는데 안쪽으로 갈수록 고수준입니다.

바깥쪽의 원은 메커니즘(Mechanism), 안쪽의 원은 정책(Policy)입니다.


(여기서 등장하는 '고수준', '저수준' 이라는 용어에 대해서는 두가지 의견이 있는데,

추상화의 정도를 기준으로 고수준은 추상화된 개념,  '저수준'은 추상화된 개념의 실제 구현같은 세부개념이라는 것과

비즈니스 로직을 담고있느냐를 기준으로 비즈니스 로직을 담고있는게 '고수준', 아닌게 '저수준' 이라는 의견이 있습니다.

정확한 의미는 밥삼촌이 아시겠지만, 위 두 의견 모두 맞는 얘기입니다...!)


안쪽으로 갈수록 추상화 수준이 올라가고, 바깥쪽 원은 저수준의 구체적인 상세정보를 담고있습니다.

그리고 이 아키텍쳐가 가능하게 하는 중요한 규칙이 바로 의존규칙입니다.


클린아키텍처의 핵심이 바로 의존성의 방향입니다.
의존규칙은 그림과같이 안쪽을 향해서만 의존할 수 있습니다.


안쪽의 원들은 본인보다 바깥쪽 원들은 전혀 모른다는 얘기입니다.

안쪽 원은 바깥쪽의 어떤것도 참조해서는 안됩니다.
안쪽원으로 이동해가면서 소프트웨어는 추상화되고 고수준의 정책을 캡슐화할 수 있게 됩니다.

마찬가지로 바깥쪽 원에서 사용하는 데이터 포맷을 안쪽 원에서 사용하지 않아야합니다.


  Entity (엔티티)  

 

Entity는 비즈니스 규칙을 캡슐화 한 것입니다.

변경될 가능성이 가장 적은 부분이지요.

 

예를들어 한 회사가 맛집 검색 서비스를 제공할 때, 검색 될 맛집리스트는 서비스의 '근본'이자 원천이 되는 데이터일거고(Model),

이 데이터를 처리하는 비즈니스 로직이 있을겁니다.

이 둘을 합쳐서 Domain이라 부르는데 클린아키텍쳐에서는 Entity와 UseCase가 이 Domain에 해당합니다.

이들은 서비스가 Web이든 App이든 형태가 똑같고,

회사의 사업이 바뀌기 전까지는 변하지 않을 것이고, 앱의 디자인이 바뀌든, 보여주는 형태가 바뀌든 불변일 부분입니다.
여기서는 '맛집'이라는 라는 핵심 데이터 구조가 Entity라고 할 수 있습니다

 

Entity는 바깥 원에서 무엇이 변경되더라도 절대 바뀌지 않습니다


  UseCase (유스케이스)  

UseCase 계층도 위에서 설명했듯이 Domain 부분이고, 그 중 비지니스 로직이라하는 핵심 로직이 포함되어있습니다.

 

예를들어 위에서 말한 맛집 검색 서비스라면, 검색기능이 비즈니스 로직이 될 수 있습니다.

 

밥삼촌은 Entity로부터의 데이터 흐름을 조합한다고 표현했습니다.
UseCase스가 변해도 Entity에 영향을 미치면 안됩니다.

UseCase는 Entity를 알지만 Entity는 UseCase를 전혀 알지 못합니다.
또한 외부 프레임워크가 바뀌든, 데이터를 저장한 DB가 어디든간에 Usecase는 영향을 받지 않습니다.


  Interface Adapters  

 

 

그림엔 Interface Adapters영역에 Controller, GateWays, Presenters가 있습니다.

 

이 계층에서는 데이터가 Entity나 UswCase에 사용하기 쉬운 형태에서,
데이터베이스(DB)와 같은 외부 프레임워크에 사용하기 쉬운 형태로 변환되는 곳입니다.

 

그리고, MVVM을 아신다면 ViewModel의 역할이 이곳에 해당됩니다. 

모르신다면 Entity를 사용자에게 보여주기 위해 전처리 되고, 보여주는 단계라고 생각하시면 됩니다.

 

이 계층보다 안쪽의 원들은 데이터베이스 관련해서는 아무것도 몰라야 합니다.
데이터베이스 관련있는 부분은 이 계층에 제한되어있어야합니다.

또, 이 계층에서는 외부 서비스를 이용하기 위한 형식 외부서비스용 형식에서

UseCase, Entity에 사용할 수 있는 내부 형식으로 데이터를 변환하기 위한 기타 모든 어댑터들을 둘 수 있습니다.


  Frameworks and Drivers  

 

그림에서 가장 바깥원에는 DB, Web, Device, UI, External Interfaces가 담겨있습니다.

 

UI를 담당하는 View도 이곳에 해당되네요.

이 계층은 보통 프레임워크나 도구로 구성됩니다.

예를들어 데이터베이스나 웹 프레임워크 같은 것들 말입니다.

 

이 계층에서는 안쪽 원과 통신할 연결코드 외에는 별다른 코드가 없습니다.

그리고 내부 원들과 비교해 변경이 잦은 부부이라 할 수 있습니다.

 


  꼭 4개의 원 이여야하나?  

아닙니다.

이 원은 컨셉일 뿐, 이 외에도 필요하다면 추가되거나 통합해서 사용할 수 있습니다.
하지만, 의존 규칙의 방향은 항상 안쪽으로 향해야한다는 것은 지켜져야합니다.


  경계 넘어가기  

 

그림 우측 하단에는 어떤식으로 원의 경계를 넘을 수 있는지 보여줍니다.


여기서는 Controller와 Presenter가 바로 경계 안쪽 계층인 UseCase와 어떻게 대화하는지 보여줍니다.

흐름은, Controller에서 UseCase를 거쳐서 Presenter에서 실행되고있는 흐름인데

의존성은 모두 안쪽의 UseCase방향이란 것이 중요합니다.

흐름과 의존의 방향이 역방향으로 구현하는 데는 의존관계 역전 원칙(DIP)으로 해결하는 경우가 많습니다.

 

위에서 UseCase가 Presenter를 호출해야할 때,

의존성 규칙으로 바깥원을 호출할 수 없으므로

UseCase는 안쪽원에 있는 Interface(UseCase Outer port라고 적혀있는)를 호출합니다.

그리고 원 바깥쪽의 Presenter는 이 인터페이스를 구현합니다.


  어떤 데이터가 경계를 교차하는가?  

대게 경계를 넘나드는 데이터는 단순한 구조의 데이터입니다.
예를들어 DTO나 단순한 함수의 인수도 될수있고 객체로 구성된 무엇이도 좋습니다.


중요한건 격리된 단순한 구조의 데이터가 경계를 넘나든다는 점입니다.

절대, Entity나 DataBase의 행자체를 전달하지 않습니다.


  클린아키텍쳐를 왜쓰나!?  

그럼 왜 클린아키텍쳐를 쓰는가!

궁극적인 목표가 관심사의 분리인 만큼 위에서 언급한데로 관심사를 분리하는 이유와 같습니다! 유지보수!

 

예를들어 클린 아키텍쳐를 이용해 계층으로 분리가 잘되어있을 때
디자인이 바뀌었다고 하면 Interface Adapters부분까지만 수정하면 되겠죠,

그 내부는 어차피 외부를 알지도 못하기 때문에 UseCase와 Entity는 수정하지 않아도 됩니다.

 

이렇게 변화에 유연하게 대처할 수 있는게 유지보수가 편하다는 뜻이라고 할 수 있습니다. 클-린하다..!


이렇게 밥삼촌의 클린 아키텍쳐를 알아보았습니다..!
전체적인 흐름은 알 것 같은데 코드로 직접 리팩토링해봐야 유지보수가 쉽겠다는 것을 체감할 수 있을 것 같습니다.

그리고, 이건 큰 틀인만큼 밥삼촌도 말씀하셨듯이 의존성의 방향을 지키며 필요한 계층을 추가하거나 통합해서 사용하면 될 것 같습니다.

 

다음 포스팅은 'iOS에 적용한 클린 아키텍쳐'가 될 것 같습니다.

모바일 소프트웨어에 적용한 클린 아키텍쳐에서는 오늘 본 네 개의 계층(Layer)중,
Entity와 UseCase를 합쳐서 Domain계층으로,
Presenters, UI를 합쳐러 Presentation 계층으로,
DB, API같은 것을 묶어 Data Repositories 계층으로 나누어서

 

3개의 계층으로 적용하던데 다음 포스팅에서 예제코드와 함께 정리해 보겠습니다!

👉 iOS에서의 클린아키텍쳐


참고:
The Clean Code Blog
The Clean Architecture
위키피디아 - 관심사 분리
관심사의 분리란?

반응형
Comments