[1]의 4장은 패턴 언어 개요를 다루고 있다. 여기서는 기본 메시지 구조 관련한 패턴에 대해 살펴 보자

 

1. 아토믹 파라미터 (Atomic Parameter)

  • 설명: API 메시지에서 사용되는 가장 기본적인 단위로, 단순한 비정형 데이터(예: 숫자, 문자열, 불리언 등)를 표현.
  • 주요 특징:
    • 메시지 교환의 기본 전송 단위로 사용.
    • 단일 값으로 명확하게 정의되어 있음.
    • 이름, 타입, 선택성 등을 명시하여 데이터의 의미를 전달.
  • 포스의 충돌:
    • 과도한 사용 시 API의 효율성이 떨어질 수 있음.
    • 단일 값만으로 표현할 수 없는 복잡한 구조의 데이터 요구에 대응하기 어려움​

2. 아토믹 파라미터 리스트 (Atomic Parameter List)

  • 설명: 여러 개의 아토믹 파라미터가 밀접하게 연관되어 있을 때 이를 하나의 그룹으로 결합해 표현하는 방식.
  • 주요 특징:
    • 관련된 데이터 엘리먼트를 논리적 그룹으로 묶음.
    • 클라이언트가 특정한 데이터 필드만 선택적으로 요청할 수 있도록 허용.
    • 리스트는 위치 인덱스 또는 키로 식별되며, 필요 시 반복적으로 사용할 수 있음.
  • 포스의 충돌:
    • 과도한 중첩으로 인해 데이터 파싱과 처리의 복잡도가 증가할 수 있음.
    • 특정 플랫폼에서 스칼라 값의 제한으로 인한 구현 문제 발생 가능.

3. 파라미터 트리 (Parameter Tree)

  • 설명: 아토믹 파라미터와 리스트만으로 표현할 수 없는 복잡한 데이터를 계층적 구조로 정의.
  • 주요 특징:
    • 복잡한 데이터 구조를 계층적으로 표현해 데이터의 포함 관계를 명확히 함.
    • 각 노드는 단일 아토믹 파라미터, 리스트, 또는 또 다른 트리로 구성될 수 있음.
    • 재귀적으로 정의되며, JSON 등에서 객체의 중첩 구조를 표현하는 데 유용.
  • 포스의 충돌:
    • 중첩 구조가 지나치게 복잡해지면 대역폭과 성능 저하 우려.
    • 복잡한 구조의 데이터 트리로 인해 API 간 상호운용성이 떨어질 수 있음.

4. 파라미터 포리스트 (Parameter Forest)

  • 설명: 여러 개의 파라미터 트리를 그룹화해 최상위 레벨에서 관리하는 패턴.
  • 주요 특징:
    • 여러 트리들을 하나의 구조로 결합하여 사용자가 필요한 데이터를 쉽게 참조 가능.
    • 다양한 파라미터 트리를 독립적으로 관리할 수 있도록 함.
    • 요청이나 응답 본문에서 복수의 파라미터 트리를 노출.
  • 포스의 충돌:
    • 복잡한 데이터 구조로 인해 직렬화와 역직렬화의 부담이 커질 수 있음.
    • 구조적 복잡성으로 인해 메시지 교환 시 불필요한 데이터 전송이 발생할 위험.

 

참고 문헌
[1]  올라프 짐머만 , 미르코 스토커 , 다니엘 뤼브케 , 우베 즈둔 , 세자레 파우타소 , "마이크로서비스 API 디자인 패턴: 쉬운 통합을 위한 결합도 최적화 전략" 에이콘. 이승범 역

[1]의 4장은 패턴 언어 개요를 다루고 있다. 여기서는 API 방향 및 가시성 관련한 패턴에 대해 살펴 보자

1. 프론트엔드 통합 (Frontend Integration)

  • 설명: 모바일 앱이나 웹 애플리케이션의 사용자 인터페이스를 백엔드 서비스와 연결하여 데이터를 교환하고 기능을 수행할 수 있게 해주는 패턴.
  • 주요 특징:
    • 주로 HTTP/REST API로 구현되며 클라이언트에서 백엔드로 요청을 전달.
    • 데이터 소스 및 프로세싱 로직을 프론트엔드에 제공.
    • 클라이언트가 백엔드 활동을 호출하거나 데이터를 업로드할 수 있도록 함.
  • 포스의 충돌:
    • 데이터의 적시성과 효율성을 유지하면서 요청의 페이로드 크기를 최적화해야 함.
    • 과도한 통신으로 인한 성능 저하와 클라이언트 오버페칭을 방지해야 함.

2. 백엔드 통합 (Backend Integration)

  • 설명: 시스템의 서로 다른 백엔드 컴포넌트 간에 데이터를 교환하고 상호작용을 트리거할 수 있게 하는 패턴.
  • 주요 특징:
    • 분산된 애플리케이션의 백엔드에서 데이터를 교환하고 활동을 트리거할 수 있도록 지원.
    • 비동기 메시징, HTTP, gRPC 등 다양한 기술로 구현 가능.
    • 클라이언트가 아닌 다른 백엔드 시스템에서 독점적으로 사용됨.
  • 포스의 충돌:
    • 시스템 간 상호 운용성을 유지하면서 독립적 개발이 가능하도록 해야 함.
    • 데이터 교환과 처리 속도를 균형 있게 조정해야 함.

