도서/IT

실용주의 프로그래머

MAKGA 2022. 2. 14. 21:50
320x100

 


1. 고양이가 내 소스코드를 삼켰어요

"가장 큰 약점은 약점을 보일 것에 대한 두려움이다."

실용주의 철학의 초석 중 하나는 경력 향상, 프로젝트, 일상 업무의 면에서 자신과 자신의 행동에 대해 책임을 지는 것이다.

다른 사람이나 다른 무언가를 비난하거나 변명을 만들어 내지 말라. 모든 문제가 벤더, 언어, 경영진 혹은 동료 때문이라고 떠넘기지 말라. 이들이 모두 한몫씩 했을 수 있겠지만 변명이 아닌 해결안을 제공하는 것은 여러분에게 달려 있다.소스코드가 날아갔는데 백업이 없다면 여러분의 잘못이다. '고양이가 내 소스코드를 삼켰어요'라고 상관에게 말하는 것은 별 도움이 안 될 것이다.

"어설픈 변명을 만들지 말고 대안을 제시하라"

 

변명 대신에 대안을 제시하라. 안 된다고 하지 말고 상황을 개선하기 위해 무엇을 할 수 있는지 설명하라. (리팩터링? 프로토타입? 테스트? 자동화? 자원 추가?) 부탁하는 것을 어려워하지 말고, 도움이 필요하다는 사실을 인정하라.

은행원이나 자동차 수리공, 점원이 여러분 앞에서 어설픈 변명을 늘어놓는다면 어떻게 반응하겠는가? 결과적으로 그 회사에 대해 어떤 생각을 갖게 되는가?


2. 소프트웨어 엔트로피

소프트웨어의 무질서도가 증가할 때 프로그래머들은 이를 '소프트웨어의 부패'라고 일컫는다.

 

오랜 기간 수리하지 않고 방치된 창문 하나가 거주자들에게 버려진 느낌을 스며들게 한다.

깨진 창문을 내버려두지 말라.

'깨진 창문'(나쁜 설계, 잘못된 결정, 혹은 형편없는 코드)을 고치지 않은 채로 내버려 두지 말라. 발견하자마자 바로 고쳐라. 고칠 시간이 충분하지 않다면 판자로 덮는 것만이라도 하라. (Not Implemented이라는 메시지를 표시등) 방치는 다른 어떤 요인보다도 부패를 더 가속시킨다.

 

코드가 청순할 정도로 아름다운 프로젝트와 팀에 여러분이 속해 있다면, 아마도 불을 끄려 하지만 깨끗한 장식 때문에 불을 끄지 못하는 소방관 비유와 마찬가지로 별도의 특별한 주의를 기울여서 엉망으로 만들지 않도록 노력할 확률이 높다. 비록 불길(데드라인, 출하 날짜, 시사회 데모등)이 일어날지라도 엉망진창으로 만드는 첫째 사람이 자신이 되는 것만은 피하려 한다.


3. 돌멩이 수프와 개구리 삶기

무엇을 해야 하는지, 어떻게 해야 하는지 정확히 아는 상황이 있다. 하지만 일을 착수하려고 허락을 구하는 때부터, 뭔가가 지연되거나 사람들이 멍한 눈으로 여러분을 바라본다. 모든 사람이 각자 자신의 자원을 지키려고 할 것이다. 때때로 이걸 '시작 피로'라고 부른다.

돌멩이(마중물)를 내놔야 할 때다. 큰 무리 없이 요구할 수 있을 만한 것을 찾아내라. 그리고는 "만약 ..를 추가하기만 하면 더 나아지겠죠" 하고 그다지 중요하지 않은 것처럼 가장해 말하라. 그리고 물러나서 여러분들이 원했던 기능을 추가해 달라고 그들이 부탁하기 시작할 때까지 기다려라. 계속되는 성공에 합류하기란 쉽다. 그들에게 미래를 살짝이라도 보여주면 그들은 원조를 위해 집결할 것이다.

변화의 촉매가 되라

한 가지에 너무 지나치게 집중하느라 나머지에 대해선 잊어버리는 경우가 있다. 소프트웨어 참사는 대부분 너무 작아 알아채기 힘들 정도에서 시작하고, 프로젝트 폭주는 대부분 어느 날 갑자기 일어난다. 의욕과 팀 자체의 파괴는 종종 작은 것들의 누적에서 온다.

큰 그림을 기억하라

차가운 물이 든 냄비 속에 개구리를 넣고 조금씩 물을 덥히면 개구리는 온도가 서서히 오르는 것을 감지 못하고 삶아질 때까지 그냥 그대로 있을 것이다. 그런 개구리가 되지 마라. 큰 그림에 늘 주의를 기울여라. 개인적으로 무엇을 하고 있는가에만 정신을 쏟지 말고, 주변에서 무슨 일이 벌어지는지 지속적으로 살펴보라.


4. 적당히 괜찮은 소프트웨어

"우리는 종종 뭔가 나아지게 하려다가 괜찮은 것마저 망친다."

실세계에서는 완벽한 것을 만들어 내기란 불가능하다. 특히 버그 없는 소프트웨어는 더더욱.

그래서 우리는 적당히 괜찮은 - 자기 마음의 평화를 유지하기에 적당히 괜찮은 - 소프트웨어를 만들도록 자신을 단련할 수 있다. 하지만 '적당히 괜찮은' 이라는 문구는 너절하거나 형편없는 코드를 의미하지 않는다. 

 

타협 과정에 사용자를 참여시켜라.

여러분은 보통 다른 사람을 위해 소프트웨어를 작성한다. 하지만 소프트웨어가 얼마나 좋아야 하는지 사용자들에게 얼마나 자주 묻는가?

