https://sangwook.github.io/2016/06/14/ruby-rails-solnic.html
- 먼저요약
- solnic의 글은 한 마디로 Rails의 tight-coupling 을 지적하고 있다.좀 더 자세히는 Rails 에 대해 아래 3가지를 비판하고 있다고 생각한다.
- 매우 복잡한 로직을 “쉬운” 인터페이스 뒤에 숨긴다.
- 앱의 도메인 로직들이 레일즈프레임워크에 강하게 결합되어있다.
- ActiveSupport 는 나쁘다.
Rails는 Ruby를 인기 있게 만들었습니다. 사실입니다. 저는 루비 개발자가 되었고, 그 덕분에 제 커리어가 바뀌고 놀라운 기회를 많이 얻었습니다.
수년 동안 Rails와 DHH는 다른 커뮤니티의 사람들을 포함한 많은 사람들에게 자신이 하고 있는 일에 대해 다시 생각하도록 영감을 주었습니다. 예를 들어, 저는 Rails가 PHP 커뮤니티의 개선에 기여했다고 확신합니다(제가 틀렸다는 것을 증명하려고 노력할 수는 있지만 Java에서도 마찬가지입니다(예), Play 프레임워크가 그 예입니다. Rails에서 많은 영감을 얻은 것에 대한 기억이 생생합니다).
Rails에는 환상적인 다른 측면도 있습니다. Rails는 항상 사용 편의성과 웹 애플리케이션을 빠르게 구축할 수 있는 기능에 초점을 맞춰 왔기 때문에 Rails Girls와 같은 이니셔티브가 성공할 수 있었습니다. Rails는 프로그래밍 경험 없이도 비교적 짧은 시간 내에 스스로 무언가를 만들 수 있다는 것을 사람들에게 증명했습니다. 이는 프로그래머가 되는 것을 고려하지 않았던 사람들이 프로그래밍 세계로 쉽게 진입할 수 있는 관문이 될 수 있다는 점에서 놀라운 일입니다.
레일즈 걸스
2006년 말에 학사 학위 논문이 Rails에 관한 것이었기 때문에 루비 작업을 시작했고, 논문을 쓰는 동안 루비를 배웠습니다. 재미있고 흥미진진했으며 저에게는 새로운 일이었습니다. 당시 저는 여전히 PHP 개발자로 일하고 있었습니다. 2005~6년에 전형적인 PHP 개발자로서 저는 뷰 템플릿에 원시 SQL 쿼리를 작성하고, 절차적 PHP에 질식해 죽을 때까지 매달리고, 나만의 프레임워크와 ORM을 구축하고, 좌절하고 지치는 등 전형적인 일을 모두 해왔습니다.
- --- 폐기된 데이터매퍼 라이브러리와 엑티브레코드에대한 불만
Merb는 Ezra Zygmuntowicz가 만든 프로젝트였습니다. 파일 업로드를 더 빠르고 스레드에 안전하게 하기 위한 해킹으로 시작되었습니다. 그 해킹에서 풀스택, 모듈식, 스레드 안전, 빠른 웹 프레임워크에 이르기까지 흥미로운 과정을 거쳤습니다. 2008년부터 사람들이 이 프레임워크에 대해 많이 이야기하기 시작했고, 뭔가 새로운 일이 일어나고 있고 대단할 것이라는 놀라운 느낌이 들었던 기억이 납니다.
Rails에 "API 모드"가 추가된다는 소식에 기대가 되시죠? Merb에는 풀스택 모드, API 모드, 최소한의 기능만 남긴 마이크로 모드의 세 가지 모드가 있었는데, 루비 모드 중 가장 빨랐던 것으로 기억합니다. 7년 전의 일입니다. 잘 생각해 보세요.
Merb와 DataMapper는 우리가 더 잘할 수 있다는 희망을 가져다주었고 Rails를 위한 건전한 경쟁을 만들 수 있다는 점에서 기대가 컸습니다. 두 프로젝트 모두 모듈식 접근 방식과 스레드 안전성, 그리고 단순히 더 나은 Ruby 코딩 표준을 장려했기 때문에 기대가 컸습니다.
이 결정으로 인해 Ruby 생태계는 중요한 프로젝트를 많이 잃었고 Rails만 이득을 얻게 되었습니다. Merb를 죽이기로 한 결정이 잘한 것인지 아닌지는 개인적인 의견의 문제이며, 그 결정을 내리지 않았다면 어떤 일이 일어났을지 추측해 볼 수 있습니다. 하지만 경쟁에 대한 간단한 진실은 경쟁은 건강하다는 것입니다. 경쟁의 부재는 독점을 의미하며, 독점은 건강하지 않다는 단순한 진리가 있습니다. 경쟁은 발전과 혁신을 촉진하고, 경쟁은 더 건강한 생태계를 조성하며, 사람들이 더 많이 협업하고, 공통의 것을 공유하며, 더 나은 기반을 구축할 수 있도록 합니다. 하지만 루비 커뮤니티에서는 이런 일이 일어나지 않고 있습니다.
(장기적으로 볼 때) Merb와 DataMapper가 사실상 폐기된 후, Ruby 생태계에서 새로운 것을 구축하는 것은 매우 어려운 일이 되었습니다. 사람들의 관심이 Rails에 집중되어 있기 때문에 새로운 프로젝트는 Rails의 영향을 많이 받아왔습니다. 새로운 아이디어로 돌파구를 마련하는 것은 아무리 생각해도 어려운 일입니다. 왜냐하면 사람들은 무언가를 생각해낼 때마다 그것이 Rails와 비슷하고 Rails에서 잘 작동하기를 원하기 때문입니다. Rails에서 작동하도록 만드는 것은 어렵지만 나중에 설명하겠습니다.
지난 몇 년 동안 우리는 결국 하나의 프레임워크가 전체 생태계를 지배하면서 수천 명의 개발자에게 영향을 미치고 의심스러운 표준을 만들게 되었습니다. 2008년부터 성장하기 시작한 다양한 생태계를 잃고 Rails에 인수되었습니다.
음모론처럼 들릴 수도 있겠지만 그렇게 생각하지 마세요. 제가 여기서 말한 것은 제 개인적인 감정이 약간 가미된 사실입니다. 저는 2009년 말부터 DataMapper에 기여하기 시작했고, 그것이 무너지는 것을 보는 것은 매우 슬픈 일이었습니다.
복잡성!
- 내가 Rails 앱을 작성하는 방식.
우리는 약 6년 동안 Rails 애플리케이션의 아키텍처를 개선하는 방법에 대해 이야기해 왔습니다. 저는 기사, 컨퍼런스 강연, 그리고 여러 가지 어려운 문제를 해결하기 위해 노력하는 많은 OSS 프로젝트에 참여하면서 이 논의에 최대한 기여하려고 노력해 왔습니다.
그럼 이제 기술적인 세부 사항을 살펴보겠습니다.
Rails 편의성 지향 디자인
앞서 언급했듯이 Rails는 사용 편의성을 염두에 두고 제작되었습니다. 이것을 단순함과 혼동하지 마세요. 바로 어제 이 트윗을 우연히 발견했는데 모든 것을 말해줍니다:
쉬운 것과 단순한 것 pic.twitter.com/b6r0cTD6WO
- 데이브 체니 (@davecheney) May 19, 2016
Rails의 작동 방식은 다음과 같습니다:
User.create(params[:user])
간단한 코드 한 줄을 보고 User가 AR 모델이라는 것을 알고 있다고 가정하면 이 코드가 무엇을 하는지 즉시 알 수 있습니다. 여기서 문제는 사람들이 단순함과 편리함을 혼동한다는 것입니다. 컨트롤러에서 이 코드를 작성하고 작업을 완료하는 것이 편리(일명 "쉽다")하겠죠?
이 코드 줄은 간단하지 않고 작성하기는 쉽지만 코드 내부를 들여다보면 매우 복잡합니다:
* 매개변수는 종종 DB별 강제를 거쳐야 합니다.
* 매개변수의 유효성을 검사해야 합니다.
* 콜백을 통해 매개변수가 변경될 수 있으며, 외부 시스템으로 인해 부작용이 발생할 수 있습니다.
* 유효하지 않은 상태는 외부 시스템(예: I18n)에 따라 설정 오류 메시지를 발생시킵니다.
* 유효한 파라미터를 오브젝트의 상태로 설정해야 하며, 잠재적으로 연관된 오브젝트도 설정해야 합니다.
* 단일 객체 또는 전체 객체 그래프가 데이터베이스에 저장되어야 합니다.
이는 기본적인 문제 분리가 부족하기 때문에 복잡한 프로젝트에서 항상 문제가 됩니다. 이는 결합을 증가시키고 코드를 변경하고 확장하기가 더 어렵게 만듭니다.
하지만 Rails 세계에서는 문제가 되지 않습니다. Rails 세계에서는 SRP(및 일반적으로 SOLID)와 같은 기본 설계 지침이 "복잡성을 유발하는 불필요한 추상화"라는 조롱과 조롱을 받고 있습니다. 자체 객체를 사용하여 애플리케이션 사용 사례를 모델링하고 복잡한 부분을 명시적으로 만드는 것을 선호한다고 말하면 Rails 리더는 YAGNI라고 말할 것입니다. 코드를 더 안정적이고 유연하게 만드는 컴포지션을 사용하고 싶다고 말하면, tenderlove를 제외한 Rails 리더는 "ActiveSupport::Concerns를 사용하세요"라고 말할 것입니다.
Rails 개발자에게는 웹 양식에서 오는 데이터가 무슨 일이 일어날지 알 수 없는 ActiveRecord의 깊은 곳으로 전송되는 것은 문제가 되지 않습니다.
이 논의에서 정말 어려운 부분은 애초에 이것이 문제라는 것을 설명할 수 있어야 한다는 것입니다. 사람들은 Rails가 단순하다는 잘못된 느낌을 주기 때문에 매력을 느끼지만, 실제로는 편리한 인터페이스에 의해 복잡성이 숨겨지고 있습니다. 이러한 인터페이스는 애플리케이션을 빌드하고 설계하는 방법에 대한 많은 가정을 기반으로 합니다. ActiveRecord는 대표적인 예일 뿐이지만, Rails는 이러한 철학을 염두에 두고 제작되었으며, 모든 Rails가 그렇게 작동합니다.
코드 베이스를 개선하는 내부 리팩터링을 통해 Attributes API를 도입하는 등 ActiveRecord를 개선하기 위해 많은 노력을 기울이고 있다는 점을 말씀드리고 싶습니다. 안타깝게도 200개가 넘는 공용 메서드와 함께 제공되고 콜백 및 우려 사항의 사용을 장려하는 한, ActiveRecord는 항상 증가하는 복잡성을 처리할 수 없는 ORM이 될 것이며, 이러한 복잡성에 기여하고 상황을 악화시킬 뿐입니다.
Rails에서도 변경되나요? 그럴 것 같지 않습니다. Rails 리더들이 단순히 반대하고 있기 때문에 무언가 개선될 수 있다는 징후는 전혀 없습니다. 최근 논란이 되고 있는 ActiveRecord.suppress는 DHH가 직접 제안한 기능이라는 것이 간단한 증거입니다. 그가 또다시 독립형 루비 클래스를 조롱하며 "네, CreateCommentWithNotificationsFactory를 위한 별도의 팩토리를 사용하면 이 작업을 수행할 수도 있습니다"라고 말하는 것을 주목하세요. 오, 이런.
액티브 커플링
Rails를 애플리케이션으로 사용해야 할까요? 이 질문은 밥 아저씨의 강연을 보고 많은 사람들이 던진 중요한 질문이었는데, 그는 기본적으로 웹 파트와 실제 핵심 애플리케이션을 더 강력하게 분리할 것을 제안했습니다. 기술적인 세부 사항은 제쳐두고, 이것은 좋은 조언이지만 Rails는 이를 염두에 두고 설계되지 않았습니다. Rails를 사용한다면 이 프레임워크의 핵심을 놓치고 있는 것입니다. 실제로 DHH가 이에 대해 한 말을 들어보세요:
폴카 씨발. That. 젠장. 완전 좆같네요. "Rails는 여러분의 애플리케이션이 아닙니다." 웹 앱을 구축한다면 당연히 그렇습니다.
- DHH (@dhh) June 29, 2012
그의 생각이 무엇인지 꽤 분명하죠? 중요한 부분은 "당연히 그렇다"입니다. 그리고 그거 아세요? 저도 전적으로 동의합니다!
Rails는 여러분의 애플리케이션이며, 의도하지 않은 방식으로 사용하는 엄청난 노력을 기울이지 않는 한 항상 그럴 것입니다.
이것을 생각해 보세요:
ActiveRecord는 도메인 로직의 중심이 되어야 합니다. 그렇기 때문에 거대한 인터페이스와 다양한 기능이 함께 제공됩니다. 로직이 합리적일 때만 사물을 세분화하고 별도의 구성 요소로 추출하지만, Rails의 철학은 SRP에 신경 쓰지 않고, LoD에 신경 쓰지 않고, 도메인 로직과 지속성 간의 긴밀한 결합에 신경 쓰지 않고, ActiveRecord에 물건을 넣는 것입니다. 이것이 바로 Rails를 효과적으로 사용할 수 있는 방법입니다.
Rails의 전체 뷰 "레이어"는 ActiveModel에 결합되어 있으므로 Active Record ORM에 결합됩니다(Sequel일 수도 있고 상관없습니다).
웹 API 엔드포인트라고도 하는 컨트롤러는 Rails의 필수적인 부분이며, 여기에서도 긴밀한 결합이 이루어집니다.
Rails에서 복잡한 템플릿을 처리하는 방식인 헬퍼도 Rails의 필수적인 부분이며, 다시 한 번 긴밀하게 결합됩니다.
Rails의 모든 것, 그리고 Rails용으로 제작된 수많은 타사 보석은 상속(믹스인 또는 클래스 기반)을 통해 이루어집니다. Rails와 타사 젬은 일반적으로 재사용 가능한 독립형 객체를 제공하는 것이 아니라 객체가 상속하는 추상화를 제공하며, 이는 긴밀한 결합의 또 다른 형태입니다.
이를 염두에 두고서, Rails이 당신의 애플리케이션에 적합하지 않다고 생각하는 것은 미친 생각일 것입니다. 이러한 종속성을 피하려고 한다면, 어떤 종류의 노력이 필요하고 내장된 기능의 얼마나 많은 부분을 잃게 될지 상상할 수 있을 것입니다. 이것이 바로 Rails에서 대체 접근 방식을 보여주는 이유입니다. 이러한 대안은 과도하고 불필요한 추상화로 인해 사람들이 "무서운" Java 시대를 떠올리게 합니다. Rails은 느슨한 결합과 구성 요소 지향 설계를 고려하여 구축된 것이 아닙니다.
"거부하지 마세요. 받아들이세요."
이 모든 것을 말했지만, 제가 Rails에 대해 가장 큰 불만을 가지고 있는 것은 사실 ActiveSupport입니다. 이미 한 차례 언급했으니 반복할 필요는 없을 것 같다. 또한 링크된 블로그 게시물의 댓글을 읽어보시길 권합니다.
한 가지 덧붙이고 싶은 것은 ActiveSupport 때문에 Rails가 Ruby 생태계의 선량한 시민이라고 생각하지 않는다는 것입니다. 이 라이브러리는 저에게는 Rails의 모든 문제점이었습니다. 실제 솔루션도 없고, 확실한 추상화도 없으며, 당면한 문제를 해결하기 위한 지저분한 미봉책, 공식 API로 변질되는 미봉책, 그 결과로 화물신앙화만 존재합니다. 역겹습니다.
Rails는 폐쇄적인 에코시스템이며, 다른 프로젝트에 나쁜 요구 사항을 강요합니다. Rails에서 무언가를 작동시키려면 ActiveSupport가 필요할 때 실제로 제대로 작동하는지, 개발 모드에서 끔찍한 코드 재로드를 처리할 수 있는지, Rails에서는 사용자의 편의를 위해 모든 것을 어디서나 사용할 수 있어야 하므로 객체가 전역으로 제공되는지 등의 사항을 처리해야 합니다.
Rails의 작동 방식은 자신만의 젬을 구축하는 개발자에게 많은 추가적인 노력을 요구합니다. 우선, 여러분의 젬이 Rails와 함께 작동할 수 있어야 하는데(당연히 모든 사람이 Rails와 함께 사용할 것이기 때문에), 그 자체가 어려운 일입니다. 데이터베이스를 다루는 라이브러리가 있고 이를 Rails에서 작동하도록 만들고 싶다고요? 통합 인터페이스가 원래 Rails 3.0 이전의 ActiveRecord를 기반으로 하는 ActiveModel이기 때문에 이제 어느 정도는 ActiveRecord처럼 작동하도록 만들어야 합니다.
여기에는 Rails와의 통합을 제공하기 매우 어렵게 만드는 많은 제약 조건이 있습니다.
개발 모드에서 핫 코드 리로딩으로 작동하도록 만들려고 할 때 얼마나 많은 문제에 직면할지 모릅니다. Rails는 글로벌하고 변경 가능한 런타임 환경을 기대합니다. 모든 사람이 더 쉽게 사용할 수 있도록 Spring을 도입했습니다. 이 새로운 기능으로 인해 Rails와 함께 작동하도록 만들려고 시도하는 동안 직면할 수 있는 잠재적인 새로운 버그의 전체 범주가 열렸습니다. 이제 정말 지긋지긋합니다. Ruby에서 코드를 다시 로드하는 것은 불안정할 뿐만 아니라 젬과 애플리케이션에 완전히 불필요한 복잡성을 야기하고 있습니다. 이는 Rails와 함께 작동해야 하는 젬을 구축하는 모든 사람에게 영향을 미칩니다. 수년 동안의 비판에도 불구하고 Rails Core 팀의 어느 누구도 이 문제를 더 잘 해결할 수 있는 방법을 찾아보는 것이 좋겠다고 생각하지 않았습니다. 누군가 애플리케이션 코드를 더 빠르게 로드하는 데 집중했다면, 우리는 프로세스를 다시 시작하는 데 의존할 수 있었습니다. 게다가 방금 변경한 내용이 실제로 작동하는지 확인하려면 F5 키를 누르는 대신 자동화된 테스트를 사용해야 합니다. 그냥 하는 말입니다.
불평하는 것처럼 들릴 수 있다는 것을 압니다! 저도 Rails를 지원하려고 노력했지만 너무 답답했습니다. 더 이상 하고 싶지 않아서 포기했습니다.
제가 겪었던 문제에 대한 해결책은 액티브 서포트를 버리고, 선택한 패턴인 액티브 레코드를 제거하고, 어떤 ORM과도 분리된 실제 뷰 레이어를 추가하는 것이었기 때문에, Rails에서 이런 일이 일어날 것이라고 생각하는 것은 비합리적이라는 것을 깨달았습니다.
------------- Rails 를 떠나며
9년 동안 Rails와 함께 일하고 많은 Ruby 오픈소스 프로젝트에 열심히 기여한 결과, 저는 포기했습니다. Rails로는 더 이상 좋은 일이 일어날 수 없다고 생각했기 때문입니다. 이것은 제 개인적인 관점이지만 많은 사람들이 같은 생각을 가지고 있습니다. 동시에 여전히 Rails에 만족하는 사람들이 더 많습니다. 잘됐네요! 솔직히! Rails는 계속 유지될 것이며, 사용 사례도 있고, 여전히 사람들에게 도움이 되며, 성숙하고 잘 유지 관리되고 안정적인 웹 프레임워크입니다. 저는 Rails가 궁극적으로 나쁘다고 설득하려는 것이 아닙니다! 다만 저에게는 정말 나빴을 뿐입니다.
하지만 이 결정은 이러한 결과를 가져왔습니다. 이것이 제가 dry-rb, 하나미, 트레일블레이저 프로젝트에 참여하게 된 이유이며, 현재도 rom-rb프로젝트에 참여하고 있는 이유이기도 합니다. 저는 새로운 생태계를 구축하는 데 일조하여 Merb/DataMapper가 처음 등장했을 때 우리 모두가 느꼈던 열정을 다시 불러일으키고 싶습니다.
Translated with www.DeepL.com/Translator (free version)
자바에사 전부 추상화하는 것도 끔찍한데 루비의 엑티브레코드에서 엑티브라이브러리도 끔찍하다는