3. 퍼블릭 API (Public API)

  • 설명: 공개적으로 제공되는 API로, 전 세계 누구나 접근할 수 있는 형태로 배포됨.
  • 주요 특징:
    • 공용 인터넷에 노출되며 사용자 인증 및 액세스 제어가 필요할 수 있음.
    • API 키 또는 인증 토큰을 통해 보안 유지.
    • 서비스 레벨 계약(SLA)과 요금제 등을 통해 경제적 모델을 구축.
  • 포스의 충돌:
    • 높은 보안성과 안정성을 제공하면서 사용자 접근성을 보장해야 함.
    • 공정한 요금제 설정과 과도한 API 사용 방지를 위한 제한 필요.

4. 커뮤니티 API (Community API)

  • 설명: 여러 조직이 공동으로 사용하는 API로, 특정 사용자 그룹에게만 제한된 접근을 허용하는 형태.
  • 주요 특징:
    • 제한된 네트워크(예: 엑스트라넷)를 통해 배포.
    • 특정 커뮤니티의 회원만 사용 가능.
    • 보안 및 커뮤니티 지원 관리가 중요.
  • 포스의 충돌:
    • 보안성과 사용 편의성을 동시에 만족해야 함.
    • 커뮤니티 회원들 간의 상호작용과 API 사용 정책을 일관되게 관리해야 함.

5. 솔루션 내부 API (Solution Internal API)

  • 설명: 동일한 애플리케이션 내에서 사용되는 API로, 내부 컴포넌트 간 통신을 위해 설계됨.
  • 주요 특징:
    • 마이크로서비스, 모듈 등 내부 시스템 컴포넌트 간 데이터 전송에 사용.
    • 로컬에서 실행되거나 동일한 데이터 센터 내에서 작동하는 서비스 간 통신을 지원.
    • 외부 노출 없이 내부에서만 사용됨.
  • 포스의 충돌:
    • 시스템 내에서 효율적인 통신을 유지하면서 데이터의 일관성을 보장해야 함.
    • 독립적 배포와 함께 복잡한 시스템의 결합성을 줄여야 함.

참고 문헌
[1]  올라프 짐머만 , 미르코 스토커 , 다니엘 뤼브케 , 우베 즈둔 , 세자레 파우타소 , "마이크로서비스 API 디자인 패턴: 쉬운 통합을 위한 결합도 최적화 전략" 에이콘. 이승범 역

 

[1]의 5장은 API 설계에서 엔드포인트와 동작을 정의하는 방법에 대한 내용을 다루고 있다. 엔드포인트의 설계는 API의 아키텍처에서 중요한 부분으로, 요청 및 응답 메시지의 구조뿐만 아니라 엔드포인트 배치와 동작도 고려해야 한다.
엔드포인트의 역할은 크게 데이터 지향(Information Holder)과 활동 지향(Processing Resource)으로 나뉜다.

활동 지향 엔드포인트 역할은는 계산, 상태 변경 등의 동작을 수행하며, 클라이언트가 원격으로 처리 작업을 요청할 수 있도록 한다. 데이터 지향 엔드포인트 역할은는 데이터의 읽기/쓰기 접근을 지원하며, 데이터의 수명 및 변경 가능성에 따라 다양한 유형으로 분류됩니다. 우선, 활동 지향 관련해서 처리 리소스 패턴들과  데이터 지향 관련해서는 정보 보유자 패턴으로 나누어 살펴 보자.

 

처리 리소스

처리 리소스와 관련된 패턴들은 주로 활동 지향 엔드포인트를 설계하는 데 사용된다. 이 패턴들은 API가 클라이언트로부터 요청을 받아 어떤 작업을 수행하거나 상태를 변경할 수 있게 하는데, 이를 통해 다양한 비즈니스 로직을 처리할 수 있다. 주요 패턴과 그 특징은 다음과 같다.

1. 계산 함수 (Computational Function)

설명: 입력 값을 받아 계산 작업을 수행하고, 그 결과를 반환하는 동작.

 

주요 특징:

  • 상태 비저장(stateless)으로 동작하며, 단순하거나 복잡한 연산 작업을 수행.
  • 클라이언트가 제공한 입력에 따라 예측 가능한 결과를 생성.
  • 연산의 반복 호출 시 일관된 결과를 보장.

포스 충돌:

  • 응답 시간 대 정확성: 빠른 계산을 위해 성능 최적화가 필요하지만, 정확성을 유지해야 함.
  • 표현력 대 단순성: 더 많은 계산 기능을 제공할수록 API가 복잡해지고 학습이 어려워질 수 있음.

2. 인출 동작 (Retrieval Operation)

설명: 데이터를 조회하여 클라이언트에게 반환하는 읽기 전용 작업.

 

주요 특징:

  • 안전한 읽기 작업으로 상태를 변경하지 않음.
  • 다양한 데이터 소스로부터 데이터를 집계하여 제공할 수 있음.
  • 멱등성 보장으로 같은 요청에 대해 항상 같은 결과 반환.

포스 충돌:

  • 확장성 대 일관성: 여러 클라이언트의 동시 요청에 대해 일관된 데이터를 빠르게 제공해야 함.
  • 캐싱 대 최신성: 캐싱을 사용하면 응답 속도를 높일 수 있지만, 데이터의 최신성을 보장하기 어려울 수 있음.

3. 상태 생성 동작 (State Creation Operation)

설명: 클라이언트 요청을 받아 새로운 리소스나 객체를 생성하는 작업.

 

주요 특징:

  • 쓰기 작업으로, 데이터를 생성하고 이를 시스템에 저장.
  • 생성된 리소스에 대한 ID나 참조를 반환하여 후속 작업에 사용 가능.
  • 입력 데이터의 유효성 검사가 필요.

포스 충돌:

  • 유효성 대 성능: 유효성 검사를 철저히 할수록 성능이 저하될 수 있음.
  • 데이터 중복 대 일관성: 동일한 요청을 반복 처리할 때 데이터 중복 생성 문제가 발생할 수 있음.

