목록 화면에 검색 기능을 붙이려고 AI에게 코드를 부탁한다. 실행해 보니 검색 결과는 잘 나온다. 그런데 함수 이름이 어색하고, 요청이 실패했을 때 어떻게 처리되는지 읽기 어렵다. 고치려다 잠깐 망설인다. 잘 돌아가는데 이런 것까지 손봐야 할까.

마감이 가까우면 일단 끝내고 싶다. 화면도 제대로 나오니 당장 문제는 없어 보인다. 다만 다음에 이 코드를 고칠 동료는 화면만 보고 일할 수 없다. 함수 이름을 읽고 구조를 파악하고, 실패한 요청이 어디로 가는지 찾아야 한다. 동료에게는 그 코드도 결과물이다.

Glyph는 Programming Isn’t Special에서 프로그래밍도 예술이므로 생성형 AI를 대하는 기준에서 예외일 수 없다고 주장한다. 그가 말하는 예술에는 평범한 코드를 다듬는 일도 들어간다. 그런 일에 어떤 가치가 있는지 읽어 보고, AI를 쓸 때 어디까지 직접 판단할지 생각해 보려 한다.

실용적인 일도 창작이다

하나의 프로그램을 사용자는 동작과 화면으로, 동료 개발자는 이름과 구조로 경험하는 관계 그림
같은 프로그램도 사용자와 다음 개발자에게 다른 모습으로 읽힌다.

광고 문구는 물건을 팔려고 쓴다. 그래도 어떤 단어를 쓰고 어떤 말을 뺄지 고르는 일은 남는다. Glyph는 실용적인 글을 쓰는 사람과 예술적인 글을 쓰는 사람이 같은 솜씨를 쓴다고 설명한다. 돈을 받고 정해진 일을 하는 사람도 만드는 동안 여러 선택을 한다. 기능을 만든다는 이유만으로 그 선택을 창작에서 빼기는 어렵다.

검색 기능을 붙일 때도 그렇다. 검색어가 비었을 때 전체 목록을 보여 줄까, 아무것도 보여 주지 않을까. 요청이 실패하면 자동으로 다시 보낼지, 사용자에게 먼저 알릴지도 정해야 한다. 요구사항에 빠진 이런 선택 때문에 사용자가 겪는 일이 달라진다. 정답처럼 보이는 코드에도 누군가 정해 둔 기준이 있는 셈이다.

동료가 코드를 읽을 때는 다른 부분이 눈에 들어온다. 한 함수가 너무 많은 일을 맡고 있지는 않은지, 이름과 실제 역할이 맞는지, 오류를 어디에서 처리하는지 살핀다. 이런 판단을 미학이라고 불러도 좋겠다. 여기서는 다른 사람이 이해하고 다루기 좋은 형태를 고르는 일을 말한다. 보기 좋게 꾸미는 취향만을 뜻하지는 않는다.

예술이라는 이름을 붙여도 읽기 어려운 코드는 여전히 읽기 어렵다. 기발하게 썼는데 동료가 이해하지 못하거나, 짧게 줄였더니 실패 원인이 숨는다면 팀에는 손해다. 누가 읽고 무엇을 바꿀지까지 생각해야 한다. 창작이라는 말을 앞세워 자기 취향을 강요할 수는 없다.

Deferred는 지루한 반복에서 나왔다

호출마다 성공과 실패 함수를 전달하는 방식과 Deferred를 돌려받아 처리 순서를 연결하는 방식을 비교한 그림
Deferred는 비동기 결과를 다루는 순서를 한곳에 연결하도록 돕는다.

Glyph가 직접 겪은 일로 든 사례가 Deferred다. 다른 컴퓨터에 있는 함수를 호출하는 RPC 프로그램을 만들 때였다. 호출할 때마다 성공 처리 함수인 callback과 실패 처리 함수인 errback을 전달해야 했다. 동작에는 문제가 없었지만 매번 쓰기가 번거로웠다. Glyph는 그 불편 때문에 새로운 형태를 찾았다고 회고한다.

비동기 작업은 결과를 기다리지 않고 다른 일을 먼저 하는 방식이다. Twisted 공식 문서에 따르면 Deferred는 나중에 생길 결과와 그 결과를 처리할 함수들을 연결한다. 호출한 쪽은 Deferred를 받아 성공과 실패 처리 함수를 등록한다. 결과가 준비되면 등록된 처리 흐름을 실행하고, 각 함수의 결과를 다음 함수에 전달한다.

처리 도중 예외가 나면 오류를 다루는 흐름으로 옮겨 간다. 오류 처리 함수가 정상 값을 돌려주면 성공 흐름으로 돌아갈 수도 있다. 성공했을 때뿐 아니라 실패했을 때 어떻게 이어질지도 정해 두는 것이다. 호출한 쪽은 이 규칙에 맞춰 결과를 처리할 순서를 적는다.

반복이 싫어서 더 나은 도구를 찾았다는 점이 눈에 남는다. 만약 그때 누군가 callback과 errback을 대신 타이핑해 줬다면 어땠을까. Glyph는 불편을 덜 느꼈을 테고, Deferred도 나오지 않았을지 모른다. Glyph는 Deferred의 영향이 JavaScript의 Promise를 거쳐 async/await까지 이어졌다고 말한다. 같은 코드를 계속 생성해 주는 도구는 당장의 수고를 줄여 준다. 호출 방식 자체를 고치면 그 뒤에 코드를 쓸 모든 사람이 편해진다.

아름다운 코드의 기준을 말로 설명한다

