콘텐츠로 바로가기

Software Construction & Code Physics

상위 설계를 실제 동작하는 코드로 구체화하는 과정에서 핵심인 코드의 물리적 가독성, 유지보수성 및 객체 지향 원칙의 수리적 결합을 다루는 학습 노드입니다.

Article
M

Me

hyunyoun's Blog

software-engineering-devopssoftware-engineeringdev-opssdlcprocesssoftware-constructioncode-physicsrequirements11 min read

1. Overview

소프트웨어 구현과 코드 물리학(Software Construction & Code Physics)은 설계도의 상상력을 벗어나 키보드를 두드리는 순간부터, 개발자 여러 명이 하나의 코드 베이스에 달려들며 벌어지는 병합(Merge)의 유혈 사태와 형상 통제의 물리학을 해부합니다.

학습자는 최종_진짜최종_이게마지막.zip으로 코드를 덮어쓰며 밤을 새우던 원시시대를 박살 낸 **버전 관리(Git)**의 불변성(Immutability)과 스냅샷(Snapshot) 철학을 뜯어봅니다. 나아가 수십 명의 개발자가 각자의 우주(Branch)에서 코드를 짜다가 한곳에서 충돌 없이 섞이기 위해 진화해 온 Git-flow와 Trunk-based Development 브랜칭 역학을 장악합니다. 마지막으로, 동료의 썩은 코드가 메인스트림에 침투하는 것을 막는 방파제인 코드 리뷰(Code Review) 문화와, 이미 돌아가고 있는 끔찍한 코드를 수술대 위에 올리는 **리팩터링(Refactoring)**의 멱등성 역량을 확보합니다.

2. Scope & Boundaries

In-Scope

  • Version Control System (Git): 분산형 형상 관리, Commit (Snapshot), Tree, Hash(SHA-1), Merge vs Rebase.
  • Branching Strategies: 무거운 Git-flow (Feature \rightarrow Develop \rightarrow Release \rightarrow Master) vs 빠르고 애자일한 Trunk-based Development (Main 하나로 달리기).
  • Code Review: Pull Request (PR) 기반의 비동기 코드 리뷰, 승인 게이트웨이, 피드백 루프.
  • Refactoring Physics: 외부 동작(기능)은 1%도 바꾸지 않으면서 내부 구조(설계)만 뜯어고치는 안정화된 외과 수술 기법.

Out-of-Scope

  • Git 내부 객체(Blob, Tree)의 바이너리 구현체: Git 코어의 C언어 레벨 메모리 관리 \rightarrow 시스템 프로그래밍 영역.
  • 객체지향 설계(SOLID) 및 클린 코드 철학: 코드를 어떻게 '아름답게' 짤 것인가의 이론 \rightarrow 09-03 Architecture & Design 영역으로 위임 (본 문서는 '짜여진 코드를 어떻게 합치고 깎을 것인가'에 집중).

Boundaries

  • Adding Feature vs Refactoring: 기능을 추가할 때는 모자가 '기능 모자'입니다. 에러가 나도 되고 테스트 코드가 깨져도 됩니다(나중에 고치면 되니까). 하지만 리팩터링을 할 때는 모자를 바꿔 씁니다 '리팩터링 모자'. 이때는 절대 기능을 추가해선 안 되며, 기존 테스트 코드가 단 1개라도 깨지면 즉시 롤백(Rollback)해야 합니다. 이 두 가지 모자를 섞어 쓰다가 코드를 맹장 수술 중에 성형 수술까지 해버려 환자(시스템)가 죽어버리는 안티 패턴에 명확한 선을 긋습니다.

3. Counterexample

  • 빅뱅 머지(Big-Bang Merge)의 지옥: 개발자 5명이 3달 동안 각자의 브랜치에서만 코딩을 했습니다. 배포를 1주일 앞두고 처음으로 5명의 코드를 Master에 병합(Merge)합니다. Conflict(충돌) 메시지가 3,000줄이 떴습니다. 누가 짠 코드가 맞는 건지 기억도 안 나서, 서로의 코드를 덮어쓰며 지우다가 멀쩡하던 기능 10개가 박살 났습니다. 코드를 작게 자주 병합(Continuous Integration)하는 Trunk-based 원칙을 무시하고, 지독한 고립을 자초한 브랜칭 붕괴입니다.
  • 리팩터링을 빙자한 폭파: 코드가 더럽다며 신입 개발자가 3일 동안 2,000줄의 결제 로직을 다 뜯어고쳤습니다. "더 깔끔해졌죠?"라고 PR을 올렸으나, 테스트 코드(Unit Test)를 덮어놓고(혹은 아예 없이) 수술을 한 탓에 특정 카드사의 할인 결제가 안 먹히기 시작했습니다. 겉보기 동작을 보장하는 테스트 그물망 없이 벌이는 리팩터링은 '개선'이 아니라 '무책임한 폭파 철거'라는 공학적 무지의 끔찍한 결과입니다.