4. 상태 전이 동작 (State Transition Operation)

설명: 기존 리소스의 상태를 변경하거나 업데이트하는 작업.

 

주요 특징:

  • 읽기-쓰기 작업으로, 리소스의 상태를 업데이트하거나 수정.
  • 상태 변경에 대한 명확한 정의가 필요하며, 멱등성을 고려하여 반복 호출 시 결과가 일관되게 유지.
  • 예를 들어, 주문 상태를 "처리 중"에서 "배송 중"으로 전환.

포스 충돌:

  • 멱등성 대 복잡성: 상태 변경 작업의 멱등성을 보장하려면 복잡한 설계가 필요할 수 있음.
  • 성능 대 일관성: 빠른 상태 전환을 위해 비동기 처리를 사용하면 일관성을 유지하기 어려울 수 있음.

정보보유자

정보 보유자와 관련된 패턴들은 주로 데이터 지향 엔드포인트 설계에 사용된다. 이 패턴들은 API가 데이터를 클라이언트에게 제공하고, 필요에 따라 데이터를 읽고 쓰는 작업을 지원하도록 돕는다. 주요 패턴과 그 특징은 다음과 같다.

1. 운용 데이터 보유자 (Operational Data Holder)

설명: 일상적으로 자주 변경되는 데이터를 관리하며, 클라이언트가 데이터 생성, 읽기, 업데이트, 삭제(CRUD) 작업을 수행할 수 있도록 지원.

 

주요 특징:

  • 읽기-쓰기 작업을 지원하며, 실시간 데이터 처리가 중요한 경우 사용.
  • 짧은 수명의 데이터를 자주 업데이트하며, 빠른 응답과 처리 속도가 요구됨.
  • 예: 쇼핑몰의 주문 내역, 은행 계좌 거래 내역.

포스 충돌:

  • 속도 대 데이터 일관성: 빠른 데이터 처리가 중요하지만, 데이터 일관성을 유지해야 함.
  • 가용성 대 보안: 데이터를 자주 사용하고 접근할 수 있어야 하지만, 민감한 정보일 경우 보안 조치를 강화해야 함.

2. 마스터 데이터 보유자 (Master Data Holder)

설명: 상대적으로 안정적이고, 자주 변경되지 않는 주요 참조 데이터를 관리하는 리소스.

 

주요 특징:

  • 읽기 전용 또는 제한된 쓰기 작업을 지원하며, 주요 비즈니스 데이터를 안정적으로 제공.
  • 변경 빈도가 낮으며, 데이터의 일관성과 품질을 유지하는 데 중점.
  • 예: 고객 정보, 제품 카탈로그.

포스 충돌:

  • 일관성 대 성능: 데이터 일관성을 유지해야 하지만, 이를 위해 성능이 저하될 수 있음.
  • 확장성 대 최신성: 클라이언트의 확장성 요구에 따라 성능을 높이면서도, 데이터가 최신 상태임을 보장해야 함.

3. 참조 데이터 보유자 (Reference Data Holder)

설명: 국가 코드, 통화 코드 등 기본적이고 자주 변경되지 않는 참조 데이터를 제공하는 리소스.

 

주요 특징:

  • 읽기 전용으로 제공되며, 고정된 데이터를 여러 클라이언트가 참고할 수 있음.
  • 데이터 변경이 드물기 때문에 캐싱을 통해 빠른 응답이 가능.
  • 예: 언어 코드, 국가 및 지역 코드.

포스 충돌:

  • 최신성 대 캐싱 효율성: 캐싱을 사용하여 성능을 높이려 하지만, 데이터의 정확성과 최신성을 보장해야 함.
  • 보안 대 접근성: 특정 참조 데이터를 보안이 필요한 경우 접근 제한이 필요하지만, 동시에 다양한 클라이언트가 접근할 수 있어야 함.

4. 데이터 전송 리소스 (Data Transfer Resource)

설명: 클라이언트 간 데이터 공유 및 전송을 위한 임시 저장소 역할을 하는 리소스.

 

주요 특징:

  • 클라이언트가 데이터를 임시로 저장하고, 다른 클라이언트로 전송할 수 있음.
  • 단기 보유 및 관리로, 데이터를 저장한 후 일정 시간이 지나면 삭제하거나 이동.
  • 예: 파일 업로드/다운로드 서비스, 메일 서버의 큐.

포스 충돌:

  • 저장 기간 대 가용성: 데이터를 얼마나 오랫동안 보관할 것인지와 이를 쉽게 접근할 수 있도록 할 것인지 간의 균형.
  • 보안 대 효율성: 전송 데이터를 암호화하고 보호해야 하지만, 이를 처리하는 과정에서의 성능 저하를 방지해야 함.

 

5. 링크 조회 리소스 (Link Lookup Resource)

설명: 다른 정보 보유자 리소스로의 링크를 제공하며, 데이터 관계를 유지하고 탐색을 지원하는 리소스.

 

주요 특징:

  • 읽기 전용으로, 다른 리소스 간의 관계를 정의하고 참조를 관리.
  • 데이터 관계를 명확히 하여 클라이언트가 다른 리소스 간의 데이터 연결을 쉽게 탐색할 수 있게 함.
  • 예: 제품과 관련된 리뷰, 고객과 관련된 주문 내역.

포스 충돌:

  • 데이터 연결성 대 독립성: 여러 리소스를 연결해야 하지만, 각 리소스는 독립적으로 관리되어야 함.
  • 응답 시간 대 일관성: 빠르게 데이터 관계를 조회해야 하지만, 데이터의 일관성을 유지해야 함.

 

 

