팀 이름을 DevOps가 아니라 Cloud Platform으로 지은 이유 채용 공고를 둘러보면 인프라를 다루는 팀의 이름은 대개 셋 중 하나입니다. DevOps, Infra, Cloud. 플렉스팀에서 이 일을 하는 팀의 이름은 Cloud Platform입니다. 처음 듣는 분들은 거의 같…
코딩 에이전트가 Spring을 못 짠다면, component scan부터 걷어내 보세요 라이브러리 버전을 올리던 중 컨트롤러 테스트 하나가 10번 실행해 10번 모두 실패했습니다. 로그에는 같은 이름의 빈이 두 번 정의됐다는 BeanDefinitionOverrideException이 남…
설정값에서 OpenFeature까지, 피처 플래그는 어떻게 바뀌어 왔을까요 2012년 8월 1일 아침, Knight Capital의 주문 시스템에서 오래전에 사용을 멈춘 Power Peg 코드가 다시 실행됐습니다. 45분 동안 154개 종목에서 약 4백만 건의 체결이 발생했습니다. 이…
Spring Boot 4.1까지 나온 지금, 무엇이 바뀌었고 무엇을 먼저 준비해야 할까요 Spring Boot 4로 올린 서비스 하나가 기동조차 하지 못한 적이 있습니다. 로그는 짧았습니다. 보안 설정 클래스가 Jackson2ObjectMapperBuilder 빈을 주입받으려 했는데,…
"다 됐습니다" 알림, 대체 언제 보내야 맞나 완료 알림이 실제보다 먼저 나갔다 버튼 한 번 누르면 시작되는데 끝나기까지는 한참 걸리는 작업이 있습니다. 쌓인 걸 한 번에 몰아서 처리하거나, 대량으로 뭔가를 찍어내는 배치성 작업이요. 시작한 사람은 화면 앞에 앉아 기다리지 않죠. 걸어두…
@TransactionalEventListener는 왜 조용히 무시될까 어느 날 검색 색인에 빠진 문서가 하나 발견됐습니다. 저장은 분명히 됐고, 화면에도 정상으로 떠 있는데, 검색으로는 잡히지 않았습니다. 저장이 끝나면 색인을 갱신하도록 이벤트를 발행하고, 그 이벤트를 받는 리스너가…
격리 안 된 테스트의 초록불은, 에이전트가 믿을 수 없습니다 테스트를 짤 시간이 없던 시대는 끝났다 예전에는 테스트를 못 짜는 이유가 대개 시간이었습니다. 기능을 먼저 붙이고, 테스트는 여유가 생기면 쓰기로 미뤄 두다가 결국 못 쓰는 일이 흔했죠. 그런데 이제는 에이전트가 그 테스트를…
모놀리식인데, 도메인 하나만 따로 띄웁니다 명령 한 줄로 뜨는 것 저희 백엔드에서 이슈 도메인은 프로덕션에서 혼자 돌지 않습니다. 앞에 Gateway가 있고, 옆에 인증 서버가 있고, 채번이나 조직 조회 같은 걸 다른 도메인 서비스에 물어봅니다. 정상입니다. 실서비스는 원래 그렇게 얽혀…
@Scheduled 한 줄로 버티다, 트리거를 밖으로 꺼낸 이야기 Pod를 세 개로 늘렸는데, 같은 작업만 세 번 돌았습니다 5분마다 실행되는 배치가 있었는데, 대상이 만 건을 넘자 한 회차에 8분이 걸리기 시작했습니다. 이전 회차가 끝나기도 전에 다음 실행 시각이 돌아온 것입니다. 처…
사람도 에이전트도, 덜 읽을수록 더 잘 고칩니다 여섯 개의 파일 한 진단 작업의 기록을 펼쳐 봤습니다. 에이전트에게 정산 원장에 의심스러운 대목이 있으니 확인해 보라고 시킨 작업입니다. 재봉인을 하면 옛 원장 라인이 남아 새 값과 이중으로 잡히는 것 아니냐는 의혹이었죠. 에이전트가 그…
헥사고날 아키텍처, Adapter만 바꾸면 될까 파일 저장소를 다른 클라우드로 옮겨보니, 손댈 것의 절반은 Adapter 밖에 있었습니다 파일 저장소를 AWS S3에서 다른 클라우드의 오브젝트 스토리지로 옮기는 작업을 했습니다. 저장 백엔드를 갈아 끼우는 일이니, 헥사고날 아키텍처를 설…
경계를 빌드로 못 박으면, 경계를 옮기는 일도 빌드가 붙잡습니다 지키는 힘과 붙잡는 힘은 같은 힘이다 계층 경계를 물리적인 Gradle 모듈로 쪼개서 컴파일러에게 지키게 하는 방식은, 저희 팀이 오래 써 온 방법입니다. 도메인 코어는 인프라를 몰라야 한다는 규칙이 리뷰어의 눈이 아니라…
사람은 떠났는데 권한은 남았다 김팀장은 여전히 급여를 볼 수 있다 먼저 한 장면부터 말씀드리겠습니다. 김팀장이 마케팅 부서에서 개발 부서로 자리를 옮겼습니다. 인사 시스템에는 이동이 반영됐고, 조직도도 다시 그려졌습니다. 그런데 인가 시스템 안에서는 김팀장이 아직 마케팅 부서의 매니저로…
AI가 하한선을 올린 순간, 저희는 직무를 다시 그리기로 했습니다 이미 경계는 넘어가고 있었습니다 어느 순간부터 팀 안에서 낯선 장면이 자주 보였습니다. PM이 직접 프로토타입을 만들어 왔습니다. PD가 디자인 시스템을 붙잡고 제품 화면을 조립했습니다. BE 개발자가 간단한 프론트 수정…
DDL이 코드 밖에서 온다면, 테스트 DB 구성을 빌드 안에 선언한다 DDL이 코드 밖에 있었다 전제 하나부터 분명히 하겠습니다. 저희 조직에서 스키마의 진실은 애플리케이션 코드가 아닙니다. Hibernate가 엔티티를 보고 테이블을 파생시키는 것이 아니라, Liquibase chang…
제품을 만드는 시스템을 만드는 사람 인프라 운영이 아니라, 제품을 만드는 시스템을 만듭니다 Platform Engineer는 서버를 켜고 끄는 사람이 아닙니다. 저희가 만드는 것은 다른 팀이 제품을 더 빠르고 안전하게 만들도록 떠받치는 시스템입니다. 재사용 가능한 SDK, 배포 자동화,…
GitOps 하시면서, 배포 전에 뭐가 바뀔지 알고 계신가요 PR에서 안 보이는 것 저희 배포는 GitOps입니다. 배포의 출발점이 Git이라는 뜻입니다. manifests 레포의 어떤 브랜치가 곧 그 환경이 지금 원하는 상태이고, ArgoCD가 그 브랜치를 따라 Application을…
되도록 최신 버전을 사용하는게 왜 이렇게 어려울까? 해법 자체는 한 문단이면 말할 수 있습니다. 저희의 규칙은 놀랄 만큼 단순합니다 — 되도록 최신을 쓴다. 개별 레포가 "어느 버전을 박아둘까"를 고르는 대신, group name에 소속되면 그 family의 최신(검증된) 버전이 기본값…
[인프라를 소프트웨어처럼 5/5] 다섯 축의 운영 총합, 그리고 AI 시대의 플랫폼팀 모든 이야기가 가리키는 한 가지 지난 화에서 우리는 plan과 apply 사이를 테스트 가능성과 재현 가능성으로 건넜습니다. 그 앞으로는 배포·클라우드·시간·공간·테스트, 그리고 환경까지 차례로 지나왔…
[인프라를 소프트웨어처럼 4/5] plan은 동작을 모른다: 인프라를 테스트·재현한다는 것 환경을 브랜치로 찍어내려면, 그 아래가 단단해야 한다 지난 글에서 우리는 환경을 브랜치로 태어나게 했습니다. dev-variant/{이름} 브랜치를 push하면 격리된 환경이 통째로 생깁니다. 멋…
[인프라를 소프트웨어처럼 3/5] 환경은 브랜치에서 태어난다: Environment Variant 지난 글 끝의 그 사고에서 시작합니다 2화는 한 장면에서 끝났습니다. 환경은 만들기 어려웠고, 지우기는 더 어려웠으며, 그래서 아무도 지우지 않은 채 방치된 환경 하나가 어느 날 공유 de…
[인프라를 소프트웨어처럼 2/5] 코드가 모르는 그 '환경'은 누가 만드는가 "환경은 바깥에 있다"는 말의 빈칸 1화에서 우리는 다섯 축의 약속을 다시 꺼냈습니다 — 코드는 '무엇을'만 정의하고, '어디서·언제·어떤 환경'은 바깥에서 주입한다. 그리고 거기에 조용한 빈칸이 하나 있다고…
[인프라를 소프트웨어처럼 1/5] Infrastructure as Code, 그리고 그다음 terraform plan은 "바뀌는지"는 보여주지만 "되는지"는 모릅니다 인프라를 코드로 다뤄 본 사람이라면 익숙한 장면이 있습니다. 한 줄을 고치고 terraform plan을 돌립니다. 수십…
[의존성의 방향을 따라 5/5] Evergreen이 가능했던 이유 다시, 1화로 이 글들의 제목은 "의존성의 방향을 따라"입니다. 의존성이 향하는 방향을 따라 변경이 전파되고, 그 전파를 자동화하는 Evergreen 파이프라인을 네 편에 걸쳐 살펴봤습니다. 마지막 화에서는 한 발 물러서…
[의존성의 방향을 따라 4/5] PR을 전파하는 Distributer 코드가 바뀌었다. 그 다음은? 3화에서 Updater가 OpenRewrite와 Claude를 사용해 코드를 변환했습니다. 변환된 코드는 아직 로컬 브랜치에만 존재합니다. 이 변경을 실제로 각 레포에 반영하려면, PR을…
[의존성의 방향을 따라 3/5] OpenRewrite와 Claude가 코드를 변환한다 Updater의 두 가지 무기 Planner가 전파 순서를 결정하면, Updater가 각 레포에서 실제 코드 변환을 수행합니다. Updater에게는 두 가지 무기가 있습니다. - OpenRewrite…
[의존성의 방향을 따라 2/5] 의존 그래프를 읽는 Planner 레포 사이에도 의존성이 있다 하나의 레포 안에서 모듈 간 의존성은 build.gradle.kts의 dependencies 블록으로 명확하게 드러납니다. 하지만 레포 간 의존성은 어떨까요? 레포들은 Nexus를 통해 아티팩…