품질을 요구사항으로 만들어라

놀랍게도 많은 사용자들은 멀티미디어 버전을 위해 일 년을 기다리느니 차라리 오늘 당장 좀 불편한 소프트웨어를 사용하고 싶어 한다. 오늘의 훌륭한 소프트웨어는 내일의 완벽한 소프트웨어보다 낫다. 사용자들에게 직접 만져볼 수 있는 것을 일찍 준다면, 피드백을 통해 종국에는 더 나은 솔루션에 도달할 수 있을 것이다.

 

언제 멈춰야 할지 알라

완벽하게 훌륭한 프로그램을 과도하게 장식하거나 지나칠 정도로 다듬느라 망치지 말라. 완벽하지 않을 수도 있다. 하지만 걱정하지 마라. 완벽해지기란 불가능 하다.


5. 지식 포트폴리오

"지식에 대한 투자가 언제나 최고의 이윤을 낸다."

 

포트폴리오 만들기

주기적인 투자: 자신의 지식 포트폴리오에 주기적으로 투자해야 한다. 소량일지라도 습관 자체가 금액의 합계만큼이나 중요하다.

다각화: 여러 가지를 알면 알수록 자신의 가치는 더욱 높아진다. 기본적으로 현재 작업에 사용하는 특정 기술의 등장과 퇴장을 알아야 한다. 더 많은 기술에 익숙하다면, 변화에 더 잘 적응할 수 있을 것이다.

리스트 관리: 어느 날 갑자기 무너질지 모를 위험에 모두 투자하는 것이 좋은 생각은 아니다. 여러분의 기술 달걀을 한 바구니에 모두 담지 마라.

싸게 사서 비싸게 팔기: 새롭게 떠오르는 기술이 인기를 끌기 전에 미리 알고 학습하는 것은 어려울 수 있지만, 이익 또한 그만큼 클 수 있다.

검토 및 재조정: 이 산업은 매우 동적이다. 인기 있던 기술이 사라질 수 있고, 한동안 사용하지 않았던 기술을 복습해야 할 필요가 생길지도 모르겠다.

지식 포트폴리오에 주기적으로 투자하라

목표

자신의 포트폴리오에 자금을 제공할 지식 자산을 얻는 최선의 길은 무엇일까?

Θ 매년 새로운 언어를 최소 하나는 배워라: 다른 언어는 동일한 문제를 다르게 푼다. 몇 개의 서로 다른 접근법을 알면 사고를 확장하고 판에 박힌 사고에 갇히는 걸 예방하는데 도움이 된다.

Θ 기술 서적을 분기마다 한 권씩 읽어라: 습관이 들면 한 달에 한 권씩 읽어라. 현재 사용하는 기술을 완전히 익혔다면, 가지치기를 해서 지금 하는 프로젝트와 관련 없는 분야까지 공부 범위를 넓혀라.

Θ 비 기술 서적도 읽어라: 컴퓨터를 사용하는 것은 사람이라는 점을 기억하는 게 중요하다. 인간이라는 변수를 잊지 마라.

Θ 수업을 들어라: 근처의 대학, 시사회에서 열리는 흥미로운 강좌를 찾아보라.

Θ 지역 사용자 모임에 참여하라: 듣고만 오지 말고, 적극 참여하라. 고립은 경력에 치명적일 수 있다.

Θ 다른 환경에서 실험해보라: 윈도우에서만 일을 해 왔다면, 집에서는 유닉스를 갖고 놀아보라.

Θ 요즘 흐름을 놓치지 마라: 업계의 잡지와 기타 저널을 구독하라. 여러분의 현재 프로젝트와 다른 기술을 다루는 것도 몇 개 선택하라.

Θ 인터넷을 이용하라: 여러분이 찾는 정보의 원천을 찾기 위해 웹 서핑을 하라.

 

학습의 기회

누군가 질문을 한다. 여러분은 답이 뭔지 전혀 알지 못하고, 허물없이 그걸 인정한다.

거기에서 멈추지 말고 웹을 검색하고 도서관에 가보라. 스스로 답을 찾지 못하겠거든, 누가 답을 찾아줄 수 있을지 그 사람을 찾아라. 다른 사람들과 이야기함으로써 개인 네트워크를 구축하는데 도움이 되기도 하고, 답을 찾는 도중에 별로 관련이 없어 보이는 문제들에 대한 해답을 찾아서 놀라는 일도 생길 것이다.

독서와 연구는 시간이 걸리고, 시간은 늘 부족하다. 할 일 없는 시간을 위해 늘 읽을거리를 준비하라.

 

비판적 사고

마지막으로 중요한 점은 여러분이 읽거나 듣는 것에 대해 '비판적으로' 생각하는 것이다. 웹 검색 엔진에서 첫 머리에 나온 결과라고 해서 그것이 최선이 아니다. 콘텐츠 제공자가 돈을 지불했을 수도 있다.

읽고 듣는 것을 비판적으로 분석하라

6. 소통하라!

최고의 아이디어, 최상의 코드 혹은 가장 실용주의적인 사고 등이 있다고 해도 다른 사람들과 소통할 수 없다면 그것들은 궁극적으로 아무 효용이 없다.

개발자로서 우린 여러 층과 소통해야 한다. 최종 사용자의 요구를 이해하려고 노력하며 그들과 함께 일한다. 코드를 작성해 의도를 기계에 전달하고, 사고를 문서화해 다음 세대의 개발자들에게 전달한다. 제안서를 작성해 자원을 요구하기도 하고 보고하며, 새로운 접근법을 제안하기도 한다. 하루 중 가장 많은 시간을 소통하며 보내기 때문에 이를 잘해야 할 필요가 있다.

 