참고 문헌
[1]  올라프 짐머만 , 미르코 스토커 , 다니엘 뤼브케 , 우베 즈둔 , 세자레 파우타소 , "마이크로서비스 API 디자인 패턴: 쉬운 통합을 위한 결합도 최적화 전략" 에이콘. 이승범 역

[1]은 API 설계에 관한 심도 있는 가이드로, 1장에서는 API 설계에 필요한 기본 개념과 패턴을 다룹니다. 주요 내용은 다음과 같다.

API 기본 개념:
API(Application Programming Interface)가 무엇인지 설명하고, 현대 소프트웨어 아키텍처에서 API의 중요성을 강조한다. API 설계에서 자주 겪는 문제(결합도, 세분화 등)를 설명하고, API가 어떻게 기능을 노출하면서도 구현 세부 사항을 숨기는지 설명한다.

 

원격 API:
API가 서로 다른 서버나 지역에 분산된 애플리케이션 간의 통신을 어떻게 가능하게 하는지 다룬다. RPC, SOAP, REST와 같은 다양한 원격 API 기술이 등장한 역사와 발전 과정을 설명한다.

 

API 설계의 어려움과 패턴:
다양한 클라이언트의 요구를 충족시키면서 확장성과 유지보수가 가능한 API 설계의 어려움에 대해서 설명한다. API를 모듈화하고 유연성을 유지하면서도 호환성을 지키는 설계 전략을 제시한다.

 

아키텍처적으로 중요한 요구 사항:

1장에서는 다음과 같은 내용을 언급한다.

  • 이해 가능성: API의 요청 및 응답 메시지 구조는 이해하기 쉽고, 불필요한 복잡성을 피해야 한다. 이를 위해 API는 도메인 모델을 따르는 것이 좋다. 중요한 점은 내부 구현 세부 정보가 외부에 드러나지 않도록 해야 한다.
  • 정보 공유와 정보 숨기기: API 설계에서 중요한 것은 클라이언트가 필요로 하는 정보를 정의하면서도, 불필요한 세부 사항을 숨기는 것이다. 구현 세부 정보가 외부로 노출되면 API가 진화할 때 클라이언트에 부정적인 영향을 미칠 수 있다.
  • 결합도(Coupling): 느슨한 결합(Loose Coupling)은 API 설계에서 필수적인 품질 속성이다. API 클라이언트와 프로바이더가 서로 독립적으로 진화할 수 있도록 하는 것이 목표이다. 이를 위해 플랫폼 자율성, 시간 자율성, 형식 자율성 등의 요소를 고려하여 결합도를 최소화해야 한다.
  • 수정 가능성(Modifiability): API는 진화 과정에서 유연성을 유지해야 하며, 버전 관리와 호환성을 고려해 설계해야 한다. 기존 클라이언트의 동작에 영향을 주지 않으면서도 쉽게 수정될 수 있어야 한다.
  • 성능 및 규모 확장성: 네트워크 지연 시간과 대역폭 사용에 영향을 받는 클라이언트 응답 시간, 마샬링 및 언마샬링 등의 성능 문제가 중요한다. API의 처리량과 확장성은 더 많은 클라이언트를 지원하면서도 응답 시간을 저하시키지 않아야 한다.
  • 데이터 간결성: 성능과 보안을 위해 API는 필요 이상으로 많은 데이터를 주고받지 않도록 설계되어야 한다. API가 진화함에 따라 불필요한 데이터가 축적될 가능성이 크기 때문에, 데이터의 간결함을 유지하는 것이 중요하다.​

이러한 요구 사항들은 API 설계 및 운영에서 필수적인 품질 속성으로 간주되며, API가 성공적으로 작동하고 진화할 수 있도록 돕는다.

 

사례 연구와 의사 결정 모델:

보험 회사의 서비스 통합 사례를 통해 API 사용 사례를 다룬다. API 설계에서 의사 결정을 내릴 때 고려해야 할 모델과 설계 체크리스트를 제시한다.

 

고급 주제:

클라우드 네이티브 API, 마이크로서비스와 같은 최신 API 설계 방식이 확장성과 독립적인 배포에 어떻게 기여하는지 설명한다. API 버전 관리 및 시간이 지남에 따라 발생하는 변경 사항을 어떻게 처리할지에 대한 전략을 설명한다. 소프트웨어 아키텍트와 개발자들이 견고하고 확장 가능하며 통합이 용이한 API를 설계하는 데 필요한 지식을 제공한다.

 

참고 문헌
[1]  올라프 짐머만 , 미르코 스토커 , 다니엘 뤼브케 , 우베 즈둔 , 세자레 파우타소 , "마이크로서비스 API 디자인 패턴: 쉬운 통합을 위한 결합도 최적화 전략" 에이콘. 이승범 역

크리스토퍼 알렉산더(Christopher Alexander, CA)는 오스트리아 출신의 건축가(Architect)이다. 사용자 중심의 설계 방식과 패턴 언어(Pattern Language)를 통한 건축 설계 방식으로 유명하다. 특히, 다른 건축가들과 다른 부분은 건축과 도시 설계를 보다 인간 중심적이고 살아 있는 방식으로 접근해야 하는 것을 강조했다. 이러한 접근법은 그는 여러 저서를 남겼는데,  유명한 초기 저서인 "영원의 건축"[1]이나 "패턴 랭귀지"[2] 뿐만 아니라 그의 마지막 4권의 저서인 "Nature of Order"[3] 등에서 상세히 설명한다. 이 책들에서 자연의 형태와 어울리는 건축적 원리를 제시하며, 디자인 프로세스에서 "살아 있는 구조"를 창조하는 방법에 대해 설명한다.

