기술블로그

php,CodeIgniter4로 객체지향프로그래밍 설계

닥치고개돌 2020. 1. 12. 21:39
728x90

회사에 들어온지 1년 정도 되면서 개발할 때 어떻게 하면 유지 보수하기 쉽게 개발할 지 고민하던 중 api개발에 투입하게 되었다.

우아한 형제들 기술 블로그나 웹서핑 등을 통해 찾아본 객체지향 프로그래밍이 절차지향보다 어떻게 유지보수에 도움이 될 지, 현재 우리의 php, Codeigniter4에 녹아들지 생각해 보았다.

 

지금부터 아래에서 언급하는 내용은 제가 이해한 내용과 업무를 진행하면서 적용한 내용이기 때문에 틀린 부분이 있을 수 있음.

 

 

대부분의 아키텍처는 세부적인 차이는 있어도 공통적인 목표는 계층을 분리하여 관심사의 분리하는 것, 이런 아키텍처가 동작하기 위해서는 의존성 규칙을 지켜야 한다고 한다.

모든 소스코드 의존성은 반드시 외부에서 내부로, 고수준 정책을 향해야 한다. 업무 로직(고수준 정책)은 세부 사항들(저수준 정책)의 변경에 영향을 받지 않도록 할 수 있다.

 

고수준, 저수준이라는 단어가 자주 등장하는데 대략적으로 다음과 같다고 생각함. 1. 고수준 : 상위 수준의 개념, 추상화된 개념 - 예시: 데이터를 저장한다, 유저리스트를 출력한다. 2. 저수준 : 추상화된 개념을 실제 어떻게 구현할지에 대한 세부적인 개념 - 예시: DB에 데이터를 저장한다, 관리자인 유저리스트를 출력한다.

 

첫 번째로는 경계 간의 데이터를 전달할 때 무엇을 전달해야 하는가에 대한 이야기다. 의존성 규칙을 지키기 위해서는 우리가 사용하는 단순하고, 고립된 형태의 데이터 구조를 사용하는 것을 추천함. 만약 DB의 형식의 데이터 구조 또는 Framework에 종속적인 데이터 구조가 사용되게 된다면, 이러한 저수준의 데이터 형식을 고수준에서 알아야 하기 때문에 의존성 규칙을 위반하게 된다.

 

 

고수준의 정책은 저수준의 정책에 의존해서는 안된다는 예이다.

 

Controller -> Service -> RDBRepository

이러한 제어의 흐름과 같이 소스코드 의존성을 가지게 된다면 Service가 구체적인 RDBMS를 구현한 구현체(저수준의 정책)를 직접 참조하게 되는데 이는 의존성 규칙을 위반하게 된다. 이러한 문제의 가장 간단한 해결책은 DIP(의존성 역전의 원칙)을 적용하는 것.

 

Controller -> Service -> Repository <- RDBRepository

 

추상화된 Repository 인터페이스를 두어서 Service가 이를 참조하고, 구체적인RDRepository가 이러한 인터페이스를 구현하게 된다면 소스코드의 의존성을 역전시킬 수 있습니다. 이러한 DIP를 통해 우리 Service는 DB의 구체적인 세부사항을 알 필요도 없고, DB의 변경에도 영향을 받지 않게 된다.

 

service
  기능


repository의 method를 이용, 적절한 Business Logic을 처리한다.
DAO로 DB에 접근하고 DTO로 데이터를 전달받은 다음, 비지니스 로직을 처리해 적절한 데이터를 반환한다.

 

repository(dao)
  기능
    

실제로 DB에 접근하는 객체이다.
Service와 DB를 연결하는 고리의 역할을 한다.

SQL를 사용(개발자가 직접 코딩)하여 DB에 접근한 후 적절한 CRUD API를 제공한다.
        

 

이번 프로젝트에서도 이러한 경계 간의 데이터를 전달할 때 간단한 구조의 Data Transfer Objects(DTO)를 이용하려고 한다. 또한 디비에서 나온 데이터는 Entity를 사용함.

 

여기서 말한 DTO와 Entity를 정리해보자

 

 

