코드는 현실의 번역이다

도메인 리터러시에 대한 단상

코드는 현실의 번역이다

소프트웨어 개발이 번역과 닮았다는 생각을 종종 한다. 현실 세계의 복잡하고 모호한 요구사항을, 컴퓨터가 이해할 수 있는 명료한 언어로 옮기는 일이니까. 좋은 번역가가 원문의 뉘앙스를 깊이 이해해야 훌륭한 번역을 해낼 수 있듯, 개발자 역시 우리가 해결하려는 문제—그리고 그 문제를 안고 있는 사람—를 이해할수록 더 나은 코드를 쓸 수 있지 않을까.

이것을 '도메인 리터러시(Domain Literacy)'라고 부르곤 한다. 업계 용어 몇 개를 더 외우는 게 아니라, 이 일을 하는 사람들이 무엇 때문에 고민하고, 어떤 제약 속에서 판단을 내리는지 이해하는 능력 같은 것.

개발자가 기술 그 자체보다 '사람의 문제'에 깊이 파고들 때 더 나은 제품이 나오지 않을까. 이 글은 그런 생각을 바탕으로, 도메인 리터러시를 높이기 위해 어떤 노력을 해볼 수 있을지 정리해본 것이다.

1. 기획서 너머의 사람을 보기

요구사항 뒤에 있는 고충

개발자는 자칫하면 기획서나 피그마 화면 안에만 갇히기 쉽다. 나도 그렇다. 그런데 텍스트로 적힌 '요구사항'이라는 건, 누군가의 고충이 한 차례 가공된 결과물이다. 그 가공 이전의 이야기—이 기능을 요청한 사람이 실제로 어떤 어려움을 겪고 있는지—를 더 알 수 있다면 좋겠다는 생각이 든다.

정산 담당자가 매월 말 엑셀 파일과 씨름하며 느끼는 피로. 실수하면 안 된다는 압박감. CS 담당자가 고객 문의에 답하려고 여러 화면을 오가며 느끼는 답답함. 영업 담당자가 계약 조건을 확인하려고 슬랙을 뒤지며 허비하는 시간. 이런 구체적인 고충을 알게 되면, '왜 이 기능이 필요한가'라는 질문에 더 진지하게 답할 수 있지 않을까.

대화가 드러낼 수 있는 것들

기획자에게 "이 기능 요청한 분이 누구예요? 직접 얘기 좀 들어봐도 될까요?"라고 물어보는 건 어떨까. 거창한 인터뷰가 아니라, 점심 먹으면서 "요즘 제일 귀찮은 일이 뭐예요?" 하고 물어보는 정도로도 충분할 때가 있을 것 같다.

그렇게 들은 이야기 중에 기획서에는 없던 맥락이 담겨 있을 수 있다. "사실 이거 원래 다른 방식으로 하고 있었는데, 그게 너무 번거로워서요." "이 숫자가 틀리면 제가 직접 고객한테 전화해서 사과해야 해요." 이런 문장들이 기능의 우선순위나 에러 처리 방식을 결정하는 데 영향을 줄 수 있지 않을까 싶다.

2. '무엇'보다 '왜'를 묻는 습관

질문이 열어주는 것들

기획자가 "취소 기능을 만들어주세요"라고 했을 때, 곧바로 cancel() 메소드를 구현하고 싶은 마음이 든다. 하지만 요즘은 먼저 질문부터 던지려고 한다.

"이 취소 기능이 필요한 상황이 어떤 건가요?" "지금은 취소 요청이 들어오면 어떻게 처리하고 계세요?" "제일 난감한 케이스는 어떤 거예요?"

이런 질문들을 던지다 보면, '취소'라는 단순해 보이던 단어 뒤에 여러 상황이 숨어 있다는 걸 발견하게 된다. 고객이 마음을 바꾼 경우, 재고가 없어서 어쩔 수 없이 취소하는 경우, 배송이 이미 시작된 후에 취소 요청이 들어온 경우. 각각 처리 방식이 다르고, 담당자가 느끼는 부담도 다르다. 질문하는 과정 자체가 도메인을 조금씩 내 것으로 만드는 과정인 것 같다.

