AI 코딩 도구는 코드를 빠르게 생성할 수 있지만, 속도만으로는 가장 어려운 소프트웨어 엔지니어링 문제를 해결할 수 없습니다. 개발자는 여전히 컨텍스트를 제공하고, 결과를 검증하고, 유지 보수성을 보호하며, 출시되는 것에 대한 책임을 져야 합니다.
경험이 풍부한 개발자들이 그 균형을 어떻게 맞추는지 알아보기 위해, 우리는 Java 사용 경력이 10년이 넘는 세 명의 Java Champion과 이야기를 나눴습니다. 그들은 프로덕션과 오픈 소스에서 GitHub Copilot을 사용한 구체적인 사례와, AI가 생성한 결과물을 신뢰할 수 있는 소프트웨어로 만들기 위해 사용하는 실천 방법들을 공유했습니다.
다음은 그들이 우리에게 공유한 팁들입니다.
Vlad Mihalcea
GitHub 프로필: @vladmihalcea
GitHub Copilot이 최근에 어떤 도움을 주었나요?
Hypersistence Utils와 Hypersistence Optimizer의 다양한 기능을 분석, 설계, 구현하는 데 사용하고 있습니다.
예를 들어, 저는 오랫동안 Optimizer 이벤트 기록을 제공하는 웹 애플리케이션을 개발하고 싶었습니다. 그래야 성능 개선 노력이 애플리케이션 성능에서 어떻게 실현되고 있는지 볼 수 있기 때문입니다. AI 이전에는 개발에 몇 주가 걸릴 것이기 때문에 이 작업을 계속 미루고 있었습니다. 하지만 Copilot을 사용하는 것은 새로운 팀원이 생긴 것 같아서, 이를 사용하여 Hypersistence Optimizer의 다음 버전에 포함될 앱을 만들었습니다. 이 작업은 몇 주가 아니라 단 이틀 만에 구현되었습니다.
일반적으로 어떻게 사용하시나요? GitHub Copilot을 IDE 플러그인으로 사용하시나요, 아니면 GitHub Copilot 앱으로 사용하시나요?
저는 IntelliJ IDEA에서 GitHub Copilot을 사용합니다. 소스 코드를 검토하거나 디버그 세션을 진행하는 동안 실행하기에 편리하기 때문입니다.
코드 어시스턴트로서 매우 유용하며, 조사 작업과 검증이 필요한 기능의 프로토타입 제작 속도를 높이는 데 도움이 됩니다.
저는 여전히 AI가 생성한 계획과 코드를 검토합니다. 그 목적은 제를 완전히 대체하는 것이 아니라 생산성을 향상시키는 것이기 때문입니다. AI가 많은 상황에서 올바른 답을 제공하지만, 여전히 응답이 만족스럽지 않아 제가 개입해야 하는 때가 있습니다.
몇 가지 팁과 모범 사례를 공유해 주실 수 있나요? 예를 들어, 어떤 스킬을 사용하시나요?
저는 Copilot이 생성하는 텍스트가 제가 손으로 작성한 것처럼 보이도록 자신만의 스킬을 만들었습니다.
이 스킬은 제가 발표한 65개의 글에서 제 문체를 학습합니다. 따라서 초안이 언어 모델처럼이 아니라 제 블로그처럼 나옵니다. 이 프로젝트의 문서를 생성할 때 특히 유용한데, 12년간의 블로그 운영에서 LLM이 학습하여 표현력, 테스트 용이성, 단순성과 같은 동일한 원칙을 따르는 예제를 제공하기 때문입니다.
소프트웨어 엔지니어로서의 제 경력 전반에서 배운 것은, 우리가 코드 작성보다 코드 유지 보수에 훨씬 더 많은 시간을 소비한다는 것입니다. 따라서 기존 제품에는 유지 보수와 안정성이 매우 중요하기 때문에, AI가 최소 놀람의 원칙에 따라 기존 코드 관행을 모방하도록 돕는 스킬을 개발했습니다.
한 가지 팁은 작업 유형에 따라 모델 유형을 변경하는 것입니다. 깊은 사고가 필요할 때는 1 million 컨텍스트 윈도우와 Extra High 또는 Max 추론을 갖춘 Opus를 사용합니다. 하지만 보고서 생성, 릴리스 노트 작성 또는 문서 검증과 같은 더 간단한 작업에는 토큰을 더 적게 소비하는 더 가벼운 모델을 사용합니다.
Patrick Baumgartner
GitHub 프로필: @patbaumgartner
귀하의 업무에는 팀 코칭이 포함되어 있는데, 어떤 접근 방식을 취하시나요?
제 업무의 상당 부분은 일반 업무가 계속 진행되어야 하는 상황에서 이루어집니다. '전환'을 위해 모든 것을 6개월간 멈출 수는 없습니다. 우리는 보통 즉각적인 문제를 함께 해결하는 것으로 시작하고, 팀이 현재 어디에 있는지 파악하고, 우리가 어디로 가고 싶은지 그리고 개선되고 있는지를 어떻게 알 수 있는지 정의한 후, 한 걸음씩 그곳으로 나아갑니다.
상황에 따라 이는 TDD, 리팩토링, 지속적 전달 및 XP와 같은 Software Craft 실천 방법, Spring Boot, Spring Modulith를 활용한 아키텍처와 모듈화, Spring Security, 컨테이너를 위한 Java 및 Spring Boot 애플리케이션 최적화, 또는 점점 더 많아지는 에이전트 엔지니어링을 의미할 수 있습니다.
저에게 중요한 부분은 제가 일하는 방식입니다 함께 팀입니다. 우리는 함께 결정을 내립니다. 팀이 저에게 의존하게 되는 것을 원하지 않습니다. 이상적으로는 시간이 지나면 어쩌면 스파링 파트너 정도를 제외하고는 더 이상 저를 필요로 하지 않게 되는 것입니다.
그리고 어쩌면 이것이 제가 이 새로운 세대의 AI 도구들을 흥미롭게 느끼는 이유를 설명해 줄지도 모릅니다. 저는 사람들과 함께 일하고, 배우고, 실험하고, 문제를 해결하는 것을 좋아합니다. AI는 바로 그런 일을 하는 데 도움이 되는 또 하나의 매우 강력한 도구를 우리에게 제공합니다.
최근에 GitHub Copilot이 도움이 된 좋은 사례를 공유해 주실 수 있나요?
GitHub Copilot와 함께 작업하는 방식에 대한 제 생각을 바꾼 실제로 매우 다른 세 가지 예가 있습니다.
첫 번째 것부터 시작해 보겠습니다.
하나는 15개 프레젠테이션에 걸친 약 900장의 교습용 슬라이드를 Reveal.js에서 Marp로 옮기는 마이그레이션이었습니다. 이것들은 단순한 슬라이드가 아니었습니다. 많은 슬라이드에 코드, 애니메이션, 심지어 수업 중에 JavaScript를 실시간으로 바꿔볼 수 있는 인터랙티브 예제까지 들어 있었습니다. 더 중요한 것은, 이 프레젠테이션들이 이미 학생들과 함께 실전 검증을 거쳤다는 점이었습니다. 흐름이 잘 맞아떨어졌습니다. 작은 조각 하나만 잃어도 교실에서 제가 사용하는 스토리가 깨질 수 있었습니다.
그 마이그레이션을 수작업으로 했다면 아마 일주일 이상 걸렸을 것이고, 현실적으로는 너무 지루한 작업이라 그냥 안 했을 가능성도 큽니다.
Copilot과 함께할 때는 다른 방식으로 접근했습니다. 먼저 기존 자료를 분석하고, 목표를 정의하고, 마이그레이션 계획을 세우고, 제약 조건을 확립하고, 예제를 제공하고, 무엇이 그대로 유지되어야 하는지를 정의했습니다. 그다음 큰 구조적 변경에서부터 세부 사항으로 내려가며 작업했습니다.
정말 중요한 부분은 검증이었습니다.
Reveal.js 버전과 Marp 버전의 스크린샷을 생성해 시각적·알고리즘적으로 비교했습니다. 두 슬라이드 덱을 나란히 실행해 애니메이션을 수동으로 확인할 수 있는 작은 애플리케이션도 만들었습니다. 생성된 PDF까지 비교했습니다.
그 덕분에 에이전트가 단지 "마이그레이션 완료"라고 말하는 데 그치지 않았습니다. 우리에게는 증거가 있었습니다.
전체 마이그레이션에 대략 8~10시간이 걸렸습니다. 콘텐츠, 교습 의도, 의미 있는 모든 변경은 여전히 제 소유였습니다. Copilot이 오타는 자동으로 고칠 수 있었지만, 콘텐츠, 버전, 날짜 또는 의미가 바뀌는 부분은 우리가 함께 논의했습니다.
저에게 그 경험은 중요한 원칙을 다시 일깨워 주었습니다: 실행은 위임하되, 책임은 위임하지 않는다. 결과의 소유자는 저입니다.
두 번째 예도 들어주실 수 있을까요?
두 번째 예는 Tamboui로 터미널 UI 애플리케이션을 만들면서 생긴 것입니다. 처음에는 WSL의 리눅스에서 완벽하게 작동했고, 누군가 Windows CMD나 PowerShell에서 직접 실행할 수 있다는 사실을 완전히 잊고 있었습니다.
그런데 실제 사용자가 그렇게 했습니다.
그 사용자는 일부 폼에서 Enter 키가 그냥 무시된다는 것을 발견했습니다. 이것은 제가 강하게 믿는 또 다른 원칙과 맞닿아 있습니다: 소프트웨어를 일찍 출시하라. 사람들이 실제로 어떻게 사용하는지에서 배우게 되기 때문입니다.
우리는 Copilot을 사용해 그 피드백을 재현 가능한 UI 테스트로 바꿨습니다. 리눅스에서는 Copilot이 tmux로 애플리케이션을 탐색했습니다. 함께 작업하면서 psmux에 대해 알게 되었고 PowerShell에서도 비슷한 흐름을 실행할 수 있었습니다. 우리는 문제를 재현하고, 로컬 수정을 만들고, 진짜 문제를 Tamboui까지 추적했고, 저는 상위 저장소 수정을 제출했고 그것이 머지되었습니다.
이 작업 중에 테스트 설명 자체가 가용한 컨텍스트에는 너무 커졌습니다. 그래서 Copilot에게 테스트를 표현하는 방식을 다시 설계하도록 도와달라고 요청했습니다. 식별자, 이름, 반복되는 설명이 담긴 장황한 테이블 대신, 훨씬 간결한 화살표 표기법, 즉 step → step → input 방식을 제안했고, 추가 정보는 중요한 곳에만 두었습니다.
이것은 저를 놀라게 했습니다. 우리는 단순히 AI로 정보를 실행하는 데 그치지 않고 실행을 위해 정보를 어떻게 표현할 것인가에 대해 함께 작업하고 있었습니다. 표현은 인간에게 최대한 친화적일 필요는 없었습니다. 의미론을 보존하면서 에이전트에게 효율적이기만 하면 되었습니다.
세 번째 예는 어떤가요?
세 번째 예는 또 완전히 다릅니다.
저와 가까운 사람이 수학 연습이 필요했고, 저는 이렇게 생각했습니다: 작은 학습 앱을 만들어 보면 어떨까?
이 앱은 1학년부터 4학년까지를 대상으로 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지가 있는 나눗셈을 다룹니다. 하지만 저는 또 하나의 단순한 퀴즈 애플리케이션을 만들고 싶지 않았습니다. Copilot과 함께 간격 반복, 즉각적 피드백, 적응형 난이도, 동기 부여, 협동 학습, 다크 패턴 없는 게임화 같은 학습 접근법을 조사했습니다.
흥미롭게도 그 조사 과정에서 Copilot은 제 초기 가정 중 하나에 이의를 제기했습니다. 저는 처음에 이 애플리케이션을 모든 아이들을 위한 범용 앱으로 만들고 싶었습니다. 조사 결과 우리는 실제 학교 교육과정을 살펴보는 방향으로 나아갔습니다. 주제가 도입되는 순서, 연산, 수 범위가 나라마다 충분히 달라서 처음부터 "범용"으로 만드는 것은 불필요하다는 것을 깨달았습니다.
그래서 우리는 우선 스위스에 집중하고 그에 맞춰 학습 진행 순서를 정렬했습니다. 스위스는 다언어 국가이기 때문에 애플리케이션은 독일어, 프랑스어, 이탈리아어, 영어로 제공됩니다.
또한 협동 및 경쟁 2인 플레이 모드가 있고, 누군가 답을 틀리면 애플리케이션이 한 가지 풀이 방법을 설명하고 유사한 문제를 간격 반복을 통해 다시 제시합니다.
저는 백엔드 없는 아키텍처를 의도적으로 선택했습니다. 서버에 아이들의 개인 데이터를 수집할 이유가 없으므로, 데이터는 기기에 머무르고 애플리케이션은 GitHub Pages에 간단히 호스팅될 수 있습니다.
작은 실험으로 시작한 것이 이제는 친구들 사이에서 사용되고 공유되고 있습니다. 어느새 작은 제품이 되어 버렸습니다.
그 경험을 통해 Copilot의 또 다른 면을 보았습니다: 자신의 솔루션을 구현하는 데만 사용하지 마십시오. 빌드를 시작하기 전에 솔루션 공간을 확장하고 도전적으로 검토하는 스파링 파트너로 활용하십시오.
보통 Copilot을 어떻게 사용하시나요?
사실 저는 이제 클래식한 Copilot 자동완성 경험은 더 이상 사용하지 않습니다.
제 작업은 거의 완전히 에이전트 워크플로로 옮겨갔습니다.
촘촘한 시각적 피드백 루프가 필요할 때, 즉 문서, 코드, 프레젠테이션이나 중간 결과물을 자세히 살펴보면서 진행 과정을 그때그때 조정하고 싶을 때는 VS Code를 사용합니다.
규모가 큰 실행 중심 작업의 경우에는 터미널에서 코딩 에이전트와 함께 작업하는 경우가 많습니다. 그때는 작업 조각을 위임하고 실행되도록 두었다가 완성된 결과를 검토하는 편이 더 편안합니다. 어떤 인터페이스를 선택할지는 주로 필요한 피드백 루프에 따라 달라집니다.
JavaLand으로 이동하는 여정에서도 GitHub을 통해 코딩 에이전트 워크플로를 사용하면서 흥미로운 경험을 했습니다. 저는 Spring Boot 자동 구성(auto-configuration) 중 어떤 것이 로드될지 최적화하는 Maven 플러그인에 대한 아이디어를 탐색하기 시작한 상태였습니다. 약 4시간에 걸친 이동 중에 저는 휴대폰으로 에이전트를 이끌었습니다: 작업을 지시하고, 에이전트가 한 일을 검토하고, 다음 단계를 생각하고, 다음 지시를 보내는 식이었습니다.
도착했을 때 저는 동작하는 Maven 플러그인, CI 파이프라인, 샘플 애플리케이션을 대상으로 한 성능 테스트, 그리고 최적화가 실제로 효과가 있었는지 보여줄 수 있는 보고서를 갖고 있었습니다.
그렇게 일해본 것은 처음이었고, 실제로 잘 작동한다는 점이 놀라웠습니다. 저는 휴대폰에서 Java를 작성하려던 것이 아니었습니다. 저는 에이전트가 실행하는 동안 검토하고, 결정하고, 방향을 이끌고 있었습니다.
저는 유용한 기능이나 컨텍스트를 제공할 때 MCP 서버도 사용합니다. 예를 들어, 문서화를 위해 Context7을 사용했고, 제 Logseq 지식 베이스와의 통합을 사용했으며, Adobe Premiere Pro용 MCP 통합도 실험해 보았습니다.
하지만 사용할 수 있으니까 무조건 MCP를 쓰지는 않습니다. 좋은 CLI가 존재한다면, 저는 CLI가 더 직접적이고 빠르게 느껴지기 때문에 종종 CLI를 선호합니다.
또한 에이전트는 제 사고 모델에서 "주니어 개발자"가 아닙니다. 저는 그것을 훨씬 더 스파링 파트너로 생각합니다. 하지만 프로젝트에 합류하는 누구와 마찬가지로, 먼저 상황을 파악하도록 만들어 주어야 합니다.
컨텍스트가 왕입니다.
몇 가지 팁과 모범 사례를 공유해 주실 수 있나요?
제가 권하는 가장 중요한 것은: 원샷 프롬프팅을 그만두라는 것입니다.
사소하지 않은 모든 작업에 대해 저는 실행이 시작되기 전에 문제를 이해하고 싶어합니다. 상당히 자주 저는 에이전트에게 먼저 저를 인터뷰하도록 명시적으로 요청합니다. 그 인터뷰의 목적은 아직 암묵적으로 남아 있는 가정과 기대를 드러내는 것입니다.
좋은 에이전트는 잘못된 아이디어를 믿을 수 없을 만큼 빠르게 실행할 수 있습니다. 그렇다고 그 우회가 더 저렴해지지는 않습니다.
저는 Spring Boot 자동 구성 최적화기를 작업하면서 이를 직접 경험했습니다. 처음에는 Spring Boot 3.5와 4.x를 모두 지원하고 싶었습니다. 아키텍처상의 차이가 있었기 때문에 두 접근 방식을 모두 구현했습니다. 나중에 3.5 경로가 더 이상 필요 없다는 것을 깨달았고, 그것을 제거하는 것은 고통스러웠습니다.
교훈은 간단했습니다: 우회는 비용이 많이 듭니다. 가속하기 전에 요구 사항을 바로잡으세요.
의도가 명확해지면 저는 계획을 원합니다. 그 계획을 검토할 때 저에게 특히 중요한 네 가지는 다음과 같습니다: 가정이 드러나 있는가, 검증 게이트가 정의되어 있는가, 접근 방식이 아키텍처에 부합하는가, 불필요한 작업을 피하고 있는가?
두 번째 원칙은 작업별 검증 게이트를 정의하는 것입니다.
"완료"는 모델이 완료되었다고 말하는 것을 의미해서는 안 됩니다.
리팩토링의 경우 게이트에는 통과하는 테스트, 의도된 모든 파일이 처리되었음을 증명하는 것, 문서 업데이트, TODO를 남기지 않는 것이 포함될 수 있습니다. 슬라이드 마이그레이션의 경우 게이트에는 스크린샷, 시각적 diff, 애니메이션, PDF 출력, 콘텐츠 완전성이 포함되었습니다.
게이트는 작업에 따라 달라집니다. 원칙은 그렇지 않습니다: 에이전트는 작업이 완료의 정의를 충족한다는 증거를 제공할 수 있어야 합니다.
저는 최근에 비슷한 아이디어를 따르는 다음과 같은 스킬을 접했습니다: unlazy 명시적인 게이트를 만들고, 신중하게 하나씩 수행하며, 지름길을 택하는 대신 완료되었음을 증명하는 것입니다.
세 번째 원칙은 배운 것을 재사용 가능한 스킬로 만드는 것입니다.
저는 제 자신의 Agent Skills를 작성하고 유지보수하기 시작했습니다. 실행에서 무언가를 배울 때—예를 들어 에이전트가 컨벤션을 오해했거나, 유용한 검사가 빠져 있었거나, 작업에 접근하는 더 나은 방법을 발견했다면—저는 스킬을 업데이트합니다.
다음에 그 작업을 수행할 때는 교훈이 이미 거기에 있습니다.
한 가지 예는 제가 부르는 다음 스킬입니다: maintainer-audit오픈 에이전트 스킬 커뮤니티의 작업에서 영감을 받은 것으로, 저는 제 저장소 전반에서 이를 사용합니다. 이 스킬은 유지보수되는 프로젝트가 갖추어야 한다고 제가 기대하는 것들—저장소 문서, CI 파이프라인, Dependabot 구성, CodeQL, 일관된 정리 및 기타 프로젝트 표준—을 검사하고, 적절한 경우 수정합니다.
목표는 제가 읽을 또 하나의 감사 보고서를 생성하는 것이 아닙니다. 이 스킬은 저장소를 제가 원하는 기준선으로 자동으로 되돌려 놓습니다. 그 덕분에 제 프로젝트는 더 일관성 있고 유지보수하기 쉬워집니다.
저는 이러한 스킬을 다음과 같이 생각합니다. 살아있는 엔지니어링 지식 정적인 프롬프트가 아니라.
네 번째 원칙은 확률적 모델 주변에 결정론적 엔지니어링 도구를 배치하는 것입니다.
저는 Checkstyle, PMD, Spring Modulith 아키텍처 검사 같은 도구들을 감싸서 에이전트가 소비할 수 있는 통합 리포트를 생성하는 자체 품질 하니스를 갖고 있습니다. 이를 훅(hook)에서 실행하여 에이전트가 반복하도록 할 수 있습니다:
변경 → 검사 실행 → 결과 확인 → 수정 → 다시 실행.
발견 사항이 더 이상 없을 때까지 계속됩니다.
그렇다고 소프트웨어를 더 이상 살펴보지 않는다는 뜻은 아닙니다. 저는 여전히 애플리케이션을 실행하고, 직접 상호작용하며, 기대한 대로 동작하고 보이는지 판단합니다. 때로는 피드백 루프가 훨씬 촘촘하기 때문에 의도적으로 기능 단위로 구현하기도 합니다.
저는 “AI가 할 수 있으니까”라는 이유로 모든 것을 한 번에 요청하는 것이 대개 좋지 않은 생각이라는 것을 배웠습니다. 크고 일반적인 명세는 크고 일반적인 구현으로 이어지며, 나중에 그것을 정리하는 것이 더 작은 단위로 올바르게 만드는 것보다 어려울 수 있습니다.
좀 더 넓은 관점에서, 우리 개발자들은 이러한 도구를 어떻게 사용하는지에 대해 훨씬 더 많이 이야기해야 한다고 생각합니다. 잘 작동한 실험을 공유하고, 그렇지 못한 실험도 공유하세요. 하나의 보편적인 AI 개발 프로세스를 찾기보다 서로의 아이디어를 빌려 자신의 상황에 맞게 적용하세요.
그래서 저는 AI를 스파링 파트너로 삼는 아이디어를 좋아합니다. 금요일 밤에 무언가를 실험해 보고 싶은데 함께할 인간 페어가 없을 때, 갑자기 아이디어를 검증하고 접근 방식을 리뷰해 주거나 아주 정교한 고무 오리로 활용할 수 있는 누군가—혹은 무언가—가 생기는 것입니다.
하지만 그 아이디어는 여전히 실제 사람들에게 가져가서 검증합니다. 인간의 피드백, 제품에 대한 이해, 그리고 실제 세계의 맥락은 여전히 필수적입니다.
AI가 우리 직업을 어떻게 바꾸고 있다고 생각하시나요?
저는 소프트웨어 공학 학생들이 코드를 생산하는 기계가 되는 것을 주된 목표로 삼아서는 안 된다고 생각합니다. 그들은 강력한 문제 해결사가 되어야 합니다. 사용자와 이해관계자를 이해하고, 요구사항 뒤에 있는 진짜 문제를 발견하고, 가정에 의문을 제기하고, 제품과 시장을 이해하고, 아키텍처 트레이드오프를 판단하고, 비판적으로 사고하고, 체계적으로 일하고, 한 맥락에서 유용한 솔루션을 다른 맥락으로 옮겨 적용할 수 있어야 합니다.
모델은 가능성을 생성하고 일을 실행하는 데는 놀라울 정도로 뛰어납니다. 하지만 인간인 저는 실제 맥락에 대해—아무도 문서화하지 않은 것들까지도—훨씬 더 많이 알고 있는 경우가 대부분입니다.
그래서 저는 솔루션을 형성하는 일의 주도권을 유지하고, 실행의 상당 부분을 에이전트에게 맡기고 싶습니다.
그런 의미에서 저는 AI가 소프트웨어 엔지니어링에 엔지니어링을 되돌려 놓고 있다고 생각합니다.
그리고 저는 그 점이 마음에 듭니다.
Frank Delporte
GitHub 프로필: @FDelporte
기술 분야에 어떻게 입문하셨나요?
저는 11살 때 Commodore 64를 받은 이후로 컴퓨터에 매료되어 있었습니다. 학교를 졸업한 후에는 비디오 제작과 텔레비전 일로 잠시 우회했지만, 비디오를 DVD에 담아야 했고 아주 초창기 웹사이트들을 만들면서 다시 코딩으로 돌아왔습니다… 네, 저는 그만큼 나이가 있는 사람입니다 ;-).
최근에 GitHub Copilot이 어떤 도움을 주었나요?
풀 리퀘스트를 평가하고 버그 리포트를 조사하는 데 완벽한 동반자입니다.
주목할 만한 이야기 중 하나는 Raspberry Pi의 전자 부품과 상호작용하는 Java 애플리케이션을 만들 수 있게 해주는 Pi4J 라이브러리 에 관한 것입니다. 2026년 2월에 우리는 Foreign Function & Memory API를 사용하는 새로운 플러그인이 포함된 V4를 출시했습니다. 출시 전에 철저히 테스트했지만, 그럼에도 불구하고 출시 직후 누군가 5개의 입력 버튼을 사용할 때 예상대로 작동하지 않는다고 보고했습니다. 처음 구성된 네 개의 버튼 중 하나를 누르면 예상대로 코드가 실행되는 반면, 다섯 번째 버튼은 아무 반응이 없었습니다.
이것은 여러분이 받고 싶지 않은 종류의 리포트입니다. 겉으로 보기에 깨진 것은 아무것도 없었습니다. 예외도 없고, 로그에 경고도 없었으며, 다섯 번째 버튼은 그저 조용할 뿐이었습니다. 그리고 상황은 더 나빴습니다. 이전 버전의 gpiod 플러그인에서는 정확히 동일한 하드웨어와 정확히 동일한 애플리케이션이 잘 작동했습니다. 그래서 문제는 Linux 커널의 GPIO 문자 디바이스 위에 있으며 네이티브 호출을 통해 그것과 통신하는 우리의 새로운 FFM 코드에 있었습니다. 그것은 코드베이스에서 빠른 답을 찾을 것으로 기대하는 부분이 아니었습니다.
그래서 저는 이 이슈를 Copilot 코딩 에이전트에 할당하고 시작점으로 두 개의 파일 경로, 즉 provider 클래스와 FFMDigitalInput을 알려주었습니다. 약 30분 후에 하나의 풀 리퀘스트가 도착했고, 정말 예상하지 못한 설명이 함께 있었습니다.
각 입력은 네이티브 poll() 호출에서 블로킹되어 커널이 자신의 GPIO 라인의 변화를 보고해 주기를 기다리는 이벤트 와처를 실행합니다. 이 와처들은 가상 스레드에서 실행되었습니다. 그런데 네이티브 호출 내부에서 블로킹되는 가상 스레드는 캐리어 스레드에서 언마운트될 수 없습니다. 호출이 진행되는 전체 기간 동안 그 자리에 고정(pinned)된 채로 있습니다. Raspberry Pi 4는 코어가 4개이므로 가상 스레드 스케줄러에는 캐리어 스레드가 4개 있습니다. 입력을 4개 등록하면 4개의 캐리어가 모두 poll() 에 영원히 주차된 채가 됩니다. 다섯 번째 와처는 생성되지만 결코 스케줄링되지 않습니다. 바로 보고된 그 버그입니다. “이벤트가 불안정하다”가 아니라 “다섯 번째는 아무 작동도 하지 않는다”는 것이었습니다.
제가 가장 마음에 들었던 것은 diff가 아니라 리뷰에서 이어진 대화였습니다. 저는 Copilot에게 이를 더 자세히 설명해 달라는 코멘트를 남겼습니다:
가상 스레드의 목표가 바로 플랫폼 스레드 한계에서 벗어나는 것이 아니었나요? 그렇다면 Raspberry Pi 같은 4코어 프로세서에서 4개의 가상 스레드가 4개의 스레드를 블로킹하는 것이 어떻게 문제가 될 수 있죠?
전체 대화는 풀 리퀘스트에서 확인하세요. Copilot은 4개의 CPU 코어를 가진 Raspberry Pi의 사용과 보고된 문제를 연결 지을 수 있었습니다. 또한 문제에 대한 간단한 수정안과 함께, 조사 과정에서 발견한 몇 가지 추가 개선 사항을 제안할 수 있었습니다.
몇 가지 팁과 모범 사례를 공유해 주실 수 있나요?
- 어디를 찾아봐야 하는지 알려주세요: Pi4J 이슈 #622의 경우, 저는 두 개의 파일 경로를 추가했습니다. 이는 아주 적은 노력으로 대규모 코드베이스에서 방대한 양의 검색 작업을 없애주는 일입니다. 버그에 대해 전혀 모를 때도 보통 어느 근처인지에 대한 감은 있기 마련입니다. 그 정보를 도구에 알려주면 전체 코드를 조사할 필요가 없어집니다.
- 증거와 테스트를 요구하세요: “변경 사항을 검증하는 단위 테스트를 추가해 줘”라는 요청을 요즘 많이 합니다. 사실, '했다'고 해야겠죠. 이제는 제 지침 파일의 규칙이 되었으니까요. 이는 진단이 틀렸던 경우도 방지해 주는데, 테스트가 기존 코드에서 실패하지 않기 때문입니다.
- 이유를 물어보세요: 수정 내용을 이해하지 못하겠다면, 그렇게 말하고 물어보세요. 그 설명 역시 하나의 산출물이며 프로젝트 문서나 티켓, 풀 리퀘스트 안에 추가되어야 합니다. 나중에 그 정보를 읽는 모든 사람에게 도움이 됩니다. 예를 들어, 이것이 Pi4J 팀 내에서 네이티브 호출 시 가상 스레드 피닝(virtual thread pinning)에 대한 더 많은 질문을 촉발시키기도 했습니다.
- 주도권을 잡으세요: Pi4J의 이 모든 풀 리퀘스트는 병합되기 전에 메인테이너들의 검토와 승인을 거쳤습니다. 이것이 이 프로젝트에서 가장 잘 작동하는 모델입니다. 즉, 에이전트가 조사를 수행하고, 사람들은 출시되는 코드에 대한 책임을 지는 것입니다. 그뿐만 아니라 다른 제 프로젝트에서도 항상 도구가 생성한 코드를 검토합니다. 저는 항상 코드를 읽기 쉽고 유지 관리 가능한 상태로 유지하고 싶습니다. 도구가 중복된 메서드를 만들거나 다른 곳에 이미 존재하여 통합되어야 할 것을 다시 만들어내는 경우가 너무 흔합니다. 그것은 바로 여러분의 책임입니다. 요즘 AI 보조 코딩으로 매우 빠르게 작업할 수 있는데, 이는 곧 매우 빠르게 엉망을 만들 수도 있다는 뜻입니다. 그러지 마세요. 코드를 관리 가능한 상태로 유지하세요. 나중에 버그를 조사하거나 개선 작업을 해야 하는 동료들과 미래의 자신이 고마워할 것입니다.
태그:
작성:
수석 클라우드 애드버킷(Principal Cloud Advocate)
관련 게시물
AI & MLVS Code에서 GitHub Copilot 앱 세션을 계속하는 방법
GitHub Copilot 앱의 에이전트 세션을 대화 내용, 코드 변경 사항, 작업 컨텍스트를 잃지 않고 VS Code로 옮기는 방법을 알아보세요.
AI & MLGitHub의 시크릿 탐지 모델: 더 적은 노이즈로 더 많은 시크릿 찾기
GitHub의 컨텍스트 인식 시크릿 분류기는 탐지 품질을 개선하여 가중 수용률을 11.5% 높이고, 중간 스캔 실행 시간을 86% 단축합니다.
AI & MLGitHub Copilot 입문자용 앱: Copilot에게 코드베이스를 가르치는 방법
리포지토리에 사용자 지정 지침과 스킬을 추가하고, 사용자 지정 에이전트를 사용하고, Playwright 같은 MCP 서버에 연결하는 방법을 알아보세요.