책을 읽어보자/좋은 코드 나쁜 코드

[우테코 권장도서] 좋은코드 나쁜코드 1장

강한 맷돼지 2023. 8. 6. 15:36

1장 코드품질

드디어 사랑스러운 책 좋코나코를 할수있어서 기쁘다. 책을읽는데 많은생각이 들고 요즘 겪는 문제를 고민해볼수있어서 좋았다.

이제 책을 읽으며 느낀 감상을 정리해보려고 한다.

서론

우리는 일상생활에서 소프트웨어에 많이 의존하고있다. 다양한 프로그램이 있겠지만 버그가 났을시 그냥 짜증나고 마는 프로그램(우리가 오류처리안하고 그냥 배째라 넘어가는 앱같은거 -> 문제있음), 하지만 누군가의 인생이 뒤틀릴수도 있는 신뢰도가 필요한 은행프로그램도 있을것이다(실제로 은행권 사람들은 개발에 부담이있어서 가벼운 부서로 소속되기를 원하는것도 봤다.)

어쩃든 이런 코드의 신뢰도 혹은 유지보수가 높은 코드를 짜려면 고품질의 코드를 짜려는 노력을 해야하고 이는 단순 하나하나를 뜯어보면 보잘것 없어보이지만 스노우 볼링으로 모여서 결국 소프트웨어의 전반적인 품질을 결정하는것이다.(지금 고민하는게 너무 가지만 않는다면 맞다 신념을 가지자)

여기서 고품질 코드라면 당연히 갖춰야할 4가지 목표를 제시하는데 하나하나 살펴보자.

1.1 코드는 어떻게해서 소프트웨어가 되는가?

개발 배포 테스트 전반의 과정에대해서 다루고있다(이러이러한 프로세스를 통해서 개발된다는 설명.)

궁금하다면 한번쯤 읽어보고 넘어가면 될것같다.

1.2 코드 품질의 목표

일단 코드품질은 주관적일수 있다(책에서도 좋은코드라고 생각하는 이유가 근거없는 직감일때도 있다고 명시한다. 함부로 남의 코드를 평가절하하지 말자 -> 내가 갖춰야하는 자세같다.)

어쨋든 이런걸 떠나서 좋은 코드를 판단하려면 코드가 달성하려는 목표를 살펴보고 한발짝 물러서서 멀리서 보라는 충고를 한다.

또한 모든 코드에서 공통적으로 나타나는 목표는 책에서 4가지를 정의해주었다.

  1. 작동해야한다
  2. 작동이 멈춰서는 안된다.
  3. 변화하는 요구 사항에 적응해야 한다.
  4. 이미 존재하는 기능을 또다시 구현해서는 안된다.

이제 이걸 자세히 살펴보며 나의 견해를 끼워넣어 보겠다.

1.2.1 코드는 작동해야 한다

한마디로 진짜 목표이다 코드는 동작해야한다는 뜻이다. 근데 여기서는 보수적으로 한가지 더 있는데 버그가 없어야한다고 한다. 버그가 없는 프로그램은 나사에나 있을것 같은데 흐음 어쩃든 목표는 보수적으로 잡는게 맞다고 생각하니 애초에 엣지케이스 까지 다 고려하여 이상적으로 버그는 없는 코드가 나오는게 맞을것이다.(개발자가 버그를 허용한다면 그 코드는 아마 엉망이 될것이다.)

1.2.2 코드는 작동이 멈추면 안 된다

코드가 단순 오늘만 동작하는것인지 앞으로 쭉 역사에 길이남을 오래 사용할수있는 코드가 될수 있는 지 여부를 정하는 기준이다.

과연 내가 짠 코드가 내일 혹은 1년후에도 여전히 동작할 수 있는가? 에 대한 고민인데 이런 고민은 항상 해왔지만 이 책에서는 고민내용이 좀 과한감이 없지않아 있는것같다.

