개인적으로 개발 중인 웹 애플리케이션 'mojica'에서 인공지능(AI)을 활용한 테스트 주도 개발(TDD)을 시도해 보았습니다.
그 결과, 배포 후 수동 확인 작업을 상당히 줄일 수 있었습니다.
반면, AI가 생성한 테스트 케이스나 코드에 대한 리뷰는 예상보다 훨씬 어려웠습니다.
이번 글에서는 AI를 활용한 TDD를 통해 느낀 장점과 어려움, 그리고 리뷰 부하를 줄이기 위해 노력했던 점들에 대해 소개합니다.
mojica는 '덕질(推し活)'을 목적으로 개발된, 문자를 이용해 아트를 생성하는 웹 애플리케이션입니다. 사용자가 원하는 문자나 색상을 지정하여 문자 아트 이미지를 생성할 수 있으며, X 아이콘이나 배경 이미지에도 대응합니다.
먼저 앱 화면입니다.
[IMG:N]
생성하면 예를 들어 다음과 같은 이미지를 출력할 수 있습니다.
앱 본체는 주로 다음 기술들로 구성되어 있습니다.
이번에 AI를 활용하여 TDD를 진행하고 코드 리뷰까지 수행한 부분은, React 프론트엔드와 ASP.NET Core 백엔드 API입니다.
테스트 케이스는 양쪽 모두에서 리뷰했지만, 구현 후의 테스트나 코드는 주로 프론트엔드 쪽에 초점을 맞춰 확인했습니다.
개발 과정은 다음 순서로 진행되었습니다.
- AI에게 테스트 케이스를 생성하도록 요청한다.
- 생성된 테스트 케이스를 검토(리뷰)한다.
- AI를 활용하여 TDD 방식으로 구현한다.
- 구현 후의 테스트와 코드를 리뷰한다.
먼저, AI에게 테스트 케이스 생성을 맡긴 뒤 사람이 그 내용을 검토했습니다. 이후 테스트 케이스 확인을 마친 후에는 TDD로 구현을 진행했고, 구현 후의 테스트 및 코드에 대해서도 리뷰를 했습니다.
이처럼 AI에게 모든 것을 맡기기보다는, 인간이 리뷰 과정을 거치면서 개발을 진행하는 형태입니다.
실제로 AI를 활용하여 TDD를 진행해 본 경험 중 좋았다고 느낀 점이 있습니다. 가장 좋았던 부분은 배포 후 수동 확인 작업이 상당히 줄었다는 것입니다.
자동 테스트가 존재하기 때문에, 매번 사람이 화면이나 동작을 확인할 필요성이 줄어들었습니다. 배포 후 검증에 소요되는 시간을 단축할 수 있었습니다.
이는 AI 자체의 능력이라기보다는, 자동 테스트 환경을 갖추게 된 덕분에 얻은 이점이라고 생각합니다.
AI를 활용함으로써 테스트 생성과 TDD 구현을 진행할 수 있었다는 점도 좋았다고 느꼈습니다. 하지만 TDD로 인해 수동 확인 작업은 줄어든 반면, 리뷰 부하는 상당히 컸습니다.
특히 힘들었던 부분은 리뷰 대상의 양이 많다는 것, 그리고 기대했던 코드나 테스트와 괴리가 많았다는 점입니다.
먼저, 리뷰 대상의 양이 많았습니다. 테스트 케이스가 많아지면서 이에 따른 테스트 파일도 늘어났습니다. 게다가 구현된 프로덕션 코드의 줄 수도 많아졌습니다.
AI는 대량의 코드를 생성할 수 있지만, 사람이 그 내용을 확인하는 데에는 시간이 걸립니다. 단순히 읽기만 해도 시간이 소요되고 피로도가 쌓입니다.
또한, 코드를 읽는 것 외에도 구현 의도나 테스트의 타당성까지 검토해야 합니다.
이 때문에 코드를 작성받는 시간이 짧아지더라도, 그만큼 리뷰에 시간을 할애하게 되는 경우가 있었습니다.
코드 리뷰에서는 예를 들어 다음과 같은 괴리가 발견되었습니다.
i18n을 이용해 일본어와 영어를 전환하는 처리 같은 분기 처리에 삼항 연산자가 과도하게 사용됨 -
- 화살표 함수(Arrow function)를 사용했으면 좋겠다고 기대했는데,
function 키워드가 사용됨 -
- E2E 테스트에서 Page Object Model (POM)이 사용되지 않음
이러한 것들이 반드시 기술적으로 잘못된 구현은 아닙니다. 삼항 연산자는 예를 들어 언어 전환 처리 시 일본어와 영어만이라면 문제가 없을 수도 있습니다. 하지만 향후 언어가 늘어났을 때 확장성이 떨어집니다.
또한, function을 사용하는 것 자체가 문제가 아니라, 이번 개발에서 기대했던 코드 스타일과 달랐다는 점이 문제였습니다.
더 나아가 E2E 테스트의 경우, 유지보성을 높이기 위해 POM 사용을 기대했으나, 그 구성으로 되어 있지 않은 코드가 생성되는 경우가 있었습니다.
이러한 괴리가 있을 때마다 리뷰에서 지적할 필요가 있었습니다.
테스트에서도 다양한 문제가 발견되었습니다.
- 중복된 테스트가 존재함
- '이 테스트는 여기서 작성하지 않아도 좋지 않을까?' 싶은 부분이 있음
- 의미가 모호한 테스트가 있음
- Google의 Test Sizes를 기준으로 분류했지만, 분류가 잘못됨
- 코드로는 재현할 수 없는 테스트 케이스가 생성됨
특히, 테스트의 개수가 많다는 것과, 테스트 내용이 적절하다는 것은 별개의 문제임을 느꼈습니다.
테스트가 대량으로 생성되었더라도 같은 내용을 반복해서 확인하거나, 그 테스트가 놓인 위치에 어색함이 느껴질 때도 있습니다.
또한 Google의 Test Sizes를 기준으로 테스트를 분류했지만, 분류가 잘못된 경우도 있었습니다.
테스트 케이스로 작성되어 있더라도 실제로는 그 방법으로 재현할 수 없는 것도 있었습니다.
이러한 문제들은 단순히 테스트가 실행 가능한지 여부만으로는 판단할 수 없습니다.
무엇을 테스트하고 있는지, 그 테스트가 정말 필요한 것인지까지 인간이 확인해야 했습니다.
이번 개발 과정을 되돌아보면, 크게 두 가지 원인이 있었다고 생각합니다.
첫 번째는 AI에게 개발상의 규칙을 충분히 보여주지 못했다는 것입니다.
예를 들어 다음과 같은 규칙들이 있습니다.
- 코딩 규칙 (Coding rule)
- 테스트 작성 기준
- 중복된 테스트를 피하는 기준
- 어떤 종류의 코드를 원하는지
이러한 규칙들을 처음부터 충분히 명시하지 못했습니다.
그 결과, AI가 생성한 코드는 동작 자체에는 문제가 없었지만, 제가 기대했던 구현과는 다른 경우가 있었습니다.
두 번째는 테스트 케이스를 어느 정도 모아서 작성한 후에 리뷰했다는 것입니다.
테스트 케이스를 대량으로 만들게 하고, 그 결과를 사람이 취합하여 리뷰하는 방식이었습니다. 이 방법으로는 도중에 기대치와의 차이가 발생하더라도 알아차리지 못한 채 대량의 테스트 케이스가 생성되어 버립니다.
예를 들어, 테스트 작성 기준에 대한 인식이 어긋나 있었다면, 그 기준에 맞지 않는 테스트가 여러 개 만들어질 가능성이 있습니다.
결과적으로, 기대치와 차이가 난 상태로 생성된 것을 나중에 모아서 리뷰하는 구조가 되어버린 것입니다.
처음부터 기대치를 충분히 조율하지 못한 것에 더해, 중간에 확인하는 기회도 적었기 때문에 리뷰 부하(Review load)가 커졌다고 생각합니다.
리뷰 부하를 줄이기 위해 실제로 시도했던 것도 있습니다. TSKaigi에서 발표된 내용 중 리뷰에서 반복적으로 나오는 지적 사항을 Lint나 규칙으로 되돌리는 방식을 참고했습니다.
리뷰 과정에서 나온 지적들 중 기계적으로 체크할 수 있는 것은 Lint나 규칙에 추가했습니다. 예를 들어, 코드 스타일 관련 지적은 사람이 여러 번 지적하는 것이 아니라, 규칙으로서 체크할 수 있도록 하는 개념입니다.
그 결과, 같은 코드 스타일에 대해 반복적으로 지적되는 경우는 줄어들었습니다.
한편, 테스트의 필요성이나 테스트 케이스의 타당성 등은 Lint만으로는 판단할 수 없습니다. 따라서 기계적으로 체크 가능한 것은 시스템에 맡기고, 인간은 그 외의 리뷰에 집중하는 것이 중요하다고 느꼈습니다.
앞으로는 테스트 케이스를 모아서 대량으로 만든 후 리뷰하기보다는, 도중에 작게 확인하면서 기대치를 조율하고 싶습니다.
그 방법으로 grill-me 같은 것을 사용해보고자 합니다. 이는 구현이나 테스트 케이스 작성 전에 AI 측에서 질문을 받으며 기대하는 사양이나 구현 방침을 맞추어 가는 방식입니다.
예를 들어, 테스트 케이스를 만들기 전에 무엇을 테스트해야 하는지, 어느 범위까지 테스트할 것인지, 어떤 테스트 구성을 할 것인지를 확인하는 이미지를 가지고 있습니다.
그 위에 바로 대량의 테스트 케이스를 만드는 것이 아니라, 작은 단위로 생성과 리뷰를 반복하고 싶습니다. 이를 통해 기대치와의 차이를 빠른 단계에서 발견하여, 나중에 대규모 수정이 필요한 상황을 줄일 수 있지 않을까 생각합니다.
아직 시도해보지 않았기 때문에 실제로 얼마나 효과가 있을지는 모르지만, 도전해보고 싶습니다.
AI를 활용한 TDD 덕분에 배포 후의 수동 확인(manual check)은 상당히 줄어들었습니다.
반면, 리뷰 부하까지 자동으로 줄어드는 것은 아니었습니다. 실제로는 테스트 케이스나 코드의 양이 많다는 점과, 기대치와 차이가 있는 상태로 대량 생성될 경우 리뷰 부하가 매우 커졌습니다.
그 원인으로는 규칙을 충분히 보여주지 못한 것과, 도중에 기대치를 조율할 기회가 적었다는 것이 있다고 느낍니다.
리뷰에서 반복적으로 나오던 지적 사항을 Lint나 규칙으로 되돌림으로써 같은 지적은 줄일 수 있었습니다. 다음 단계는 테스트 케이스를 만드는 단계부터 AI와의 대화를 늘려, 기대치와의 차이 자체를 작게 만들어 나가는 것입니다.
이번 경험을 통해 AI에게 대량의 코드를 작성하게 하는 것뿐만 아니라, 어떻게 하면 인간이 리뷰하기 쉬운 형태로 개발을 진행할 수 있을지 고민하는 것도 중요하다고 느꼈습니다.