4. Prerequisites

  • 협업과 폭포수 (Basic): 고전적 SDLC에서의 코딩(구현) 단계의 위치. (09-01-01 SDLC Models)
  • 자료구조 (Basic): Tree와 DAG(Directed Acyclic Graph) 구조에 대한 이해. (04 Data Structures)

5. Learning Map

Sequence Core Cluster Objective & Description Evidence (BoK)
1 The Physics of Git 시간을 돌리고 평행우주를 창조하는 마법. 차이(Diff)가 아니라 찰나의 스냅샷(Snapshot)을 해시 알고리즘으로 엮어내는 Git의 뼈대를 쥡니다. P1
2 Git-flow vs Trunk-based 안정적이지만 무거운 컨베이어 벨트(Git-flow)를 탈 것인가, 아니면 위험하지만 극도로 빠른 1차선 고속도로(Trunk)를 달릴 것인가를 해부합니다. P5
3 The Code Review Gateway 내 코드가 남의 눈물로 씻겨지기 전까지는 절대 메인 서버에 닿을 수 없게 막아버리는 Pull Request(PR)의 위대한 방어막을 뜯어봅니다. Industry
4 Refactoring Under the Net "작동하는 건 건들지 마라"는 금기를 깨고, 테스트 코드라는 안전망 위에서 썩은 내장을 하나씩 도려내는 안전한 외과 수술을 장악합니다. Industry

6. Learning Topics

Basic

Core Topic 01: 스냅샷과 시간 여행 (The Physics of Git)

  • Why to Learn: SVN처럼 변경된 줄(Line)만 추적하다가 꼬이는 낡은 방식을 버리고, 파일 시스템 전체의 '순간 캡처(Snapshot)'를 해시 묶음으로 추적하는 분산형 버전 관리를 통찰하기 위함입니다.
  • What to Learn:
    • Concepts: Distributed Version Control, Commit (Snapshot), DAG (Directed Acyclic Graph), SHA-1 Hash, Immutable History.
    • Skills: 내 컴퓨터(Local)와 원격 서버(Remote)가 완벽히 동일한 역사를 공유하며, 서버가 날아가도 내 컴퓨터의 .git 폴더 하나로 100% 복구 가능한 탈중앙화(Decentralization) 증명.
  • How to Learn:
    • 1단계: Diff의 저주 (SVN): 예전 시스템은 "A 파일 3번째 줄에 콤마 추가됨"만 기록했습니다. 중간에 역사가 하나 날아가면 그 뒤의 모든 덧셈 뺄셈이 꼬여서 소스코드가 걸레짝이 되었습니다.
    • 2단계: 스냅샷의 마법 (Git): 리누스 토르발스는 다르게 짰습니다. 커밋을 할 때마다 사진기(Snapshot)로 폴더 전체를 찍습니다. 안 바뀐 파일은 링크만 걸고, 바뀐 파일은 통째로 새로 저장합니다. 그리고 그 사진에 40자리 고유 번호(Hash, 예: a1b2c3d...)를 부여합니다.
    • 3단계: 불변의 역사 (Immutability): 이 사진들은 서로 꼬리물기(DAG)로 이어집니다. 과거 사진 하나를 조작(Tamper)하면 해시값이 연쇄적으로 다 깨져버려서 즉각 발각됩니다. 안전하게 과거로 시간 여행(Checkout)을 하고 여러 갈래로 우주를 분화시키는(Branch) Git의 물리학을 해부합니다.
  • Implement: Git Snapshot 메커니즘 시뮬레이터.
    1. Commit A: 100MB 프로젝트 저장. (스냅샷 1: 100MB).
    2. 1KB 파일 하나 수정 후 Commit B. (SVN은 1KB만 저장하려 하지만, Git은 100MB 통째로 새로 스냅샷 찍는 것처럼 보이나 내부적으로는 1KB만 새로 만들고 99.9MB는 이전 객체 재참조(Pointer)). Diff 델타에 의존하지 않아 결코 파일이 깨지지 않는 완전성(Integrity) 원리 시각화.