말하고 싶은 게 무언지 알아라

형식적인 의사소통에서 가장 어려운 부분은 말하고자 하는 것이 정확히 무엇인지 생각해 내는 것이다.

무엇을 말할지 미리 계획하고 개요를 작성하라. 그리고 잘 전달 되는지 자문하라. 그렇게 될 때까지 다듬어라.

 

청중을 알아라

전형적인 개발자가 난해한 기술의 장점에 대해 긴 독백을 읊조리는 동안, 앉아 있는 마케팅 부서장의 눈이 흐리멍텅해지는 회의에 참석해 봤다. 이것은 소통이 아니라 지껄임일 뿐이다.

 

WISDOM - 청중 이해하기

Θ 무엇(what)을 배우길 원하는가?

Θ 말하려는 것에서 그들이 관심(interest) 있어 하는 건 무엇인가?

Θ 얼마나 소양(sophisticated)이 있는가?

Θ 어느 정도의 구체적인(detail) 내용을 원하는가?

Θ 누가 정보를 소유(owe)하길 원하는가?

Θ 그들이 경청하도록 동기(motive)를 주려면 어떻게 해야 할까?

 

예컨데 최종 사용자가 버그 보고를 할 수 있는 웹 기반 시스템을 제안하고 싶다고 해보자. 이 시스템을 청중에 따라 여러 가지 방법으로 보여줄 수 있다. 최종 사용자는 24시간 버그 제보를 할 수 있고, 영업부는 이 사실로 판촉 활동을 할 수 있으며, 지원 부서는 직원이 덜 필요하고, 개발자들은 웹 기반 클라이언트 서버 기술을 경험할 수 있음에 기뻐할 것이다.

각 그룹에 맞는 접근을 통해, 그들이 모두 여러분의 프로젝트에 대해 열광하도록 만들 수 있다.

 

때를 골라라

청중이 무엇을 듣기 원하는지 이해하기 위해서는, 그들의 우선순위를 알아야 한다. 말하는 내용만 아니라 말하는 시간도 적절하게 하라. 가끔 '~에 대해 이야기할 좋은 때일까?'라는 간단한 질문을 해보는 것만으로도 충분하다.

 

스타일을 골라라

전달하는 스타일이  청중에 어울리도록 조정하라.

어떤 사람들은 '그저 사실만 전달하는' 브리핑을 원하고, 다른 사람들은 본론에 들어가기 전에 길고 폭넓은 한담을 원한다. 어떤 이는 두꺼운 문서로 보고 받길 좋아하는 반면, 다른 이는 간단한 메모나 이메일을 기대한다.

 

멋져 보이게 하라

많은 개발자들은 문서를 만들 때에 내용에만 집중한다. 아이디어가 중요하지만, 청중에게 전달하기 위한 멋있는 매개물이 필요하다.

문서를 꾸미고, 맞춤범도 검사하라.

 

듣는 사람이 되어라

사람들이 하는 말을 귀기울려 듣지 않는다면, 그들 역시 여러분의 말을 귀기울여 듣지 않을 것이다. 질문을 해서 사람들이 이야기를 하도록 북돋우거나, 여러분이 한 말을 그들이 요약하도록 하라.

 

응답하라

누군가에게 질문을 했는데 아무런 응답도 없다면 무례하다고 느낄 것이다. 여러분은 얼마나 자주 응답을 못하는가? 늘 사람들에게 응답을 해주면 때때로 일어나는 실수에 대해 훨씬 더 관대하질 것이고, 여러분이 그 사항을 아직 잊지 않았다는 느낌을 줄 것이다.


7. 중복의 해악

소프트웨어를 신뢰성 높게 개발하고, 개발을 이해하고 유지보수하기 쉽게 만드는 유일한 길은 우리가 DIY 원칙이라고 부르는 것을 따르는 것뿐이라 생각한다.

