프로그래밍 언어와 프레임워크의 교육적 가치
초보 루비 온 레일즈 개발자가 개발을 하다 보면 쓸데없이 크고 엉망진창인 모델을 만들기 마련입니다. 흔히 하는 실수죠. 저도 마찬가지였습니다. 경험 있는 개발자가 곁에 있어서 그런 실수를 하는 것을 막아줬으면 다행이었겠지만 안타깝게도 제 주변엔 없었습니다. 결국 스스로 그 상황을 해결할 방법을 찾아야 했죠.
해결책을 찾는 과정에서 수많은 블로그 글을 읽으면서 이 문제를 저만 겪고 있는 것이 아니란 사실을 알게 되었습니다. 레일즈 개발자 사이에서는 상당히 흔한 문제로 레일즈가 액티브 레코드 패턴을 사용하는 방식 때문에 발생하는 것이었죠. 검색을 하다보니 레일즈 앱 구조의 역사 비슷한 것도 보이더군요. 컨트롤러가 복잡하던 시대, 모델이 복잡하던 시대, 그리고 요즘은 루비 오브젝트를 사용하는 시대구요. 완전히 다른 해법도 있었습니다. 예를 들어 Ruby Object Mapper나 Hanami 프레임워크는 그냥 액티브 레코드 패턴을 버리고 데이터 매퍼 패턴을 사용해버렸습니다.
같은 실수를 여러 사람이 반복한다면 그건 개발자 개개인의 잘못때문에 발생한 문제가 아닙니다. 레일즈 자체에 사람들이 그런 실수를 반복하도록 오도하는 디자인 문제가 있다는 것이 더욱 타당한 해석이죠. 물론 디자인 문제는 충분히 있을 수 있습니다. 애초에 영원히 완벽한 시스템은 존재할 수가 없으니까요. 그리고 레일즈는 잘못된 부분보다는 잘 된 부분이 훨씬 많은 프레임워크입니다.
디자인 문제가 고쳐지지 않는 경우는 안타깝게도 너무 많다
하지만 디자인 문제가 고쳐지지 않는 것은 용납하기 어렵습니다. 특히 해결책이 이미 존재하고 잘 알려진 경우에는 더더욱 그렇습니다. 예를 들어 레일즈가 액티브 레코드 패턴을 사용하는 방식을 고치지 않고 있는 것이 그렇죠. 로버트 마틴이 쓴 클린 코드를 보면 다음과 같은 내용이 나옵니다.
Active Records are special forms of DTOs [Data Transfer Object]. They are data structures with public variables; but they typically have navigational methods like save and find. Typically these Active Records are direct translations from database tables, or other data sources.
Unfortunately we often find that developers try to treat these data structures as though they were objects by putting business rule methods in them. This is awkward because it creates a hybrid between a data structure and an object.
The solution, of course, is to treat the ActiveRecord as a data structure and to create separate objects that contain the business rules and that hide their internal data (which are probably just instances of the ActiveRecord).
이 책은 2008년에 출판된 책으로 프로그래머 사이에서는 꽤나 유명한 책입니다. 액티브 레코드 패턴의 문제와 해법이 이미 잘 알려져 있다는 것을 증명해줍니다. 물론 레일즈의 첫 버전이 이 책 출판보다 훨씬 이른 2004년에 공개된 것은 알고 있습니다. 하지만 사실 저 책 내용은 당시에 관록 있는 개발자라면 누구나 알고 있었을 내용이라고 생각합니다. 레일즈 프레임워크를 개발한 사람들도 당연히 그 안에 들어갈 것이고요.
그리고 시간이 흘러 2016년인데 레일즈는 아직도 개발자가 모델에 도메인 로직과 퍼시스턴스 로직을 섞어 쓰도록 오도하고 있습니다. 이 문제를 해결할 수 있는 메이저 버전 업데이트가 12년 동안 네 번이나 있었는데도 수정하지 않았죠. 아무리 실제 환경에서 사용하면서 사용자 피드백을 얻어도 그걸 시스템에 반영하지 않으면 결국 아무 의미가 없습니다.
레일즈는 하나의 예시일 뿐입니다. 이러한 패턴은 소프트웨어 개발 분야 전체에 광범위하게 나타는 것 같습니다. Ruby Rogues 팟캐스트에서 패널들이 Structure and Interpretation of Computer Programs라는 책에 관해서 비슷한 얘기를 한 적이 있습니다. 오늘날 업계에서 겪는 여러 문제에 대한 해답이 1979년에 출판된 저 책에 이미 제시되어 있었다는 한탄이었죠. 하지만 그런 해답이 제시되어도 결국 실제로 사용되지 않으면 무슨 의미가 있을까요?
현업에서 쌓은 지식이 계속 잊혀지게 되는 구조적 문제
이 업계에는 현업에서 쌓은 지식이 계속 잊혀지게 되는 구조적 문제가 있습니다. 그런 지식을 후대에 전달할 체계 자체가 없으니 새삼스레 놀랄 일은 아니죠. 컴퓨터 과학 쪽은 워낙 고고해서 현업쪽 지식에는 관심도 없고, 소프트웨어 공학 쪽은 하나의 일관된 분야를 형성하기에는 아직 공통의 원칙이나 주제가 없습니다. 숙련된 개발자가 은퇴하고 오래된 회사가 폐업하면서 현업에서 축적한 지식은 자연스럽게 잊혀지고 사라지게 됩니다.
게다가 소프트웨어 개발 분야의 실전 지식은 암묵적인 지식이라서 글이나 말로 다른 사람에게 전달하기가 어렵다는 문제도 있습니다. 예를 들어 글로 적힌 설명만 읽는다고 자동차 운전하는 방법을 배울 수는 없죠. 아직까지는 직접 차를 운전하는 것 외에는 운전을 배울 방법이 없습니다.
하지만 사람들이 운전을 배울 때 좋은 운전 습관을 가지도록 유도하는 것은 확실히 가능합니다. 앞 차와의 간격을 측정하는 센서가 있으면 안전한 차간 거리를 확보하도록 도와줄 수 있고, 후방 시야를 보여주는 카메라가 있으면 후진할 때 도움이 됩니다. 차선 표시를 선명하게 하면 차선을 잘 지키도록 유도할 수 있죠.
다행히도 오픈 소스 소프트웨어가 급격히 성장하면서 소프트웨어 개발 분야에도 이러한 변화가 일어나고 있습니다. 새로운 프로그래밍 언어는 현업에서 자주 겪는 문제에 대한 해결책을 언어 수준에서 제공합니다. 새로운 프레임워크는 개발을 보다 효과적이고 즐겁게 할 수 있도록 다양한 개발 원칙을 섞어가며 더 나은 방식을 찾아갑니다.
언어와 프레임워크의 교육적 역할
하지만 이런 일련의 흐름의 목표는 업무 생산성을 높이고 불필요한 스트레스를 줄이는 정도에 그치는 것 같습니다. 저는 신입 개발자가 언어나 프레임워크를 어떻게 사용하고 그 과정에서 무엇을 배울지에 대해서도 사람들이 더 주의를 기울였으면 합니다. 즉, 이런 시스템의 교육적 가치에 대해서 말이죠. 만약 어떤 언어나 프레임워크를 쓰는 것만으로도 신입 개발자가 좋은 개발 습관을 습득할 수 있다면 업계 전반적으로 개발자 훈련에 들이는 시간과 자원을 크게 절약할 수 있을 것입니다.
예를 들어 레일즈가 프레임워크 차원에서 도메인 로직과 퍼시스턴스 로직을 분리하도록 권장한다면 신입 개발자는 그런 습관을 자연스럽게 배우게 될 겁니다. 그러면 지금처럼 신입 개발자가 자기도 모르게 나쁜 코딩 습관을 익히고, 그런 상황에서 코드를 작성해서 발생한 여러 문제를 해결하기 위해 낭비되는 이 모든 비용과 삽질을 방지할 수 있겠죠.
새로운 시스템을 만들 때 교육적 가치가 주요 고려사항이 되어야 한다는 말은 아닙니다. 그건 주객전도입니다. 하지만 신입 개발자가 시스템을 어떻게 사용하는지 잘 관찰하고, 더 좋은 습관을 익힐 수 있도록 적절한 장치를 구현할 필요와 가치는 충분히 있다고 생각합니다. 지금은 조금 귀찮은 일이라 생각될 수도 있지만 장기적으로 보면 모두가 더욱 편해지는 길이라고 봅니다.