Core Topic 02: 두 갈래의 브랜칭 역학 (Git-flow vs Trunk-based)

  • Why to Learn: 조직의 배포 속도에 맞춰, 철저한 검증을 거치는 무거운 브랜치 전략(은행, 의료)과 하루에 10번씩 배포하는 애자일 전략(스타트업) 중 하나를 설계하기 위함입니다.
  • What to Learn:
    • Concepts: Branching Strategy, Git-flow, Trunk-based Development, Feature Branch, Continuous Integration (CI), Big-Bang Merge.
    • Skills: "Master \leftarrow Release \leftarrow Develop \leftarrow Feature" 4단계를 거쳐 한 달에 한 번 배포하는 Git-flow와, "Main \leftarrow Feature(하루 1번 씀)"으로 극단적으로 단순화한 Trunk-based의 트레이드오프 비교.
  • How to Learn:
    • 1단계: Git-flow (견고한 성곽): 은행입니다. 안전이 최고입니다. 새로운 걸 만들려면 Feature 브랜치에서 땁니다. 다 만들면 Develop으로 모읍니다. 한 달 치가 모이면 Release 브랜치로 빼서 QA팀이 2주간 미친 듯이 테스트합니다. 버그가 잡히면 드디어 Master로 올리고 배포합니다. 튼튼하지만 너무 느리고 관료적입니다.
    • 2단계: Trunk-based (고속도로): 스타트업입니다. Main(Trunk) 브랜치 딱 하나만 씁니다. 개발자는 기능을 만들 때 길어야 1~2일 안에 어떻게든 쪼개서 Main으로 병합(Merge)해 버립니다.
    • 3단계: 충돌의 최소화: 브랜치가 한 달 동안 떨어져 있으면 병합할 때 지옥(Merge Conflict)이 열립니다(Big-Bang). Trunk-based는 코드를 100줄 짤 때마다 계속 Main에 때려 박으므로, 충돌이 나도 5줄이라 1초 만에 해결됩니다(진정한 CI). 조직의 민첩성을 결정짓는 브랜칭 철학을 뜯어봅니다.
  • Implement: 브랜치 생명주기에 따른 충돌 률(Conflict Rate) 매트릭스 도출. Git-flow: 5명의 개발자가 4주간 고립 코딩 \rightarrow 4주 차 Merge 시 50개 파일에서 대규모 Conflict 터짐 \rightarrow 해결에 3일 소요. Trunk-based: 5명의 개발자가 매일(Daily) PR 머지 \rightarrow 충돌 나더라도 1~2줄 \rightarrow 해결에 5분 소요. 브랜치의 '수명(Lifetime)'이 길어질수록 통합의 고통이 기하급수적으로 커지는 아키텍처 역학 렌더링.

Practical

Core Topic 03: 품질 통제 게이트웨이, 코드 리뷰 (The Code Review Gateway)

  • Why to Learn: 아무리 똑똑한 개발자도 혼자 짜면 쓰레기 코드를 양산한다는 것을 인정하고, 동료의 집단 지성으로 결함을 엣지(Edge)에서 차단하는 PR(Pull Request) 문화를 장악하기 위함입니다.
  • What to Learn:
    • Concepts: Code Review, Pull Request (PR), Four Eyes Principle, Asynchronous Feedback, CI Checks.
    • Skills: approve 권한을 가진 리뷰어 2명이 OK 해야만 Main 브랜치로 코드가 섞이도록 GitHub/GitLab 브랜치 보호 룰(Branch Protection Rule)을 강제하는 워크플로우 설계.
  • How to Learn:
    • 1단계: 오만함의 대가: "내가 짠 코드는 완벽해."라며 확인 없이 Main에 직접 푸시(Push)했습니다. 띄어쓰기 오타 하나 때문에 실서버가 다운되었습니다.
    • 2단계: PR (코드 결재 서류): 코드를 다 짰다고 바로 합치는 게 아닙니다. "저 코드 이렇게 고쳤는데, 메인에 합쳐(Pull) 주실래요(Request)?" 하고 동료들에게 결재 서류(PR)를 올립니다.
    • 3단계: Four Eyes Principle (네 개의 눈): 내 코드를 만든 내 눈(2개) 말고, 객관적인 동료의 눈(2개)이 코드를 한 줄 한 줄 까봅니다. "여기 N+1 쿼리 터질 거 같은데요?", "변수명이 직관적이지 않네요." 피드백이 오가고 코드가 세탁됩니다. 여기에 더해 CI 봇(Bot)이 빌드 테스트를 통과해야만 초록색 버튼(Merge)이 활성화되는 겹겹의 방파제를 해부합니다.
  • Implement: Pull Request 비동기 방어 시뮬레이터. Dev A: Feature-Payment 브랜치 생성 후 코드 1,000줄 작성 \rightarrow PR 생성. CI Bot: Unit Test 실패! (Coverage 75% < 80% 기준 미달) \rightarrow 머지 버튼 비활성화 (Block). Dev A: 테스트 코드 50줄 추가 후 재커밋 \rightarrow CI 통과. Dev B (Reviewer): "라인 45: 보안 취약점 보임, 수정 요망." \rightarrow Request Changes. 기계(CI)와 인간(Reviewer)이 이중으로 방어막을 쳐서 Main 브랜치의 청정도를 지켜내는 플로우 렌더링.

