태그 - TIL, nomadcoder, 개발자북클럽, 노개북, 서평, 책
모든 수단을 동원하여 가능한한 느슨하고 유연한 코드를 작성해야 한다. 현대의 미친듯한 변화의 속도에 따라 가려면,
이번장의 목표는 불확실성 속에서도 우리가 작성한 코드들이 유연성과 적응력을 잃지않는 방법을 다룬 파트이다.
높은 결합도는 변경의 적이다. 결합도가 높다면 이리저리 연결되어 있어 여러가지의 가지들을 동시에 바꿔야 하기 때문이다. 높은 결합도는 필연적으로 모두 바꿔야 하기에 많은 시간이 걸린다. 그렇지 않다면, 우리는 원인모를 오류를 만나게 될것이다.
위 구조는 부품간의 연결이 모여 전체구조를 단단하게 만들었다.
또 위의 구조는 위 구조만큼 연결이 촘촘하지가 않다. 하지만 각각의 연결을 움직일 수 있고 그 부분도 따라서 움직이게 되는 구조이다.
건물을 건설할때, 그 구조물이 바뀌지않길 바라기 때문에 단단하게 설계가 되지만, 소프트웨어는 언젠가 바꿔지기 때문에 첫번째 구조보다 두번째 구조가 적절하다. 이렇듯 결합도가 낮은 코드가 바꾸기 쉽다.
(책 열차사고 뷰어 209, 184페이지)
우리가 어떤 것 하나만을 골라내려 해도, 그것이 모든것과 얽혀있음을 깨닫게 된다. - 존 뮤어
사람들이 결합도에 대한 이야기할때 언급하는 법칙이다. 테메테르 라는 프로젝트를 수행하는 도중 개발자들에게 보다 깨끗하고 결합도가 낮은 함수를 작성하는 방법을 알려주기위해 만들었다.
책에서는 원칙자체는 유효하지만 설명하기 더쉬운 표현으로 바꿨다.
결합된 코드는 바꾸기 힘들다. 코드 한곳을 바꾸면 다른곳에 여파가 미친다. 찾기힘든곳에 문제가 생기는 바람에 서비스후에 오류가 발생하면서 문제의 실상이 드러나기도 한다. 직접적으로 아는것만 부끄럼쟁이 코드를 계속 유지해야한다. 그러면 애플리케이션 결합도를 낮게 유지할 수도있고 결과적으로 코드바꾸기 쉬울것이다.
그냥 일어나는 일은 없다. 일어나도록 만들어진것이다. -존 F.케네디
오늘날 우리는 많은것을 기대한다. 사람이 컴퓨터에 맞추기보다 컴퓨타가 우리의 세계안으로 들어와야한다.
끊임없이 사건이 일어나고, 우리가 작성하는 애플리케이션은 맡은 일을 어떻게든 수행해야 한다.
사용자가 버튼을 클릭하거나, 정보가 갱신될때 외부에서 올수 있다. 혹은 내부에서 생길수가있다. 어디에서 온것이든 애플리케이션은 이벤트에 반응하도록, 그에 기반해서 하는일을 조절하도록 만들면 진짜 세상에서 더 잘 작동하는 애플리케이션이 탄생할 것이다.
이벤트에 잘 반응하는 애플리케이션의 4가지 전략
대부분 FSM 구현은 고작 몇줄에 불과하지만 , 그덕분에 엄청난 난장판을 만들지 않을수있다. 이것은 정말 쓰기 편하지만 많은 개발자들이 사용을 꺼린다. 어쩌면 이해하기 힘든 라이브러리를 써야 하거나, 하드웨어에서만 쓴다고 생각하지만 이것은 모두 사실이 아니다.
단지 이벤트를 어떻게 처리해야할지에 대한 명세일 뿐이다. 정해진 상태들이 있고 그중 하나가 '현재상태'이다. 상태마다 그 상태일때 의미가 있는 이벤트들을 나열하고, 이벤트별로 시스템의 다음 '현재상태'를 정의한다.
우리는 '초기상태' 에서 시작한다. 헤더 메시지를 받으면 '메시지 수신중'상태로 이행하며, '메시지 수신중'엔 두가지 분기가있다. 트레일러 메시지를 받으면 '완료', 그밖에 다른 메시지를 받으면 '오류'상태로 이행한다.
FSM은 오로지 데이터만으로 표현할수 있다는 것이다.
(코드읽기, 뷰어 221page, 책 196 page )
여기에 특정한 상태 이행이 일어날때 수행하는 '행동' 을 추가하여 FSM을 더 강력하게 만들 수 있다.
이행을 나타내는 선에 두가지 설명이 붙었으며, 위의것은 상태 이행을 일으키는 이벤트, 밑의것은 상태를 이행하면서 수행할 행동이다.
(코드읽기, 뷰어 222page, 책 197page)
이 패턴은 이벤트를 발생시키는 쪽인 감시대상과 이런 이벤트에 관심이 있는 클라이언트인 감시자로 이루어진다.
감시자는 자신이 관심있는 이벤트를 감시대상에 등록, 나중에 이벤트가 발생하면 감시대상은 등록된 감시자 목록을 보면서 함수들을 일일히 호출한다. 이때 발생한 이벤트를 감시자 함수의 인자로 넘긴다.
감시자-감시대상 패턴은 수십년간 쓰여왔고 잘 작동한 패턴이다. 사용자 인터페이스 시스템에 널리 쓰이는데 , 어떤 상호작용이 일어났다는 것을 애플리케이션에 콜백으로 알려주는 방식을 사용한다.
하지만 문제가 있는데 모든 감시자가 감시대상에 등록을 해야하기 때문에 결함이 생긴다. 게다가 감시대상이 콜백을 직접 호출하도록 구현하기 때문에 이 부분에 성능이 병목될수 있다.
혹은 발행-구독 모델은 줄여서 '펍섭' 이라고 부르며 감시자 패턴을 일반화 한것이다. 동시에 감시자 모델의 결합도를 높여 문제와 성능 문제도 해결했다.
아주 기초적인 게시-구독 시스템을 직접 구현하는 것은 불가능하지는 않지만 우리가 진짜 구현할 일은 없을것이다. 대부분 클라우드 서비스가 게시&구독 서비스를 제공한다. 게시&구독은 추가적인 결합없이 '비동기 이벤트'를 구현하기에 아주 좋은 기술이다. 기존 코드를 수정하지않고 이벤트 처리 코드를 추가하거나 교체할 수 있다. 단점으론 게시&구독 모델을 아주많이 사용하는 시스템에 현재 어떤일이 일어나고 벌어지는지 파악하기가 힘들다. 메시지를 보내고 확인했더라도 어떤 구독자가 그 메시지를 처리하는지 바로 이어서 볼 수없다.
다른셀을 참조하고있을때, 참조된 셀의 값을 바꾸면 첫번째 셀의값도 바뀐다. 값이바뀌면 다른값이 '반응 react' 하는 것이다. 하지만 이벤트를 이리저리 연결하는것은 쉽지않으며 이것은 '스트림'으로 수행한다.
'스트림'은 이벤트를 일반적인 자료와 구조처럼 다룰수 있게 해준다. 이벤트가 도착하면 리스트가길어지는 셈이다.
모든 프로그램은 데이터를 변환한다. 하지만 우리는 설계를 고민할때 변환을 만드는것에 대해 거의 생각하지 않는다. 오로지 클래스와 모듈, 자료구조, 알고리즘, 언어 프레임워크에 대해서만 걱정할 뿐이다.
우리는 이렇게 코드만 집중하면 핵심을 놓칠수 있다고 본다. 프로그램이란 입력을 출력으로 바꾸는 것이라는 사고방식으로 돌아갈 필요가 있다.
이렇게 생각하면 그동안 고민하던 많은 세부사항이 모두 사라진다.
아래 그림은 단계별로 흘러간 데이터 도식화이다.
한쪽이 원료데이터를 공급하면 반대쪽 끝에서 완성제품인 정보가 나온다.
프로그래밍은 코드에 관한것이지만 프로그램은 데이터에 관한것이다.
때에 따라선 요구사항에서 시작하는 변환을 찾는게 가장 쉬운 방법이다. 요구사항에서 입력과 출력이 무엇인지 찾으면 프로그램 전체를 나타내는 함수가 정해진다. 일종의 '하향식' 접근방식이다.
단어찾기의 비결은 어떤기준으로 '특성값'이 같은 단어끼리 모은 사전이 있으면 된다. 같은 알파벳을 가진 단어는 모두 같은 특성값을 갖도록 한다. 간단한 방법으론 단어안의 글자를 정렬하여 특성값으로 삼는 방법이다.
변환모델에선 데이터 전체 시스템 여기저기 작은 웅덩이에 흩어놓는대신 데이터를 거대한 강으로 '흐름'으로 생각한다. 데이터는 기능과 동등해지며, 파이프 라인은 코드 ->데이터->코드->데이터의 연속이된다. 더이상 클래스를 정의할때처럼 특정함수들과 묶이지 않는다. 대신 애플리케이션이 입력을 출력으로 바꾸어 나가는 진행상황을 데이터로 자유롭게 표현할 수있다. 이말인 즉슨 결합을 대폭 줄일수 있다는 것이다. 또 다른 함수의 출력결과와 맞기만한다면 어디서나 재사용이 가능하다.
객체지향 언어로 프로그래밍하는가? 상속을 하는가 ? 그렇다면 멈춰야한다! 우리에게 필요하는것은 상속이 아닐수도 있다.
상속도 일종의 '결합'이다. 자식클래스와 부모클래스, 부모의 부모, 또 그 부모 이렇게 연결되는것은 물론 , 자식클래스를 사용하는 코드도 이 클래스의 모든 조상과 얽히게 된다.!
상속을 새로운 타입을 정의하는 방법이라 여기기도한다. 설계할때 이들이 가장좋아하는 그림은 '클래스 계층도'로 자꾸 풀어야할 문제를 종류별로 분류하려한다. 하지만 안타깝게도 클래스사이의 아주 작은 미묘한 차이까지 잡아내서 표현하기위해 계층위에 계층을 덧붙이다보면 클래스 계층도는 순식간에 벽면 전체를 덮는 괴물로 자라난다. 이런 복잡성은 어플리케이션을 더 취약하게 만들며, 변경사항이 나타나면 위아래로 큰 영향을 미칠수 있다.
더욱 나쁜것은 다중상속 문제이다. 모델링을 하려면 다중상속이 필요할 수도있지만 모호성 방식에 의심스러운 부분들이 있었기에, 그 결과 이제는 많은객체 지향 언어에서 다중상속을 지원하지않는다.아무리 복잡한 클래스 계층도가 마음에 들더라도 어차피 우리의 도메인을 정확히 모델링 할 순 없다.
프로그래밍의 다른 모든것과 마찬가지로 우리의 목표는 의도를 가장 잘 드러내는 기법을 사용하는 것이어야 한다. 그리고 정글 전체를 끌어들이지 않도록 조심하라.
당신이 원한 것은 바나나 하나였지만, 당신이 받은 것은 바나나를 들고 있는 고릴라와 정글 전체이다. -조 암스트롱
외부 설정으로 애플리케이션을 조정할 수있게 하라
일반적으로 설정 데이터안에 넣는것은 다음과 같다.
대부분 프레임워크와 상당수의 애플리케이션이 설정을 일반파일이나 데이터베이스 테이블로 관리한다. 정보를 일반파일로 관리할때는 널리쓰이는 일반 텍스트형식을 사용하는 추세이다.
2021년 기준으로 JSON이 제일 많이 쓰인다. 만약 정보가 구조화되어있고 사용자가 바꿀수 있는경우 데이터베이스 테이블에 저장하는 편이 나을것이다.
정적설정이 많이 쓰이지만 우리는 다른 방식을 더 선호한다. 설정 정보를 애플리케이션 외부에서 관맇는 것은 동일하지만, 일반 파일이나 데이터베이스가 아니라 서비스 API 뒤에서 관리하는 것을 선호한다. 이런 서비스형 설정에는 몇가지 장점이 있다.
여러 애플리케이션이 설정 정보를 공유할 수있다.
(인증/접근 제어를 붙여서 앱마다 정보가 다르게 만들수도 있다.)
여러 인스턴스에 걸쳐서 전체설정을 한번에 바꿀 수있다.
설정 데이터를 전용 UI로 관리할 수있다
설정 데이터를 동적으로 계속 바꿀 수 있다.
설정데이터를 동적으로 바꿀수있는것은 고가용성 애플리케이션을 만들때 매우 중요하다. 설정 서비스를 사용하면 애플리케이션의 각 컴포넌트가 자신이 사용하는 설정값이 바뀔때 알림을 보내달라고 등록할 수 있다.
실제로 변경이 일어나면, 설정서비스가 바뀐값을 담은 메시지를 일일이 보내준다. 어떤 형태를 사용하든, 설정 정보가 애플리케이션의 동작을 제어해야한다. 설정 정보를 바꾸기위해 빌드가 필요해선 안된다.
외부설정을 사용하지않는다면 코드는 '적응성'과 '유연성'을 포기해야한다. 도도는 인간과 가축의 등장에 적응하지 못하고 순식간에 멸종한 새이다.
우리의 프로젝트와 경력이 도도의 전철을 밟지않도록 해야할것이다.
이번 파트 역시 가면갈수록 어려워지고있다. 다시 보며 읽어가며 이해가 필요할듯 싶다. 정말 다른분들의 리뷰를 꼭 챙겨봐야할 시점이된것이다.
첫 토픽은 그나마 조금이라도 이해를 하고 넘긴 수준이었지만, 마지막 토픽 전까지 마치 설사하듯 읽고 써내려간 수준이었다.. 어렵다..ㅠ 그런의미에 내일 복습을 잘해야할것이다.