이 부분에 대해서 책이 고려해야하는 것을 3가지를 제시하는데 1번은 100%동의하지만 2,3번 같은경우 이에 대한 대처 가능성을 열어놓는거지 현시점에 미래를 위한 완벽한 대응이 가능한지는 의문이다. 이게 가능하다면 이책을 읽는 나는 엄청난 슈퍼파워를 얻게될테니 오히려 개이득이다.

그래서 고려해야하는 3가지는

 

1.코드는 다른 코드에 의존할수 있는데, 그 코드가 수정되고 변경될수있다.

이에대해 항상 라이브러리 사용을 경계하고 믿을건 언어, 안드로이드 개발의 경우 가끔 장난질을 치긴하지만 그래도 믿을 수 있는 구글 제공 라이브러리, 혹은 안드로이드 전역에 퍼져있는 써드파티 라이브러리 정도일것이다.

이런 라이브러리를 제외한다면 그 무엇도 믿지 않고 만약 일단 라이브러리로 구현했더라도 그부분을 직접 이해하고 다시 구현해서 이어 붙여야 완전해질것이다.

하지만 항상 이상적일 수는 없다. 이런 사례로 그 강력한 네이버 조차 이 부분에 문제점을 나타내는 사례를 보았다. 이 슬픈사연을 여기에 쓰기는 길고 네이버 조차도 다른 코드에 의존적일 수 밖에 없는 현실인데 내가 처한 상황과 적당히 타협하지만 내 코드가 오래갈 수 있도록 노력해야할것이다.

 

2.새로운 기능이 필요할때 코드를 수정해야 할 수도 있다.

이건 당연한 소리인데 드는 의문이 이걸 어느정도 까지는 예측하고 방향성을 열어놓겠지만 이걸 내가 1년후의 상황까지 예측해서 완벽대응을 할 수 있는가?

이정도면 코딩이 아니라 점집을 차려야한다. 뭐 물론 이책도 가능성을 열어놓으라는 소리를 강하게 이야기한다고 생각한다.

 

3.우리가 해결하려고 하는 문제는 시간이 지남에 따라 변경된다. 소비자 선호, 비즈니스 요구, 고려해야할 기술등이 바뀔 수 있다.

이 또한 2번과 마찬가지로 이래서 유지보수가 중요한 것이도 유지보수가 쉽도록 가능성을 열어주는 부분이 최선이라고 생각한다.

1.2.3 코드는 변경된 요구 사항에 적응할 수 있어야 한다.

아까 위쪽과 같은 이야기인데 당연히 유지보수를 해야할것이다.

근데 여기서 두가지 예시를 보여준다.

미친 개똥코드를 빠르게 짜긴하지만 유지보수가 안되서 망하는 예시와

너무 고민만 하다 완성조차 못하고 망해버리는 망해버리는 바보멍청이의 예시이다.

원해 나는 미친 개똥코드 파였는데 우테코를 하면서 완성못하는 멍청이가 된것같다.

지금 현재 진짜 고민을 너무많이하는 멍청이중에 멍청이가 된것같아서 문제점을 느끼기도 하고 개발바닥 같이 자주보는 채널 같은데서도 고민을 너무 많이하는 신입도 별로라고 하는것에 가끔은 흔들리지만 나는 현재 내상황에서는 고민해야한다고 생각한다.

왜냐하면 학습적인 프로젝트를 하고 있는 나의 고민은 지금의 내가 아니라 미래의 내가 와서 써먹을것이기 때문이다.

미리 고민을 해봐야 빠르게 거지같이 짜도 내가했던 많은 고민을 믿고 예전의 방식을 따라서 빠르게 진행할 수 있다.

그래서 지금 내가 미친듯이 고민하는것에 만족한다.

나는 빠르게 짜야할때 나의 코드를 자기복제한다. 그래도 나는 내 코드를 믿을수 있어 빠른 코딩도 어느정도 코드품질을 유지할 수 있다고 생각한다.