Advanced

Core Topic 04: 그물 위에서의 수술, 리팩터링 (Refactoring Under the Net)

  • Why to Learn: "돌아가는 코드는 절대 건드리지 마라"는 낡은 금기를 깨고, 썩어가는 스파게티 코드를 안전하게 해체하고 조립하여 기술 부채를 지속적으로 탕감해 내는 엔지니어링의 정수를 장악하기 위함입니다.
  • What to Learn:
    • Concepts: Refactoring, Tech Debt (기술 부채), Code Smells, Regression Bug, Test Harness.
    • Skills: 길이가 300줄인 끔찍한 메서드 하나를 50줄짜리 6개의 메서드로 쪼개는 과정(Extract Method)에서, 단 1%의 비즈니스 로직 훼손도 없음을 증명하는 테스트망(Test Net) 운용.
  • How to Learn:
    • 1단계: 기술 부채의 공포: 1년 전에 급하게 짠 if/else 100개짜리 함수가 있습니다. 버그가 났는데 무서워서 아무도 못 건드립니다(돌아는 가니까). 이 코드는 썩은 내(Code Smell)를 풍기며 시스템 전체의 유지보수를 마비시킵니다.
    • 2단계: 안전망 설치 (Test Harness): 리팩터링을 시작하기 전, 무조건 '현재 동작'을 검증하는 테스트 코드부터 짭니다. 이 테스트들이 전부 초록불(Pass)이 뜨면, 내 밑에 튼튼한 '안전 그물'이 쳐진 겁니다.
    • 3단계: 외과 수술: 코드를 미친 듯이 찢고 함수를 분리합니다(Extract Method, Rename Variable). 밖에서 볼 때(입력/출력)는 예전과 100% 똑같이 동작해야 합니다(멱등성). 코드를 한 번 고칠 때마다 테스트를 돌립니다. 만약 빨간불(Fail)이 하나라도 켜지면? 내가 수술하다 혈관을 잘못 자른 겁니다. 즉시 Ctrl+Z를 누르거나 Git Rollback을 합니다. 두려움 없이 레거시 코드를 썰어버리는 무자비하고도 안전한 리팩터링 춤사위를 뜯어봅니다.
  • Implement: Refactoring vs Regression(퇴행) 테스트 검증 플로우. Legacy Code: 500줄짜리 CalculateTotalPrice() 함수. (테스트 10개 Pass). Action: ApplyDiscount() 로직을 별도 클래스로 분리. Verification: 테스트 10개 실행. \rightarrow 만약 1개 Fail (VIP 할인 미적용됨) 발생: 기능 추가(Feature)가 아닌 기존 동작이 망가진 회귀(Regression) 버그 감지. \rightarrow 즉각 코드 원상 복구(Revert) 후 더 작은 단위로 안전하게 재수술 시작. 테스트 커버리지가 리팩터링의 유일한 생명줄임(Life-line)을 시각화.

7. Terminology

