정상혁정상혁

(이 글에서는 위키페디아의 정의에 따라 '카멜 케이스’를 UpperCamelCase와 lowerCamelCase를 포괄하는 개념으로 사용했습니다.)

자바나 코틀린에서 약어(acronym)가 클래스명이나 메서드명의 일부로 들어갈 때 최대 두 글자까지만 대문자로 표기하는 방식을 권장합니다. 비슷하게 카멜 케이스를 쓰는 자바스크립트와 같은 다른 언어에서도 이 관례가 무난하다고 생각합니다. 기존의 바꿀 수 없는 코드나 외부 라이브러리 사용 등으로 어쩔 수 없는 경우에는 전부 대문자로 쓰더라도 이를 최소화하는 노력을 하고 프로젝트 내부 문서로도 예외의 경우로 명시하면 좋습니다.

위의 관례는 약어 전체를 대문자로 표기하는 관례에 비해서 다음과 같은 장점이 있습니다.

  • 연속된 약어가 조합될 경우 단어 사이의 구문이 더 잘 인지됩니다.

    • 예: XMLRPCAPIURL vs XmlRpcApiUrl

  • 일관성을 유지하기가 더 쉽습니다.

    • 전부 대문자로 표기해야할 단어들을 따로 기억할 필요가 없습니다.

    • 사람마다 다르게 판단할 여지가 적은 단순한 규칙입니다.

    • 영향력이 큰 책이나 가이드에서 지지받고 있는 규칙입니다. 새로 합류한 구성원도 따를 가능성이 높습니다.

자바와 코틀린으로 나누어서 이 관례에 대해 참고할 수 있는 자료를 정리합니다.

자바의 관례

JDK 내부에서는 이 관례가 통일되어 있지 않습니다. 다음과 같이 약어를 쓸 때 전부 대문자와 첫 글자만 대문자 표기가 혼재하고 있습니다.

  • java.net.HttpURLConnection (한 클래스 이름에서도 Http는 첫글자만 대문자, URL은 다 대문자로 표기했습니다.)

  • javax.xml.bind.annotation.XmlElement

Effective Java의 3판에서는 약어라도 첫글자만 대문자로 하는 방식에 대한 지지도를 더 높인 느낌입니다. 2판의 Upppercase may be more common 문구가 `Some programmers still use uppercase`로 바뀌었습니다.

:camel-casing

3판에서의 해당 단락의 전체 내용은 아래와 같습니다.

Item 68: Adhere to generally accepted naming conventions (원서 289~290 페이지)
There is some disagreements as to whether acronyms should be uppercase or have only their first letter capitalized. While some programmers stil use uppercase, a strong argument can be made in favor of capitalizing only the first letter: even if multiple acronyms occur back-to-back, you can still tell where one word starts and the next word ends. Which class name would you rather see, HTTPURL or HttpUrl?
아이템 68: 일반적으로 통용되는 명명 규칙을 따르라 (번역서 382 페이지)
약자의 경우 첫 글자만 대문자로 할지 전체를 대문자로 할지는 살짝 논란이 있다. 전체를 대문자로 쓰는 프로그래머도 있지만, 그래도 첫 글자만 대문자로 하는 쪽이 훨씬 많다. HttpUrl처럼 여러 약자가 혼합된 경우라도 각 약자의 시작과 끝을 명확히 알 수 있기 때문이다. (HTTPURL과 비교해보자)

자바 초창기에 비해 점점 첫 글자만 대문자로 쓰는 점유율이 높아졌다고 해석될만도 합니다.

스프링 프레임워크에서도 초창기에는 두 방식이 혼재하다가 점점 첫글자만 대문자로 쓰는 관례로 바뀐 것으로 보입니다. URL 단어 표기는 다음과 같은 예시가 있습니다.

DAO, XML, SQL 등은 모두 처음부터 첫글자만 대문자로 표기된 것으로 보입니다.

코틀린의 관례

코틀린 언어 사이트의 코딩 컨벤션 가이드에서도 약어의 표기 방식에 언급하고 있습니다. 약어가 두 글자라면 다 대문자로 쓰고, 길어지면 한 글자만 대문자로 쓰라고 권장하고 있습니다.

Choose Good names
When using an acronym as part of a declaration name, capitalize it if it consists of two letters (IOStream); capitalize only the first letter if it is longer (XmlFormatter, HttpInputStream).
좋은 이름을 선택해라
선언된 이름의 일부에 약어가 들어 갈 때는 두 개의 문자로 구성된 약어는 대문자로 쓰고(IOStream) 긴 문자는 첫 글자만 대소문자로 쓰세요. (XmlFormatter, HttpInputStream).

언어 공식 사이트의 가이드에 있는 내용이므로 보편적으로 인지되고 유지될 가능성이 높은 관례입니다.

필독 개발자 온보딩 가이드

Jackson으로 JSON을 파싱한 속성값을 객체의 생성자로 전달할 수 있는 여러가지 방법을 정리했습니다.

정상혁정상혁
Table of Contents
Cover

감상

(내돈내산 후기입니다)

많지 않은 분량으로 실무 개발자의 폭넓은 업무를 다루면서 결코 얄팍하지 않은 지식을 전달하는 책입니다. 협업, 설계, 구현, 테스트, 문서화, 긴급 대응, 경력 관리 등 다양한 분야에 대한 알찬 조언을 책 한권에 눌러 담았고 더 많은 분량을 학습하고 싶은 독자를 위한 참고자료들도 매 장마다 소개하고 있습니다.

이 책은 신입 개발자를 대상으로 한 책으로 홍보되고 있지만 경력이 많은 개발자가 읽을만한 가치도 충분합니다. 저도 과거의 경험을 돌아보면서 생각을 정리할 수 있었습니다. 스스로 절실하게 얻은 교훈이 이 책에도 적혀 있는 보면 반가웠고 깊은 공감이 되는 문장들도 많이 만날수 있었습니다.

예를 들면, Dark launching이나 Feature toggle 같이 제 경험에서 유용했던 기법이 개발 실무의 액기스를 전하는 이 책에서도 소개되니 반갑고 안심이 되었습니다. 긴급 대응을 위한 당번(on call) 제도와 같이 더 개선을 해야 할 요소도 독서 후에 더 크게 느껴지기도 했습니다. 전에는 썼지만 근래에는 활용하지 않았던 Liquibase를 통한 DB 스키마 관리도 다음 프로젝트에서는 다시 시도해봐야겠다는 생각도 듭니다.

유용하다고 느낀 지침과 조언을 새겨두고 실천하기 위해 여러 번 읽어야겠다는 생각을 하면서 마지막 장을 덮었습니다.

의견 메모

책을 보다가 의견을 메모한 부분을 옮겨봅니다.

p102

예외는 일찍 던지고 최대한 나중에 처리하자.

최대한 나중에 처리하는 것보다는 적절한 추상화 레이어에서 처리하자는 것이 좋다고 생각한다. 예를 들면 사용자의 ID로 조회했을 때 DB 조회가 실패했을 때 생기는 `EmptyResultDataAccessException`을 어플리케이션 콜스택의 마지막에서 처리하기보다는 비지니스 로직을 다루는 레이어에서 `UserNotFoundException`과 같이 비지니스 맥락의 의미가 부여된 예외로 바꾸는 것이 좋을 때도 있다.

p204

기능 브랜치 기반 개발은 트렁크의 코드가 사용자에게 릴르스하기엔 너무 불안정해서 트렁크를 안정화시키는 동안 개발자가 기능 개발을 수행할 수 없는 경우에 사용하는 방법이다. 고객이 각자 다른 버전의 소프트웨어를 사용하는 경우에 보편적으로 기능 브랜치 기반 개발 전략을 채택한다. 서비스 지향 시스템(service-oriented systems)은 일반적으로 트렁크 기반 개발 전략을 채택한다.

가장 보편적인 기능 브랜치 전략은 2010년 빈센트 드리센이 소개한 깃플로(Gitflow)라고 부르는 전략이다.

Git-flow는 필요에 따라 팀 브랜치 정책의 종착역은 될수 있지만 시작점으로 권장하고 싶지는 않다. 자세한 의견은 Git-Flow에 대해서 다시 생각해보기라는 글로 따로 정리했다.

p212

버전 제어 시스템을 릴리스 리포지토리처럼 사용할 수는 있지만 원래 용도라고 보기 어렵다. 버전 제어 시스템에서는 검색이나 배포 관련 기능을 별로 제공하지 않는다. 대규모 배포를 위해 만들어진 시스템이 아니므로 그런 상황에서는 문제를 일으킬 수도 있다. 버전 제어 시스템 머신과 동일한 머신이 개발자 체아크웃, 도구로부터의 요청, 배포 요청을 모두 담당하면 프로덕션 배포에 영향을 미칠 수 있다.

Node.js나 Go언어의 오픈소스 생태계에서는 GitHub.com을 릴리스 리포지토리처럼 쓰는 관행이 굳어졌다. 하지만 사내에서라면 이를 분리하는 것이 좋다는 저자의 의견에 동의한다. 버전 관리 시스템은 GitHub Enterprise를 쓰더라도 릴리스 저장소는 Nexus나 Artifactory를 쓰는 식이다. 분리하면 두 시스템을 각각 업그레이드하기에도 유리하다.

p213

릴리스는 최대한 자주 수행하자. 릴리스 주기가 늘어지 거짓된 안정감을 심어줄 수 있다. 즉 릴리스 사이의 주지가 길면 변경사항을 테스트할 충분한 시간이 있는 것처럼 느껴지기 때문이다. 실제로 릴리스 주기를 짧게 가져가면 더 안정적인 소프트웨어를 구현할 수 있어 버그가 발견됐을 때 더 쉽게 처리할 수 있다. 매 주기마다 릴리스되는 변경사항의 수가 더 적으므로 각 릴리스의 위험도도 낮아진다.

공감한다. 1~2주에 한번 릴리스하는 조직과 한달에 한번 릴리스하는 조직을 비교했을 때 후자의 릴리스가 훨씬 힘겹고 위험한 일이 되는 현상을 몇 번 목격했다. 테스트와 모니터링의 자동화 수준이 높아져야 릴리스의 비용이 적어져서 더 자주 릴리스하게 될 수 있기도하다.

p212

배포를 원자적으로 만드는 가장 쉬운 방법은 기존에 설치된 소프트웨어를 덮어쓰는 것이 아니라 다른 경로에 소프트웨어를 설치하는 것이다. 일단 패키지가 설치된 다음에는 단축 아이콘이나 심볼릭 링크를 이용해 교체하면 된다.

(의견) 많이 쓰던 기법이다. 사내 배포 시스템에서 디폴트로 제공이 되기도한다. 이동욱 님이 발표한 우아한스프링배치 발표에서도 이 기법을 응용한 무중단 배포를 소개하고 있다. 배포된 최신 버전 파일로 심볼릭 링크를 교체하고 (ln -s -f v2.jar app.jar) readlink 명령어로 그 파일을 실행하는(java -jar ${readlink ./app.jar}) 이용하는 방식이다.

p219

한 번에 모조리 새 코드로 전환하는 일은 위험하다. 테스트를 아무리 많이 해도 버그 발생 가능성을 없앨 수는 없으며 한 번에 모든 사용자에게 코드를 롤아웃하면 모두가 동시에 문제를 겪을 수 있다. 따라서 변경 사항을 점진적으로 롤아웃하고 시스템 상태 지표를 모니터링 하는 편이 좋다.

규모가 있는 시스템을 변경하는 개발자라면 절실하게 읽어야할 문장이다.

p311

데이터베이스 스키마 마이그레이션 도구인 Liquibase 등을 소개함.

데이터베이스와 애플리케이션 수명주기를 결합해서는 안 된다. 애플리케이션 배포 과정에서 스키마를 마이그레이션하는 것은 위험하다.

의도한 바은 아니지만 JPA의 스키마 관리 기능이 운영환경에서 실행되어서 발생하는 장애를 종종 전해듣는다. 스프링 부트의 spring.jpa.hibernate.ddl-auto 같은 옵션도 Local PC에 DB가 따로 설치되어 있거나 Embeded DB를 쓸때만 활성화해야 한다고 생각한다. 공용 개발 DB에서부터는 Liquibase와 같은 스키마 관리 도구를 활용하는 것이 좋다. 공용 개발 DB라도 여러 개가 있는 것이 다양한 테스트를 하는데 유리하고, 개발 DB가 여러개가 되면 스키마 관리 도구의 필요성이 높아진다. Oracle 등 개발자가 여러 인스턴스를 설치하는데 제약이 있는 DB를 오랫동안 써 온 개발자는 이런 도구의 필요성을 느끼거나 적용할 수 있는 기회를 얻기가 어려울 수도 있다.

운영DB는 DBA가 따로 SQL파일을 실행해서 스키마를 반영하는 회사라도 Liquibase는 충분히 사용 가능하다. Liquibase는 오프라인 지원 기능이 있어서 실제 DB에 스키마 변경을 실행하지 않고 DDL을 파일로 뽑아낼수도 있다. 예를 들어 스키마 버전 1.0.0-RC1과 1.0.0-RC2 버전 사이에 변경된 컬럼을 반영하는 DDL을 담은 .sql파일을 뽑을 때는 아래 명령어로 가능하다.

rm target/release.csv
mvn liquibase:updateSQL -Dliquibase.url='offline:mysql?changeLogFile=target/release.csv' -Dliquibase.toTag=1.0.0-RC1
mvn liquibase:updateSQL -Dliquibase.url='offline:mysql?changeLogFile=target/release.csv' -Dliquibase.toTag=1.0.0-RC2

추천자료

이 책에서는 각 장의 끝무렵에 ’레벨업을 위한 읽을 거리’로 해당 장에서 다룬 주제를 더 깊이 있게 학습하는데 도움이 되는 자료를 추천했습니다. 여러 번 언급되는 구글의 SRE 관련 책들은 https://sre.google/books/ 에서 무료로 열람도 가능합니다.

표기된 제목이 여러가지 이유로 달라진 책들은 다음과 같습니다.

2장 역량을 높이는 의식적 노력

4장 운영 환경을 고려한 코드 작성: 개발환경과 프로덕션 환경은 엄연히 다르다.

5장 피할 수 없는 코드 의존성의 관리: 복잡한 프로그램을 짜봐야 비로서 깨닫는 의존성이 진실

7장 올바로 주고받는 코드 리뷰: 원만한 팀 협업과 높은 코드 품질을 목표로

9장 긴급대응 온콜 업무

10장 견고한 소프트웨어를 위한 기술 설계 절차

11장 소프트웨어 수명주기를 고려한 진화하는 아키텍처 구현

12장 효율적인 협업을 위한 애자일 문화

13장 관리자, 팀장, 상사와 함께 일하기

정상혁정상혁

Git의 브랜치 전략으로 Git-flow가 가장 유명하고 자주 언급됩니다. 그런데 이 전략은 복잡도와 실행하는 난이도가 높은 편입니다. Git-flow를 쓰고 있다고 주장하는 조직에서도 창시자 Vincent가 제안한 원래의 프로세스를 그대로 쓰는 경우는 드물다고 느껴집니다.

Git-flow가 특히 인터넷 서비스 개발에서 보편적으로 권장할만한 전략일지는 저는 의문입니다. 브랜치 전략은 복잡하게 시작해서 단순하게 줄여나가기 보다는 단순하게 시작해서 필요에 따라 복잡도를 늘여가는 편이 시행착오가 적다고 생각합니다. 여러 버전을 동시에 운영하고 백포트 패치를 해야하는 설류션 개발에서는 Git-flow가 적합한 조직이 있을법도 합니다. 즉, Git-flow는 필요에 따라 종착역은 될수 있지만 시작점으로 권장하고 싶은 정책은 아닙니다.

Git-flow가 그 이름 때문에 필요 이상으로 권장되고 있다고 저는 생각합니다. Git이 지금보다 대중화되지 않았을 때 제안된 모델이고 그 당시 다른 유명한 모델이 없겠기에 Git-flow라고 불리지 않았을까 추정하기도합니다. 만약 창시자의 이름을 딴 Vincent-flow정도의 이름이였다면 많은 사람들이 따르려고 생각하지 않았을지도 모릅니다. Git-flow가 유용해보인다면 그 이름이 Vincent-flow라도 마찬가지일지를 한번 돌아봐도 이름에 과도하게 끌린건 아닌지 돌아보는데 도움이 될듯합니다.

뱅크 샐러드에서는 Git-flow보다 더 단순한 전략으로 리뷰-배포 프로세스를 개선했다는 사례도 있습니다.

먼저 Git-flow를 활용한다면 하나의 기능을 배포하는 데 있어서 무려 5번의 branch switching이 필요하고, 6번의 Pull Request와 이에 따른 6번의 Code Review가 필요했습니다. 이 말은 다르게 말하면 코드 오너가 6번이나 코드를 리뷰하고 승인을 해줘야 한다는 것이죠. 이렇게 복잡한 프로세스는 자연스럽게 배포를 귀찮은 존재로 만듭니다. 이로 인해 간단한 수정 사항의 경우 develop branch에 merge 한 뒤 배포하지 않는 일이 종종 발생하기 시작했습니다. 이런 배포되지 않은 변경 사항이 쌓이면서 나중에 필요할 때 한 번에 너무 많은 변경사항을 포함한, 부담스러운 배포를 진행해야만 했습니다. 배포 시 변경 사항이 많을수록 장애가 발생할 수 있는 확률은 당연히 증가하기 때문에 개발자에게는 배포는 무서운 존재가 되었습니다.

저는 GitLab-flow정도면 많은 사람이 협업하는 인터넷 서비스를 개발하는 브랜치 전략으로도 괜찮다고 생각합니다. 이를 참고해서 필요한 나름의 정책을 추가로 정의할 수도 있겠습니다.

Git-flow의 창시자 Vincent Driessen는 그의 아티클에 10년간의 회고를 덧붙였습니다. 거기서 지속적인 배포를 하는 프로젝트에서는 GitHub-flow와 같은 더 단순한 모델을 권장한다는 언급을 했습니다.

If your team is doing continuous delivery of software, I would suggest to adopt a much simpler workflow (like GitHub flow) instead of trying to shoehorn git-flow into your team.

귀사의 팀이 지속적으로 소프트웨어를 제공하고 있다면, 귀사의 팀에 git-flow를 도입하는 대신 훨씬 간단한 워크플로우(GitHub flow와 같은)를 채택하는 것을 제안합니다.

(번역은 파파고에게 맡겼습니다.)

많은 조직에서는 특히 운영 환경에서는 지속적인 배포(continuous delivery)와는 먼 프로세스를 택하고 있을 수도 있습니다. 그럼에도 개발과 테스트 환경에서라도 자주 활발히 통합되어 테스트되고 리뷰되는걸 추구한다면 Vincent의 회고를 더 깊이 새겨둘만합니다.

아래 문장으로 Vincent의 10년만의 회고는 끝이 납니다.

To conclude, always remember that panaceas don’t exist. Consider your own context. Don’t be hating. Decide for yourself.

결론적으로, 만병통치약은 존재하지 않는다는 것을 항상 기억하세요. 자신만의 맥락을 고려하세요. 미워하지 말고, 스스로 결정하세요.