시니어분들의 고민은 생각은 이미 그분들이 많이 고민을 해서 이미 고인물이라 개똥같이 빠르게 짜도 잘짜서 하는 이야기 아닌가 싶다.

어쨋든 어느정도 타협은 해야겠지만 지금의 나는 학습을 진지하게 고민해야할 때이다.(미래의 나를 고용할 사람을 위해)

1.2.4 코드는 이미 존재하는 기능을 중복 구현해서는 안된다.

이는 이미 내가 뼈저리게 느끼고 이펙티브 코틀린에서 보고 감명깊었던 내용중 하나이다.

이 부분에 대한 나의 팁은 이러하다.

 

1.일단 언어를 믿자 언어는 개똑똑한 천재들이 만들어 놓은거니 잘활용하자.

언어에서 제공하는 standard library를 잘 활용한다면 사실상 쉽게쉽게 많은걸 만들수 있을것이다.

만약 뭐가 필요하다면 코틀린 공식문서부터 뒤지자

 

2. 믿을만한 라이브러리를 선별하는 능력을 갖고 그것에는 의존해도된다.

내가 생각하는 이러한 라이브러리가 square사에서 나온것들 인데 라이브러리를 보면 미래에 대한 대응도 잘해놓고 물론 언젠가는 대체되겠지만 현재 미친 강력한 라이브러리 이므로 내가 뭘 만들고 뭐하고 하는것보다(내가 만든게 더 거지같은 레거시가 될 확률이 높으니) 라이브러리를 커스텀하는 방향으로 바라보는것이 더 좋을때가 많다는 생각이다.

이런식으로 이 두가지를 생각하며 믿고 의지한다면 되지않을까 싶다.(이것을 제외하면 아무도 믿지마라 특히 인터넷에 떠다니는 코드조각)

1.3 코드 품질의 핵심 요소

앞으로 책에서 살펴볼 코드 품질을 결정짓는 구체적인 전략이 뭔지 6가지를 소개한다.

  1. 코드는 읽기 쉬워야한다.
  2. 코드는 예측 가능해야한다.
  3. 코드를 오용하기 어렵게 만들라
  4. 코드를 모듈화하라
  5. 코드를 재사용 가능하고 일반화할 수 있게 작성하라
  6. 테스트가 용이한 코드를 작성하고 제대로 테스트하라

대충 쉬운것처럼 적어놨지만 하나하나가 경험도 있어야하고 진짜 본인의 노하우가 응집된 결과물들이 아닌가 싶다.

->난 아직 모든게 흔들리는것 같다.

1.3.1 코드는 읽기 쉬워야한다.

변수명 일부러 거지같이하고 잘읽히지도 않게 써놓은 글로 예시를 들었다.

한마디로 읽기 쉽도록 작성하라는것인데 이런것은 앞으로 자세히 설명할 책의 다음장들에서 살펴보면 좋을것 같다.

1.3.2 코드는 예측 가능해야 한다.

이 부분에 대해서 엄청 고민이 많고 과연 무엇이 맞는것인지 모호하다.

물론 지금 옆에서 제이슨이 내가 하는 고민자체가 바보라는걸 대충 깨우쳐 주고 간것 같긴한데 아직도 고민해야할게 산더미이다.

나의 고민은 이런것이였다.

레포지토리에서는 로컬과 서버의 데이터 출처를 추상화하는 목적으로 안드로이드 진영에서는 쓰이는 경향도있는데

getNickName이라는 레파지토리의 함수가 있다고 가정해보자 그럼 서버로부터 닉네임을 받아왔을때 로컬에 저장하는것이 getNickName네이밍 만으로 예측이 가능한가? 지금의 예시같은경우 별 파급효과가 없지만 뭔가 크리티컬한 경우의수가 있다고 쳤을때 지금 전화 리다이렉트 예시와 비슷한것 아닌가 라는 생각이 들었다.

이에 대한 부분은 스터디원들과 오늘 토론 배틀을 떠야겠다.