Term (EN / ko, abbr) 1문장 정의 단계(기본/권장/실무/심화) 역할/맥락 관련 개념 유사/대비/함께 사용 오해 포인트 Evidence(Primary/Secondary/Industry) Flags(core)
Version Control (버전 관리/Git) Ctrl+Z가 통하지 않는 협업 코딩의 세계에서, 프로젝트 폴더 전체의 시간을 사진 찍듯(Snapshot) 멈춰 불변의 해시(Hash)로 박제해 두는 타임머신이자 평행우주입니다. 기본 코드 히스토리 추적 및 협업 기저 Snapshot / Commit / Hash SVN (Diff 기반) Git은 파일의 바뀐 '차이(Diff)'만 저장하는 게 아니라, 내부적으론 변경된 파일을 통째로 새로 저장해 완벽한 무결성을 보장함 P1:CS2023 core
Trunk-based Development (트렁크 기반 개발) Git-flow처럼 브랜치를 수개월씩 고립시키지 않고, 하루에도 몇 번씩 메인(Trunk) 브랜치로 코드를 때려 박아 충돌(Merge Conflict)의 고통을 아주 작게 분산시키는 애자일 브랜칭 전략입니다. 권장 CI/CD 민첩성 극대화 브랜치 전략 Main Branch / CI / Feature Flag Git-flow (무거운 관리형) 트렁크로 계속 머지한다고 해서 덜 완성된 기능이 고객에게 배포되는 건 아니며, Feature Flag로 숨겨두고 코드만 미리 합쳐두는 것임 P5:SFIA core
Code Review / PR (코드 리뷰 / 풀 리퀘스트) 내가 짠 코드를 메인 스트림에 밀어 넣기(Merge) 전, 동료들의 집단 지성과 자동화된 CI 봇(Bot)의 검증을 통과해야만 문이 열리는 무자비하고도 안전한 방어 게이트웨이입니다. 실무 품질 통제 및 지식 공유(Silo 방지) PR / Four Eyes Principle Pair Programming 코드 리뷰의 목적은 남의 코드를 까내려(Blame) 잘난 척하는 게 아니라, 잠재적 버그를 엣지에서 차단하고 팀 전체의 설계 컨텍스트를 동기화하는 것임 Industry core
Refactoring (리팩터링) 시스템이 밖에서 볼 때 동작하는 결과는 단 1%도 변하지 않게 유지한 채, 그 안의 썩은 코드(Code Smell)와 복잡한 내장 구조만 아름답게 뜯어고치는 외과 수술입니다. 심화 기술 부채 탕감 및 설계 유지보수 Code Smell / Test Harness Rebuilding (처음부터 재개발) 테스트 코드라는 '안전 그물(Safety Net)'이 없이 진행하는 리팩터링은 리팩터링이 아니라 그냥 시스템을 무책임하게 부수고 다니는 폭파 행위임 Industry core

8. References

Primary

  • [P1] CS2023 - Software Engineering (SE) - Software Construction and Evolution (Refactoring)
  • [P5] SFIA - Programming/Software Development (PROG) - Version Control and Code Review

Secondary

  • [Refactoring: Improving the Design of Existing Code] Martin Fowler - Principles of Refactoring, Code Smells
  • [Pro Git] Scott Chacon - Git Internals (Objects, Trees, Commits)

Industry

  • [Google Engineering Practices] - How to do a code review
  • [TrunkBasedDevelopment.com] - Trunk-Based Development Introduction
  • [Atlassian Git Tutorial] - Comparing Workflows (Gitflow vs Trunk-based)

9. Final Checklist

Primary

  • 과거 SVN(Subversion) 방식이 변경분(Diff)에 의존하여 히스토리가 꼬이는 현상을, Git이 파일 시스템 전체의 스냅샷(Snapshot)과 SHA-1 해시 포인터 매커니즘을 통해 어떻게 완벽히 방어(Immutability)하는지 설명할 수 있는가?
  • 엄격한 결재 단계(Develop, Release)를 거쳐 월 단위 배포에 적합한 Git-flow와, 작고 빈번한 병합을 강제하여 CI(Continuous Integration)를 극대화하는 Trunk-based Development의 조직적 트레이드오프를 비교할 수 있는가?

Secondary

  • 브랜치(Branch)의 수명(Lifetime)이 길어질수록 발생할 수밖에 없는 '빅뱅 병합 충돌(Big-Bang Merge Conflict)'의 공포를, 어떻게 짧은 주기의 PR(Pull Request)과 비동기 코드 리뷰 문화로 조기 억제(Shift-Left)하는지 증명할 수 있는가?
  • 외부 기능(Behavior)을 변경하거나 버그를 고치는 '기능 모자'와, 기능 변경 없이 내부 구조(Design)만 개선하는 '리팩터링 모자'를 동시에 썼을 때 발생하는 심각한 퇴행(Regression)의 위험성을 지적할 수 있는가?

Industry

  • 500줄짜리 끔찍한 레거시 메서드를 Extract Method로 쪼개는 리팩터링을 수행할 때, 수정된 코드가 기존 비즈니스 로직을 하나도 망가뜨리지 않았음을 보장해 주는 자동화된 테스트 그물망(Test Harness)의 절대적 필요성을 논증할 수 있는가?
  • 아직 완성되지 않아 UI가 깨진 기능이라도 Trunk(Main) 브랜치로 즉시 병합하여 충돌(Conflict)을 예방하되, 런타임 환경에서는 고객에게 해당 기능이 노출되지 않도록 제어하는 피처 플래그(Feature Flag) 기법의 런타임 스위칭 원리를 설계할 수 있는가?

SDLC & Requirements

7 / 8