Files
softwaredesign/wiki/concepts/additive-programming.md
minsung f868de1ce7 feat: wiki/concepts/ 핵심 개념 페이지 8개 생성
SDF 챕터들에서 추출한 핵심 개념:
- additive-programming: 가산적 프로그래밍 (전체 관통 테마)
- generic-procedures: 제네릭 프로시저 (Ch3, Ch5, Ch6)
- combinators: 컴비네이터 (Ch2~Ch5)
- partial-information: 부분 정보 (Ch1, Ch4, Ch6, Ch7)
- degeneracy: 퇴화성 (Ch1, Ch7)
- layered-data: 레이어드 데이터 + 의존성 추적 (Ch2, Ch3, Ch6, Ch7)
- propagation: 전파 모델 (Ch1, Ch5, Ch6, Ch7)
- domain-specific-language: DSL (Ch2~Ch5)

wiki/index.md Concepts 섹션 등록, wiki/log.md 기록

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 14:55:04 +09:00

5.3 KiB

title, tags, sources, updated
title tags sources updated
가산적 프로그래밍
concept
SDF
SDF-ch1-flexibility
SDF-ch2-dsl
SDF-ch3-generic-procedures
SDF-ch4-pattern-matching
SDF-ch5-evaluation
SDF-ch6-layering
SDF-ch7-propagation
2026-04-30

가산적 프로그래밍

한 줄 정의

동작하는 코드를 수정하지 않고 새 코드를 추가하는 것만으로 새 기능을 구현하거나 기존 기능을 새 요구사항에 맞추는 프로그래밍 스타일.

핵심 내용

왜 "수정"이 아닌 "추가"인가

소프트웨어 수명주기에서 가장 비싼 비용은 재작성과 리팩토링이다. 요구사항이 변할 때마다 기존 코드를 건드리면 다음과 같은 문제가 발생한다:

  • 회귀 버그: 잘 동작하던 부분이 수정 여파로 깨짐
  • 예상치 못한 결합(coupling): 수정이 다른 곳에 영향
  • 테스트 재작성 부담

가산적 접근은 변경 대신 레이어를 쌓거나(Ch6), 핸들러를 추가하거나(Ch3), 규칙을 추가하거나(Ch4), 전파기를 배선도에 더하는(Ch7) 식으로 기능을 확장한다. 기존 코드는 원래대로 남아 있다.

가산성을 가능하게 하는 전제 조건

"In order for additive programming to be possible, it is necessary to minimize the assumptions about how a program works and how it will be used."

세 가지 전제 조건:

  1. 가정의 최소화: 컴포넌트가 자기 역할 외의 것을 가정하지 않아야 새 컨텍스트에서도 재사용 가능
  2. just-in-time 결정: 실행 환경에 기반해 결정을 늦춤. 미리 굳힌 가정은 나중에 변경할 수 없음
  3. 관심사의 명확한 분리: 의도치 않은 상호작용을 줄여야 변경이 국소적으로 머뭄

SDF 전체에 걸친 구현 패턴

각 챕터는 가산성을 다른 차원에서 구현한다:

챕터 가산성 메커니즘 추가 단위
Ch2 컴비네이터 새 컴비네이터/프리미티브 부품
Ch3 제네릭 프로시저 새 타입 핸들러
Ch4 규칙 시스템 새 패턴 규칙
Ch5 제네릭 인터프리터 새 표현식 타입 핸들러
Ch6 레이어드 데이터 새 메타데이터 레이어
Ch7 전파 네트워크 새 전파기 노드

정확성 요구와의 긴장

"모든 것을 증명 가능하게 만들라"는 규율은 역설적으로 시스템을 취약하게 만든다. 일반적 메커니즘의 일반적 속성을 증명하기는 특수 메커니즘의 특수 속성을 증명하기보다 훨씬 어렵기 때문에, 증명 요구는 부품을 가능한 한 특수화하도록 유도한다. 특수화된 부품의 조합은 변화의 여지가 없다.

Postel의 법칙이 여기 적용된다: "Be conservative in what you do, be liberal in what you accept from others." 컴포넌트가 넓은 입력을 수용할수록 재사용성이 높아지고, 출력은 하위 컴포넌트에 최소한의 가정을 강요한다.

SDF에서의 등장

  • SDF-ch1-flexibility: 개념의 철학적·생물학적 기반을 제시. 퇴화성, 탐색적 행동, 스마트 파츠 원칙으로 동기 부여
  • SDF-ch2-dsl: 컴비네이터와 래퍼를 통한 첫 번째 구체적 구현. 믹스앤매치 부품 체계
  • SDF-ch3-generic-procedures: 핸들러를 추가하는 방식으로 제네릭 프로시저를 확장
  • SDF-ch4-pattern-matching: attach-rule!로 나중에 패턴 규칙을 동적으로 추가
  • SDF-ch5-evaluation: g:eval을 제네릭 프로시저로 구현하여 새 표현식 타입을 핸들러 추가만으로 도입
  • SDF-ch6-layering: 기존 코드를 전혀 수정하지 않고 단위·의존성 레이어를 추가
  • SDF-ch7-propagation: 배선도에 새 전파기를 추가하는 것이 곧 기능 확장

실천 시 주의점

컴비네이터의 한계: Ch3에서 지적하듯, "다이아몬드 구조"(컴비네이터로 완성된 아름다운 폐쇄 시스템)는 이후 확장이 매우 어렵다. 가산성과 폐쇄성(closure)은 상충한다. 컴비네이터가 가산적인 것은 새 부품을 조합하는 한에서이고, 컴비네이터 자체를 수정해야 할 때는 그렇지 않다.

순서 의존성: 제네릭 프로시저에서 핸들러를 추가할 때, 적용 가능성이 겹치는 규칙들의 우선순위가 추가 순서에 따라 달라질 수 있다. 이 의존성은 암묵적이어서 디버깅이 어렵다.

비용: 가산성은 공간(여러 레이어를 유지), 계산 시간(디스패치 오버헤드), 프로그래머 시간(복잡한 인프라 이해) 비용을 수반한다. 수명이 짧거나 변경이 없는 코드에서는 과잉 투자다.

진짜 가산성인지 확인: "추가만으로" 확장이 이루어지는지 아니면 기존 코드를 수정해야 하는지를 의식적으로 확인해야 한다. 많은 경우 '수정하는 곳'이 숨어있다.

관련 개념

  • generic-procedures — 가산적 확장의 핵심 메커니즘: 핸들러 추가
  • combinators — 가산적 조합의 기반 도구
  • layered-data — 수정 없는 메타데이터 추가의 구현
  • propagation — 배선도에 노드를 더하는 가산적 계산 모델
  • degeneracy — 가산성의 생물학적 대응물: 여러 메커니즘의 공존
  • domain-specific-language — 가산적 확장이 자연스러운 도메인 언어 구축