1.3.3 코드를 오용하기 어렵게 만들라

애초에 코드룰 오용하기 힘들게 짜라는건데 아직 감이 안온다. 이는 추후 책을 읽다보면 방법을 터득하게 될것같다.

1.3.4 코드를 모듈화하라

모듈화는 분명 강력하고 테스트 용이성도 올려준다.

하지만 모듈화 자체의 난이도가 높은것 또한 간과할 수 없다고 생각한다.

이 책에서는 모듈화된 시스템의 주요 특징이 인터페이스가 잘정의되어 서로다른 구성요소간의 상호작용이 규격화 되어있다는 것인데

개발 초심자 입장에서는 이런 인터페이스 정의자체가 어렵고 잘못된 인터페이스 정의와 이로인한 파급효과는 겉잡을수 없다는것을 경험으로 깨달았다.

예전에 프로젝트에 대한 이해도 없이 초반부터 모든 feature 별로 모듈을 나눠서 진행한 프로젝트에서 재사용,의존성 등등의 문제로 지옥을 겪고 경험 혹은 구조에 대한 이해없는 모듈화는 오히려 악영향을 미칠수 있다는 경험을 하였다.

이를 통해 나는 모듈화에 대한 관점이 생겼는데 그냥 좋아보인다고 나누는것이 아닌

 

1. 특정한 이유가 있다면 팀원과의 합의와 많은 경우의수를 따져보고(의존성 관련) 나눈다.

예를들어 최근본 예시인데 서버와 안드로이드 모두 상태를 나타내는 enum이 광장히 많아 각각 동기화 관련하여 관리 문제를 겪어서 이를 라이브러리화 하여 떼어내서 같이 사용한다는 것이였다. 이런경우 굉장히 좋은 아이디어라고 생각하고 좋은 경험을 선사할것이라고 생각한다.

물론 이방법 쓰는곳을 못봤다고하고 제이슨이 이런경우의 문제가 될수있는 지점을 짚어줬는데 들었을때 그래서 안쓰는구나 이런생각도 든다.(근데 난 아직 좋다고 생각함)

 

2. 모놀리틱으로 진행하다 재사용이 많아질경우 공통사항을 분리해낸다

이때도 굉장히 기준이 명확해야하고 분명 단위별로 묶이는 이유가 있는 상태로 떼어내야겠지만 그냥 애초에 기능들을 만들기전부터 분리하는것보다 훨씬 실패할 가능성이 적다고 생각한다.

 

3. feature 별로 분리할것이라면 도메인에 대한 이해도 및 많은 경험이 기반해야한다.

이건 분명이 머리가 많이 깨지겠지만 또 분리의 이점은 분명하다 고로 이런 것들을 복구할수 있는 실력 혹은 이미 예측할 수 있는 실력과 경험이 쌓였을때 시도하는것을 추천한다.

1.3.5 코드를 재사용 가능하고 일반화할 수 있게 작성하라

이내용도 어떤내용이 나올지 감이안온다.

나는 일반화의 경우 기능일 최대한 잘게 쪼개놓고 조합하는것이 일반화의 가장 기본같다는 생각이 드는데 뭔가 대단한게 숨겨져있을것같다.

최근 느낀 재사용,일반화의 예시는 안드로이드 권한관리를 데코레이터 패턴을 통해서 만들어야 좀더 유연하게 대처할수있겠다는 생각을 한것이다.

1.3.6 테스트가 용이한 코드를 작성하고 제대로 테스트 하라

이 또한 당연한 이야기 이지만 테스트는 참 어렵고 프로덕션 코드의 고민보다 더 많은 고민을 해야한다고 생각한다.

뭐 시험문제 출제자랑 시험문제 푸는사람이랑 누가 더 학식이 높아야할까? 라는 것과 비슷하다고 생각한다. 일반적으로 테스트성이 용이한 코드를 이책을 통해서 배워나가야겠다.