소프트웨어 설계에서 내리는 결정의 상당수는 “무엇을 남기고 무엇을 버릴 것인가”다. 어떤 필드를 타입에 남길지, 인터페이스를 뽑아낼지, 구조를 코드로 고정할지 설정으로 뺄지가 모두 그렇다. 이 선택이 감으로 내려지면 목적에 맞지 않는 구조와 형식뿐인 인터페이스가 코드에 쌓여 간다. 이 선택을 다루는 개념이 추상화이고, 추상화를 정확히 쓰려면 자주 뒤섞이는 또 하나의 개념인 메타와 구분해야 한다. 설계 논의에서 흔히 쓰는 “한 단계 위로 올리자”는 말이 실은 서로 다른 두 방향을 가리키기 때문이다.
이 글은 두 움직임이 어떻게 다른지, 소프트웨어에서는 왜 구분하기 어려워지는지를 노선도 예시를 중심으로 설명하고, 인터페이스가 두 축의 어디에서 일하는 도구인지 확인한다. 이 구분에서 진짜 추상과 겉모습뿐인 추상을 가려내는 기준이 나오고, 구조를 타입으로 굳힐지 데이터로 열어 둘지 판단하는 관점이 생긴다.
먼저 추상화가 무엇인지부터 보자. 소프트웨어는 현실 세계를 그대로 다룰 수 없다. 예를 들어 서울 도심의 지도를 그린다고 하자. 같은 지역이라도 목적이 다르면 그리는 방식은 완전히 달라진다.
노선도는 역과 환승만 알면 충분하다. 그래서 실제 선로의 곡선이나 역 사이 거리의 편차는 버리고, 등간격으로 늘어선 역과 직선만 남긴다. 도로 지도는 그 반대다. 길의 형태와 교차로가 핵심이 되고, 전철 노선은 필요 없다. 둘 다 목적에 필요한 것만 취하고 나머지는 버린다. 이것이 추상화 다. 추상화란 어려운 말로 바꾸는 것이 아니라, 현실의 대상을 목적에 맞게 다루기 쉬운 형태로 잘라내는 것이다.
추상화는 갑자기 타입이 되지 않는다
노선도를 소프트웨어로 만든다고 하자. 처음에 써야 할 것은 Station이라는 타입이 아니다. 먼저 생각해야 할 것은, 경로 안내라는 관점에서 철도에 대해 무엇이 필요한가이다.
경로 안내 관점에서의 철도
- 어떤 역이 있는가
- 어떤 역과 어떤 역이 연결되어 있는가
- 연결 하나를 지나는 데 시간이 얼마나 걸리는가거리나 선로의 형태는 여기에 나오지 않는다. 노선도가 그것들을 버린 것과 같다. 여기까지가 추상화다. 머릿속에서든 종이 위에서든 이것으로 충분하다. 어떤 역이 있고, 어떻게 연결되며, 얼마나 걸리는가. 필요한 것만 파악하면 그 이상의 세밀한 형태는 필요 없다.
소프트웨어에서는 구조를 써내야 한다
하지만 이것을 소프트웨어로 만들려면 이야기가 달라진다. 선택한 것을 구조로 써내야 한다. 어떤 항목이 있고, 각각 어떤 타입인지 명시해야 한다.
record Station(StationId id, String name) {}
record Connection(StationId from, StationId to, Duration time) {}머릿속에서는 “어떤 역이 있고 어떻게 연결되는가”로 충분했던 것이, 여기서는 id, name, time 같은 명확한 형태가 된다. 이렇게 구조를 적어 내는 일은 추상화 자체에는 필요 없다. 소프트웨어로 만들기 때문에 필요해진 것이다.
나아가 모호함도 남길 수 없다. 사람끼리의 대화라면 “환승해서 가면 된다”로 통하지만, 프로그램은 그렇지 않다. 환승역은 하나의 역으로 표현할 것인가, 노선마다 별도의 노드로 나눌 것인가. 환승에 걸리는 시간은 어디에 둘 것인가. 운행이 중지된 구간은 연결되지 않은 것으로 볼 것인가, 표시만 붙일 것인가. 이런 것들을 결정하지 않으면 경로 탐색은 동작하지 않는다.
여기서 관점을 바꿔보자. 지금까지 생각해 온 대상은 역이었다. 그러나 코드를 쓴 순간, 우리가 다루고 있는 것은 역 그 자체가 아니라 “역을 어떻게 표현할까”라는 구조가 되었다.
메타란 무엇인가
여기까지 역 데이터의 구조를 만들어 왔다. 어떤 항목이 있고, 어떤 타입이며, 무엇을 허용하 는가. 추상화로 필요한 것을 선택하고, 코드로 그것을 모호함 없이 써낸 것이다.
그러나 써낸 이 구조는 역 그 자체가 아니다. 역의 데이터가 어떤 구조인지 적어 놓은 기술이다. 데이터에 대한 데이터, 즉 메타데이터 다. 구조를 쓴 시점에서 다루는 대상은 더 이상 역이 아니라, 역 데이터에 대한 기술로 바뀐다. 이것이 메타다.
추상화와는 방향이 다르다. 추상화는 아무리 단순하게 만들어도 다루는 대상은 여전히 현실의 철도다. 노선도가 그리는 것도 현실의 철도다. 반면 메타에서는 다루는 대상 자체가 현실의 철도에서 그것을 써낸 구조로 이동한다. 흔히 “하나 위로 올라간다”고 표현하기 때문에 추상의 층을 올라가는 것, 즉 더 추상적으로 되는 것과 혼동되지만, 이 둘은 별개의 움직임이다.
추상의 층과 메타의 층
앞 절에서 추상화와 메타는 방향이 다른 움직임이라고 했다. 게다가 둘 다 하나의 층으로 끝나지 않고 각각 층을 쌓아 올린다.
추상화의 층은 서울역을 “역”으로 묶고, 역을 다시 “교통 거점”으로 묶는 식으로 겹쳐진다. 위층일수록 대략적이다. 같은 것이 아래층에서 보면 추상이고, 위층에서 보면 구체가 된다. 추상화의 층은 경계가 느슨해서 사이에 얼마든지 중간층을 만들 수 있다. 어디까지 세밀하게 할지, 어디서 멈출지는 목적이 결정한다.
메타의 층은 다르게 쌓인다. 역의 데이터가 있고, 그 구조를 기술한 타입이 있고, 더 나아가 “타입이란 무엇인가”를 정하는 언어가 있다. 기술에 대한 기술을 거듭 쌓아 올라가는 것이다. 메타의 층은 추상처럼 연속적으로 변하지 않고, 다루는 대상 자체가 바뀌는 이산적인 층으로 나타난다. 데이터와 타입, 타입을 정하는 언어는 질적으로 서로 다른 별개의 것이기 때문이다. 추상화처럼 목적에 따라 중간층을 자유롭게 끼워 넣을 수는 없다.
중요한 것은 이 두 층이 별도의 축으로 쌓인다는 점이다. 타입을 “역”에서 “거점”으로 일반화해도 그것은 여전히 데이터를 기술한 것이고, 메타의 층은 움직이지 않는다. 반대로 타입을 고정한 채 “타입이란 무엇인가”로 화제를 옮기면, 추상도는 그대로 둔 채 메타의 층만 올라간다. 한쪽을 움직여도 다른 쪽은 움직이지 않는다. “하나 위”라는 말이 계속 혼란스러웠던 것은 이 두 가지 “위”를 섞어 썼기 때문이다.
두 층은 성질도 다르다. 추상의 층에는 천장이 없어서 위로는 얼마든지 대략적으로, 아래로는 얼마든지 세밀하게 내려갈 수 있다. 메타의 층은 겹쳐 쌓아도 실용적인 의미가 희미해지는 경우가 많다. “타입이란 무엇인가”를 정하는 언어는 그 언어 자신도 같은 방식으로 기술할 수 있어서, 그 위에 또 층을 쌓을 필요가 없기 때문이다.
이 메타의 층 구분은 실무에서 “누가 언제 구조를 결정하는가”라는 문제로 나타난다. 역의 구조를 타입으로 고정할 것인가, 실행 중에 읽고 쓸 수 있는 데이터로 가질 것인가. 이것은 그 기술을 메타의 어느 층에 둘 것인가 하는 선택이며, 이 선택이 결정하는 사람과 결정되는 시점을 나눈다. 타입으로 고정하면 결정하는 사람은 개발자이고, 결정되는 시점은 코드를 쓸 때다. 데이터로 가지면 결정하는 사람은 이용자이고, 결정되는 시점은 프로그램이 돌아가는 중이다. 후자가 더 자유로워 보이지만, 그만큼 타입이 보장해 주던 약속은 희박해진다.