다섯 번의 '왜'

도요타 생산 시스템에서 유래한 '5 Whys'라는 기법이 있다. 문제의 뿌리에 닿을 때까지 "왜?"를 다섯 번 묻는 것이다. 소프트웨어 개발에서도 써먹을 만하다.

"왜 이 보고서가 필요하세요?" — "경영진이 매출 추이를 보고 싶대요."

"왜 매출 추이를 보려고 하시는 거죠?" — "다음 분기 재고 발주량을 정해야 해서요."

"왜 그 결정에 이 형식의 보고서가 필요한 거예요?" — "...사실, 실시간으로 볼 수 있으면 더 좋긴 한데, 그게 되는지 몰랐어요."

이런 식으로 세 번째 '왜'쯤에서 진짜 니즈가 드러날 수 있다. 요청자가 원한 건 월간 PDF 보고서가 아니라, 필요할 때 바로 확인할 수 있는 방법이었던 거다. 질문하지 않았다면, 아무도 만족시키지 못하는 기능을 만드느라 시간을 썼을 수도 있다.

3. 언어의 해상도를 높이기

같은 단어, 다른 의미

도메인을 잘 모르면, 모든 걸 뭉뚱그려 부르게 된다. 누구든 'User', 어떤 돈이든 'Price'. 이렇게 뭉뚱그려진 언어는 뭉뚱그려진 코드로 이어지기 쉽다. 흔히 말하는 God Class, 모든 걸 다 하려다 아무것도 제대로 못 하는 그런 클래스.

그런데 실제로 그 일을 하는 사람들과 이야기해보면, 같은 단어를 쓰면서도 서로 다른 걸 떠올리고 있는 경우가 많다. 마케팅팀이 말하는 '고객'과 CS팀이 말하는 '고객'과 물류팀이 말하는 '고객'은 사실 다른 개념이다. 마케팅에게는 '타겟 세그먼트'고, CS에게는 '문의를 남긴 사람'이고, 물류에게는 '배송지 주소'에 가깝다.

에릭 에반스가 Domain-Driven Design에서 이야기한 '유비쿼터스 언어'가 이런 맥락이다. 함께 일하는 사람들이 같은 단어를 같은 의미로 쓸 때, 소통 과정에서 정보가 새는 걸 줄일 수 있다는 것.

사람들이 실제로 쓰는 말에 귀 기울이기

도메인 전문가들—그러니까 그 일을 매일 하는 사람들—이 실제로 쓰는 표현을 주의 깊게 듣는 게 도움이 된다. 그들이 '배송'과 '발송'을 구분해서 쓴다면, 거기에는 이유가 있다. '출고'와 '발송'이 다르다고 말한다면, 그 차이가 업무에서 중요하다는 뜻이다.

이런 미묘한 차이를 코드에 반영하지 않으면, 나중에 상태값이 꼬이거나 예외 케이스를 처리하지 못해서 고생하게 될 수 있다. 반대로, 사람들이 쓰는 언어를 그대로 코드에 담으면 "이 클래스가 뭐 하는 거예요?"라는 질문에 대답하기가 훨씬 쉬워진다.

용어집이라는 도구

프로젝트 초반에 팀 전체가 합의한 용어집을 만들어두면 나중에 편하다. 단순한 사전이 아니라, 이 단어가 누구 입장에서 어떤 의미인지, 어떤 단어와 헷갈리기 쉬운지, 코드에서는 뭐라고 쓰기로 했는지를 적어두는 것.

처음에는 번거롭게 느껴지는데, 새로운 팀원이 합류하거나 몇 달 뒤에 코드를 다시 볼 때 이게 있고 없고의 차이가 크다. 과거의 나와 현재의 나 사이, 또는 나와 동료 사이의 소통 도구 같은 거다.