"영원의 건축"의 "건물군 설계하기"에서는 캘리포니아에 세워질 정신과 병원 설계에 대한 사례를 소개 한다. 이 장의 초기에 언급되어 있듯이 실재 병원의 주요 이해관계자인 병원장, 의료진, 관련 연구원들이 설계에 참여한다. 시작은 이해관계자들이 생각하는 "기능"이나 "활동"을 기반으로 적용해야 하는 패턴들을 포함시키거나 제외하는 작업들을 상당히 긴 시간의 토론을 통해 찾아간다. 이러한 패턴에 합의하게 되면 설계 준비가 되었다고 보고 설계를 시작한다. 이 때, 사무실에 설계를 하는 것이 아니라 건물이 세워질 대지에 나가서 이해 관계자들과 함께 이야기를 나누며 진행된다. 이러한 과정을 거칠 때, CA는 "눈을 감고 생각해보라"라는 요청을 많이 했다.

"Nature of Order"의 Book 2의 13.9 "The process of Finding a Good Centers"에도 비슷한 사례가 나온다. 앙드레와 애나 부분의 집 설계에 관한 부분이다. 일반적으로 부억, 거실, 식당과 같은 구조를 만들면서도 가족들은 아이들과 보낼 장소에 대한 필요가 있었던 것 같다. 가족방(family room)이 일반적인 해법이겠지만, CA는 적절한 해결책이 아니라 생각한 것 같다. 역시, 이해 관계자들과 3일간의 토론이 있었다. 눈을 감고 미소 띄운 앙드레가 떠올린 것은 프랑스 남부에 있는 그의 할아버지 집이었고 벽난로, 테이블 그리고 밖에서 들어오는 남향의 햇볕이었다. 이를 기반으로 이 집의 여러 중요 부분 중 하나인 농가의 부엌(farmerhouse kitchen)이 만들어졌다.

일본의 학교법인인 Eishin School(盈進学園, 영진학원)도 CA가 참여했고 이 과정이 "The Battle for the Life and Beauty of the Earth: A Struggle Between Two World-Systems"[4]에 담겨져 있다. 여기서도 위에서 이야기한 병원 설계와 유사하게 이해관계자들과 진행한 내용들이 담겨져 있다. 특히 8장을 보면 안드레의 사례와 비슷하게 이해 관계자들이 눈을 감고 상상하게 한다. 그런데, 이게 자신이 중요하다고 생각하는 구체적인 경험과 연결된다. 인터뷰이는 부끄러워 하기도 하고, 주저하기도 하지만 꿈같은 이야기를 꺼내게 된다. 이러한 과정을 통해 정리된 패턴 랭귀지는 수 개월에 걸처 이해관계자들에게 채택되게 된다. 이후 9개월에 걸처 부지에 직접 나아가서 병원에서의 사례와 같이 설계를 진행하는 과정을 거친다.

CA가 소프트웨어 공학에 많은 영향을 끼치기도 했고, 이러한 것들이 소프트웨어 설계에도 영향을 많이 미치고 있다고 생각된다. 위에서 CA가 사용한 방법을 보면, 이해관계자를 참여 시키는 것을 넘어 그 들에게 중요한 기능이나 활동 그리고 거기에 숨어 있는 요구 사항을 함께 찾는 것이 핵심인 것을 살펴 볼 수 있다. 이 부분을 소프트웨어 아키텍처 설계 측면에서 살펴 보면, 아키텍처 드라이버, 포스(force) 혹은 품질 속성(Quality Attribute)라는 것으로 볼 수 있다. 이런 것들을 발견하여 건축물의 "살아있는 구조"를 만들 수 있는 것처럼 소프트웨어의 "살아있는 구조"도 만들어 낼 수 있을 것으로 기대해 본다. 이러한 과정을 도와 줄 수 있는 것들이 도메인 주도 설계(DDD), Quality Attribute Workshop(QAW) 혹은 ATAM이 있다. 이러한 프로세스를 통해서 건축물을 설계할 때, 이해 관계자들과 소통하는 부분과 연결하여 이해할 수 있다.

참고문헌
[1] 크리스토퍼 알렉산더 "영원의 건축", 한진영 역, 안그라픽스 
[2] 크리스토퍼 알렉산더, 사라 이시가와, 머레이 실버스타인, "패턴 랭귀지" 이용근, 양시관, 이수빈 공역, 인사이트
[3] Christopher Alexander, "The Process of Creating Life: Nature of Order, Book 2: An Essay on the Art of Building and the Nature of the Universe", The Center for Envionmental Structure
[4] Christopher Alexander (Author), HansJoachim Neis Maggie Moore Alexander. 
"The Battle for the Life and Beauty of the Earth: A Struggle Between Two World-Systems", Center for Environmental Structure, 16 1st Edition