코드가 아름답다고만 말하면 서로 다른 얘기를 하기 쉽다. 각자 좋아하는 스타일을 떠올리기 때문이다. Glyph는 소프트웨어를 두고 이런 철학을 세운 예로 Python의 설계 원칙을 모은 PEP 20을 든다. 거기에는 이런 문장이 있다.

Readability counts.

읽기 쉬운 코드가 중요하다는 말이다. 맞는 말이지만, 이 말만으로는 무엇을 고칠지 알기 어렵다. 이름을 바꾸면 무엇을 더 쉽게 알 수 있는지, 함수를 나누면 어떤 수정이 편해지는지까지 말해야 동료도 그 선택이 괜찮은지 따져 볼 수 있다.

동료가 검색 기능의 정상 동작은 금방 이해하는데 오류가 어디로 가는지 못 찾는다고 하자. 이때는 코드를 더 짧게 줄이기보다 실패 처리가 눈에 들어오도록 고치는 편이 낫다. 이미 이해하기 쉬운 코드를 나누느라 여러 파일을 오가게 만들면 오히려 복잡해진다. 읽는 사람이 어디에서 막히는지를 보고 고칠 부분을 정한다.

반복을 덜어도 판단은 남길 수 있다

목적을 정하고 AI 초안을 검토하고 동작을 확인한 뒤 새로 발견한 조건을 다시 목적에 반영하는 순환 그림
AI 초안 뒤에 검토와 확인이 있어야 다음 작업의 기준도 쌓인다.

Glyph가 걱정하는 것은 평범한 실무를 전부 AI에 맡기는 습관이다. 직접 해 보며 생각하고 솜씨를 기를 기회까지 없어질 수 있기 때문이다. 그렇다고 추상화나 자동화를 거부하지는 않는다. 그는 프로그래밍을 추상화의 예술이라고 부른다. 작은 생각을 묶어 더 큰 생각을 만드는 일이라는 뜻이다. 이해를 한 단계 위로 올려 주는 자동화는 괜찮다. 문제는 이해 자체를 없애고, 만드는 동안 내리던 결정까지 지워 버리는 자동화다.

검색 기능을 맡기기 전에 빈 검색어와 요청 실패를 어떻게 처리할지 직접 적어 두면 어떨까. AI가 구현한 코드를 그 기준과 비교해 본다. 구현하면서 새 조건을 발견했다면 요구사항도 고친다. 작업 순서가 조금 바뀌었지만 개발자가 할 일은 분명하다. 무엇을 만들지 정하고, 나온 결과를 쓸지 결정한다.

비교할 때는 질문을 던지며 읽는다. 왜 이 이름을 썼을까. 오류를 여기서 잡는 이유는 뭘까. 조건이 바뀌면 어디를 고쳐야 할까. AI에게 물으면 설명은 나온다. 설명대로 동작하는지는 직접 확인해야 한다. 이유가 그럴듯하다는 것만으로 코드가 맞다고 할 수는 없다.

처음 배우는 일에서는 직접 확인할 부분을 더 작게 잡아도 좋다. 비동기 오류 처리를 익히는 중이라면 완성된 코드만 받기보다 실패하는 작은 예를 먼저 실행해 본다. 언제 정상 흐름을 벗어나 오류 흐름으로 갈지 예상하고 결과와 비교한다. AI에게는 설명이나 반례를 부탁한다.

익숙한 형식의 코드는 AI에 맡겨도 새로운 조건을 고민하는 시간은 남길 수 있다. 반복 작업을 전부 직접 할 필요는 없다. 다만 결과를 읽지 않고 계속 받아들이면 직접 판단하는 일도 줄어든다. 오늘 얼마나 많은 코드를 만들었는지보다, 어떤 결정을 했고 그 이유를 설명할 수 있는지가 더 중요하다.

평범한 작업에서도 배운다

프로그래밍이 예술이라는 말에 동의하지 않을 수도 있다. Glyph의 글도 실험 결과가 아니라, 창작과 AI를 어떻게 대할지에 관한 자기 생각이다. 그래도 기능만 돌아가면 충분하다고 할 때 놓치는 것은 남는다. 코드를 읽는 동료, 나중에 다시 고치러 올 자신도 그 코드를 써야 한다.

오늘 붙인 검색 기능이 대표작이 될지는 모른다. Glyph는 평범한 작업 하나가 대단한 결과로 이어질 확률을 0.1% 정도로 어림한다. 그의 어림일 뿐이고, 작은 숫자다. 하지만 평범한 작업을 모두 AI에 맡기면 이 확률은 0이 된다. Deferred도 그런 평범한 작업에서 나왔다. 대단한 결과가 나오지 않더라도, 빈 검색어를 처리하고 실패 흐름을 고치며 배운 것은 다음 기능을 만들 때 쓸 수 있다.

다음에 AI가 만든 코드를 받으면 한 부분만 골라 설명해 보자. 이 함수는 무슨 일을 맡았는지, 실패하면 누가 처리하는지, 어떤 조건에서 다른 방식보다 나은지. 설명하다 막히면 그 부분을 읽고 실행해 본다. 평범한 코드 하나라도 그렇게 내 것으로 만들면 된다.

Glyph의 글에는 이런 문장이 있다.

Slop is slop, no matter the medium.

대충 찍어 낸 결과물은 매체가 무엇이든 대충 찍어 낸 결과물이라는 뜻이다. 프로그래밍도 다른 창작처럼 연습으로 늘고, 연습을 건너뛰면 실력도 멈춘다. 그 점에서 프로그래밍은 특별하지 않다.