📖 구조 노트 목차 Chapter 7 읽는 중

7. 프로그램은 관계를 기록한 것이다

구조 노트 Chapter 7 2026. 07. 13.

지하철 2호선을 타고 가다가 사당역에서 4호선으로 갈아타면 상록수역까지 그대로 도착한다. 길찾기 어플리케이션은 이 경로를 통째로 알고 있는 것이 아니라, “2호선을 타면 사당역에 닿는다”와 “사당역에서 4호선으로 갈아타면 상록수역까지 닿는다”는 두 개의 구간 정보를 이어 붙였을 뿐이다. 이것이 함수 합성과 같은 구조다.

이 이어 붙이기에는 조건이 하나 있다. 아무 구간이나 순서 없이 붙일 수는 없다. 앞 구간이 도착하는 역과 다음 구간이 출발하는 역이 같아야 한다. 2호선 구간의 도착역이 사당이면 다음 구간은 반드시 사당에서 출발해야 하고, 그렇지 않으면 두 구간은 이어지지 않는다. 두 경로를 이어 붙여 더 큰 경로를 만드는 일은, 결국 앞의 끝과 뒤의 시작이 맞물리는가를 확인하는 일과 같다.

6장에서 본 order.getUser().getCompany()도 같은 방식으로 작동한다. getUser()가 돌려주는 사용자 객체는 getCompany()가 받아야 할 입력과 정확히 일치하는 종류의 대상이다. 그래서 두 메서드는 아무 문제 없이 이어 붙는다. 여기에 getCompany().getRegion()을 한 번 더 이어 붙이면 주문 하나가 지역 하나로 곧장 연결되는 새로운 경로가 생긴다. 이 경로는 어디에도 따로 저장되어 있지 않다. 세 개의 작은 함수가 이어진 결과로 그때그때 존재할 뿐이다.

실제로 코드베이스 전체를 펼쳐 놓고 보면 이런 이어 붙이기의 누적이 프로그램의 상당 부분을 설명할 수 있다는 사실이 드러난다. 함수 하나하나는 하나의 관계를 기록해 둔 것에 지나지 않는다. getUser는 주문과 사용자 사이의 연결을, getCompany는 사용자와 회사 사이의 연결을 기록한다. 프로그래머가 새로운 기능을 만든다는 것은 대개 완전히 새로운 길을 발명하는 일이 아니라, 이미 기록해 둔 길들을 골라 새로운 순서로 이어 붙이는 일에 가깝다. 프로그램이 커질수록 이 지도는 더 촘촘해지고, 어떤 대상에서 어떤 대상으로도 몇 단계만 거치면 도달할 수 있게 된다.

이 지도에는 특이한 구간도 하나 있다. 사당역에 도착한 뒤 개찰구를 나가지 않고 같은 승강장에 그대로 남는 경우를 생각해 보자. 출발지와 도착지가 똑같이 사당역이라는 점만 빼면, 이것도 하나의 이동으로 기록할 수 있다. 코드에서도 마찬가지다. 입력을 받아 아무것도 바꾸지 않고 그대로 돌려주는 함수가 있다. 언뜻 쓸모없어 보이지만, 이런 함수는 다른 함수와 이어 붙여도 그 함수의 결과를 조금도 바꾸지 않는다는 성질을 가진다. 어떤 지도든 출발지와 도착지가 같은 이 최소한의 경로 하나쯤은 반드시 포함하고 있다.

이렇게 보면 프로그램은 무언가를 새로 계산해 내는 기계라기보다, 관계를 기록하고 그 기록들을 이어 붙이는 장치에 가깝다. 5장에서 대상보다 관계가 먼저라고 했고, 6장에서 함수는 그 관계를 실제로 건너가는 통로라고 했다. 이 둘을 합치면, 프로그램 전체는 작은 관계들의 기록이 이어져 만들어진 하나의 지도다. 새 기능을 추가한다는 것은 이 지도에 새로운 길을 내거나, 이미 있는 길들을 새로운 순서로 걷는 일이다.

그런데 이 지도 위에서 아무 함수나 아무 관계에나 자유롭게 이어 붙일 수 있는 것은 아니다. 앞 구간의 도착지가 뒤 구간의 출발지와 일치해야 한다는 조건이 있었듯, 함수를 이어 붙이려면 앞 함수가 돌려주는 것과 뒤 함수가 받아들이는 것이 서로 맞아야 한다. 그렇다면 이 맞음을 프로그램은 어떻게 미리 약속해 두는 걸까.