결과 중심 프로그래밍 (Results-Oriented Programming)
요약
프로그래밍의 패러다임이 코드의 작동 방식(How)을 검증하는 것에서 결과물(What)을 검증하는 '결과 중심 프로그래밍'으로 변화하고 있음을 설명합니다. 결정론적 코드부터 모델 기반 시스템까지, 결과의 정답 여부를 확인하는 오라클(Oracle) 중심의 테스트 중요성을 강조합니다.
핵심 포인트
- 프로그래밍의 무게 중심이 '어떻게'에서 '무엇을'로 이동 중
- 결정론적 시스템에서는 골든 세트를 통한 결과 검증이 가장 강력함
- 복잡한 동작이나 결정의 경우 단일 값으로 환원하기 어려움
- 과정(How)을 추적하는 디버깅보다 결과(That)의 정답 여부가 핵심
최근 글에서 제가 거의 지나치듯 던졌던 한 문장이 있는데, 그 이후로 계속 머릿속을 맴돌고 있습니다. 바로 프로그래밍이 코드가 '어떻게' 작동하는지를 검증하는 것에서 코드가 '무엇을' 만들어내는지를 검증하는 것으로 계속 표류하고 있다는 점입니다. 저는 이 실타래를 제대로 풀어보고 싶습니다. 왜냐하면 이것은 현재 이 직업이 실제로 작동하는 방식에 있어, 조용하지만 더 중대한 변화 중 하나이기 때문입니다.
무엇이 표류하고 있는지 명확히 하자면, 우리가 이전에는 결과를 확인하지 않았다는 뜻이 아닙니다. 테스트는 항상 존재해 왔고, 테스트를 작성하는 것은 항상 좋은 관행이었습니다. 업계가 마땅히 작성해야 할 만큼 작성하지 않았던 긴 기간 동안에도 말이죠. 이 변화는 '무게 중심'의 변화입니다. 제 경력의 대부분 동안
가장 깔끔한 버전은 출력이 하나의 값(value)을 가리킬 때입니다. 저의 가격 책정 시스템 (pricing system)은 숫자를 인용합니다. 해당 재료, 원산지, 고객에게 적절한 숫자이거나, 그렇지 않거나 둘 중 하나입니다. 저는 그것을 계산한 코드를 읽지 않습니다. 대신 고객이 승인한 골든 세트(golden set)를 유지하고, 출력이 그와 일치하는지 확인하는 테스트를 수행합니다. "정답인지 아닌지"를 결정하는 _오라클 (oracle)_은 정확하고 감사 가능하며, 결정적인 순간에 그 누구의 판단도 개입되지 않습니다. Claude가 주말 동안 엔진을 세 번 리팩터링(refactor)하더라도, 테스트 세트가 통과(green) 상태로 유지되는 한 저는 상관하지 않습니다. 이 단계에 도달할 수 있다면, 반드시 도달하십시오. 이것이 이 아이디어의 가장 강력한 형태입니다.
어려운 지점: 결과가 동작(behavior)일 때
하지만 우리가 만드는 대부분의 것은 하나의 숫자로 환원되지 않습니다.
수천 개의 상호작용하는 조건 속에서 올바른 _결정 (decision)_을 내려야 하는 규칙 엔진(rules engine). 비즈니스를 규제 범주로 분류하는 분류기(classifier). 단일 단언(assertion)으로는 포착할 수 없는 방식으로 출력이 "합리적"인지 아닌지를 결정하는 스케줄링 루틴(scheduling routine). 작업 도중 설명을 요청할지 아니면 그냥 진행할지를 선택하는 에이전트(agent). 녹취록이 되지 않으면서도 충실해야 하는 요약문. 이 중 일부는 순수하게 결정론적(deterministic)인 코드이고, 일부는 모델 기반(model-driven)이지만, 이들은 여기서 중요한 공통 속성을 공유합니다. 즉, "결과"가 동작 (behavior) 또는 _결정 (decision)_이며, 비교할 수 있는 골든 넘버(golden number)가 없다는 점입니다. 두 개의 완벽하게 훌륭한 출력물이 서로 전혀 닮지 않았을 수도 있습니다.
유혹은 오래된 습관으로 퇴보하는 것입니다. 즉, 출력을 고정할 수 없다면 그것이 어떻게 도달했는지를 읽는 방식으로 돌아가는 것이죠. 그리고 종종 그것을 읽을 수는 있습니다. 규칙 엔진 (rules engine)의 분기들은 바로 그곳에 있으며, 모델조차도 추론 (reasoning), 도구 호출 (tool calls), 중간 단계와 같은 흔적을 남깁니다. 그 경로(path)는 흔히 편리하게 부르는 것처럼 완전히 봉인된 블랙박스 (black box)가 아니며, 이를 조사하는 것은 디버깅 (debugging)과 해당 시스템을 얼마나 신뢰할지 보정하는 데 진정으로 유용합니다. 하지만 그것은 결과가 올바른 곳에 도달했는지(that)가 아니라, 어떻게(how) 도달했는지를 알려줄 뿐입니다. 깔끔해 보이는 추적 (trace)이 틀린 답에 도달할 수도 있고, 엉킨 추적이 맞는 답에 도달할 수도 있습니다. 이는 코드에서도 항상 사실이었으며, 우리가 단순히 함수를 다시 읽는 대신 테스트 (tests)를 작성했던 바로 그 이유이기도 합니다. 이 스펙트럼의 끝단에서, 경로를 읽는 것은 정보를 제공할 뿐, 정확성을 확정 짓지는 못합니다. 정확성 확인은 여전히 결과 (result) 단계에서 이루어져야 합니다.
따라서 결과 중심 (results-orientation) 방식이 여기서 무너지는 것이 아니라, 단지 오라클 (oracle)이 바뀔 뿐입니다. 정확한 일치 (exact match) 대신 더 풍부한 검증 체계를 구축하게 되며, 이는 주관성의 사다리를 올라갑니다. 규칙 엔진의 경우 행동 사양 (behavioral specs), 속성 테스트 (property tests), 시나리오 세트 (scenario suite)를 사용하고, 당신이 방어할 수 있는 호출들을 포함한 대표 사례들의 평가 세트 (eval set)를 구성하며, 진정으로 판단이 필요한 출력물에 대해서는 때때로 당신이 작성한 기준에 따라 LLM이 점수를 매기게 합니다. 저는 이전에 LLM-as-judge가 언제 의지할 수 있을 만큼 신뢰할 수 있는지에 대해 주장한 바 있습니다. 바로 이 지점이 그것이 중요한 지점입니다. 왜냐하면 스펙트럼의 끝단에서 당신의 판사(judge)가 곧 당신의 검증 (verification)이기 때문입니다. 테스트 대상은 여전히 결과이며, 단지 결정론적인 비교기 (deterministic comparator)를 정의되었지만 주관적인 비교기로 교체했을 뿐입니다. 그리고 엔지니어링 작업은 그 검증을 가능한 한 원칙적이고 반복 가능하게 만드는 쪽으로 이동합니다.
이 스펙트럼 자체가 핵심입니다. "4,200.00과 일치함을 단언하라"에서부터 "기준 패널이 이 분류 결정이 합리적이라고 말한다"에 이르기까지, 이는 서로 다른 해상도에서 이루어지는 동일한 움직임입니다. 즉, 결과를 명시하고, 그것을 검증하는 무언가를 구축하며, 경로를 감시하는 일을 멈추는 것입니다.
이것이 일어나는 이유
이 중 어느 것도 제가 채택한 철학이 아닙니다. 이것은 경로(path)를 생성하는 비용이 저렴해짐에 따른 대응입니다.
모델이 구현(implementation)을 작성할 때, 두 가지 현상이 동시에 뒤집힙니다. 경로를 생성하는 비용은 거의 무료에 가까워지는 반면, 그것을 읽는 비용은 비싸지고 때로는 무의미해집니다. Claude가 1분 만에 생성한 600줄짜리 diff(차이점)를 검토하는 데 저는 한 시간이 걸릴 수 있으며, 그 한 시간이 끝난 뒤에도 저는 테스트 스위트(test suite)를 5초간 훑어봤을 때보다 그것이 올바른지에 대해 더 적게 알게 되는 경우가 많습니다. 주의력의 경제학(economics of attention)이 역전된 것입니다. '어떻게(how)'를 읽는 작업은 더 이상 우리가 그것을 생산하는 속도와 비례하여 확장되지 않습니다.
한편, 결과(result)는 사용자나 클라이언트가 실제로 접하는 유일한 것입니다. 그들은 당신의 제어 흐름(control flow)을 경험하지 않습니다. 그들은 가격, 결정, 요약본을 경험합니다. 검증(verification)은 가치와 리스크가 실제로 존재하는 곳, 즉 입력(input)과 출력(output) 사이의 경계로 이동합니다. 왜냐하면 그 부분은 저렴해지지 않았기 때문입니다. 무엇이 "올바른지"를 정의하는 것은 여전히 어렵고 인간적인 작업입니다. 모델은 그저 중간 단계를 가로챘을 뿐입니다.
슬로건을 망치는 미묘한 차이
여기서 결과 중심 프로그래밍(results-oriented programming)을 위험할 정도로 오해하기 쉬운 지점이 발생합니다. 만약 출력(output)만이 중요하다면, 중간에 있는 코드는 전혀 중요하지 않은 걸까요? 테스트만 통과한다면 중복과 영리한 해킹(hacks)이 뒤섞인 진흙탕 같은 코드여도 상관없을까요?
아니오. 그 이유는 "훌륭한 엔지니어는 장인 정신을 중요하게 여긴다"라는 말보다 훨씬 더 날카롭습니다.
내부 품질(Internal quality) — 모듈성(modularity), 명확한 경계(clear boundaries), 보안(security), 컨벤션(conventions) — 은 여전히 중요하며, 어쩌면 이전보다 더 중요할 수도 있습니다. 하지만 그것이 중요한 '이유'가 변했고, 그 대상(audience) 또한 변했습니다. 우리는 과거에 다음에 이 코드를 읽을 '사람'을 위해 코드를 깨끗하게 유지했습니다. 하지만 점점 더, 다음 독자는 '에이전트(agent)'가 되고 있습니다. 유지보수성(Maintainability)은 '인간을 위한 유지보수성'에서 '에이전트를 위한 유지보수성'으로 이동하고 있습니다. 모델은 깨끗한 접합부(seams), 정직한 이름(honest names), 그리고 긴밀한 모듈(tight modules)로 구성된 코드베이스에서 더 나은 결과를 더 안정적으로 만들어냅니다. 이는 인간이 그러한 이유와 거의 동일합니다. 즉, 유지해야 할 컨텍스트가 적고, 오류가 발생할 경로가 적으며, 변경을 수행할 위치가 더 명확하기 때문입니다. 지저분한 내부 구조는 단순히 미적 취향을 해치는 것에 그치지 않습니다. 그것은 당신이 최적화하려는 바로 그 '결과'를, 단지 지연된 형태로 저하시킵니다. 다음 분기에 치르게 될 가혹한 대가는 종종 이번 분기에 당신이 모델이 남기도록 방치한 엉킨 코드(tangle) 때문에 발생합니다.
따라서 결과 중심주의(results-orientation)는
그것이 결과 중심 프로그래밍 (results-oriented programming)의 논리적 종착점입니다. 당신은 목표(target)와 가드레일(guardrails)을 지정하고, 모델은 그 경로를 탐색합니다. 당신의 영향력(leverage)은 당신이 작성하는 코드가 아니라, 당신이 정의하는 목적(objective)의 품질과 그 주변에 구축하는 하네스(harness) — 즉 테스트(tests), 평가(evals), 판정자(judges), 규칙(rules), 체크포인트(checkpoints) — 로 옮겨갑니다. 이것들을 잘못 설정하면 유능한 모델조차 잘못된 방향을 향해 자신 있게 최적화해 버립니다. 반대로 이것들을 제대로 설정한다면, 당신이 중간 과정을 건드리지 않고도 결과를 개선하는 무언가를 구축하게 된 것입니다.
그렇기에 저는 "결과 중심적"이라는 말이 "게으름"을 의미한다고 생각하지 않습니다. 그것은 어려운 부분이 이동했음을 의미합니다. 과거에는 그 어려움이 코드를 작성하는 과정에 있었다면, 이제는 당신이 실제로 원하는 것이 무엇인지 — 기계가 준수할 수 있을 만큼 정밀하게 — 정의하는 것과, 모델을 그곳에 붙들어 매어둘 장치(apparatus)를 구축하는 것에 존재합니다. 경로를 찾는 비용은 저렴해졌습니다. 대신 무엇이 "옳은지(right)\
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기