개발자 99% 커뮤니티에서 수다 떨어요!
FSM 설계 방식에 대해 시각을 넓혔으니 한번 적용해보자.
단계적 절차를 밟는 코드에 한번 파이프라인을 적용해보자.
이제는 delegate와 mixin을 활용해 상속의 늪에서 벗어나 보자.
2022-05-21
5장. 구부러지거나 부러지거나 (p.181 ~ p.239)
높은 결합도는 변경의 적이다. 결합도가 높으면 이리저리 연결되어 있어서 여러 가지를 동시에 바꿔야 하기 때문이다. (p.182)
전역 데이터는 여러 가지 방법으로 코드의 결합도를 높인다. (p.190)
전역적이어야 할 만큼 중요하다면 API로 감싸라. (p.191)
직접적으로 아는 것만 다루는 부끄럼쟁이 코드를 계속 유지하라. 그러면 애플리케이션의 결합도를 낮게 유지할 수 있을 것이고, 결과적으로 코드를 바꾸기 쉬워질 것이다. (p.192)
코드를 일련의 (중첩된) 변환으로 생각하는 접근 방식은 프로그래밍을 해방시킨다. (p.222)
당신이 원한 것은 바나나 하나였지만, 당신이 받은 것은 바나나를 들고 있는 고릴라와 정글 전체다. - Joe Armstrong (p.224) ㅋㅋㅋ
다형성은 인터페이스로 표현하는 것이 좋다. (p.230)
서비스에 위임하라. Has-A가 Is-A보다 낫다. (p.232)
믹스인으로 기능을 공유하라. (p.235)
외부 설정으로 애플리케이션을 조정할 수 있게 하라. (p.236)
개인적으로 코드 리뷰(셀프)를 진행하면서 점검하는 포인트가 크게 네 가지 있다.
스타일이 통일성을 유지하고 있는가?
코드가 충분한 가독성을 갖추고 있는가?
코드가 각각 제 자리에 맞게 위치했는가?
최적화가 최대한 이루어진 것인가?
각각의 항목은 다루는 내용이 다르며, 보통은 1번부터 차례대로 눈이 가게 된다. 그중 세 번째 포인트인 ‘3. 코드가 각각 제 자리에 맞게 위치했는가?’ 라는 건 다른 말로 ‘이 코드를 여기에 이렇게 두는 게 맞는 건가?’로서 코드 설계를 점검하는 과정이다. 이 과정의 내용들이 [Topic 28. 결합도 줄이기]에서 다룬 내용들과 대체로 유사했다.
특히 ‘글로벌화의 해악’에 대해서는 정말 잘 짚어주었다고 생각한다. 무지성 코딩을 하던 미숙한 시절에는 실제로 전역 데이터를 남용했었다. 하지만 이후에 뼈저리게 깨닫게 되었다. 해당 전역 데이터를 사용하는 부분이 많으면 많아질수록 단단하게 엉켜버린 끈처럼 되어, 나중에 가위로 자르는 것(큰 비용을 들여 해당 전역 데이터에서 탈피하도록 리팩토링하는 것) 외에는 방법이 없게 될 수도 있다는걸…
하지만 전역 데이터의 사용을 완전히 피할 수는 없다고 생각한다. 앞서 다뤄진 사례들에 비해서 전역 데이터가 리팩토링 비용이 비교적 크게 발생하기 쉬운 지점이므로, 미래에 [Topic 3. 소프트웨어 엔트로피]에서 말한 ‘깨진 창문’처럼 되지 않도록 신중하게 적용해야 한다고 생각한다.
비전공자로서 프로그래밍 세계에 입문했기 때문에 이론이 많이 부족하여(사실 노력을 안 한 것) FSM(유한 상태 머신) 설계에 대해서는 한참 나중에서야 알게 됐었다. 가독성도 안 좋은 긴 if-else 나 switch 의 조건문 피라미드들이 하나의 Key-Value 데이터 안으로 들어가게 되는 걸 처음 봤을 때의 그 강렬한 쾌감이 떠올랐다. 게다가 p.197 ~ p.198의 구현 예시처럼 조건문뿐 아니라 데이터 처리까지 직접적으로 관여하도록 확장해 적용한 건 내 시야를 넓혀지게 했다.
[Topic 29. 실세계를 갖고 저글링하기]에서는 앞선 FSM과 함께, 중요한 반응형(Reactive) 프로그래밍 방식에 대해 알려주고 있다.
클라이언트를 개발할 때 비동기 처리 방식으로 구현하게 되는 부분이 굉장히 많다. 하지만 비동기 처리 방식으로 코드를 구현하다 보면 데이터의 관리가 쉽지 않고 코드가 과하게 복잡해지는 등 문제가 많다. 이런 문제점들을 해결하고자 반응형 프로그래밍이란 개념과 설계 방식이 탄생했고, 이를 더욱 쉽게 활용하기 위해 Rx라는 기술이 나타났다. Reactive와 Rx에 대해 읽히기 쉽게 정리해둔 포스팅이 있어 아래 첨부해둔다.
기억을 더듬어보면 파이프라인을 적극적으로 활용해본 건 Vue.js에서 데이터 출력에 filter를 적용했던 것 외엔 마땅히 떠오르지 않는다. [Topic 30. 변환 프로그래밍]에서는 애너그램 출력 프로그램을 구현하면서, 변환 설계방식의 핵심이 되는 파이프라인을 다루는 법을 잘 보여주었다.
혹시 지금 메인으로 다루는 Ruby안에도 파이프라인이 있지 않을까? 하고 찾아봤더니 있었다! Ruby로 개발하면서 메소드 체이닝 방식으론 해결이 안 되는 부분들은 어쩔 수 없이 ‘X 언어에는 파이프라인이 없는데요’ 사례처럼 임시 변수들을 팍팍 섞어 넣었다. 이제는 파이프라인의 존재도 알았고 에러 처리방식에 대해서도 숙지했으니 한번 활용해보고 싶은 욕심이 생겨났다.
앞쪽의 [Topic 28. 결합도 줄이기]의 말미에, 뒤쪽에서 상속에 대해 다룬다고 했을 때 살짝 긴장됐었다. 아니나 다를까 [Topic 31. 상속세]에서 상속을 사용하는 개발자의 이유가 ‘타입이 싫거나’ 혹은 ‘타입이 좋거나’의 두 가지로 정리됐는데, 개인적으로는 타입이 싫기도 하면서 타입이 좋기도 한, 다소 모순적인 이유를 가지고서 상속을 즐겨 사용했기 때문이다.
실제로 ‘코드를 공유하기 위해’ FirebaseMessaging 클래스와 FirebaseAuthentication 클래스를 만들어 공통된 함수들(ex. GoogleAPI 인증, 로깅 등)을 묶어 GoogleAPI 부모클래스를 만들었고, ‘타입을 정의하기 위해’ ApiErrors 상위 클래스를 만들어 UnauthrizedError, ForbiddenError, NotFoundError 와 같은 자식클래스들을 구현했었다. 코드를 거의 혼자서만 관리해왔기에 미처 생각이 닿지 못했던 문제점들을 책을 통해 알 수 있게 되었다.
현재 메인으로 활용하는 백엔드 프레임워크인 RoR(Ruby on Rails), 거기서 자주 쓰는 delegate(위임)가 저런 개념을 가지고 있었구나.. 하고 깨닫게 되었다. mixin(믹스인)도 RoR이 모델이나 컨트롤러에서 사용하도록 Concern(mixin의 역할을 하는 기능)이라는 기능을 제공해주었기에, 모델과 컨트롤러 안에서만 사용했었지, 일반 코드에까지 mixin을 적용해볼 생각은 못 했었다. 이제 상속의 늪에서 벗어날 수 있는 무기들이 갖추어졌다. delegate나 mixin을 활용한 구조로 리팩토링해 볼 가치가 있으므로 현재 프로젝트에 적용할 수 있는 부분이 있나 한번 검토해봐야겠다.
RemoteConfig(원격 구성) 시스템은 정말 중요하다. 유저의 반응을 보기 위해 A/B 테스트에 활용해 볼 수 있고, 서버를 꺼둔 상태에서도 클라이언트에 서비스 점검 상태를 알려줄 수도 있으며, 사용하는 앱의 최신버전이 나왔는지 검사를 하는 데 활용하기도 한다. [Topic 32. 설정] 중 서비스형 설정에 적용하기 좋은 시스템이 바로 RemoteConfig 방식이다. RemoteConfig는 Firebase 나 Unity에서 제공하는 서비스를 이용하거나 직접 구현하는 방식으로 활용할 수 있다.
Ruby의 delegate 구현방식에 대해 더욱 깊이 파보기
RoR Concern에 대해 더욱 깊이 파보기
4장 내용으로 작성된 TIL 전부
Rx? 리액티브 프로그래밍? 왜 비동기 처리로 사용될까? - 포스팅 (p.202 ~ p.206)
ReqRes - REST API 구조를 활용(체험)해 볼수 있는 서비스 (p.204)
도움이되는 추천 Mac용 어플리케이션