DRY - 반복하지 마라 (Don't Repeat Yourself)

DRY를 따르지 않는다면, 남는 방법은 똑같은 것이 두 군데 이상에 표현되게 하는 것이다. 하나를 바꾼다면 나머지도 바꿔야 함을 기억해야 한다.

 

어떻게 중복이 생기는가?

우리가 보아온 대부분의 중복은 다음 범주 중 하나였다.

 

Θ 강요된 중복: 여러 플랫폼을 지원해야 하는 경우, 각각에 대해 프로그래밍 언어, 라이브러리, 개발 환경이 필요하고 여기서 공유된 정의와 프로시저들이 중복되게 된다.

하지만 각각의 지식을 한 곳에 두면서 DRY 원칙을 따르고, 동시에 우리의 삶을 더 편하게 만드는 길이 존재한다.

- 정보의 다양한 표현 양식: 클라이언트 쪽과 서버 쪽에서 서로 다른 언어를 사용하지만 공통된 구조를 양쪽 모두에서 표현해야 할 때가 있다. 보통은 약간의 창의력만 있으면 중복의 필요를 제거할 수 있다. 흔히 간단한 필터나 코드 생성기를 작성하는 것이 해답이다. 소프트웨어가 빌드될 때마다 간단한 코드 생성기를 사용해 공동의 메타데이터 표현에서 여러 개의 언어에 걸쳐 있는 구조를 만들어낼 수 있다.

- 코드 내의 문서화: DRY 원칙은 낮은 차원의 지식은 그것이 속하는 코드를 놔두고, 주석은 다른 높은 차원의 설명을 위해 아껴두라고 말한다. 그러지 않으면 매번 코드와 주석을 바꾸어야 한다.

- 문서화와 코드: 문서와 코드는 모두 동일 지식에 대한 표현이다. 하지만 마감이 다가올 수록 문서의 갱신을 뒤로 미루기 쉽다는 걸 안다.

- 언어에 관한 문제: 많은 언어가 소스코드에 상당한 양의 중복을 강요한다. 보통 인터페이스와 모듈을 분리하는 경우에 발생한다. 언어적인 부분은 어쩔 수 없지만, 헤더와 구현 파일 양 쪽에 있는 주석은 두 개 파일에 걸쳐 중복될 이유가 없다. 헤더 파일에는 인터페이스에 대한 사항을 기록하고, 구현 파일에는 그 코드의 사용자가 알 필요 없는 상세한 것을 기록하라.

 

Θ 부주의한 중복: 때때로 설계 실수로 중복이 나타나기도 한다. 내재하는 비즈니스 모델에 따라 그것을 정규화 하라.

 

Θ 참을성 없는 중복: 모든 프로젝트는 시간의 압박을 받는다. 원래의 것을 복사하고 약간만 바꾸도록 유혹받을 것이다. 만약 그렇다면 '돌아가는 길이 지름길이다'라는 진부한 격언을 기억하라. 지금 당장 몇 초를 절약할 수  있을지라도, 나중에는 몇 시간을 잃게 될런지 모른다.

 

Θ 개발자간의 중복: 한 프로젝트에서 일하는 서로 다른 개발자 사이에서 발생한다. 높은 차원의 해법으로, 깨끗한 설계와 강력하고 기술적인 프로젝트 리더, 그리고 그 설계 내에서 책임의 분배가 제대로 이해되도록 하는 것, 이런 것들로 개발자 간의 중복 문제를 다루어라. 우리가 느끼기에 최선책은 개발자간에 적극적이고 빈번한 소통을 장려해서 공통의 문제를 다루기 위한 토론장을 만들어라.

재사용하기 쉽게 만들라.

8. 직교성

컴퓨팅에서 직교성이란 일종의 독립성이나, 결합도 줄이기를 의미한다. 하나가 바뀌어도 나머지에 영향도 주지 않으면 서로 직교한다고 할수 있다.

 

비직교적인 시스템

헬리콥터는 왼쪽 레버를 낮추면 이를 상쇄해 주도록 오른쪽 막대기를 뒤로 당기고 오른쪽 페달을 밟아야 한다. 이 변화 각각이 다시 다른 모든 조종 행위에 영향을 끼친다. 헬리콥터 조종은 단연코 직교적이지 않다.

 

직교성의 장점

시스템의 컴포넌트들이 고도로 상호의존적인 경우, 특정 국지적 부분만 수정하는 방법이란 없다.

관련 없는 것들 간에 서로 영향이 없게 해라.

컴포넌트들이 각기 격리되어 있으면 어느 하나를 바꿀 때 나머지 것들을 걱정하지 않아도 된다.

직교적인 시스템을 작성하면 두 가지 큰 장점이 있다. 생산성 향상과 리스크 감소.

 

생산성 향상

Θ 변화가 국소화되서 개발 시간과 테스트 시간이 줄어든다. 간단한 컴포넌트들은 설계하고, 코딩하고, 단위 테스트 하고, 잊어버릴 수 있다.

Θ 재사용을 촉진한다. 컴포넌트들에 명확하고 잘 정의된 책임이 할당되어 있다면 애초의 구현자들이 미처 생각하지 못했던 방식으로 새로운 컴포넌트와 결합할 수 있다.

 

리스크 감소

Θ 감염된 코드는 격리된다. 그 부분만 도려내고 새롭고 건강한 코드로 이식해 넣기도 쉽다.

Θ 시스템이 잘 깨어지지 않는다. 어떤 부분을 바꾸고 수리해도 거기서 생기는 문제점들은 그 부분에만 한정될 것이다.

Θ 직교적인 시스템은 해당 컴포넌트들에 대해 테스트를 설계하고 실행하기 훨씬 쉽기 때문에, 아무래도 더 많은 테스트를 하게 된다.

Θ 써드파티 컴포넌트로 연결되는 인터페이스들이 전체 개발의 작은 부분에 한정되기 때문에 특정 플랫폼에 덜 종속될 것이다.

 

직교성의 원칙을 일에 적용할수 있는 몇 가지 방법을 알아보자.

 

프로젝트 팀

팀 내 업무가 겹치는 영역이 많다면 구성원들은 책임 영역에 대해 혼동하게 된다. 뭘 하나 바꾸려고 해도 그들 중 누구라도 영향을 받을 수 있기 때문에 전체 팀원이 모여야 한다.

해결을 위해 우리는 애플리케이션에서 인프라를 분리하는 방식을 선호한다. 주된 인프라 컴포넌트(데이터베이스, 커뮤니케이션 인터페이스, 미들웨어 레이어 등)마다 서브팀을 할당한다. 애플리케이션 기능의 분할 역시 유사하게 나뉜다.

프로젝트 팀 구조가 얼마나 직교성을 갖는지 측정해보려면 요청된 변화에 대한 회의에 참석해야 하는 사람이 몇 명인가를 보라. 숫자가 클 수록 그룹의 직교성이 낮다. (서브팀끼리 지속적으로 의사소통을 장려한다)

 

설계

시스템은 협력하는 모듈들의 집합으로 구성되어야 하고, 각 모듈은 다른 부분과 독립적인 기능을 구현해야 한다. 때로는 이런 컴포넌트들이 레이어로 조직되기도 하는데, 각 레이어는 하나의 추상화 층을 이루게 된다.

이 레이어식 접근은 직교적 시스템을 설계하는 강력한 방법이다. 각 레이어는 자기 밑에 있는 레이어들이 제공하는 추상화만을 이용하기 때문에, 코드에 영향을 끼치지 않으면서 아래에 있는 다른 구현들을 바꾸는 높은 유연성을 얻을 수 있다.

직교적인 설계를 테스트하는 손쉬운 방법이 있다. '특정 기능에 대한 요구사항을 극적으로 변경했을 경우, 몇 개의 모듈이 영향을 받는가?' 직교적인 시스템에서는 답이 '하나'여야 한다.

 

툴킷과 라이브러리

써드파티 툴킷이나 라이브러리를 도입할 때, 시스템의 직교성을 보존할 수 있는지 주의 깊게 살펴보기 바란다. 도입할 때 이것이 여러분의 코드에 있어서는 안 될 변화를 강요하고 있지 않은지 검토해 보라. 만약 객체 영속 방식이 투명하다면 이것은 직교적이다. 하지만 특별한 방식으로 객체를 생성하고 접근해야 한다면 그렇지 않다.

직교성에 흥미로운 변형은 애스펙트 지향 프로그래밍(AOP)이다. 예를 들면, 로그 메시지는 소스코드 이곳저곳에 흩뿌려져 있는 로그 함수 호출을 통해 기록된다. AOP를 사용하면 로깅되고 있는 코드와 직교적으로 로깅을 구현할 수 있다. 다음은 Fred 클래스의 모든 메서드에 진입하기 전에 로그를 남기는 에스팩트다.

aspect Trace {
  advise * Fred.*(..) {
    static before {
      Log.write("->Entering" + thisJoinPoint.methodName);
    }
  }
}

 

코딩

코딩할 때 직교성을 유지하기 위해 사용할 수 있는 몇 가지 기법이 있다.

Θ 코드의 결합도를 줄여라: 부끄럼타는 코드를 작성하라. 즉 불필요한 어떤 것도 다른 모듈에 보여주지 않으며, 다른 모듈의 구현에 의존하지 않는 코드를 작성하라. 디미터 법칙을 따르려 노력해보자. 객체의 상태를 바꿀 필요가 있다면, 객체 스스로가 여러분을 위해 그러한 일을 수행하게 만들라.

Θ 전역 데이터를 피하라: 코드가 전역 데이터를 참조할 때마다 데이터를 공유하는 다른 컴포넌트와 묶이게 된다. 일반적으로 모듀링 필요로 하는 컨텍스트를 명시적으로 넘겨주면 코드를 이해하고 유지보수하기 쉽게 된다. 객체지향 애플리케이션에서는 컨텍스트를 객체 생성자의 매개 변수로 넘기기도 한다. 또한 컨텍스트를 포함하는 구조체를 만들어 이를 필요로 하는 모듈에 레퍼런스로 넘겨줄 수도 있다.

Θ 유사한 함수를 피하라: 종종 유사해 보이는 함수의 집합을 구현해야 할 때가 있다. 아마 시작과 끝에서는 공통 코드를 공유하지만 중간의 알고리즘이 다를 것이다. 중복 코드는 구조적 문제의 징후다. 스트래티지 패턴을 사용해 더 나은 구현을 할 수는 없는지 고려해보라.

 

테스트

직교적으로 설계된 시스템은 컴포넌트 간의 상호작용이 형식화되고 제한되었기 때문에 테스트의 많은 부분을 각각 모듈 수준에서 수행할 수 있어 테스트가 쉽다. 우리는 모듈이 자신만의 단위 테스트를 위한 테스트케이스를 갖고, 테스트가 정규 빌드 과정의 일부로 수행되어야 한다고 생각한다.

단위 테스트를 위해 시스템의 나머지 상당 부분을 끌여들여 테스트케이스를 만들고 링크해야 하지 않은가? 그렇다면 이는 결합도를 적절히 줄이지 못했다는 증거다.


9. 가역성

당신이 가진 생각이 딱 하나밖에 없다면, 그것만큼 위험한 것은 없다.

 

무언가를 구현하는 방법에는 여러 가지 길이 있고, 보통 하나의 솔루션에는 여러 벤더의 제품이 존재한다. '이것은 이 방법으로만 해결할 수 있어'와 같은 근시안적인 생각을 갖고 프로젝트에 참여한다면 아마도 예상치 못했던 경우에 의해 한숨지을 일이 많을 것이다.

 

가역성

우리가 프로젝트 초기에 항상 최선의 결정을 내리진 못한다. 개발 도중 처음 결정과 달라지는 경우가 많다. 아이디어를 올바르게 추상화하여 어떤 하나의 지점이 영속 서비스를 제공하도록 만들었다면 도중에 말을 갈아탈 수 있는 유연성을 갖게 될 것이다.

최종 결정이란 없다.

 

유연한 아키텍처

많은 사람들이 코드를 유연하게 유지하려고 노력한다. 하지만 아키텍처, 배포, 벤더 통합 영역의 유연성에 대해서도 관심을 기울일 필요가 있다.

보통 특정 벤더 제품에 대한 의존도 등은 잘 정의하고 추상화한 인터페이스를 통해 감출 수 있다. 만약 벤더 의존적인 코드를 깨끗하게 분리하지 않으면 어떻게 될까? 벤더 의존적인 수행문들이 코드 전반에 흩어져 있을 것이고, 이는 유지보수성, 유연성을 극도로 떨어뜨리게 된다. 요구사항을 메타데이터에 넣고, 필요한 수행문을 코드에 넣을 때 애스팩트나 펄 등을 이용해 메커니즘을 자동화시켜라. 그리고 어떤 메커니즘을 이용하든 이를 되돌릴 수 있도록 하라. 무언가 자동으로 추가할 수 있다면, 역시 자동으로 빼낼 수도 있다.


10. 예광탄

예광탄은 탄창의 일반 탄환들 사이에 일정한 간격으로 끼어있어 타겟과 총 사이에 빛의 궤적을 남겨 목표를 정확하게 맞출 수 있다.

 

어둠 속에서 빛을 내는 코드

예광탄이 효과 있는 까닭은 일반 탄환과 동일한 환경과 제약 조건에서 발사되고 날아가기 때문이다.

코딩에서도 동일한 효과를 얻으려면, 우리를 요구사항으로부터 최종 시스템의 일부 측면에까지 빨리, 눈에 보이게, 반복적으로 도달하게 해줄 무언가를 찾아야 한다.

목표물을 찾기 위해 예광탄을 써라.

 

예광탄 코드는 나중에 버리려고 만드는 것이 아니다. 그것은 계속 사용할 코드다. 예광탄 코드에도 상용 코드와 마찬가지로 모든 에러 검사, 구조화, 문서화, 자기 검사가 포함된다. 단지 아직 완전한 기능이 들어있지 않을 뿐이다. 하지만 시스템을 구성하는 요소를 모두 연결해 놓은 후라면 목표물에 얼마나 가까이 다가섰는지 확인할 수 있으며, 필요하다면 조정도 할 수 있다. 그렇게해서 일단 목표물을 맞춘다면 기능을 추가하는 일은 쉽다.

 

예광탄 코드 접근 방법에는 여러 장점이 있다.

Θ 사용자들은 뭔가 작동되는 것을 일찍부터 보게 된다: 사용자들은 지금 보는 것이 아직 완성되지 않은 것임을 이해할 것이다. 기능이 없다고 실망하지 않을 것이며, 오히려 자기가 쓸 시스템에 눈에 보이는 진전이 있음을 보게 되어 기뻐할 것이다.

Θ 개발자들은 들어가서 일할 수 있는 구조를 얻는다: 아무것도 쓰여 있지 않은 백지가 가장 채우기 힘든 종이다. 일단 애플리케이션의 모든 요소간 상호작용을 다 만들고 코드로 구체화까지 해 놓은 후라면, 더 이상 무에서 많은 것을 만들어 낼 필요가 없어진다.

Θ 통합 작업을 수행할 기반이 생긴다: 시스템의 요소들이 모두 연결된 다음에는 코드를  추가할 수 있는 어떤 환경이 생긴다. 새로 도입된 부분이 어떤 영향을 주는지는 더욱 명확하게 보이며, 상호작용들은 더 제한적이다.

Θ 보여줄 것이 생긴다: 투자자들은 빠르게 데모를 보고 싶어 하는 경향을 보인다. 예광탄 코드 방법에서는 그들에게 보여줄 무엇인가가 언제나 마련되어 있다.

Θ 진전 상황에 대해 더 정확하게 감을 잡을 수 있다: 개발자들은 유스 케이스를 한 번에 하나씩 다룬다. 하나가 끝나면 다음으로 넘어간다. 이러면 수행을 평가하기도 쉽고 사용자들에게 얼마나 진전되었는지 보여주기도 쉽다.

 

예광탄이 언제나 목표물을 맞추는 것이 아니다.

예광탄은 지금 맞추고 있는 것이 무엇인지 보여준다.

예광탄 코드도 마찬가지다. 일이 어떻게 될지 100% 확신할 수 없는 상황에서 사용된다. 지금 있는 것을 목표물에 가까이 가져가려면 어떻게 바꾸어야 할지 생각해내고, 가벼운 개발 방법론을 선택했다는 사실에 감사하라.

 

예광탄 코드 대 프로토타이핑

프로토타입은 최종 시스템의 어떤 특정한 측면을 탐샣 보는 것이 목표다. 어떤 개념을 구현해 보려고 시도할 때 대충 끼워 맞춘 것들을 모두 버린 다음, 실험 과정에서 얻은 교훈을 바탕으로 다시 코드를 만들게 된다.

예광탄 코드 접근 방법은 다른 종유릐 문제에 대한 대응 방법이다. 애플리케이션이 전체적으로 어떻게 연결되는지를 알고 싶다. 사용자들에게 실제로 애플리케이션의 요소들이 어떻게 상호작용 하는지 보이고 싶고, 개발자들에게는 코드를 붙일 아키텍처적 골격을 제시하고 싶다. 이 경우, 여러분은 대강 구현한 컨테이너 채우는 알고리즘과 단순하지만 동작은 하는 사용자 인터페이스로 구성된 예광탄을 만들 것이다.

 

프로토 타입은 나중에 버릴 수 있는 코드를 만들고 예광탄 코드는 기능은 별로 없지만 완결된 코드이며, 최종 시스템 골격 일부를 이룬다.


11. 프로토타입과 포스트잇

소프트웨어 프로토타입은 위험 요소를 분석하고 노출시키며 이를 매우 저렴한 비용으로 바로잡을 기회를 얻는 것이다.

코드 외에 포스트잇은 작업흐름과 애플리케이션 로직과 같은 동적인 것들을 프로토타이핑해 볼 수 있는 훌륭한 도구다. 기능은 구현하지 않고 인터페이스만을 그려보는 방법으로 프로토타입을 만들 수 있다.

 

프로토타입의 대상

프로토타입을 통해 조사할 대상은 무엇인가? 위험을 수반하는 모든 것이다. 또한 이전에 해본 적이 없는 것, 최종 시스템에 매우 중요한 것 등이 대상이 된다.

Θ 아키텍처

Θ 기존 시스템에 추가할 새로운 기능

Θ 써드파티 도구나 컴포넌트

Θ 사용자 인터페이스 설계

프로토타이핑은 학습 경험이며, 프로토타입의 가치는 생성된 코드에 있는 것이 아니라 이를 통해 배우게 되는 교훈에 있다.

프로토타입을 통해 학습하라

 

아키텍처 프로토타이핑

많은 프로토타입들이 전체 시스템을 모델링하기 위해 만들어진다. 프로토타입에 기대하는 것은 전체적으로 시스템이 어떻게 동작할지에 대한 감을 잡는 것이다. 다시 말하지만 세부사항은 무시한다. 다음은 아키텍처 프로토타입에서 규명할 만한 사항이다.

Θ 주요 컴포넌트의 책임이 잘 정의되었고 적절한가?

Θ 주요 컴포넌트 간의 협력관계가 잘 정의되었는가?

Θ 결합도는 최소화되었는가?

Θ 잠재적 중복을 찾아낼 수 있는가?

Θ 인터페이스 정의와 제약 사항은 수용할만한가?

Θ 각 모듈이 실행 중에 필요로 하는 데이터에 접근할 수 있는 경로를 갖고 있는가? 모듈은 데이터를 필요로 할 때 데이터에 접근할 수 있는가?

 

어떻게 프로토타입을 사용하지 않을 것인가?

프로토타입을 코드로 만들 때는 시작하기 전에 항상 모든 사람에게 폐기처분할 코드를 작성하고 있다는 사실을 이해시켜야 한다.

만약 작업하는 환경이나 문화에서 프로토타입 코드의 목적이 잘못 해석될 가능성이 크다고 느낀다면, 예광탄 접근 방식을 취한는 게 나을 것이다. 향후 개발에서 사용할 수 있는 프레임워크를 얻을 수 있기 때문이다.

 


12. 도메인 언어

언어의 한계가 곧 자기 세계의 한계다

 

컴퓨터 언어는 여러분이 문제에 대해 생각하는 방식과 의사소통에 대해서 생각하는 방식에 영향을 미친다. 모든 언어에는 그 언어의 특징들이 딸려오는데, 이 특징들은 어떤 해결 방안을 제시할 수도 있지만 가려버리기도 한다. 거꾸로 도메인의 언어가 프로그래밍적 해결 방안을 제안하기도 한다.

어떤 시스템을 제안하는 사용자의 말을 듣다보면, 그들이 정확히 시스템이 어떻게 동작해야 하는지 우리에게 말해주는 경우도 있다. 사용자들이 정리가 잘 된 진술을 많이 해준다면, 여러분은 그들이 원하는 내용을 정확히 표현하는, 그 애플리케이션 도메인에 맞추어진 소형 언어를 만들 수 있다.

이 언어가 꼭 실행가능할 필요는 없다. 명세로만 쓰여도 되고, 나아가 어떻게 구현할지 생각해 볼 수도 있다.

문제 도메인에 가깝게 프로그래밍하라

 

우리는 프로젝트를 문제 도메인에 가까운 곳으로 옮길 방법들을 궁리해봐야 한다고 생각한다. 더 높은 추상화 수준에서 작업함으로써 사소한 구현의 세부사항들을 무시하고 도메인의 문제들을 푸는 일에만 정신을 집중할 수 있다.


13. 추정

추정에 대한 지식을 배운 후에 경험을 통해 추정 능력을 계발하고, 어디에 크기에 대한 직관적 느낌을 적용해야 할지 알게 된다면, 무언가의 가능성을 가늠할 수 있는 마술과 같은 능력을 발휘할 수 있게 될 것이다. 코딩할 때에도 어떤 시스템을 최적화해야 하고, 어떤 서브시스템을 그대로 남겨두어도 될지를 판단할 수 있는 능력을 갖게 될 것이다.

추정을 통해 놀람을 피하라

 

얼마나 정확한 것이 충분히 정확한 것인가?

어떤 의미에서 모든 답은 추정치이다. 단지 누가 남보다 좀 더 정확한지가 다를뿐이다. 그러므로 누군가 추정치를 물었을 때, 자신에게 물어보아야 할 첫번째 질문은 여러분의 답변이 사용될 '상황'이다. 질문자가 매우 높은 정확도의 답을 요구하는가, 아니면 단순히 큰 그림만을 요구하는가?

추정에서 한 가지 재밌는 사실은 사용하는 단위가 결과의 해석에 차이를 가져온다는 것이다. 130일은 5~7달 이라는 단위보다 더 높은 정확성을 내포한다. 여러분이 전달하려는 정확도를 고려하여 답변의 단위를 선택하라.

 

추정치는 어디에서 오는가?

모든 추정치는 문제의 모델에 기반한다. 하지만 모델을 작성하는 기술에 대해 깊이 있게 파고들기 전에 그 일을 해본 사람에게 물어봐라. 그들이 어떻게 문제를 해결했는지 이해하려 노력해보자. 다른 사람의 경험을 통해 성공적인 추정치를 낼 수 있다는 것을 알게 될 것이다.

 

무엇을 묻고 있는지를 이해하자

어떤 추정이건 첫 번째 단계는 상대방이 무엇을 묻고 있는지에 대해 이해하는 것이다. 앞선 정확도만이 아니라 도메인의 범위에 대해 감을 잡을 필요가 있다. 보통 이는 질문에 명시적으로 드러나진 않지만 미리 생각하는 습관을 기르는 것이 좋다.

 

시스템의 모델을 만들어보라

클라이언트가 요청한 것이 무엇인지 이해한후에는 대략적이고, 꾸밈없는 모델을 만들어 보라. 프로젝트에서 모델은 여러분의 조직이 개발을 하는 동안 사용할 디딤대가 되어줄 뿐 아니라 시스템을 어떻게 구현해야 할지에 대한 대략적인 그림을 제공해 줄 것이다.

모델을 만드는 과정에서 표면에 명확히 드러나지 않았던 이면의 패턴과 프로세스를 발견하게 된다.

 

모델을 컴포넌트로 나누어라

모델을 가졌다면 이를 컴포넌트로 분해할 수 있다. 각 컴포넌트가 전체 모델에 어떻게 기여하는지에 영향을 미치는 매개 변수를 갖고 있다는 것을 알게 될 것이다.

 

각 매개 변수에 값을 주어라

결과에 큰 영향을 미치는 매개 변수가 무엇인지를 규명하고, 이 매개 변수의 값들을 최대한 정확히 산출해내는 것이다. 이런 중요 매개 변수를 계산하는 데 취한 방법은 나름의 근거가 있어야 한다.

 

답을 계산하라

중요 매개 변수들의 값을 변경시켜 가면서 여러 번 계산을 해보고, 이 가운데 어떤 것이 모델과 잘 들어맞는지 찾아내라. 그리고 이러한 매개 변수에 기준해서 답변하라.

 

추정치를 기록하는 용기

여러분이 계산한 추정치를 기록해 놓고, 이 값이 실제 결과에 얼마나 가까운지를 평가해 보는 것은 좋은 생각이다.

추정치가 잘못되었더라도 도망가지 마라. 왜 추측과 실제 값이 달라졌는지 원인을 찾아야 한다. 매개 변수가 잘못되었든 모델 자체가 잘못되었을 수도 있다. 시간을 들여 규명하라. 다음 추정치는 훨씬 나아질 것이다.

 

프로젝트 일정 추정하기

추정에 대한 일반 법칙은 변화하는 애플리케이션의 복잡성과 변덕스러움 앞에 와해되기 쉽다. 프로젝트의 일정을 정할 수 있는 유일한 방법은 진행하는 해당 프로젝트를 경험하는 것뿐이란 사실을 알게 된다.

초기 기능의 구현과 테스트를 마친 후, 이를 첫 번째 반복의 끝으로 삼아라. 이 경험에 기반해 반복의 횟수와 각 반복에서 무엇을 할지에 대한 초기 추측을 다듬을 수 있다.

코드와 함께 일정도 반복하며 조정하라

 

이 방법은 경영자들에게 별로 인기가 없다. 그들은 프로젝트가 시작하기도 전에 정확한 숫자를 원하기 때문이다. 여러분은 그들이 팀, 팀의 생산성 그리고 환경이 일정을 결정한다는 사실을 이해하도록 도와야 한다.


14. 일반 텍스트의 힘

일반 텍스트란 사람이 직접 읽고 이해할 수 있는 형태의 인쇄가능한 문자로 이루어진 텍스트를 말한다.(XML등)

일반 텍스트를 사용하면 그걸 생성하는 애플리케이션에 상관없이 어떤 의미인지 자명한 데이터 흐름을 얻을 수 있다.

지식을 일반 텍스트로 저장하라

 

단점

일반 텍스트를 사용하면 압축된 이진 포맷을 사용하는 것보다 더 많은 공간을 차지할 수 있고, 일반 텍스트 파일을 해석하고 처리하는 데에 더 많은 계산이 필요할 수 있다.

 

텍스트의 힘

그럼 일반 텍스트를 사용하는 이유는 뭘까?

 

Θ 구식이 되는 것에 대한 보험: 사람이 읽을 수 있는 형태의 데이터는 다른 형태를 사용한 애플리케이션보다 오래 살아남는다

Θ 호환성: 컴퓨팅 세계의 거의 모든 도구들은 일반 텍스트를 다룰 수 있다.

Θ 더 쉬운 테스트: 특별한 도구를 만들어야 할 필요 없이 간단히 테스트 데이터를 추가 업데이트, 수정할 수 있다.


15. 조개 놀이
16. 파워 에디팅
17. 소스코드 관리
18. 디버깅
19. 텍스트 처리
20. 코드 생성기
21. 계약에 의한 설계
22. 죽은 프로그램은 거짓말을 하지 않는다
23. 단언적 프로그래밍
24. 언제 예외를 사용할까
25. 리소스 사용의 균형
26. 결합도 줄이기와 데미테르 법칙
27. 메타프로그래밍
28. 시간적 결합
29. 단지 뷰일 뿐이야
30. 칠판
31. 우연에 맡기는 프로그래밍
32. 알고리즘의 속도
33. 리팩터링
34. 테스트하기 쉬운 코드
35. 사악한 마법사
36. 요구사항의 구렁텅이
37. 불가능한 퍼즐 풀기
38. 준비가 되어야만
39. 명세의 함정
40. 동그라미와 화살표
41. 실용주의 팀
42. 유비쿼터스 자동화
43. 가차 없는 테스트
44. 결국은 모두 글쓰기
45. 위대한 유산
46. 오만과 편견


 

320x100

'도서 > IT' 카테고리의 다른 글

게임 프로그래밍 패턴  (0) 2022.09.17
C++ 최적화  (0) 2022.09.16
백세코딩  (0) 2022.01.30
[도메인 주도 설계란 무엇인가]  (0) 2021.11.27
C/C++ 프로그래머가 몰랐던 프로그램의 동작 원리  (0) 2021.10.30