4. 코드에 남은 판단의 흔적

복잡한 코드 뒤에는 이유가 있다

코드는 어느 한 시점의 스냅샷이지만, 비즈니스는 시간 속에서 계속 변해왔다. 지금 눈앞에 있는 복잡한 로직은, 과거 어느 시점에 누군가가 내린 판단의 결과물이다.

"도대체 왜 이렇게 복잡하게 짜놓은 거야?"라고 불평하기 전에, 그 코드가 쓰여질 당시 상황을 물어보면 이해가 될 때가 있다. 대형 고객의 특수 요청 때문에 들어간 분기문, 한때 시행되다가 폐지된 정책의 흔적, 예상치 못한 예외 케이스를 급하게 처리하느라 생긴 임시 로직 같은 것들.

그 맥락을 아는 사람과 이야기해보면, 단순히 "레거시니까"라고 치부했던 코드에서 당시의 고민과 트레이드오프가 보이기 시작한다. 그러면 같은 실수를 되풀이하지 않을 수 있고, 더 나은 방향을 제안할 수도 있게 된다.

결정의 이유를 기록해두기

ADR(Architecture Decision Records)이라는 게 있다. 중요한 기술 결정을 내릴 때, '뭘 결정했는가'뿐 아니라 '왜 그렇게 결정했는가', '다른 선택지는 뭐였는가', '어떤 트레이드오프가 있었는가'를 함께 적어두는 관행이다.

3년 뒤 새로 합류한 동료가 "이거 왜 이렇게 돼 있어요?"라고 물었을 때, ADR이 있으면 설명이 된다. 당시 상황과 고민의 흔적이 남아 있으니까. 결정을 내린 사람이 퇴사한 뒤에도 그 맥락이 조직에 남아 있게 하는 방법이라고 생각한다.

5. 서로 다른 관점을 인정하기

부서마다 다른 세계

도메인을 깊이 들여다보면, 모든 걸 하나의 모델로 통합하려는 유혹에서 벗어나게 되는 것 같다. 같은 회사 안에서도 부서마다 세상을 보는 방식이 다르다.

마케팅팀에게 고객은 '타겟 세그먼트'고, 영업팀에게는 '클로징해야 할 리드'고, CS팀에게는 '문제를 해결해줘야 할 사람'이고, 물류팀에게는 '택배 받을 주소'다. 각자의 관점에서는 다 맞는 말이다. 이걸 전부 하나의 Customer 클래스에 우겨넣으려 하면, 수천 줄짜리 괴물이 되기 십상이다.

'바운디드 컨텍스트(Bounded Context)'란 이런 경계를 명시적으로 인정해주는 것이다. 각 영역 안에서는 그 맥락에 맞는 언어와 모델을 쓰고, 영역 사이의 소통은 정해진 인터페이스를 통해서만 한다. 서로 다른 관점을 억지로 통합하지 않고, 각자의 방식을 존중하면서 연결하는 것.

'아니오'라고 말할 수 있을 때

그 일을 하는 사람들의 관점을 이해하면, 가끔은 요청받은 기능이 그들에게 실제로 도움이 안 될 거라는 게 느껴질 때가 있다. 그럴 때 "기술적으로 어렵습니다"라고 말하는 대신, "그 방식보다 이렇게 하면 원하시는 걸 더 쉽게 얻으실 수 있을 것 같아요"라고 제안해볼 수 있게 된다.

이건 거절이 아니라, 상대방의 진짜 문제를 함께 풀어가는 대화의 시작이다. 그 사람이 뭘 힘들어하는지 알아야, 더 나은 방법을 제안할 수 있으니까.

6. 함께 그려보는 시간

알베르토 브란돌리니가 만든 '이벤트 스토밍(Event Storming)'이라는 워크숍 방식이 있다. 도메인 전문가와 개발자가 함께 모여 비즈니스 프로세스를 시각화하는 건데, 방법은 단순하다. 주황색 포스트잇에 '주문이 들어왔다', '결제가 됐다', '물건이 나갔다' 같은 이벤트를 적어서 벽에 붙인다.

