나의 기술적인 기벽들
7512바이트
어디 메모도 안 해두고 바로 작성부터 들어간 글은 이게 처음이다. 다른 게 아니라, 프로필 단위(~/.config/AGENTS.md)로 에이전트 설정을 슬슬 적어두려는데 어차피 언젠가 써야지 싶었던 내용과 겹치기도 하고 블로그에 쓰던 형식으로 주절주절 적어두는 게 빠를 것 같아서 좀 적어두려 한다. 어째서 이걸 이제서야 하는지는 별개의 문제이고, AGENTS.md는 형식도 다르고 영어로 써두려는 작정이다. 분명 이게 다가 아닐 거라서 대충 한 바닥 적은 다음에, 점차 다듬어 나가려 한다.
언어
- 정적 타이핑, ADT와 패턴 매칭 등을 조합한 exhaustiveness check 등 컴파일 타임에 최대한 빠르게 오류나 문제가 검출될 수 있는 방식을 선호한다.
- pritimitive type을 지양하고 template literal, branded type 등 기존의 타입에 부가 정보를 포함해 타입 제약을 활용한다.
any,object와 같이 불필요하게 느슨한 타입은 사용하지 않는다.- nominal type보다는 structural type을 선호한다.
- 사용자 입력, 네트워크 응답 등 비정형 또는 신뢰할 수 없는 데이터는 항상 취득하자마자 타입 검사 후 캐스팅하여 사용한다.
TypeScript
- 가능하다면
Promise보다는await-async구문을 사용한다. - 불가피한 경우가 아니라면
const를 사용한다. - IIFE를 사용해 변수 범위를 최소화하거나 코드를 단순화할 수 있다면 그렇게 한다.
라이브러리
- 항상 의존성 관리 도구를 사용해 락파일, 버전 제약 등을 관리한다.
- 런타임 버전 또한 프로젝트에 포함한다.
- 어떤 동작을 구현하기 전에 표준 라이브러리 또는 de facto 라이브러리가 있는지 확인한다.
- 서드 파티 라이브러리의 경우 프로젝트가 활발하게 관리되고 있는지, 불필요한 의존성이 없는지 등을 확인한다.
- 상용보다는 오픈 소스를 사용한다.
코드 형식
변수와 함수
- 변수와 함수의 선언 범위는 항상 최소한으로 한다.
- 변수와 함수의 이름은 길더라도 선언적이고 명료하도록 짓고, 특별한 이유가 없다면 약자 사용을 자제한다.
- 대소문자는 언어 표준을 따르되 두문자어
HTTP, URL등은Http,Url`과 같은 방식을 선호한다. - 반복문, 익명 함수 등에 있어서 변수가 하나 또는 두 개인 경우
x(임의의 값),i(인덱스),k, v(키 값 쌍)와 같이 짧은 이름을 사용한다.- 단, 비슷한 역할의 변수가 중첩되는 경우 1, 2 등을 붙이지 않고 보다 명료한 이름을 사용한다.
- hoisting 등으로 의도하지 않은 방식의 접근이 가능하지 않도록 주의한다.
- HTTP 상태, 언어 코드 등의 경우 상수를 따로 정의하기 전에 라이브러리에 이미 선언되어 있는 값이 있는지 확인한다.
- 특히 값이 많거나 타입이 비교적 단순한 경우, positional parameter보다 named paramter를 선호한다.
- 변수와 함수의 접근 가능 범위는 최소한으로 한다.
- 코드가 지나치게 복잡해지지 않는 선에서 불변형인 참조와 값을 선호한다.
주석
- 주석으로 섹션을 나누는 대신 함수와 같은 방식으로 쪼개어 동작을 구분한다.
- 이 코드가 무엇을 하는지 대신 이 코드가 왜 있는지, 상세하게 어떻게 동작하고 주의할 점은 무엇인지를 적는다.
- 그러나 코드의 자체적인 형식으로 더 명료하게 나타낼 수는 없는지 다시 점검한다.
- 주석 형식은 언어의 표준을 따르며 도구를 이용한 문서화가 용이하도록 한다.
- 코드 작성에 참고한 링크나 관련된 링크가 있다면 주석으로 적어둔다.
- 우회 코드, 임시 구현 등이 있다면 그 사실 또한 반드시 적어둔다.
일반
- 계층이나 역할보다는 소속 도메인을 우선으로 하여 디렉토리 구조를 선정한다.
- 한 파일이 지나치게 방대해지는 것을 지양하며 경우에 따라 200~300 줄 내외를 최대 한도로 한다.
- trailing comma, newline before EOF 등 VCS에서 추후 diff가 최소화될 수 있는 방식으로 작성한다.
- 기본적으로 비공개 변수의 접근 등 해서 안 되는 일은 물리적으로 불가하거나 오류가 발생하도록 구조를 잡는다.
설정 및 도구
- 모든 설정은 코드의 형태로 기록되어 추적과 관리가 가능해야 한다.
- 항상 린터와 포매터, 그리고 가능하다면 타입 체커를 사용한다.
- 이에 대응하는 VS Code 설정을 프로젝트에 포함한다.
- 항상 EditorConfig을 사용한다.
- 도구의 경고나 오류를 suppress하기 전에 실제로 해결할 수 없는지 점검한다.
- 불가피하다면 왜 무시 처리를 했는지 또한 주석으로 같은 줄에 적어둔다.
- 검증된 도구를 선택하되 단순 점유율만 고려하지 않고 현대적이며 검증된 대안이 있다면 그것을 고르도록 한다.
- 프로젝트는 그 자체로 완결성을 갖추어야 하며 구동 등에 필요한 도구와 환경이 전부 갖추어져 있도록 한다.
- direnv와 Nix Shell을 사용한다.
- 민감한 정보의 취급은 SOPS를 표준으로 한다.
- 일반적으로 필요한 스크립트는
scripts/디렉토리에 포함한다.- 작성 시 항상 shebang을 사용하고 합리적인 선에서 portability를 고려한다.
- 도구나 라이브러리의 설정 시에는 항상 해당하는 버전의 README 또는 공식 문서를 참조한다.
테스트
- 유닛 테스트, 통합 테스트, 그리고 필요한 경우 E2E를 작성한다.
- 가급적 mock보다 테스트 구현체를 사용하도록 한다.
- private member 테스트는 지양하고 reflection 등 기술적 잔재주를 부리지 않는다.
- white-box testing은 지양하고 입출력과 행동 중심의 black-box testing으로 작성한다.
- 대략적으로 given-when-then 순서로 작성한다.
- 하나의 케이스는 하나의 사항만 검증할 수 있도록 노력한다.
- parameterized test를 통해 여러 케이스를 같은 코드로 검증할 수 있도록 한다.
- 테스트가 실패한 경우 stack trace가 올바르게 표시되도록 한다.
- assertion 또한 콘솔 출력으로부터 즉각 실패 원인을 알 수 있도록 작성한다.
- 테스트 작성 시에는 일부 제약을 우회할 수 있으나 임시 방편의 일환으로서 소스 코드를 수정하지는 않도록 한다.
VCS
- 커밋의 범위는 논리적으로 가능한 최소 단위로 한다.
- 커밋 메시지는 접두사(
prefix:)를 사용하지 않고, 대문자로 시작하는 plain English로 작성한다.- 커밋의 목적이나 이유가 아니라 어떤 변경을 담고 있는지 작성한다.
- 커밋 메시지가 모호하게 느껴진다면 커밋을 분리하는 등 범위를 조정할 수 없는지 확인한다.
- 목적과 이유 등 부가 정보를 포함해야 한다면 두 번째 메시지로 들어가도록 한다.
- 에이전트가 작성한 코드는 항상
Co-authored-by:trailer를 포함한다.
CI/CD
- GitHub Actions를 표준으로 한다.
- 필요한 secret의 개수는 최소로 한다.
- 코드 블락이 길지 않다면 각 스텝의 이름은 별도로 지정하지 않는다.