리엔지니어링 패턴의 8장 중복 코드 감지는 소프트웨어 시스템에서 중복된 코드를 탐지하고 관리하는 패턴에 초점을 맞추고 있으며, 소프트웨어의 품질과 유지 보수에 미치는 중요성과 영향을 강조한다.

  1. 중복 코드 감지의 중요성: 중복 코드는 소프트웨어 개발에서 주요한 "코드 스멜"로 강조되며, 일반적으로 산업용 소프트웨어의 8%에서 12%를 차지한다. 15% 이상은 심각하다고 고려할 수 있다. 이는 유지 관리 비용과 복잡성을 증가시키며, 미래의 변경을 더욱 오류가 발생하기 쉽고 어렵게 만든다.
  2. 중복 코드 식별 방법:
    • 기계적 비교: 모든 코드 줄을 기계적으로 비교하여 중복을 탐지한다. 코드 줄을 정규화(주석, 공백 등 제거)하고 해싱을 사용하여 효율적인 비교를 수행한다.
    • 도트 플롯을 이용한 코드 시각화: 도트 플롯은 다른 파일 또는 동일 파일 내에서 동일하거나 유사한 줄의 발생을 표시함으로써 중복 코드 세그먼트를 시각적으로 식별하는 수단을 제공한다.
  3. 중복 코드의 함의:
    • 중복 코드는 모든 인스턴스의 중복 기능을 수정해야 하므로 변경을 구현하기 어렵게 만들며 버그 발생 가능성을 높인다.
    • 시스템 로직을 중앙 집중화하기보다는 여러 부분에 흩어지게 함으로써 시스템 이해와 유지 보수를 복잡하게 만든다.
  4. 탐지 후 전략: 중복된 코드를 식별한 후에는 "메소드 추출"과 "데이터 가까이 작업 이동"과 같은 여러 리팩터링 패턴을 적용하여 시스템의 설계를 개선하고 향후 유지 보수 부담을 줄일 수 있다.

이 문서는 엔지니어와 관리자가 중복 코드를 인식하고 처리하는 데 도움을 주며, 소프트웨어의 유지 보수성을 향상시키고 복잡성을 줄이는 데 기여한다.

 

참고 문헌
[1] Serge Demeyer et al., "Object-oriented Reengineering Patterns"
[2] https://github.com/blcktgr73/OORP

리엔지니어링 패턴의 7장마이그레이션 전략은 레거시 시스템에서 새 시스템으로의 전환을 위한 주요 방법과 고려 사항을 다룬다. 레거시 시스템의 마이그레이션은 단순히 리엔지니어링하고 배포하는 것 이상의 전략적 과정이다. 이 과정은 전형적인 대규모 워터폴 프로젝트로 처리되는 함정을 피하기 위해 신중한 계획이 필요하다. 키 메시지는 사용자의 신뢰와 협력을 얻기 위해 점진적인 변경과 통합을 통해 한 번에 전체를 개편하는 대신 점진적이고 고통 없는 마이그레이션 절차의 필요성을 강조한다.

 

주요 패턴은 다음과 같다.

  1. 사용자 참여시키기: 이 패턴은 사용자를 리엔지니어링 과정 전반에 걸쳐 깊이 참여시켜 변경 사항의 수용을 극대화하는 데 초점을 맞춘다. 사용자의 정기적인 피드백과 참여는 새 시스템이 호의적으로 받아들여지고 성공적으로 통합될 가능성을 높인다.
  2. 자신감 구축하기: 이 패턴은 정기적으로 가치 있는 결과를 보여줌으로써 이해 관계자와 사용자들 사이에서 프로젝트가 성공적으로 진행되고 있음을 확신시키는 데 목적이 있다. 단기적인 성공을 보여줌으로써 모든 당사자의 신뢰를 유지한다.
  3. 시스템 점진적 마이그레이션하기: 이른바 "치킨 리틀"로 알려진 이 패턴은 큰 변화와 관련된 위험을 피하기 위해 점진적 마이그레이션을 지지한다. 마이그레이션 과정을 관리 가능하고 리스크가 낮은 작은 부분으로 나누어 점진적으로 처리할 것을 제안한다.
  4. 목표 솔루션 프로토타입하기: 프로토타입을 사용하여 새로운 아키텍처 결정과 기술적 리스크를 테스트한다. 프로토타입은 개념을 검증하고 마이그레이션의 리스크를 줄이는 데 도움이 된다.
  5. 실행 버전 항상 보유하기: 지속적인 통합과 테스팅을 위해 항상 작동하는 시스템 버전을 유지하는 것이 중요하다. 이 패턴은 마이그레이션 과정 전반에 걸쳐 시스템의 안정성을 유지하도록 한다.
  6. 변경할 때마다 회귀 테스트하기: 새로운 변경 사항이 기존 기능을 손상시키지 않도록 보장하여 시스템의 안정성을 유지한다.
  7. 뉴 타운으로 가는 브리지 만들기: 데이터 브리지를 생성하여 레거시 시스템에서 새 시스템으로 데이터를 점진적으로 이전하면서 두 시스템을 병렬로 운영할 수 있다. 이 단계별 접근 방식은 중단을 최소화하고 데이터 무결성을 유지한다.
  8. 올바른 인터페이스 제시하기: 레거시 컴포넌트를 새 인터페이스로 래핑하여 원하는 추상화를 반영하도록 한다. 이를 통해 새 시스템 아키텍처로의 부드러운 전환과 통합이 가능해진다.

각 패턴은 마이그레이션 과정에서 특정 도전을 해결하며, 위험을 최소화하고 레거시 시스템에서 새로운 효율적인 시스템으로의 성공적인 전환을 촉진하는 전략적 접근을 제공한다.

 

참고 문헌
[1] Serge Demeyer et al., "Object-oriented Reengineering Patterns"
[2] https://github.com/blcktgr73/OORP

스타워즈는 우리나라에서 크게 흥행하지는 않았지만, 프랜차이즈 영화로서는 인지도는 상당하다.  "May the Force be with you"는 스타워즈에서 제다이 기사들이 해어질 때 주로 쓰는 인사 말이다. "포스가 그대와 함께하길" 정도로 해석이 된다. 포스(Force)는 중국 무협 소설의 내공과 비슷한 것이라고 이해할 수 있다. 그렇다면, 소프트웨어 아키텍처에서의 포스(Force)는 무엇일까?

