지난 한 달은 뉴스레터보다 회사에 조금 더 많은 시간을 쏟아부었던 시간이었어요. 서비스를 만들고 운영하는 일부터 새로운 기능 실험, 제품 방향성 검증, 그리고 예상치 못한 문제 해결까지 여러 가지 일을 동시에 진행하다 보니 정신없이 시간이 흘러갔네요.
AI 덕분에 예전보다 훨씬 많은 일을 더 빠르게 할 수 있는 시대가 되었지만, 지난 한 달 동안은 한 가지 사실을 다시 실감하기도 했어요. 결국 많은 일을 지속적으로 해내기 위해서는 사람의 체력이 뒷받침되어야 한다는 점이에요. 도구는 강해졌지만, 그것을 꾸준히 활용하고 판단하고 실행하는 사람의 에너지가 바닥나면 속도도 품질도 함께 흔들릴 수밖에 없더라고요.
아직 눈에 띄는 성과를 이야기할 단계는 아니에요. 하지만 한국에 있을 때보다 훨씬 다양한 시도를 해보고 있고, 이전에는 생각해보지 못했던 새로운 방식으로 제품을 만들고 실험하고 있어요. 결과보다 과정에서 배우는 것이 많은 시기이기도 하고, 메이커로서의 경험치는 그 어느 때보다 빠르게 쌓이고 있다는 느낌을 받고 있어요.
다만 그 과정에서 퇴근하면 그대로 잠들어버리는 날들이 많아졌고, 자연스럽게 뉴스레터 발행도 예정보다 많이 늦어졌어요. 기다려주신 분들께 양해와 감사의 말씀을 드립니다.
흥미롭게도 지난 5월의 Ruby와 Rails 소식의 큰 흐름 역시 화려한 신기능보다는 운영과 안정성, 그리고 기본기에 가까웠어요. Ruby 4.0의 보안 업데이트부터 Rails의 안전한 기본값, 그리고 실제 운영 환경에서 쌓여가는 작은 습관들까지. 서비스를 오래 운영하기 위해 필요한 것들이 무엇인지 다시 생각하게 만드는 이야기들이 많았어요.
🎧 10분 요약 오디오로 들어보시겠어요? → YouTube로 듣기
새로운 소식
Ruby 4.0은 이제 운영 모드로 들어섰어요
2026년 5월의 Ruby 소식은 “새로운 기능”보다 “운영 중인 런타임을 어떻게 안전하게 유지할 것인가”에 가까웠어요. Ruby 4.0.5가 릴리스됐고, 핵심은 getaddrinfo timeout handler에서 발견된 use-after-free 취약점인 CVE-2026-46727 수정이에요. Ruby 4.0.0부터 4.0.4까지 영향을 받으며, Addrinfo.getaddrinfo(..., timeout:)나 Socket.tcp(..., resolv_timeout:)처럼 DNS resolution timeout을 직접 사용하는 코드가 있다면 업데이트 우선순위가 높아요.
같은 달 RubyGems.org에서는 신규 가입이 일시 중단되는 일도 있었어요. RubyGems 측은 DDoS와 스팸성 패키지 발행 캠페인에 대응했고, bot 계정을 차단하고 악성 또는 스팸성 패키지를 yanked 처리했어요. 기존 gem 설치와 기존 사용자 push는 영향을 받지 않았지만, 이 사건은 gem registry가 Rails 앱의 공급망에서 얼마나 중요한 신뢰 경계인지 다시 보여줬어요.
- RubyGems.org Status - Spam and DDoS incident
- RubyGems Suspends New Signups After Spam Package Campaign
개인 개발자 글 중에서는 Brad Gessler의 A Ruby Timeout that works가 이 흐름과 잘 맞아요. 글은 Anthropic API 호출에 걸린 background job이 멈추면서 worker와 ActiveRecord connection pool까지 잠식한 사례에서 출발해요. Ruby의 Timeout.timeout이 blocking syscall을 실제로 끊지 못한다는 오래된 문제를 짚고, Linux의 TCP_USER_TIMEOUT을 Ruby에서 사용할 수 있도록 만든 tcp_user_timeout gem을 소개해요.
Sidekiq, Solid Queue, GoodJob 같은 background job 환경에서 외부 API timeout을 어디까지 믿을 수 있는지 다시 생각하게 해주는 글이에요. Ruby 4.0.5의 timeout 관련 보안 릴리스와 함께 읽어보면, “timeout은 설정값 하나로 끝나는 문제가 아니다”라는 점이 더 분명해져요.
이번 달 운영 체크포인트는 꽤 분명해요. Ruby 4.0을 사용 중이라면 4.0.5 이상으로 올리고, bundle-audit이나 RubySec 기반 점검을 다시 돌려보는 것이 좋아요. Devise, Faraday, ruby-jwt, sidekiq-cron처럼 Rails 앱에서 자주 쓰이는 gem들의 5월 보안 공지도 함께 확인해볼 만해요.
Rails main은 화려한 기능보다 “안전한 기본값”을 쌓는 중이에요
5월의 Rails main 브랜치는 한 번에 눈에 띄는 큰 기능보다, 오래 운영되는 앱에서 중요한 작은 개선들이 많았어요. 새 Rails 앱에는 config/bootsnap.rb를 통해 frozen string literal을 활성화하는 기본값이 들어갔고, RuboCop 설정도 이에 맞춰 조정됐어요. 의존성 전체가 아니라 애플리케이션 코드에 적용되는 변화지만, Rails가 새 앱의 기본값을 조금씩 더 성능과 예측 가능성 쪽으로 옮기고 있다는 신호로 볼 수 있어요.
Active Job 쪽에서는 ActiveJob::Attributes가 추가됐어요. Job 안에서 타입이 있는 attribute를 선언하고, continuation 사이에서 해당 값을 serialize/restore할 수 있게 하는 기능이에요. 복잡한 job을 여러 단계로 나누거나 재개 가능한 workflow를 만들 때, 매번 serialize와 deserialize를 직접 만지는 코드를 줄여주는 방향이에요.
Active Record 쪽에서는 매우 긴 문자열에 대해 무제한으로 to_i를 호출하지 않도록 제한하는 변화가 들어갔어요. 평소에는 잘 보이지 않는 경계 조건이지만, 긴 문자열 coercion이 DoS 벡터가 될 수 있다는 점을 고려한 방어적 수정이에요. 같은 주에는 PostgreSQL 18.4 이상의 NOT ENFORCED foreign key 지원, in_order_of의 배열 값 지원, Active Storage MirrorService 병렬화 같은 개선도 함께 소개됐어요.
월말에는 Action Cable server adapterization 작업이 소개됐어요. socket 처리, concurrency primitive, transport-specific behavior 같은 낮은 수준의 책임을 ActionCable::Server 추상화로 분리해요. 애플리케이션의 channel/connection 코드는 유지하면서도, 장기적으로 다른 server 구현이 들어올 수 있는 길을 여는 변화예요. 같은 업데이트에는 Ractor shareability shim, default_order, enum error message 개선, Active Record Pool Reaper thread leak 수정도 포함됐어요.
이 흐름을 한 문장으로 정리하면, Rails는 이번 달에도 “개발자가 매일 쓰는 API는 크게 흔들지 않되, 그 아래의 기본값과 경계 조건을 더 단단하게 만드는 중”이라고 할 수 있어요.
현실의 Rails 앱은 /config, 배포 순서, 작은 운영 습관에서 완성돼요
Ben Sheldon의 One year of Ruby on Rails configuration은 이번 달에 꼭 소개하고 싶은 개인 글이에요. GoodJob을 만든 Ben은 새 Rails 앱을 1년 동안 운영하면서 /config 디렉터리에 쌓인 monkey patch, initializer, app-wide behavior를 공개했어요.
Rails의 “convention over configuration”은 여전히 강력하지만, 실제 제품을 1년 운영하다 보면 팀의 도메인과 취향, 운영상의 판단이 /config에 자연스럽게 스며들어요. 이 글은 그 과정을 솔직하게 보여줘요.
예를 들어 PostgreSQL의 datetime을 timestamptz로 다루는 설정, Capybara 설정, custom type 등록, Turbo와 함께 쓰기 위한 dom_target, GoodJob과 UUIDv7 관련 설정처럼 “이론적인 Rails”가 아니라 “실제 제품의 Rails”에서 만나는 선택들이 담겨 있어요. 이 글의 재미는 정답을 제시한다기보다, Rails 앱이 시간이 지나며 어떻게 자기만의 운영 문법을 갖게 되는지 보여준다는 데 있어요.
운영 팁으로는 Akshay Khot의 How to Safely Drop Columns in Rails도 좋아요. 글은 ActiveRecord가 production boot 시점에 model schema를 cache하기 때문에, column을 바로 drop하면 old process가 이미 삭제된 column을 참조해 장애가 날 수 있다는 문제를 설명해요. 해결책은 먼저 ignored_columns로 ActiveRecord가 해당 column을 보지 않게 배포하고, 그다음 migration으로 실제 column을 삭제하는 2단계 절차예요.
Kamal을 여러 host에서 사용할 때의 migration 문제도 나왔어요. t27duck은 Running Migrations Once During a Multi-Host Kamal Deploy에서 여러 web host가 동시에 뜨면서 각 container가 db:prepare를 실행하고, migration advisory lock을 두고 경쟁하는 문제를 다뤘어요. 해결책은 Kamal pre-deploy hook에서 migration을 한 번만 실행하고, container entrypoint에서는 migration 실행을 제거하는 방식이에요. Rails 8 이후 Kamal 배포가 더 보편적인 흐름이 된 만큼, 실제 운영 환경에서 꽤 유용한 글이에요.
작은 view helper 습관도 놓칠 수 없어요. Andy Croll은 Stop usinghtml_safe서 html_safe 대신 tag, safe_join, sanitize를 쓰자고 이야기해요. 문자열을 직접 이어 붙인 뒤 html_safe를 호출하면 Rails의 XSS protection을 우회할 수 있기 때문에, HTML element를 만들 때는 tag, 조각을 합칠 때는 safe_join, 사용자 제공 HTML을 받아야 할 때는 sanitize를 쓰는 편이 더 안전해요.
이 섹션의 핵심은 단순해요. Rails 앱의 안정성은 큰 아키텍처 결정에서만 나오지 않아요. /config에 쌓이는 작은 결정, migration을 배포하는 순서, timeout을 어디에서 강제할지, view helper에서 어떤 문자열을 신뢰할지 같은 습관들이 결국 production Rails의 품질을 만들어요.
Ruby 개발 도구는 “대규모 코드베이스를 이해하는 방향”으로 움직이고 있어요
5월의 도구 관련 소식 중 가장 큰 흐름은 Ruby 생태계가 대규모 코드베이스를 더 잘 이해하기 위한 공통 기반을 만들고 있다는 점이에요. Shopify의 Rails at Scale 팀은 Rubydex를 소개했어요. Rubydex는 코드 인덱싱과 타입 분석을 위한 portable static analysis engine으로, Ruby LSP, Tapioca, Packwerk, Spoom 같은 도구들이 반복해서 구현하던 기반 기능을 하나의 엔진으로 모으려는 시도예요.
Rubydex가 흥미로운 이유는 “하나의 완성된 개발자 도구”가 아니라 “다른 도구들이 올라탈 수 있는 엔진”이라는 점이에요. 클래스, 모듈, 상수, 메서드 정의 수집, RBS 문서 인덱싱, constant reference 해석, ancestor chain linearization, descendant 추적 같은 기능을 제공하고, Rust, C, Ruby API로 여러 환경에서 사용할 수 있도록 설계됐어요. Ruby LSP나 Packwerk 같은 도구가 더 정확하고 빠르게 동작하기 위한 기반이 되는 셈이에요.
개인 글로는 Janko Marohnić의 Extending Ruby LSP with Prism이 이 흐름을 잘 보여줘요. Janko는 Ruby LSP add-on을 만들어 Rails view template 안의 render partial 호출에 “Go to Definition”을 붙이는 과정을 설명했어요. Prism AST를 따라가며 render 호출을 찾고, 해당 partial 파일 경로를 찾아 editor location으로 돌려주는 흐름은 Ruby/Rails 개발 경험이 점점 더 현대적인 IDE와 LSP 환경으로 이동하고 있음을 보여줘요.
ERB 쪽에서는 GitHub의 Herb 도입기가 인상적이었어요. Joel Hawksley는 Adopting Herb at GitHub에서 GitHub.com Rails monolith에 Herb를 적용한 경험을 공유했어요. GitHub에는 약 50만 줄의 ERB와 약 1만 개의 ERB 파일이 있고, Herb는 기존 tooling과 테스트가 놓친 invalid HTML과 ERB 안의 invalid Ruby를 찾아냈어요. 다만 production 적용에는 boot time과 compile performance 같은 과제가 남아 있다는 점도 솔직하게 다뤘어요.
성능 쪽에서는 Aaron Patterson의 A new Register Allocator for ZJIT도 함께 읽어볼 만해요. 새 allocator는 SSA form 기반 linear scan register allocator이며, ZJIT가 method 전체를 컴파일한다는 특성을 활용해 block 경계를 넘어 값을 register에 더 오래 유지할 수 있게 해요. 이 작업은 tight loop에서 불필요한 store/load를 줄이고, 앞으로의 method inlining을 위한 기반 작업이기도 해요.
이 모든 소식을 묶어보면, Ruby의 개발 도구는 단순히 syntax highlight나 lint 수준을 넘어 “코드베이스 전체를 이해하는 도구”로 이동하고 있어요. Rails monolith가 커질수록, 그리고 AI 도구가 코드를 읽고 수정하는 비중이 커질수록, 이런 정적 분석 기반은 더 중요해질 가능성이 커요.
AI 시대에도 Rails다운 개발 방식은 테스트, 단순한 환경, 즐거운 언어 경험 위에 있어요
지난 소식에서 Rails와 AI의 흐름을 다뤘다면, 5월에는 그 흐름을 조금 더 실무적으로 볼 수 있는 글들이 나왔어요. Jason Swett의 My Agent Skill for Test-Driven Development는 AI agent가 테스트를 잘 쓰도록 어떻게 유도할 것인가를 다뤄요. Jason은 uncoached agent가 작성하는 테스트가 모호하거나 과하게 복잡하거나 의미 없는 경우가 많다고 지적하면서, Kent Beck의 Canon TDD에 가까운 방식으로 agent를 이끄는 TDD skill을 소개해요.
글에서 제안하는 흐름은 specify → encode → fulfill이에요. 먼저 만들 기능의 specification을 정리하고, 이를 automated test로 encode한 다음, 그 test를 만족하는 코드만 작성하게 하는 방식이에요. AI가 코드를 많이 쓰는 시대일수록 “얼마나 빨리 생성하느냐”보다 “무엇을 기준으로 생성하게 할 것인가”가 더 중요해진다는 점을 잘 보여줘요.
개발 환경 쪽에서는 Yaroslav Markin의 Bundlebun bundles Bun이 흥미로워요. Bundlebun은 Bun JavaScript runtime, package manager, builder를 Ruby gem으로 패키징해서 Gemfile 안에 넣고, bundle install만으로 팀 전체가 같은 JavaScript runtime을 쓰게 하려는 시도예요. 글은 단순한 gem 소개를 넘어, Sprockets, Webpacker, importmap, jsbundling/cssbundling, Rails의 #nobuild 흐름까지 돌아보며 Rails와 JavaScript runtime의 관계를 정리해요.
이 시도는 AI와 직접 연결된 도구는 아니지만, AI agent가 로컬 개발 환경이나 CI에서 코드를 실행해야 하는 일이 늘어날수록 “프로젝트에 필요한 runtime이 lockfile에 고정되어 있다”는 점은 더 중요해질 수 있어요. 사람이든 agent든 같은 환경에서 같은 명령을 실행할 수 있어야, 생성된 코드도 검증 가능해지기 때문이에요.
마지막으로 Caio Bianchi의 Why Ruby Still Feels Like Home After All These Years는 좋은 마무리 글이에요. Caio는 Ruby가 가장 빠르거나 가장 유행하는 언어는 아니지만, web application, background processing, internal tooling 같은 넓은 영역에서 여전히 개발자 행복을 준다고 이야기해요. Kamal, Solid Queue, GoodJob, JIT 개선처럼 최근 생태계의 변화도 언급하면서, Ruby가 조용하지만 계속 앞으로 가고 있다는 메시지를 전해요.
이번에 읽어 본 개인 글들을 종합해보면, AI 시대의 Rails 개발은 “AI가 코드를 대신 써준다”에서 끝나지 않아요. 테스트로 기준을 세우고, 실행 가능한 개발 환경을 단순하게 만들고, 큰 코드베이스를 이해하는 도구를 갖추고, 여전히 Ruby다운 표현력과 즐거움을 잃지 않는 방향으로 가고 있어요. Rails가 오래 버티는 이유도 결국 여기에 있는 것 같아요.