DTO(Data Transfer Object) 란?

계층간 데이터 교환을 위한 객체(Java Beans)이다.
     º DB에서 데이터를 얻어 Service나 Controller 등으터 보낼 때 사용하는 객체를 말한다.
     º 즉, DB의 데이터가 Presentation Logic Tier로 넘어오게 될 때는 DTO의 모습으로 바껴서 오고가는 것이다.
     º 로직을 갖고 있지 않는 순수한 데이터 객체이며, getter/setter 메서드만을 갖는다.
     º 하지만 DB에서 꺼낸 값을 임의로 변경할 필요가 없기 때문에 DTO클래스에는 setter가 없다. (대신 생성자에서 값을 할당한다.)
  Request와 Response용 DTO는 View를 위한 클래스
     º 자주 변경이 필요한 클래스
     º Presentation Model
     º toEntity() 메서드를 통해서 DTO에서 필요한 부분을 이용하여 Entity로 만든다.
     º 또한 Controller Layer에서 Response DTO 형태로 Client에 전달한다.

 

 

Entity Class란?

 

실제 DB의 테이블과 매칭될 클래스
      즉, 테이블과 링크될 클래스임을 나타낸다.
      Entity 클래스 또는 가장 Core한 클래스라고 부른다.    
  
  최대한 외부에서 Entity 클래스의 getter method를 사용하지 않도록 해당 클래스 안에서 필요한 로직 method을 구현한다.
    
      단, Domain Logic만 가지고 있어야 하고 Presentation Logic을 가지고 있어서는 안된다.
      여기서 구현한 method는 주로 Service Layer에서 사용한다.

 

 

  참고 Entity 클래스와 DTO 클래스를 분리하는 이유

 

      View Layer와 DB Layer의 역할을 철저하게 분리하기 위해서
테이블과 매핑되는 Entity 클래스가 변경되면 여러 클래스에 영향을 끼치게 되는 반면 View와 통신하는 DTO 클래스(Request / Response 클래스)는 자주 변경되므로 분리해야 한다.

      Domain Model을 아무리 잘 설계했다고 해도 각 View 내에서 Domain Model의 getter만을 이용해서 원하는 정보를 표시하기가 어려운 경우가 종종 있다. 이런 경우 Domain Model 내에 Presentation을 위한 필드나 로직을 추가하게 되는데, 이러한 방식이 모델링의 순수성을 깨고 Domain Model 객체를 망가뜨리게 된다.
      또한 Domain Model을 복잡하게 조합한 형태의 Presentation 요구사항들이 있기 때문에 Domain Model을 직접 사용하는 것은 어렵다.
      즉 DTO는 Domain Model을 복사한 형태로, 다양한 Presentation Logic을 추가한 정도로 사용하며 Domain Model 객체는 Persistent만을 위해서 사용한다.

변경된 app 디렉토리 구조

/app
        /Config         구성 파일 저장
        /Controllers    프로그램 흐름을 결정하는 컨트롤러
        /Database       데이터베이스 마이그레이션 및 시드(seed) 파일 저장
        /Filters        컨트롤러 전후에 실행할 수 있는 필터 클래스 저장
        /Helpers        독립형 함수 모음(Helper) 저장
        /Language       다국어 지원을 위한 언어 파일 저장
        /Libraries      카테고리에 포함되지 않는 유용한 클래스 모음
        /Models         데이터베이스와 함께 작동하는 모델 저장

            /DAO    테이블과 매핑되어 CRUD기능을 하는 클래스 모음

            /Service    비즈니스 로직 처리 레이어

        /Entities    테이블과 매핑되는 객체들 모음

        /DTO    데이터 전달 객체들 모음
        /ThirdParty     어플리케이션에서 사용할 수 있는 타사 라이브러리

 

728x90

'기술블로그' 카테고리의 다른 글

qmail  (0) 2020.07.08
인터페이스와 추상클래스 공통점 및 차이점  (0) 2020.01.12
객체지향 프로그래밍이란? (OOP 정리)  (0) 2020.01.12