[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 

Machine Learning(ML) 기술이 발전하면서 빠르게 기존 시스템과 통합이 이루어 지고 있다. LLM도 단순히 사람들이 ChatGPT와 같은 서비스를 사용하는 것을 넘어서서 Cloud를 통해서 여러 시스템과 통합이 이루어 지고 있다. 아래 그림데로 많은 ML 시스템에서 실제로 학습이나 예측에 사용되는 코드가 극히 일부에 불과하다는 것이 이미 알려져 있다[1]. 이러한 관점에서 기존의 여러 기술들이 ML 기술들과 통합되어야 한다. 이러한 관점에서 숨겨진 기술 부채(Hidden Technical Debt in Machine Learning)가 많을 수 있다.

ML 시스템에서 ML Code(검은색 부분)

 

 

특히, 기존의 성능과 관련된 항목에서도 이러한 부분을 살펴 볼 수 있다. 여기서는 성능 관점의 지연 시간(Latency)와 규모확장성(Scalability)에 대해서 잠시 살펴 보자.

 

기존 기술의 경우에도 Cloud를 기반으로 하게 되면 최종 사용자의 위치에 따라서 실재 연산을 처리하는 서버의 위치(Region)은 중요한 부분 중에 하나이다. 간단히 말하자면, 한국에 있는 사용자가 미국에 있는 서버에 접속해야 하는 경우라면 결국 요청을 미국 서버에 보내고 처리한 결과를 다시 한국에 있는 사용자에게 보내려면 시간이 걸릴 수 밖에 없다. 그렇다면, LLM의 Foundation Model을 운영하는 Cloud의 Region을 최종 사용자에 맞게 최적화 할 필요가 있다.

 

규모 확정성(Scalability)의 경우도 사용자가 많아 지면 하나의 LLM 인스턴스로 처리하는 것은 문제가 될 수 있을 것이다. 이것도 결국에는 Load balancing 이슈에 해당한다고 할수 있다. 결국 이러한 전통적인 문제는 기존과 같이 요청을 잘 분배해서 처리하는 구조가 필요하다[2].

 

참고 문헌

[1] D. Sculley et al., "Hidden Technical Debt in Machine Learning Systems",  https://papers.neurips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf

[2] https://aws.amazon.com/ko/blogs/tech/multi-rag-and-multi-region-llm-for-chatbot/

 

 

+ Recent posts