로봇과 이야기하는 것을 좋아하지 않아요
나는 안드로이드 폰을 가지고 있지만, 음성 명령을 비활성화했습니다. 나는 알렉사를 한 번도 소유한 적이 없습니다. 시리가 정확히 무엇을 하는지 확신하지 못합니다, 왜냐하면 그것이 나를 위해 플레이리스트를 찾아주지 않아도 인생을 잘 헤쳐나왔기 때문입니다. 그래서 AI 코딩 도구들이 무시하기 어려워졌을 때, 나는 서서히 수용하게 되었습니다. 한동안, 나는 어떤 사람들이 '원샷팅'이라고 부르는 것을 했습니다: 항상 해왔던 대로 일하면서, 가끔 일의 큰 부분을 AI에 위임하고, 그 결과가 무엇인지 기다리는 것입니다. 이것은 도박을 좋아하는 사람들에게 정말 멋진 접근법입니다.
제게 있어서, 불편함의 일부는 채팅 인터페이스 자체였습니다. 모델과 대화한다는 생각은 어리석게 느껴졌습니다. 저는 것을 만듭니다. 저는 텍스트 상자와 협상하지 않습니다.
하지만 스펙 주도 개발은 그렇게 작동하지 않습니다. 문제를 정확히 정의하고, AI 모델에게 고려할 파일을 알려주며, 원하는 결과를 설명한 다음, AI가 코드를 생성하기 전에 계획에 대해 채팅을 통해 서로 이야기하며 조정합니다. 오늘날의 AI 모델은 코딩은 빠르지만, 고수준 의사결정에서는 여전히 위험할 정도로 불일치합니다. AI와 함께 작업할 때, 당신의 역할은 설계 판단력을 문서화된 스펙으로 전환하는 것입니다. 그래서 당신이 직접 코드를 타이핑할 때 했을 것과 일치하는 저의사결정 단계 목록을 AI에게 제공할 수 있습니다. 그 스펙을 제대로 만들기 위해서는 협의 과정이 필요합니다.
지난 6개월 동안 저는 이것을 배웠고, 꽤 능숙해졌습니다. 손으로 코드를 거의 작성하지 않음에도 불구하고, 이전보다 더 많은 기능을 제공하고 있습니다. 소프트웨어 설계를 모델에게 미루지 않기 때문에, 25년 동안 디지털 제품을 구축하며 유지해 온 품질 기준을 그대로 적용하고 있습니다.
내가 예상하지 못한 것은 이것을 가르치는 것이 얼마나 어려울지였습니다.
나는 이미 피카소인가요?
고위 경영진 사이에서는 LLM 도구가 모든 엔지니어의 생산성을 증가시킬 것이라는 생각이 있습니다. 실제로, 저는 이를 목격하지 못했습니다. 대신, 적응력 있는 숙련된 엔지니어들이 이전보다 몇 배 더 많은 결과를 내는 반면, 다른 이들은 동일하거나 더 적은 결과를 내고 있음을 봅니다.
이것은 초보자들에게 좋은 상황이 아니에요. AI 코딩 도구는 인터페이스가 단순히 텍스트 상자이기 때문에 간단해 보이지만, 빈 캔버스에 무작위로 페인트를 칠한다고 피카소가 될 수는 없어요.
병렬 구현 증후군
나는 주니어 엔지니어들을 여러 이유로 소중히 생각합니다. 무엇보다도 그들과 함께 일하는 것이 제가 가장 좋아하는 일이기 때문입니다! 그들의 개방적 사고는 아직 위축되지 않았고, 제게 새로운 시각을 제공해 줍니다. 최근에, 저는 똑똑하고 AI 도구에 열정적이며, 적극적으로 참여하려 하고, 로봇과 대화하는 것을 전혀 주저하지 않는 젊은 엔지니어와 AI 학습 여정을 함께 했습니다.
그런데도 어쩌다 보니 제대로 되지 않았다.
첫 번째 징후는 인증 시스템이었습니다. 그녀는 기존 서비스에 OAuth를 추가해야 했고, 모델에게 전체 인증 흐름을 하나의 거대한 명세로 구축하도록 요청했습니다. 로그인, 토큰 갱신, 세션 관리, 역할 기반 접근, 그리고 로그아웃 흐름. 모든 것을요. 모델은 기꺼이 응했습니다. 그것은 100% 코드 커버리지와 통과하는 테스트를 갖춘 완벽해 보이는 수백 줄의 코드를 만들어냈습니다.
하지만 내가 검토했을 때, 문제는 구조적이었다. 모델은 이미 우리가 가지고 있던 세션 저장소를 사용하는 대신 새로운 세션 저장소를 만들었다. 그것은 우리의 API 게이트웨이와 충돌하는 토큰 갱신 패턴을 도입했다. 역할 기반 접근 로직은 이미 공유 미들웨어에 존재하던 비즈니스 규칙을 중복해서 만들었다. 기술적으로는, 이것들 중 아무것도 틀리지 않았다—작동했다. 아키텍처적으로는, 모든 것이 그랬다.
나는 그녀와 앉아서 간단한 질문을 했습니다: “이것을 프롬프트하기 전에, 오늘 우리가 세션을 어떻게 처리하는지 알고 있었나요?” 그녀는 잠시 멈췄습니다. “정확히는 아니에요.” 그것이 차이점이었습니다. 그녀는 모델에게 그것을 기반으로 구축하라고 요청하기 전에 영역 매핑을 하지 않았습니다.
다음 시도는 다르게 진행되었지만, 충분하지는 않았다. 그녀는 모델에게 새로운 제공자를 지원하도록 로그인 흐름을 수정하도록 요청했다. 이번에는 범위 축소를 했는데, 이는 좋은 점이었다. 하지만 그녀는 변화를 UI가 무엇을 하길 원하는지로 설명했지, 기존 코드가 이미 처리하는 방식으로 설명하지 않았다. 모델은 우리의 기존 제공자 추상화를 알 이유가 없었기 때문에, 처음부터 병렬 구현을 작성했다. 같은 결과: 작동 코드, 잘못된 아키텍처.
무슨 일이 있었는지 이야기를 나눴습니다. 나는 그녀에게 모델을 팀에 새로 온 계약직 팀원처럼 생각하라고 했어요. 재능 있고 빠르지만, 우리 코드베이스에 대해 아무 경험이 없죠. 계약직 팀원에게 이 프로젝트를 맡기고 그냥 떠나지 않을 거예요. 이렇게 말할 겁니다: 여기 우리 세션 저장소, 여기 미들웨어, 여기 새로운 제공자를 추가하는 패턴이 있어요. 이 안에 맞춰서 작업하세요.
그녀는 개념을 이해했다. 하지만 다음 몇 차례의 상호작용은 개념이 쉬운 부분이었음을 보여주었다. 그녀는 모델로부터 단일 계획을 받아 대안을 찾지 않고 즉시 승인했다. 그녀는 모델이 광범위한 코드 변경을 기꺼이 하는 것을 철저함으로 여겼지만, 나는 불필요한 위험으로 보았다. 그녀는 아직 '아니요, 이 변경에 대한 변경 범위가 너무 큽니다'라고 말할 직감이 없었다.
경험 많은 엔지니어라면 그 동일한 OAuth 작업을 여섯 내지 일곱 번의 집중된 라운드로 다뤘을 것입니다. 각 라운드는 그녀가 이미 이해한 시스템의 일부분에 범위가 제한되어 있었겠죠.
소프트 스킬은 새로운 하드 스킬이다
이는 AI 코딩의 생산성 향상을 무효화할 오버헤드처럼 들릴 수 있습니다. 하지만 이는 새로운 기술이 아닙니다. 경험 많은 엔지니어들은 항상 이 작업을 머릿속에서 해왔습니다. 차이점은 스펙 주도 개발이 모든 작업의 소프트웨어 디자인 계획을 외부화한다는 것입니다. 이전에는 내부적으로, 당신과 당신의 판단 사이에서 일어나던 디자인 협상이 이제는 채팅 창에서 일어납니다.
대화를 시작하기 전에 무엇을 원하는지 알아야 합니다. 구현 방법이 아니라, 동작, 제약 조건, 그리고 그 것의 형태를 알아야 합니다. 모델이 작업을 어디에 맞춰야 하는지 알려줄 수 있을 만큼 코드베이스를 잘 알아야 합니다. 모델이 답변을 돌려주면, 아마도 실행될 것입니다. 그것만으로는 충분하지 않습니다. 실제로 그것이 이미 있는 시스템에 맞는지 알아야 합니다.
가끔은 모델이 맞고 내가 틀렸다는 걸 깨닫게 될 때가 있습니다. 그런 경우를 공정하게 평가하려면 겸손이 필요하죠.
전체 과정에서, 이 도구를 잘 사용하는 사람과 빠르게 사용하는 사람을 구분 짓는 것은 인내심입니다. 즉, 두 번째 시도에서 평범한 결과를 받아들이기보다는 다섯, 여섯 번이나 반복해서 수정하려는 의지를 말합니다. 또한 코드를 직접 쓰지 않고도 코드에 대해 정확하게 서술하는 기술, 예를 들어 데이터 흐름, 경계 사례, 고장 모드를 평이한 언어로 설명하는 능력이 필요합니다. 그리고 감각이 있는데, 정의하기는 어렵지만 알아보기는 쉬운 것으로, 소프트웨어가 단순히 작동하는지 여부가 아니라 장기 유지보수 관점에서 좋은 소프트웨어가 어떤 느낌인지를 아는 감각입니다.
그리고 불편한 점이 있습니다. 대부분의 이러한 기술들은 수년 동안 잘못된 것들을 겪으면서 형성된 패턴 인식입니다. 나쁜 아키텍처 결정을 인식하는 것은 그 결과를 직접 겪어봤기 때문입니다. 모델의 초기 답변에 반대하는 것은 이전에 첫 번째 아이디어를 출시하고 후회한 경험에서 비롯됩니다.
주니어 엔지니어는 고수준의 설계 협의를 수행해야 하는 상황에 놓여 있지만, 이를 위한 교육과정은 없는 것 같습니다. 이제는 "LeetCode"에서 벗어나 설계 협의로 전환할 때이며, 이것은 이 시리즈의 향후 글의 주제가 될 것입니다.
부록
AI와 스펙 협상을 위한 소프트 스킬
협상 중
-
코드 독해 능력: 모델이 생성하는 코드를 구문뿐만 아니라 구조적 건전성에 대해 검토하세요. 당신은 버그를 찾는 것이 아니라 적합성을 판단하는 것입니다. 중요한 이유: 모델은 유효하지만 당신의 시스템에 속하지 않는 코드를 생성할 수 있습니다. 이를 빨리 파악해야 합니다.
-
아키텍처 감각: 기술적으로 유효하지만 이 시스템에 맞지 않는 솔루션을 알아차리는 것. 중요한 이유: 모델은 '우리에게 맞지 않는 것'이 무엇을 의미하는지 모릅니다. 당신은 압니다.
-
창의적 조정: 모델이 막혔을 때 대안적인 프레임을 찾으세요. 문제를 재진술하거나 비유를 제공하며, 다르게 제약을 가하세요. 중요한 이유: 모델은 당신이 프레임하는 방식에 반응하며, 더 나은 프레임은 더 나은 결과를 가져옵니다.
-
입장 취하기 시점 알기: 모델은 옵션을 중립적으로 제시합니다. 결정하고, 왜 한 접근법이 당신의 맥락에 더 나은지 설명하세요. 왜 중요한가: 그것은 공학적 판단력이며, 그것을 쌓는 데는 수년이 걸립니다.
-
생산적 회의주의: 모델의 첫 번째 답변은 해결책이 아닌 초안이라고 가정하세요. 회의론이 아닌, 수용하기 전에 압력 테스트하는 습관입니다. 왜 중요한가: 초안 출력은 유창하기 때문에 매력적입니다. 유창성은 정확성과는 다릅니다.
-
자신이 모르는 것을 아는 것: 모델이 맞을 수 있고 당신이 틀릴 수 있는 때를 인식하세요. 왜 중요한가: 협상은 양방향으로 진행됩니다. 때로는 당신이 고려하지 못했던 접근법이 드러나며, 이를 공정하게 평가하기 위해서는 겸손이 필요합니다.
전체 과정에서
-
인내: 두 번째 라운드에서 평범한 것을 받아들이기보다, 다섯에서 여섯 번 반복적으로 진행하라. 중요한 이유: 이것은 도구를 잘 사용하는 사람과 빠르게 사용하는 사람을 구분한다.
-
기술 커뮤니케이션: 코드를 직접 작성하지 않고 코드에 대해 정확하게 작성하라. 데이터 흐름, 상태 변화, 에지 케이스, 고장 모드를 평이한 언어로 설명하라. 왜 중요한가: 이는 대부분의 엔지니어들이 생각하는 것보다 더 어렵으며, 이것은 당신과 모델 사이의 주요 인터페이스이다.
-
복잡성 머릿속 유지: 현재 결정이 모델이 알지 못하는 시스템의 세 가지 다른 부분과 어떻게 상호작용하는지 파악하세요. 왜 중요한가: 모델은 지속적 아키텍처 컨텍스트가 없습니다. 당신이 작업 기억입니다.
-
감각: 사용자의 관점에서 좋은 소프트웨어가 어떤 느낌인지에 대한 감각입니다. 단순히 '작동하는가'가 아니라 '이것이 올바른 경험, 올바른 동작, 올바른 복잡도 수준인가'입니다. 왜 중요한가: 이것이 없으면, 기능적이지만 잘못된 해결책을 받아들이게 됩니다.
-
그만둘 때를 아는 것: 스펙이 실행으로 넘기기에 충분히 좋은지, 그리고 과도한 정교화를 하고 있는지 인식한다.
중요한 이유: 한계효용 체감은 분명히 존재한다. 어느 정도가 지나면, 추가 협상은 개선보다 더 많은 비용을 초래한다.