이 과정에서 재미있는 일이 벌어진다고 한다. 실무자는 개발자가 생각지도 못한 예외 케이스를 떠올리고, 개발자는 실무자조차 명확히 설명 못 하던 모호한 부분을 끄집어낸다. 같은 단어를 서로 다른 뜻으로 쓰고 있었다는 것도 발견하게 된다.

형식적인 회의보다, 이렇게 함께 뭔가를 만들어보는 시간이 서로를 이해하는 데 더 효과적이지 않을까. 결국 도메인 리터러시란 혼자 공부해서 높이는 게 아니라, 함께 일하는 사람들과의 대화 속에서 쌓이는 것 같다.

맺으며

도메인 리터러시가 높아진다는 건, 결국 함께 일하는 사람들을 더 잘 이해하게 된다는 것 같다. 그들이 무엇 때문에 힘들어하는지, 어떤 제약 속에서 일하는지, 무엇을 중요하게 여기는지. 그걸 알게 되면 '시킨 대로 만드는 사람'에서 '함께 고민하는 동료'에 가까워지지 않을까.

우리가 만드는 코드가 누군가의 문제를 실제로 덜어주고, 그 사람과 같은 언어로 이야기할 수 있으면 좋겠다. 그러려면 기획서 읽는 데서 멈추지 않고, 그 기획서를 요청한 사람의 이야기를 들어보고, 그 사람이 쓰는 언어에 귀 기울이고, 그 사람의 고민을 이해해보려는 노력이 필요하지 않을까 싶다.

"가장 훌륭한 코드는 현실의 문제를 가장 정확하게 번역한 문장들의 집합이다."

이것이 우리가 추구해야 할 장인 정신이며, 좋은 제품을 만드는 개발자가 되어가는 방향이 아닐까.

Read more

AI 시대에 가져야 할 마음

AI를 쓰다 보면 이상한 감각이 생긴다. 뭐든 금방 되니까 오히려 뭘 해야 할지 모르겠는 순간이 온다. 예전에는 시간이 부족해서 못 했다. 지금은 시간이 생겨도 방향을 모르면 똑같이 못 한다. AI는 인간을 대신하지 않는다. 오히려 비춘다. 무엇을 질문하는지, 무엇을 선택하는지, 무엇에 시간을 쓰는지가 그대로 증폭되어 돌아온다. 좋은 질문에는 좋은 답이 온다.

By Eschocolat
블로그를 Ghost로 옮겼다

블로그를 Ghost로 옮겼다

EsLog를 Ghost로 옮겼다. 처음엔 Gatsby로 만들었고, 그다음 Next.js로 갈아탔다가, 이번에 개인 서버에 Ghost를 올려서 운영하기로 했다. 이유는 단순하다. 글을 안 썼다. Gatsby로 블로그를 만들 때는 재밌었다. 정적 사이트 생성기 구조도 익혔고, GraphQL로 데이터 불러오는 것도 나름 흥미로웠다. Next.js로 옮길 때도 마찬가지였다. MDX 지원 붙이고, 코드 하이라이팅 넣고, 다크모드

By Eschocolat

사랑은 모든 것을 이긴다

세상을 바라볼 때, 마음이 답답해지는 순간들이 있다. 경쟁은 끝없이 치열해지고, 사람들은 점점 더 각자의 울타리 속으로 숨어든다. 포용과 낭만의 언어는 사라지고, 대신 물질과 성과가 사람의 가치를 재는 기준이 되어 버렸다. 눈에 보이는 성취만이 인정받는 사회 속에서 우리는 점점 지쳐가고, 인간다움마저 잃어버린 듯하다. 사실 세상은 혼자가 아니라 함께 살아가는 곳이다. 그러나

By Eschocolat