# 유동적 소프트웨어

> **이 장에서 배우는 것**
> 코드가 파생물이 되면 레거시가 무엇이 되는지, 그리고 무엇을 대신 지켜야 하는지.

## 레거시란 무엇이었나

지금까지 레거시는 이런 것이었습니다.

> **아무도 손대기 무서운 오래된 코드.**

왜 무서웠습니까? 이해하는 데 드는 비용 때문입니다.

```
5년 된 코드를 고치려면:
  1. 무슨 일을 하는지 읽어서 파악        (며칠)
  2. 왜 이렇게 만들었는지 추측           (문서가 없음)
  3. 고쳤을 때 뭐가 깨지는지 확인        (테스트가 없음)
  4. 결국 "일단 두자"                    ← 대부분 여기
```

**고치는 비용이 방치하는 비용보다 커서** 그대로 두는 것이 레거시였습니다.

## 계산이 무너집니다

[코드가 파생물](/guide/ha-intentops)이면 이 계산이 달라집니다.

```
낡은 부분을 이해하려 애쓰는 대신
→ 그 의도로 다시 만든다
```

이해 비용이 재생성 비용보다 크면, **이해하지 않고 다시 만드는 게 합리적**입니다.

```mermaid
graph TD
  A["낡은 부분 발견"] --> B{"의도와 테스트가 있나?"}
  B -->|"있다"| C["같은 의도로 재생성"]
  B -->|"없다"| D["기존 방식대로 읽고 고침"]
  C --> E["테스트로 동작 동일함 확인"]
```

**분기점이 "의도와 테스트가 있나"입니다.** 이게 없으면 유동적 소프트웨어는
성립하지 않습니다.

## 지켜야 할 것이 이동합니다

| | 기존 | 유동적 소프트웨어 |
|---|---|---|
| 자산 | **코드** | **명세 + 테스트** |
| 백업해야 할 것 | 저장소 | 저장소 (의도가 거기 있음) |
| 리뷰 대상 | 코드 변경 | **의도 변경** |
| 기술 부채 | 나쁜 코드 | **부실한 테스트** |

마지막 줄이 중요합니다. **기술 부채의 정의가 바뀝니다.**

```
기존 기술 부채:  읽기 어려운 코드, 중복, 얽힌 의존성
새 기술 부채:    테스트가 얇은 영역
```

테스트가 얇으면 그 영역은 **재생성할 수 없습니다.** 재생성해도 맞는지 확인할
방법이 없기 때문입니다. 그러면 그 영역만 예전처럼 굳어갑니다.

## 실제로는 어디까지 가능한가

솔직하게 말하면 **전부 재생성하는 조직은 드뭅니다.** 현실적인 모습은 이렇습니다.

| 영역 | 실제 |
|---|---|
| 새로 만드는 기능 | 의도 + 테스트로 시작. 재생성 가능 |
| 최근 1~2년 코드 | 테스트가 있으면 부분 재생성 |
| 오래된 핵심 로직 | 그대로 유지. 건드리지 않음 |
| 외부 연동 | 계약이 고정되어 있어 재생성 여지 적음 |

**새로 만드는 것부터 이 방식으로 하는 게 현실적인 시작**입니다. 기존 코드를 전부
전환하려 하면 시작을 못 합니다.

## 무엇이 좋아지나

### 1. 스택 이동이 쉬워집니다

언어나 프레임워크를 바꿔야 할 때, **의도와 테스트가 있으면 다시 만들 수
있습니다.** 기존에는 이게 몇 달짜리 프로젝트였습니다.

### 2. 최적화가 쉬워집니다

"동작은 그대로, 성능만 개선"이 명확해집니다. 테스트가 동작을 고정하니까 그
안에서 자유롭게 바꿀 수 있습니다.

### 3. 코드 리뷰가 짧아집니다

리뷰 대상이 **의도**로 옮겨갑니다. 구현 세부를 줄 단위로 보는 대신 "이 의도가
맞나, 테스트가 충분한가"를 봅니다.

## 무엇을 조심해야 하나

### 테스트가 곧 명세라는 뜻입니다

테스트에 안 적힌 동작은 **보장되지 않습니다.** 재생성하면 사라질 수 있습니다.

```
테스트에 없지만 실제로 의존하던 동작:
  - 응답에 항상 특정 필드가 있었다
  - 정렬이 항상 같은 순서였다
  - 오류 메시지 문구가 특정했다
```

이런 **암묵적 계약**이 재생성 후 깨집니다. 그래서 실무에서는 재생성 전에
"이 영역에 대해 다른 곳이 무엇을 가정하고 있나"를 확인합니다.

### 재생성이 항상 답은 아닙니다

작은 수정이면 그냥 고치는 게 빠릅니다. 재생성은 **낡아서 이해가 어려운 영역**에
쓰는 도구입니다.

---

## 확인

**1. 레거시의 기존 정의는 무엇이고 왜 그렇게 됐습니까?**

<details>
<summary>답</summary>

**아무도 손대기 무서운 오래된 코드**입니다. 이해하는 비용(읽고, 왜 그런지
추측하고, 깨지는지 확인하는)이 방치하는 비용보다 커서 그대로 두게 된 것입니다.
</details>

**2. 유동적 소프트웨어에서 기술 부채의 정의는 무엇으로 바뀝니까?**

<details>
<summary>답</summary>

**테스트가 얇은 영역**입니다. 테스트가 없으면 재생성해도 맞는지 확인할 방법이
없어 그 영역만 예전처럼 굳어갑니다.
</details>

**3. 재생성할 때 가장 조심해야 할 것은?**

<details>
<summary>답</summary>

**테스트에 안 적힌 암묵적 계약**입니다. 응답 필드 존재, 정렬 순서, 오류 문구처럼
다른 곳이 의존하지만 테스트에는 없는 동작이 재생성 후 깨질 수 있습니다.
</details>

---

개념 셋을 봤습니다. 이제 실제 프로세스로 들어갑니다 →
[프로세스 4단계 지도](/guide/ha-process-overview)