소프트웨어 아키텍처에 대해서 카네기 멜론 대학의 Software Engineering Institute를 이야기 하지 않을 수 없다. SEI 출신의 학자들 책인 'Software Architecture in Practice 소프트웨어 아키텍처 이론과 실제'[1]는 21년도에 4판까지 나와 있다. 이 책에서는 소프트웨어 아키텍처에서 "포스(force)"는 아키텍처 결정에 영향을 미치는 다양한 요소나 영향력을 의미한다. 이러한 포스는 기술적 요구사항, 비즈니스 전략, 사용자 요구 사항, 제약 조건 및 환경적 요인 등을 포함할 수 있다. 이 포스는 이 책의 특징인 품질 속성(Quality Attribute)로 정제되어 설계에 활용된다.

이외의 여러 문헌을 보았지만, 특히 패턴과 관련된 몇권의 책들에서 포스가 언급된다. 살펴 보았던 패턴 관련 문헌 중 가장 오래된 문헌은 브라이언 푸트와 조셉 요더의 "Big Ball of Mud"[2] 의 아래 내용이다.

By recognizing the forces and pressures that lead to architectural malaise, and how and when they might be confronted, we hope to set the stage for the emergence of truly durable artifacts that can put architects in dominant positions for years to come. The key is to ensure that the system, its programmers, and, indeed the entire organization, learn about the domain, and the architectural opportunities looming within it, as the system grows and matures.
아키텍처의 불쾌감을 유발하는 '포스과 압력'을 인식하고, 언제 어떻게 직면할 수 있는지 파악함으로써 향후 수년간 아키텍트를 지배적인 위치에 올려놓을 수 있는 아주 내구성 높은 산출물이 창발할 수 있는 발판을 마련할 수 있기를 바란다. 핵심은 시스템과 프로그래머, 나아가 전체 조직이 시스템이 성장하고 성숙함에 따라 해당 도메인과 그 안에서 다가오는 아키텍처 기회에 대해 학습하도록 하는 것이다.

이 글의 결론 부분에서 이야기하는 산출물은 패턴으로 볼 수 있다. 이 때, 포스는 패턴의 사용을 이끌어내는 여러 요소가 있다는 것을 이야기 한다고 볼 수 있다.

다른 책들의 경우는 객체 지향 리엔지니어링 패턴 "Object Oriented Reengineering Patterns"[3]에서는 각 장에서 패턴을 설명하기 전에 개요와 "포스: 주요한 요구사항(Forces)" 섹션이 있다. 즉, 관련된 패턴들이 공유하는 주요한 요구 사항들에 대해서 설명을 하고 패턴에 대해서 설명한다. 각 패턴이 집중하는 부분에 따라, 트레이드오프(Tradeoffs)가 존재하며 이에 따른 장점(Pros)와 단점(Cons)을 설명한다.

Patterns of API Design[4]의 경우도 여러 패턴을 다루는데, 여러 가지 포스/주요한 요구 사항 사이의 충돌(coflicting)이 있고, 이를 해소/해결(resolution)이 필요하다고 보고 있다. 또한 여기에는 트레이드오프(tradeoff)가 있다고 본다. 이러한 과정을 설계 결정(design decision) 혹은 아키텍처 결정(architecturla decision)이라고 한다. 책의 3장에서는 이러한 예제를 보여주는데, 다음과 같은 아키텍처 의사 결정 기록(architectural decision record, ADR) 형식을 제안한다.

[기능 또는 컴포넌트]에 해당하는 맥락에서,
[요구 사항 또는 목표로 하는 품질 속성(Quality Attribute)]을 충족할 필요가 있다,
우리는 [이익]을 우선적으로 달성하기 위해
[선택된 옵션]을 채택하기로 결정하고
그리고 [대안]은 선택하지 않아서
그 선택에 따르는 [부정적인 결과]는 받아들인다.


여러 아키텍처 책 혹은 디자인 패턴 책에서 언급하는 포스에 대해서 살펴 보았다. 앞에서 언급한데로 아키텍처에 영향을 미치는 드라이버(driver), 주요한 요구 사항, 혹은 품질 속성으로 보기도 한다. 이러한 부분은 아키텍처 결정에 어떤 영향을 미치는지 설명하는데 사용되기도 하고 패턴을 선택하는데도 사용되므로 이에 대해 이해하고 적절한 설계 결정, 즉 선택을 위해 고려되어야 한다.

참고문헌
[1] Len Bass, Paul Clements, Rick Kazman, "Software Architecture in Practice", SEI series in software engineering.
[2] Brian Foote and Joseph W. Yoder, "Big ball of mud", Pattern Languages of Program Design, volume 4, pages 654–692. Addison Wesley, 2000.
[3] Serge Demeyer, Stéphane Ducasse, Oscar Nierstrasz, "Object Oriented Reengineering Patterns"
[4] Olaf Zimmermann, Mirko Stocker, Daniel Lubke, Uwe Zdun, Cesare Pautasso, "Patterns for API Design: Simplifying Integration with Loosely Coupled Message Exchanges",  Addison-Wesley Signature Series

