[1]에서도 다루었지만, 미리 트레이닝을 해야 하는 Machine Learning의 한 종류인 LLM도 동일한 특징을 가지고 있다. ChatGPT4o의 경우도 현재 23년 10월까지 업데이트 되어 있다고 한다. 이 부분의 한계를 극복하기 위한 것이 Retrieval Augmented Generation (RAG)이다. 이 부분은 추가된 정보를 제공해서 이를 기반으로 동작하게 하는 것이다. 이 동작을 이해하기 위한 몇 가지 개념이 있는데 임베딩 모델(Embedding Model), 벡터 데이터베이스(Vector Database)와 같은 개념이 있다. 이 부분에 대해서는 간단하게 다뤄 보자.
RAG(Retrieval-Augmented Generation)는 앞에서 언급한 Foundation Model이 최신 데이터를 가지고 학습하지 못한 문제를 해결하기 위한 방법 중 하나로, LLM에 정보 검색을 결합하는 방식 또는 프로세스를 말한다. 즉, 검색된 정보를 이용해서 최신 정보와 원하는 정보를 추가하여 생성하도록 해서 신뢰성과 지식의 범위를 확장할 수 있도록 하게 한다.
이렇게 RAG를 하기 위해서 데이터를 추가 한다고 할 때, 추가된 데이터와 기존의 정보가 어떻게 관련되어 연관성이 있는지 알 수 있을까? 이를 이해하기 위해서 필요한 것이 임베딩 모델이다. 임베딩 모델은정보를 다차원 공간의 조밀한 표현으로 캡슐화하도록 훈련된 알고리즘이다[2]. 좀 더 자세한 내용은 YouTube를 함께 보는 것도 좋다. 여기서 시각화 한 것과 같이 유사도를 vector측면에 cosine similarity를 사용하는지도 알 수 있다. 그리고, L2 distance 혹은 vector product도 사용할 수 있음도 알 수 있다. 이러한 것을 활용하여 시멘틱 서치(semantic search)가 가능해 진다.
이러한 정보를 어떻게 보관하고 사용할 것인가? 이를 위한 데이터베이스가 벡터 데이터베이스(vector database)이다[3]. 기존 데이터베이스도 위와 같은 임베딩을 저장하고 sementic search를 할 수 있지만, 저장된 모든 데이터의 embedding과 query embedding의 similarity를 연산해야 하기 때문에 너무 많은 연산을 해야 하고 느리게 결과를 가져오게 된다. 벡터데이터 베이스는 자체적인 알고리즘으로 indexing하고 유사도 알고리즘을 조합하여 빠른 검색을 지원하므로 LLM에 RAG를 위해서는 이러한 데이터 베이스를 활용해야 한다.
결론은 [1]에서도 언급한 것처럼 LLM에 RAG이 적용되어야만 약점을 보완한 현대적인 아키텍처를 가진다고 볼 수 있다. 이 구조에는 임베딩 모델, 벡터 데이터 베이스들이 왜 연계되어 사용되는지, 그리고 왜 cosine similarity가 사용되는지 간단한 개념들이 살펴 볼 수 있다.
[1] 의 3장 초기 접근 방법에 다음과 같은 리엔지니어링 프로젝트 예제를 이용해서 실제 예시로 패턴에 대해 설명한다.
시나리오: 사용자 팀은 의료 소프트웨어 시스템인 proDoc을 개발하고 있으며, 경쟁사인 XDoctor의 인터넷 기능을 proDoc에 통합하려고 합니다.
주요 과제: 시스템을 통합하고 리엔지니어링하기 위해 첫 번째 평가와 계획을 수립하는 것입니다.
주요 요구사항
규모 문제: 레거시 시스템이 크고 복잡하므로 이를 관리 가능한 부분으로 나누어야 한다.
시간 부족: 프로젝트 초기에는 시간을 낭비하지 않도록 주의해야 한다.
불완전한 지식: 초기에 중요한 결정을 내릴 때 불완전한 지식으로 인해 잘못된 결정을 내릴 수 있다.
다양한 이해관계: 여러 이해관계자들이 서로 다른 의제를 가지고 있을 수 있다.
패턴 적용:
유지보수자와의 담소나누기: 시스템의 역사적, 정치적 맥락을 이해하기 위해 유지보수자와 논의한다.
한 시간 안에 모든 코드 읽기: 소프트웨어 시스템의 상태를 빠르게 평가하기 위해 집중적으로 코드를 검토한다.
모의 설치 수행하기: 리엔지니어링 적합성을 평가하기 위해 시스템을 실제로 설치하고 실행해 본다.
문서 스키밍하기: 관련 문서를 빠르게 검토하여 중요한 정보를 파악한다.
데모 중 인터뷰하기: 시스템을 사용하는 사람들과 인터뷰를 통해 추가 정보를 수집한다.
예시
예시에서는 앞에서 설명한 것의 사례에서 일어 났던 경험을 해당 패턴에 연계하여 이야기 한다.
XDoctor 인수: XDoctor의 개발팀에서 유일하게 남은 데이브와의 대화를 통해 중요한 기술적 정보를 얻고, 두 시스템을 통합하는 계획을 세훈다.
코드 검토: Java와 C로 작성된 코드를 검토하여 시스템의 구조와 품질을 평가한다.
결론
리엔지니어링 프로젝트를 성공적으로 수행하기 위해서는 초기 단계에서 정확한 평가와 계획이 중요하며, 이를 위해 다양한 패턴을 적용하여 시스템의 상태와 문제를 파악해야 한다고 이야기한다. 이 패턴들을 읽어 보면, 실재로 경험한 듯한 것들이 많다. 특히, 유지보수자와 담소나누기, 모의 설치하기 등은 마치 내 경험을 몰래 들여다 본 것 같은 느낌도 들 정도였다. 다른 것들의 경우도, 일부는 경험한 듯 하고 시간 제약을 두고 하는 것도 눈에 띄는 이야기였다. 무엇보다도 사회적 맥락에서 접근하는 패턴은 이 부분이 매우 실용적인 것이라는 생각도 많이 들었다. [2]에 번역 내용이 올라가 있다.
참고 문헌
[1] Serge Demeyer et al., "Object-oriented Reengineering Patterns"
아키텍처 드라이버는 시스템의 아키텍처에 영향을 미치는 주요 요인(Driver)이다. 이러한 드라이버는 아키텍처 결정을 내리는 데 중요한 역할을 하며, 요구사항(Requirement), 제약사항(Constraint), 원칙(Principle) 등을 포함할 수 있다. 소프트웨어 아키텍처 분야의 다양한 전문가와 저자들은 아키텍처 드라이버에 대해 논의하였는데 주요한 내용들을 정리해 보자.
아키텍처 드라이버를 언급하는 주요 인물들
그래디 부치 (Grady Booch)
공통점:
요구사항(Requirement)과 제약사항(Constraint)을 이해하는 것이 중요하다고 강조한다.
성능, 확장성, 보안과 같은 품질 속성(Quality Attribute)의 역할을 강조한다.
기능적 요구사항(Functional Requirement)과 비기능적 요구사항(Non-functional Requirement 혹은 Quality Attribute) 모두를 다룰 필요성을 강조한다.
차이점:
아키텍처 스타일을 분류하고 이해하는 데 중점을 두는 더 학문적이고 이론적인 관점을 제공한다.
바스, 클레멘츠, 카즈먼 (Bass, Clements, and Kazman) - "Software Architecture in Practice" 저자들
공통점:
품질 속성(Qaulity Attribute)이 아키텍처 결정에 중요한 역할을 한다고 강조한다.
이해관계자의 우려가 아키텍처를 형성하는 데 중요한 역할을 한다고 강조한다.
차이점:
Attribute-Driven Design (ADD) 방법 등 아키텍처 결정을 평가하고 문서화하는 자세한 프레임워크를 제공한s다.
마틴 파울러 (Martin Fowler)
공통점:
요구사항과 제약사항이 아키텍처 결정에 중요한 역할을 한다고 인정한다.
아키텍처의 유연성을 유지하여 변화하는 드라이버에 적응하는 것이 중요하다고 강조한다.
차이점:
실무 경험과 애자일 방법론을 통해 아키텍처 드라이버를 다루는 데 더 중점을 둔다.
공통점
품질 속성(Quality Attribute): 모든 저자는 품질 속성(예: 성능, 보안, 유지보수성)이 중요한 아키텍처 드라이버임을 강조한다.
이해관계자의 우려: 다양한 이해관계자의 우려를 이해하고 해결하는 것이 중요하다고 일관되게 강조한다.
기능적 및 비기능적 요구사항: 두 가지 요구사항 모두 아키텍처 결정을 내리는 데 기본적이라고 인식한다.
차이점
방법론 및 프레임워크:
그래디 부치는 모델링 언어와 프로세스에 중점을 둔다.
바스, 클레멘츠, 카즈먼은 ADD와 같은 특정 프레임워크를 제공한다.
마틴 파울러는 애자일 실천과 현실 세계의 적응성을 강조한다.
관점:
카네기 멜론대 소프트웨어 엔지니어링 인스티튜트(Carnegie Mellon University Software Engineering Institue, CMU SEI)의 메리 쇼와 데이비드 갈란은 더 이론적이고 학문적인 접근을 취한다.
마틴 파울러는 실무자 지향적 관점을 제공한다.
프로세스 vs. 패턴에 대한 강조:
그라디 부치와 마틴 파울러는 프로세스와 적응성에 중점을 둔다.
메리 쇼와 데이비드 갈란, 바스 등은 아키텍처 스타일과 패턴을 이해하고 활용하는 데 중점을 둔다.
요약
요약하자면, 품질 속성, 이해관계자의 우려, 기능적 및 비기능적 요구사항의 중요성에 대한 공통점이 있지만, 방법론, 관점, 특정 강조점에서 차이가 있다. 그라디 부치는 프로세스와 모델링에 중점을 두고, 메리 쇼와 데이비드 갈란은 이론적 이해를, 바스 등은 프레임워크를, 마틴 파울러는 실무와 애자일 방법론을 강조한다.
소프트웨어 아키텍처를 고려할 때 주요한 무기 중 하나가 추상화(abstraction)이다[1]. 추상화는 문제를 축소하여 해결하기 더 쉬운 작은 문제로 만들어 규모와 복잡성의 문제를 효과적으로 해결하게 한다. 여기서도 LLM(Large Language Model)의 여러 측면에서의 추상화를 통해서 이를 활용하는 Software Architecture에 대해서 이해도도 높이고 이를 활용해 설계하는데도 도움이 될 수 있기를 기대해 본다.
프로그래밍 모델로서의 LLM
LLM을 가지고 Prompt를 작성해서 작업을 하는 것은 마치 우리가 컴퓨터 프로그래밍하는 것과 비교가 가능하다. 아래 그림[2]이 이 부분을 잘 보여 준다. LLM은 이미 트레이닝을 마치거나 우리가 원하는데로 파인 튜닝을 마친 것이라고 볼 수 있다. 여기에 사용자의 Prompt를 전달하는 것까지 프로그래밍하는 것과 유사하다는 비교를 볼 수 있다. 물론, Prompt가 자연어에 가깝고 결과가 프로그래밍과는 조금 다르게 나올 수 있지만 LLM과 Prompt를 컴퓨터 프로그래밍과 매치 시켜보는 구조는 LLM을 가지고 원하는 작업하는 것에 대한 가장 간단한 추상화로 볼 수 있다.
[2] Program Model vs Gen AI Model
인간 인지 구조와 비교
LLM과 비교하기 위해서 인간 인지 메모리 모델을 살펴보자[3]. 결국은 기억/메모리 구조인데, 감각기억 (Sensory Memory), 단기기억 (Short-term Memory), 장기기억 (Long-term Memory)으로 구성된다.
감각기억 (Sensory Memory)은 시각, 청각 그리고 촉각과 같은 감각 기관에서 입수된 정보를 잠시 저장했다가 단기 기억으로 저장되는데 일부는 장기기억으로 전달 된다고 한다.이 단기 기억은 정보가 짧은 시간 동안 저장되고 처리되는데. 작업기억(Working Memory)으로 불리며, 정보의 일시적 저장과 조작을 담당한다. 장기 기억은 정보를 오랜 기간 동안 저장하는데, 크게는 명시적 기억(Explicit Memory)과 암묵적 기억(Implicit Memory)으로 나뉜다.
LLM은 구조적으로는 비슷해 보인다. 사용자가 LLM에 입력으로 Prompt를 제공하면 이는 마치 사람의 작업 기억 처럼 컨텍스트 윈도우(Contexnt Windows) 내의 내용만 참조하고 처리한다. LLM이 많은 내용을 학습하고 이를 통계적인 절차를 통해서 말이 되도록 생성한다.
[4] LLM 구조
다시 말하자면, LLM이 사람의 장기기억 처럼 동작하지는 않지만, 유사성이 있기 때문에 이를 잘 활용하는 것이 필요하다. 첫 째로 대량의 정보를 저장하고 있다. 즉, 대량의 텍트스 데이터를 학습하여 패턴과 지식을 내재화하였다. 그리고, 학습을 통해서 지식이 형성되어 있기 때문에 사용자의 입력에 대해 예측하고 그 결과를 제공한다. 그렇기 때문에, LLM을 "말많은 뉴비(Newbie)"로 비유되기도 한다.
LLM 애플리케이션 아키텍처
LLM 어플리케이션의 레퍼런스 아키텍처의 구성 요소를 [5]에서 잘 보여 준다. 하지만, 여러 항목이 있어서 너무 복잡해 보이기도 한다. 이를 간략화 하면 아래와 같다고 볼 수 있다.
Simplified LLM App Architecture
LLM의 경우는 미리 트레이닝을 해야 하기 때문에 최신 자료들에 대해서 처리하지 못한다. 24년 6월의 경우도, 23년 10월까지 업데이트 되어 있다고 한다. 이 부분의 한계를 극복하기 위한 것이 Retrieval Augmented Generation (RAG)이다. [5]에도 있지만, Embedding Model, Vector Database와 같은 개념이 포함된다. 이 부분에 대해서는 따로 더 자세히 다뤄 보겠다. LLM의 경우도, 상용화를 위한 Foundatation Model 뿐만 아니라 사용자와 interaction을 위한 Cache 그리고 부적절한 생성 내용을 filtering하기 위한 모듈도 포함되어 있.
마치며.
LLM과 관련된 작업 혹은 어플리케이션의 추상화를 통해서 구조적인 측면을 프로그래밍 언어 관점, 인간의 인지적 모델과 비교, 최근의 LLM 기반 어플리케이션 모델의 관점에서 살펴보았다. 어플리케이션의 관점이나 문제의 관점에서 또한 추상화와 구조의 변경이 필요하겠지만, LLM을 기반으로 하는 시스템의 소프트웨어 아키텍처 관점에서 좋은 시작점이 될 수 있지 않을까 기대해 본다.
참고문서
[1] 조지 페어뱅크스 저/이승범 역, "적정 소프트웨어 아키텍처-리스크 주도 접근법" 한빛미디어
[1]에서 가장 와닫는 말은 "나는 밥 먹기 전에 설거지하는 전략을 섞어서 쓴다. 보통은 밥 먹고 나서 설거지하는 것이 좋은 생활 습관이지만, 설거지한 이득은 다음 밥 먹을 때가 되야 발생한다. " 이다. 그렇지만, under-engineering이 당연히 좋다고 하는 것만 같아서 약간은 불편했다. 맞는 것일까? 그렇다고, 나는 over-engineering을 추종하는 것인가라고 질문했을 때도 불편했다. 그러면서도, 내가 아는 것은 무엇일까 하면서 시간이 상당히 흘렀다. 글을 쓸 거라고 생각했지만, 생각이 충분히 자라지 못하고 있었다. 비 오는 아침에 떠오르는 것이 적어 본다.
아내와 결혼하고 여러가지로 달랐다. 설거지 측면에서는 나는 요리를 하면서도 치워가면서 해야 했다. 그렇지만, 아내는 설거지는 가능한 늦게 하는 것이 좋다고 생각하는 것으로 보였다. 내가 요리하기 위해서 싱크대를 보면 시작하기 힘들어 보여 못하는 경우도 있었다. 그렇다고 해서, 나는 완벽했는가 생각해보면 그렇지 않다. 설거지 관련해서 아내가 나에게 핀잔을 주는 경우도 많았기 때문이다. 단지 달랐다고 해야 할 것 같다.
"Hacker News"에서 진행된 "over-engineering과 under-engineering 사이의 균형 찾기"[2] 에 관한 토론에서 보아도 여러 의견이 있지만 여전히 under engineering이 우세인 것처럼 보인다. 미래는 예측하기 어렵고 복잡하고 성급한 일반화가 문제 될 수 있다는 것이다. 그러면서도, 조심스럽게 이야기 하는 것은 실용적 한계 내의 균형(balance)이다. 그렇다면, over-engineering은 무엇이고 under-engineering은 어떤 것인가? 우리는 어떻게 판단할 수 있는 것인가?
앞의 에피소드에서도 이야기했지만, 배가 고파서 뭔가 해먹어야 하는데 설거지 때문에 아무것도 못하고 결국 시켜먹는다면 그것은 좋은 상황일까? 개발할 때에도 한걸음도 나아가기 어렵다면 이 상황과 비슷한 것 같다. 요구사항이 있고 진행을 해야 하는데 못하고 있다면 고민해야 한다. 내가 해야 하는 일이 한걸음도 나아가기 어렵다면? 팀이 해야 하는 일이 있는데 못한다는 결론만 난다면? 설거지 거리가 산더미처럼 쌓여 있는 것이 아닐까? 조금이라도 진전을 만들어야 한다.
산더미 같은 설거지를 보고 힘이 빠지지만, 애자일 마인드를 장착하고 지금 보다는 좋게 만들자라고 생각하고 더 개선을 한 다음 요리를 해 먹는 것은 어떤가? 여러 가지 전략이 있겠지만, 요즈음 공감이 가는 문구[3]가 있다. "First do it, then do it right, then do it better"이 그것이다. 나는 동작하는 소프트웨어가 정말 중요하다고 생각한다. 동작하지 않는 것을 고쳐서 동작하게 되어도 배우지만, 쉽지 않고 어렵다. 동작한다면 조금 더 쉽게 배우고 더 좋게 만들 수 있다.
다시 설거지로 돌아가 보자. 단순하게 하자. 우선 설거지를 하긴 해야 한다. 내가 요리하기 위한 공간도 만들어야 하고, 요리에 필요한 조리 도구도 정리해야 한다. 그것을 위해 고민하는 것 자체가 요리를 위한 설계이다. 혹시, 저녁까지 요리할 거라면 여력이 있다면 그것까지 고민하는 것이 좋겠다. 가족들과 함께할 것이라면 어떤 요리를 어느 정도 할 것 인지도 가족들과 이야기 하고 나눠야 한다. 그러고 나면, 설거지를 어느 정도 할지 정리가 된다. 이러한 상황을 개발과 빗대어 보면, 내가 under-engineering한 것인가? over-engineering한 것인가? 나 스스로와 팀과 밸런스를 맞춘 것이다.
개발도 요리처럼 느껴진다. 나 혼자를 위해 요리하기도 하지만, 나와 아내 그리고 아이를 포함한 가족을 위해 하기도 한다. 정리해 보면, 포인트는 나 그리고 팀에 맞는 방법을 쓰고 있는가, 지금 하고 있는게 밸런스에 맞다는 걸 아는가 이겠다. 흑백논리로 under-engineering과 over-engineering으로 나누기 보다는 동작하는 소프트웨어를 통해서 나와 팀이 이 미묘한 밸런스를 배우고 찾아가고 있는가가 더 중요할 수도 있겠다.
워드 커닝햄은 Wiki를 만든 유명한 프로그래머이다. 특히, 기술 부채(Technical Debt)라는 용어를 도입하기도 했다. 여기서는 이 기술 부채라는 용어를 다루고 있는 글을 이야기 해보자.
기술 부채라는 것은 [1]에서도 언급하듯이 소프트웨어 개발에서 발생하는 문제를 금융 부채에 비유한 것이다. 이글에서는, 초기 개발에서 빠르게 기능을 구현하기 위해 '부채'를 지는 것은 괜찮을 수 있지만, 이는 나중에 이는 갚아야 하는 '이자'와 함께 돌아오며 결국 원금까지 상환해야 한다는 점을 강조하는 것이라 볼 수 있다. 코드의 품질이 떨어지면 생산성이 낮아지는 것이 이자의 형태로 나타나는 것이고 이를 문제를 해결하는 것이 원금 상환하는 것까지 포함하는 것이다. 워드 커닝햄은 이 부채는 리팩토링을 통해 상환해야 한다고 한다. 상환하지 않으면 시간이 지남에 따라 문제들이 누적되어 전체 개발 조직이 만들 수 있는 진행 사항 자체가 멈출 수 있다고 보고 있다.
글에서도 이야기 하지만, 나는 기술 부채가 투자와 같은 것에 레버리지(Leverage)로서의 측면도 있다고 본다. 즉, 빠른 시장 출시를 위해 이 기술 부채를 활용하기도 한다. 기술 부채를 지는 것은 초기 제품을 더 빨리 시장에 출시하여 비즈니스 가치를 제공할 수 있게 한다는 것다. 이는 시장에 적기에 출시해서 이득도 얻을 수 있고, 또한 빠른 피드백을 얻고, 이를 바탕으로 제품을 개선하는 데 유리하기도 하다. 그러므로, 기술 부채를 전략적으로 사용하는 것은 스타트업이나 신제품 개발에서 중요한 전략이 될 수 있다. 즉, 단기적으로는 부채를 통해 빠르게 성과를 내고, 이후에 이 부채를 상환하는 방식으로 진행할 수 있는 것이다. 하지만, 우리가 자주 놓치는 것은 이 부채의 상환 계획이다. 다시 말해, 부채가 누적되지 않도록 지속적으로 관리해야 하는 것이다. 리팩토링 활동을 통해 생산성을 회복하고, 부채의 이자를 줄이는 것이 중요하다.
조금 더 구체적이지만 단순하게 생각해보자. 비유에 따라서 우리 접근 방법도 생각해 보자. 우리가 금전적으로 부채가 있다고 생각해보자. 무엇부터 해야 할까? 우선은 이자가 높은 부채 부터 갚아야 할 것이다. 그러므로, 기술 부채도 우선 순위를 정해서 이자와 원금을 먼저 갚는 것이 맞다. 우선 순위를 정했다면 실재로 내 금전적 상황에 따라서 아낄 것은 아끼고 이자와 원금을 갚아야 한다. 개발에서는 리팩터링과 개선 작업을 하는 것이다. 이는 코드의 구조, 중복, 복잡성 등 여러 측면에서 이루어질 수 있다. 부채를 갚아 본 이는 알지만, 정리가 되면 갚아야 하는 돈을 추가로 버는 듯한 느낌이어서 활력을 더 느끼기도 한다. 즉, 기술 부채 개념을 적절히 활용하면 초기 개발 속도를 높이고 장기적으로는 품질 유지와 개선을 할 수 있다. 하지만, 금융에 대한 비유에서 알 수 있듯이 시간을 어떻게 활용하고 밸런스 있게 운용하는지 고민하는 것이 더 중요하다.
Object-oriented Reengineering Pattern[1]의 저자인 세르게이 디마이어의 허락을 받아 번역을 시작한다. 전에 김창준님이 내가 관심이 있겠다고 소개해서 알게된 책이기도 하다. 이 책은 출판이 된적이 있지만, 크리에이티브 커먼즈로 공개되었다. 그렇다 하더라도, 번역하는데 허락을 받을 필요가 있다고 생각해서 저자에게 연락을 하여 확인하였다. 1장의 리엔지니어링 패턴을 번역하면서 [2]에 공유하고 내용을 요약해서 적어 본다.
1장의 내용은 소프트웨어 리엔지니어링(Software Reengineering)에 대해 다루고 있다. 특히, 레거시 시스템의 문제를 식별하고 개선하는 다양한 방법을 포함하며, 이를 통해 시스템을 더 유지보수가 가능하고 최신 요구 사항에 대응 가능하도록 조정하는 과정으로서 리엔지니어링을 설명한다. 주요 내용은 다음과 같다.
리엔지니어링의 필요성: 레거시 소프트웨어 시스템이 비즈니스에 중요함에도 불구하고 많은 비용이 들어 업그레이드나 교체가 어렵기 때문에 리엔지니어링이 필요하다.
리엔지니어링의 목적: 레거시 시스템의 복잡성을 줄이고, 적절한 비용으로 시스템을 계속 사용하고 적응할 수 있게 하는 것이다.
리엔지니어링의 이유: 성능 개선, 시스템을 새 플랫폼으로 이전하기 위함, 유지보수 비용 절감, 시스템에 대한 지식 문서화 등 여러 가지 구체적인 이유가 있다.
리엔지니어링 과정: 문제가 있는 레거시 시스템을 식별하고, 개선 방법을 모색하여 구현하는 과정을 포함한다. 이 과정에서 리버스 엔지니어링과 리엔지니어링의 차이점을 설명한다.
리엔지니어링 패턴: 리엔지니어링 과정에서 사용되는 패턴의 양식을 소개한다.
참고 문헌
[1] Serge Demeyer et al., "Object-oriented Reengineering Patterns"
마틴 파울러는 [1]에서도 소개했지만, "Refactoring"으로 유명하고, 여러 저서의 저자이기도 하다. 그는 애자일리스트로 엔지니어링 실천법(engineering practices)에 집중하는 익스트림 프로그래밍(Extreme Programming, XP)의 추종자이다.
마틴 파울러의 웹사이트에서 여러가지 소개하고 있는데, 소프트웨어 아키텍처에 대해 설명하는 글[2]도 포함되어 있다. 여기서 그는 소프트웨어 아키텍처는 소프트웨어 "시스템의 중요한 내부 설계"를 의미한다고 정의 하며, 좋은 아키텍처는 시스템이 "진화"할 수 있도록 지원해야 한다고 강조한다. 이것이 마틴이 이야기하는 애자일 소프트웨어 아키텍처의 핵심이라고도 할 수 있겠다.마틴은 이 글에서 팀이 좋은 아키텍처를 만드는 방법과 아키텍처 사고를 어떻게 개발 조직에서 장려해야 하는지에 대해서도 이야기하는데 그내용도 살펴 보자.
아키텍처의 진화
마틴 파울러의 웹사이트에서 진화적 아키텍처는 요구사항의 변화를 수용하고 지속적인 피드백을 통해 시스템이 개선될 수 있도록 지원한다고이야기 한다. 그리고, 소프트웨어 아키텍처가 일회성 계획이 아닌 지속적인 과정으로 설명한다. 그리고, 이를 위해서 다음 사항에 대해서 강조한다.
반복적 개발과 피드백 루프: 소프트웨어 개발 과정에서 짧은 반복주기를 통해 지속적으로 통합하고 테스트하는 방식을 사용함으로써, 아키텍처를 점진적으로 발전시키는 방법을 강조한다. 이는 고도의 협업과 지속적인 개선을 가능하게 한다.
피트니스 펑션의 활용: 아키텍처의 상태를 모니터링하고 진화의 방향을 가이드하는 데 사용되는 '피트니스 펑션' 개념을 사용하여 아키텍처의 건강을 측정하고 관리한다.
데이터 관리의 중요성: 진화적 아키텍처에서는 오래 지속되는 데이터의 처리가 종종 간과되기 쉬운 문제로, 이에 대한 강조를 통해 데이터 관리와 관련된 전략을 체계적으로 다루어야 함을 강조한다.
마이크로서비스와 도메인 주도 설계: 큰 단일 시스템을 더 작고, 독립적으로 관리 가능한 마이크로서비스로 분해하는 과정에서, 중요한 비즈니스 기능을 식별하고 이를 기반으로 서비스를 분리하는 전략을 사용한다. 이는 시스템의 유연성을 높이고, 변경 관리를 용이하게 한다.
마틴이 늘 강조하듯이 이러한 점들은 소프트웨어 아키텍처가 단순히 기술적인 문제가 아니라, 지속적인 비즈니스 가치를 창출하고 유지하는 중요한 역할을 한다는 것을 강조한다. 진화적 아키텍처 접근 방식은 변화하는 비즈니스 요구와 기술 환경에 효과적으로 대응할 수 있도록 돕는다고 설명한다.
팀이 만드는 좋은 아키텍처
마틴은 아키텍처가 팀에서 나온다고 믿는데, 팀이 좋은 아키텍처를 만드는 방법에 대해 다음과 같이 설명한다.
지속적인 학습과 피드백: 팀은 반복적인 피드백 루프를 통해 아키텍처를 지속적으로 개선해야 한다.
협업과 소통: 개발자 그리고 여러 이해관계자 간의 긴밀한 협업이 필요하다.
작은 변경의 관리: 아키텍처를 점진적으로 변화시켜야 하며, 이는 작은 단위의 변경을 통해 이루어져야 한다.