[1]의 6장 테스트라는 생명 보험에서는 다음 사항에 대해서 설명한다.

  1. 테스트의 중요성:
    • 리엔지니어링 프로젝트의 시작 단계에서 기존 시스템의 많은 부분을 변경해야 할 때 발생하는 여러 위험을 최소화하기 위해 테스트가 필요하다.
    • 시스템의 기능, 디자인, 아키텍처를 변경하면서도 시스템의 신뢰성을 유지하기 위해 체계적인 테스트가 필수적이다.
  2. 리엔지니어링의 주요 요구사항(Force):
    • 레거시 시스템에 정의된 테스트 절차가 부족한 경우가 많으며, 시스템 일부를 변경하는 것이 어렵다.
    • 시스템의 모든 측면을 테스트하는 것은 불가능하며, 시간에 쫓길 때 테스트 작성은 가장 먼저 제거된다.
    • 테스트 비용은 시스템의 새로운 기능 비용에 비해 고객에게 더 중요한 문제이다.
  3. 테스트의 특성:
    • 자동화(Automation): 테스트는 자동화되어 사람의 개입 없이 실행되어야 하며, 테스트를 실행하는 데 필요한 노력을 최소화하여 개발자가 주저하지 않게 해야 한다.
    • 지속성(Persistence): 테스트는 저장되어야 하며, 테스트 데이터, 수행할 작업 및 예상 결과를 문서화해야 한다.
    • 반복성(Repeatability): 변경 사항이 구현된 후 테스트를 반복할 수 있어야 하며, 새로운 기능이 추가될 때마다 기존 테스트 풀에 새로운 테스트를 추가하여 시스템에 대한 신뢰도를 높일 수 있다.
    • 유닛 테스트(Unit testing): 테스트는 개별 소프트웨어 컴포넌트에 연결되어 시스템의 어느 부분을 테스트하는지 명확히 식별할 수 있어야 한다.
    • 독립성(Independence): 각 테스트는 다른 테스트에 대한 종속성을 최소화해야 하며, 이는 테스트에 대한 신뢰를 유지하기 위해 중요한다.

다음은 이 장에서 서명하는 패턴이다.

  1. 테스트 프레임워크 사용하기:
    • 테스트를 쉽게 개발, 구성 및 실행할 수 있는 프레임워크를 제공하여 개발자가 회귀 테스트를 작성하고 사용하도록 장려해야 한다.
    • JUnit과 같은 단위 테스트 프레임워크를 사용하면 테스트 데이터를 설정하고, 실행하고, 결과를 확인하는 기본 패턴을 쉽게 따를 수 있다.
  2. 구현이 아닌 인터페이스 테스트하기:
    • 블랙박스 테스트를 통해 시스템 변경에도 살아남을 수 있는 재사용 가능한 테스트를 구축해야 한다.
    • 컴포넌트의 퍼블릭 인터페이스를 실행하는 블랙박스 테스트는 시스템의 주요 상호작용을 테스트하는 좋은 기회이다.
  3. 비즈니스 규칙을 테스트로 기록하기:
    • 비즈니스 규칙을 테스트 케이스로 명시적으로 인코딩하여 시스템이 구현하는 비즈니스 규칙과 동기화 상태를 유지할 수 있다.
    • 비즈니스 규칙을 테스트로 기록하면 규칙의 명시성을 높이고, 향후 시스템 진화 시 규칙이 올바르게 구현되는지 확인할 수 있다.
  4. 이해하기 위해 테스트 작성하기:
    • 레거시 시스템의 일부를 이해하고, 가설을 세우고 검증하기 위해 테스트를 작성해야 한다.
    • 이러한 테스트는 향후 리엔지니어링 작업에 도움을 주며, 시스템의 특정 측면에 대한 명확한 사양을 제공한다.

결론:

리엔지니어링 프로젝트에서 테스트는 시스템 변경으로 인한 위험을 줄이고, 시스템의 신뢰성을 유지하며, 향후 개발 및 유지 보수 작업을 지원하는 중요한 역할을 한다. 체계적인 테스트 절차와 프레임워크를 통해 리스크를 최소화하고, 비즈니스 규칙을 명시적으로 기록하는 등의 접근법이 강조된다.

 

참고 문헌

[1] Serge Demeyer et al., "Object-oriented Reengineering Patterns"

[2] https://github.com/blcktgr73/OORP 

[1]의 5장 "디테일한 모델 캡처"는 소프트웨어 시스템의 이해와 리엔지니어링 과정을 지원하기 위한 다양한 방법론을 제공합니다. 이 문서는 시스템을 더 잘 이해하고, 코드의 설계와 동작을 개선하기 위해 사용할 수 있는 구체적인 패턴들을 설명한다. 주요 내용은 다음과 같다.

  1. 코드에 대한 질문을 연결하기: 소스 코드에 직접적으로 질문과 주석을 추가하여, 코드의 특정 부분에 대해 이해하고, 팀 내에서 지식을 공유한다.
  2. 이해하기 위해 리팩터링하기: 코드의 일부를 반복적으로 리팩터링하여, 코드의 설계를 명확하게 하고 이해도를 향상시킨다. 이 과정은 코드에 대한 가설을 검증하는 실험으로 간주된다.
  3. 단계 별 실행해 보기: 런타임에 객체가 어떻게 인스턴스화되고 상호작용하는지 관찰하기 위해 코드를 단계별로 실행한다.
  4. 컨트랙트 찾기: 코드에서 클래스 간의 클라이언트-공급자 관계를 분석하고, 인터페이스가 어떻게 사용되어야 하는지를 명확히 한다.
  5. 과거로부터 배우기: 과거의 코드 버전을 분석하여, 특정 설계 결정들이 왜 내려졌는지 이해하고, 이를 통해 더 나은 설계 결정을 내리는 데 도움을 준다.

여기서 개발자들이 기존 소프트웨어 시스템을 이해하고, 유지 관리하며, 효과적으로 리엔지니어링할 수 있도록 돕기 위해 설계되었다.

 

참고 문헌

[1] Serge Demeyer et al., "Object-oriented Reengineering Patterns"

[2] https://github.com/blcktgr73/OORP 

+ Recent posts