채수원 님의 TDD(Test Driven Development) 개발 실천법과 도구는 소프트웨어 개발 방법론 중 하나인 TDD를 구체적으로 실천하는 방법과 그 과정에서 사용되는 도구들에 대한 내용을 다룬 책이다. TDD 대한 이해를 높이고 실제 개발에 적용하는 방법을 설명한다. TDD(Test Driven Development)는 소프트웨어 개발 방법론 중 하나로, 테스트 케이스를 먼저 작성하고 이를 통과하는 코드를 작성하는 것을 중심으로 개발하는 방법

책에서는 TDD의 개념과 원칙을 소개하며 테스트 케이스(TC) 작성, 코드 작성, 리팩토링 등의 단계별로 구체적인 예시를 보여준다. 특히 TC 작성과 이를 통한 코드 작성의 중요성에 대해 강조하며 TDD의 장점과 효과를 다양한 관점으로 보여준다. 책에서는 TDD를 실천하는 데 필요한 기본적인 원칙과 방법론을 설명하면서, 이를 구현하는 과정에서 발생하는 이슈와 해결 방법 등에 대해서도 다룬다. TDD를 적용하는 데에 있어 좋은 습관과 나쁜 습관을 비교하며 TDD를 대하는 개발자의 태도화 실천할 것들을 제시한다.

TDD를 실천하는 과정은 다음과 같다.

  • 테스트 케이스 작성 :
    먼저 개발하려는 기능에 대한 테스트 케이스를 작성. 작성한 테스트 케이스는 해당 기능이 정확히 동작하는지 검증하기 위한 목적으로 작성한다.
  • 테스트 실행 :
    작성한 테스트 케이스를 실행하여 해당 기능이 제대로 구현되어 있는지 확인.
    이때, 테스트 케이스가 실패하면 해당 기능의 구현이 제대로 이루어지지 않았다는 것을 의미.
  • 코드 작성 :
    테스트 케이스를 통과하기 위한 코드를 작성.
    이때, 테스트 케이스가 통과하도록 코드를 작성하는 것이 중요함.
  • 코드 리팩토링 :
    작성한 코드를 리팩토링하여 더 효율적이고 가독성이 좋은 코드로 개선.

이런 과정을 반복하며 개발하는 것이 TDD의 핵심이다. 이 과정에서 개발자는 작성한 코드가 정상적으로 동작하는지 항상 확인할 수 있으며, 버그를 빠르게 발견하고 수정할 수 있다고. 또한, 작성한 코드를 리팩토링하면서 코드의 유지 보수성과 확장성을 높일 수 있다고 한다.

TDD를 실천하는 개발자들은 코드 품질과 안정성을 높일 수 있으며, 개발 프로세스를 보다 효율적으로 관리할 수 있다고 한다. 또한, TDD는 기능 구현 외에도 코드의 문서화와 같은 부가적인 기능을 제공할 수 있어, 소프트웨어 개발의 생산성을 높일 수 있다고 한다.


TDD를 처음 접하는 초심자에게 유용한 정보이지만 초판 이후 어른들의 사정으로 재판이 나오지 않았고, 옛날 기술이나 라이브러리에 대한 설명이 많다. TDD를 업무에서 실 사용해보지 않은 내 입장에서는 일단 겪어봐야 할 것 같다. SW 품질을 높이는데 철학이 없는 조직에서는 TDD를 적용하기가 쉽지 않아서, 어쩌면 뜬구름 잡는 소리로 보이는 것도 있을 것 같다. 그치만 나는 내 일을 하면서 SW 품질을 높이는 데 많은 목마름이 있기에 꼭 TDD를 경험해 봐야 할 것 같다. 일단 나는 사이드 프로젝트에서 TDD를 사용해야겠다.

 
728x90
반응형

'개발도서' 카테고리의 다른 글

[독후감] 헤드퍼스트 디자인 패턴  (0) 2023.04.14
[독후감] 클린 코드  (1) 2023.03.25
[독후감] 읽기 좋은 코드가 좋은 코드다  (0) 2023.03.06
[독후감] 토비의 스프링 3.1 Vol.1  (0) 2023.03.06
필독도서  (0) 2022.07.13
  • "나쁜 코드는 깨진 유리창처럼 계속 나쁜 코드가 만들어지도록 한다."
  • "나쁜 코드는 기술 부채를 만들어 수정을 더 어렵게 하며 결국 조직의 생산성을 저하시킨다."

이 책을 추천 받은 것은 개발 쪽으로 전향한 지 얼마 안되서였던 것 같다. 인터넷에서 추천받았었는지, 아니면 국비지원 학원이 끝나갈 무렵이었는지 정확히는 기억나지 않는다. 그리고 최근에 내가 잘 따르던 선배의 강력한 추천이 한번 더 있었다.
어쨌든 토비의 스프링과 함께 한 번은 봐야지 하던 책이었고, 이번에 드디어 완독을 했다. 아니 1독을 했다고 표현해야겠다.

읽코 좋코가 이 책 보다 조금 더 쉽게 읽힌달까. 나중에 후배들을 맞이하고, 혹은 팀을 이끌어갈 때쯤 2독 3독을 해야 할 책이라고 생각된다. 충분히 많은 도움이 된 좋은 책이지만, 내 경험이 짧아 이해하기 어려운 부분도 많고 확실히 내 수준보다는 더 높았다. 아마도 TDD 라던지, 객체지향 패러다임을 잘 따르는 코드를 본 적이 없어서일까?
아무튼 프로세스를 만들 때 가져야 할 마음 가짐에 대해서 많이 생각하게 되었다. 의미를 가진 코드, 코드의 문맥, 추상화 수준과 왜 그렇게 해야 하는지의 이유도 잘 설명되었다. 코드가 마치 잘 쓰여진 소설처럼 읽힐 수 있도록 작성한다는 마음가짐으로 코딩을 하게 되었다. 단순하게 동작이 목적이 아닌 쉽게 읽힐 수 있도록 고민을 하다 보니 더 직관적이고 객체지향 구조로 코드를 짤 수 있었던 것 같다.

선배가 이 책을 추천할 때, 레거시 코드에 대해 정말 화를 내고 열변을 토했던 것으로 기억한다. 그리고 이 책을 읽으면서 그가 이 책을 추천하면서 왜 그렇게 화를 냈는지 납득했다. 저자는 나쁜 코드가 나쁜 이유에 대해서 여러 예를 들고 그중 기억에 남는 것은 위의 두 문장이다.

나 역시도 나쁜 코드를 혐오한다. 레거시 코드를 유지보수하면서 소스코드의 히스토리를 보면 왜 이런 코드가 생겼는지 납득할 수 있지만, 그렇다면 처음부터 더 좋은 구조로 작성될 순 없었는가 하는 의문이 들곤 한다. 솔직하게 말해서 나쁜 코드를 보면 화도 나고 작성자를 기둥에 묶어두고 싶다는 생각도 든다.
나를 포함한 많은 개발자들이 이 책을 읽고 객체지향 패러다임과 클린코드 원칙들을 따르는, 개발을 잘하는, 후배들에게 좋은 코드를 남기는 시니어가 될 수 있도록 갈고닦기를... 🙏🏻

 
728x90
반응형

읽코좋코

모든 전공 서적들이 빠르게 읽히지 않는데, 다른 전공서적에 비해 쉽게 읽히는 책이며 많은 공감을 하게 되었다. 제목과 내용은 동일하며 주제를 반복 강조하고 있다. 이를 위해 변수명, 함수명, 코드 컨벤션 그리고 리팩토링까지 설명하고 있다.
코드는 이해하기 쉬워야 한다, 다시 말해 코드를 읽는데 드는 비용을 줄여야 한다는 말이다. 코드 파악하는데 드는 비용이 작다는 말은 설계가 명확하고 간결하다는 의미를 내포한다.

이 책을 읽고 실제 코드로 적용할 생각을 하면 머리가 아프지만 읽는 중간 중간 이전에 보았던 코드들이 떠올랐다. 이전에 작성 했던 '성능과 가독성을 높이는 분기처리 방법'을 쓸 때 보다 시야가 더 넓어졌다. "왜?"에 대한 부분이 조금 모호했었는데, 그 부분을 채워주는 내용이였다. 그리고 내가 봐온 레거시 프로젝트들의 코드를 작성했던 개발자들에게 이 책을 던져주고 싶었다.


  1. 코드는 이해하기 쉬워야 한다
    인상 깊었던 내용은 6개월 뒤의 나 자신 또한 쉽게 이해되도록 코드를 작성하라는 내용이였다. 나 역시도 나름의 설명과 주석을 잘 붙여서 만들었다고 생각했지만 1년 뒤 해당 코드를 개선 하면서 다시 분석해 보는 헛수고를 했던 경험이 있었다. 짧은 코드가 더 좋은 코드가 아닌 읽는 순간 바로 이해되는 코드가 좋은 코드라는 뜻이다.
  2. 이름에 정보 담기
    • 구체적인 단어 사용하기
    • 이름 길이(짧은 범위에 잠깐 쓰이면 짧은 변수명, 사용 범위가 넓다면 긴 변수명, 약어 사용 지양하기 등)
    • 포맷팅으로 의미 전달하기(상수는 대문자, 클래스명은 카멜케이스 등)가 있었다.
  3. 오해할 수 없는 이름들
    • 경계를 포함하는 범위 : first, last
    • 경계를 포함/배제하는 범위 : begin, end 사용
    • 불린 : is, has, can, should 사용
    • get 남발하지 않기
    • 여러 개의 이름을 후보로 놓고 고민하기
    • '다른 사람들이 다른 의미로 해석할 여지가 있는가?'가 핵심이였다. 한 번쯤 더 생각해 보면 더 좋은 변수명을 만들 수 있다.
  4. 미학
    • 문서 작업을 하더라도 한눈에 보기 쉽게 쓰인 글이 잘 읽히듯 코드도 마찬가지다.
    • 좌우로 길게 늘어진 코드는 줄 바꿈을 하고 다른 코드들도 똑같이 맞추기
    • 헬퍼 메소드를 이용하여 지저분한 코드 깔끔하게 하기
    • 코드의 위아래 열을 맞추어 읽기 쉽게 하기
    • 코드의 순서를 '가장 중요한 것'에서 '가장 덜 중요한 것' 까지 순서대로 나열하기
    • 코드를 문단으로 만들기 (핸들러, DB 사용 등 문맥이 바뀌면 한 행을 띄우는 등 글을 쓸때 문단을 나누는 것과 동일)
    • 개인의 코드 스타일 VS 전체 코드의 일관성 = 일관성이 올바른 스타일보다 더 중요
  5. 주석에 담아야 하는 대상
    • 불필요한 설명 배제
    • 나쁜 이름에 대한 변명이 아니라 좋은 이름으로 바꿀 것
    • 작업중 생각한 통찰 등을 주석에 기록
      • ex: 하위클래스로 정리해야 할 것 같다
    • 상수의 의미를 설명할 것
    • 다른 개발자가 실수할 수 있는 부분을 예상해서 주석을 달라
      • ex : 1분 후 타임아웃 된다
    • 2, 3중 반복/조건문이 달린 함수는 무엇을 위한 것인지 요약 주석을 단다
    • 주석을 다는 것에 대한 두려움을 버려라
  6. 명확하고 간결한 주석 달기
    • 간단한 입출력 예시 사용
    • 코드의 수행 동작이 아니라 코드의 의도를 적어라
    • 파라미터에도 주석을 넣어라
    • 축약된 단어를 사용하라
      • ex : ~에서 불필요한 빈칸을 제거한다 -> 공백 제거
  7. 읽기 쉽게 흐름 제어 만들기
    • 조건문에서 유동적인 값은 왼쪽, 상대적으로 고정적인 값은 오른쪽에 쓰라
    • if/else 간단한 것을 먼저 처리하라
    • 삼항 연산자의 사용은 간단하게 쓸 상황이 아니라면 피하라
    • 중첩을 피하기 위해 함수를 중간에서 반환하라
    • 2중 if 문은 나누어서 중간에 반환하라
  8. 거대한 표현 잘게 쪼개기
    • 요약 변수 사용, 조건식의 반복되는 중요 비교 값을 상수로 만들기
    • 드모르간의 법칙 사용
    • short circuit 사용을 오용하지 말 것
      • 영리하게 작성된 코드가 혼란을 초래한다
    • 복잡한 논리를 간단하게 표현하기
    • 거대한 구문은 문맥에 따라 나누기
  9. 변수와 가독성
    • 불필요한 임시 변수, 중간 결과 저장 변수, 흐름 변수(boolean) 제거하기
    • 변수의 범위 좁히기
    • 클래스를 작은 단위로 나누기
    • 전역변수 사용 피하기
    • 변수에 다른 값을 여러번 할당하는 것 피하기
  10. 상관 없는 하위 문제 추출하기
    • 비즈니스 로직과 관계 없는 문자열 빈칸 제거, url 형식, 주소 형식등을 다루는 메소드는 분리하기
    • 재사용성을 위해 일반적인 목적을 가진 코드를 많이 만들기
    • 과유불급, 지나치게 나누지는 말기
  11. 한 번에 하나씩
    • 작성된 코드가 읽기 어렵다면, 수행하는 작업을 나열하라
    • 나열된 작업중 분리될 수 있다면 별도의 함수 또는 클래스로 나눠라
    • 파편화를 최소화 할 수 있다.
  12. 생각을 코드로 만들기
    • 논리를 명확하게 설명하기
    • 해결책을 말로 묘사하기
    • 언어에서 제공하는 라이브러리를 많이 사용해 보기
  13. 코드 분량 줄이기
    • 필요가 없는 기능을 구현하려고 애쓰지 말것
    • 코드 베이스를 작게 유지할 것
    • 요구사항에 질문을 던져 요구사항을 잘게 나누어 분석하기.
    • 표준라이브러리와 친해지기
  14. 테스트와 가독성
    • 테스트 코드는 특히 더 읽기 쉬워야 한다
    • 긴 테스트 내용은 다른 메소드로 만들기
    • 읽기 편한 에러 메세지 출력 폼 만들기
    • 좋은 테스트 입력 값 선택하기
    • 지금 작성하는 코드의 테스트 코드를 나중에 작성한다는 사실을 염두해 둘것
    • 지나친 테스트는 지양
  15. 분/시간 카운터 설계 및 구현
    • 실습 예제
 
728x90
반응형

토비의 스프링 3.1 VOL.1

스프링 사용자로서 항상 읽어야봐야 한다라는 소리에 두권을 샀지만, 엄청 어렵다는 소문에 읽을 엄두를 못 내던 책이다. 한 권에 800 페이지가 넘는 굉장한 분량에 두번의 정독 시도를 헛탕쳤었다. [유튜브] "개발바닥" 채널에서 저자 이일민님의 인터뷰와, 그 분이 이제는 스프링 부트 인강을 내시면서 이 책을 다시 시도하였고. 이번에는 1독을 끝냈다.
이제 4년차에 들어서면서 읽어보니 '어느 정도 개발을 했고, 좋은 구조와 효율을 고민해본 사람이 봐야 깊은 뜻을 더 잘 이해할 수 있겠구나' 라고 느꼈다.

이 책은 객체지향적 설계, 리팩토링, 테스트주도개발의 중요성에 대해 꾸준히 강조하고 있다. 단순하게 스프링 프레임워크의 기능 / 개념에 대한 설명도 깊게 나와있지만, 이 책의 요점은 스프링이 왜 이렇게 발전했고, 어떤 패러다임을 녹여서 만든건지 엿볼 수 있도록 도와주는 책이다. 따라서 개발 철학에 더 중점을 두고 읽어야 하는 책이라고 생각 된다.

마틴 파울러와 켄트 백이 강조하던 내용이 녹아 있으며, 아래와 같은 조언을 책 전반에 걸쳐 꾸준히 강조하고 있다.

  • '고정된 작업 흐름을 갖고 있으면서 여기저기서 자주 반복되는 코드가 있다면, 중복되는 코드를 분리할 방법을 생각해보는 습관을 기르자.'
  • '비슷한 기능이 새로 필요할 때마다 앞에서 만든 코드를 복사해서 사용할 것인가? 물론 아니어야 한다. 한두 번까지는 어떻게 넘어간다고 해도, 세번 이상 반복된다면 본격적으로 코드를 개선할 시점이라고 생각해야 한다.'

인상 깊었던 문장

인상 깊었던 문장들은 다음과 같다. 다 읽어보면 떠오르는 것이 있다. 그렇다, 대부분의 레거시 프로젝트의 소스들은 아래에서 하지 말라는 대로 개발되어 있다.

  계층형 아키텍쳐
  관심, 책임, 성격, 변하는 이유와 방식이 서로 다른 것들을 분리함으로써 분리된 각 요소의 응집도는 높여주고 서로 결합도를 낮춰줬을 때의 장점과 유익이 무엇인지 살펴봤다. 성격이 다른 모듈이 강하게 결합되어 한데 모여 있으면 한 가지 이유로 변경이 일어날 때 그와 상관이 없는 요소도 함께 영향을 받게 된다. 따라서 불필요한 부분까지 변경이 일어나고 그로 인해 작업은 더뎌지고 오류가 발생할 가능성이 높아진다. 어느 부분을 수정해야할지를 파악하기도 쉽지 않다.
  따라서 인터페이스와 같은 유연한 경계를 만들어 두고 분리하거나 모아주는 작업이 필요하다.
또, 흔히 저지르는 실수 중의 하나는 프레젠테이션 계층의 오브젝트를 그대로 서비스 계층으로 전달하는 것이다.
서블릿의 HttpServletRequest나 HttpServletResponse, HttpSession 같은 타입을 서비스 계층 인터페이스 메소드의 파라미터 타입으로 사용하면 안 된다.
계층의 경계를 넘어갈 때는 반드시 특정 계층에 종속되니 않는 오브젝트 형태로 변환해줘야 한다.
스프링을 사용하면 이런 데이터 중심의 코드를 만들 수 있을 뿐만 아니라, 실제로 매우 흔하게 발견된다.
데이터와 업무 트랜잭션 중심의 개발에 익숙한 사람들이 많고 이런 아키텍쳐를 의도적으로 선호하는 개발자도 많기 때문이다.
개발자들끼리 서로 간선없이 자신에게 할당된 기능을 독립적으로 만드는 데도 편하다.
최소한의 공통 모듈 정도만 제공되는 것을 사용하고, 그 외의 기능은 단위 업무 또는 웹 화면 단위로 만들어 진다.

하지만 이런 개발 방식은 변화에 매우 취약하다.
객체지향의 장점이 별로 활용되지 못하는데다 각 계층의 코드가 긴밀하게 연결되어 있기 때문이다.
중복을 제거하기도 쉽지 않다.
업무 트랜잭션에 따라 필드 하나가 달라도 거의 비슷한 DAO 메소드를 새로 만들기도 한다.
또한 로직을 DB와 SQL에 많이 담으면 담을수록 점점 확장성이 떨어진다.
DB는 확장에 한계가 있을 뿐 아니라 확장한다 하더라도 매우 큰 비용이 든다.
잘 작성된 복잡한 SQL 하나가 수백 라인의 자바 코드가 필요한 비지니스 로직을 한번에 처리할 수도 있다.
하지만 과연 바람직한 것일까?
이런 복잡한 sql을 누구나 쉽게 이해하고 필요에 따라 유연하게 변경할 수 있을까?
또, 복잡한 sql을 처리하기 위해 제한된 자원인 DB에 큰 부담을 주는 게 과연 바람직한 일인지 생각해볼 필요가 있다.
데이터 중심 아키텍쳐의 특징은 계층 사이의 결합도가 높은 편이고 응집도는 떨어진다는 접이다.
화면을 중심으로 하는 업무 트랜잭션 단위로 코드가 모이기 때문에 처음엔 개발하기 편하지만 중복이 많아지기 쉽고 장기적으로 코드를 관리하고 발전시키기 힘들다는 단점이 있다.
스프링은 그 개발철학과 목표를 분명히 이해하고 사용해야 한다.
자바의 근본인 OOP 원리에 충실하게 개발할 수 있으며,
환경이나 규약에 의존적이지 않은 POJO를 이용한 애플리케이션 개발은
엔터프라이즈 시스템 개발의 복잡함이 주는 많은 문제를 해결할 수 있다.
POJO 방식의 개발을 돕기 위해 스프링은 IoC/DI, AOP, PSA와 같은 기능 기술을 프레임워크와 컨테이너라는 방식을 통해 제공한다.
728x90
반응형

벌써 2023년이 되었다.
지난 2022년을 되돌아 작년의 목표가 얼마나 지켜졌는지 확인해보고 2023년에 대한 목표를 잡아보고자 한다.


2022년 회고

[방통대 졸업]

물론 2022년 이전 학기부터 학점이 쌓여 온 것이지만 어쨌든 3. 후반대 학점으로 졸업 했다.
졸업은 했지만, 시험을 위한 공부를 한 탓에 CS 지식이 많이 모자라다는 것을 느끼고 2023년에도 CS 공부를 부지런히 해야겠다.

[SQLD 취득]

생각보다 노력을 덜 하고 sqld를 땄다. 6주 정도 퇴근하고 3시간, 출퇴근 길에 요약 내용 복습 정도로 공부하고 붙었으니 운이 좋았던 것 같다.
사실 자격증이 있다고 실무를 잘 하는 건 아니지만, 자격증을 딴 덕분에 쿼리를 짜거나 DB 구조를 변경할 때 한 번 더 생각하게 되었다.
물론 아직은 경험치가 모자라니 더 정진해야겠다.

[JPA 학습]

인프런에서 인강을 듣긴 했지만, 완강하지 못했다. 아무래도 지금 일 하는 곳, 지금 까지 일 했던 곳은 MyBatis를 사용하다보니 JPA 공부에 절실하지 않았던 것 같다. 테크기업 이직을 생각하고 JPA를 꼭 미리 학습 하도록 해야겠다.

[알고리즘 문제풀이]

1학기 끝나고 7월부터 인강과 함께 코테공부를 했었다. 과거형이다.
10월부터 극심한 야근의 늪에 빠지면서 지금까지 게을리 해버렸다. 올해는 꼭 프로그래머스 3레벨까지는 풀어야 겠다.

[경력기술서 지속적인 업데이트]

블로그엔 올리지 않았지만 분기별로 업데이트를 잘 했다고 생각한다. 23년에도 잘 정리해서 이직 준비 해야겠다.

[다른 개발자들과의 교류]

따로 커뮤니티를 하는 것은 아니지만 동네 스터디 모임에 들어갔고, 이전 직장 동료들이나 친구들과 꾸준히 연락하면서 소식을 듣고 있다. 나랑 다른 분야의 선후배 개발자들이나 같은 분야의 다른 회사사람들을 통해 업계 소식을 조금씩 듣고 있다. 이렇게 조금이나마 간접 경험을 하고 있고, 다른 사람의 시각이나 생각을 들으면서 내 식견도 늘리려 하고 있다.


2023년 목표

목표를 너무 많이 세우지 않고 작은 목표를 집중적으로 수행하려 한다.

[Java, Spring 더 깊게 공부하기]

Spring 소스코드도 뜯어보고, 인강이나 토비의 스프링 책읽기등을 하면서 레벨업을 해야겠다고 느꼈다. 회사 과제를 수행하면서, 종종 기초지식이 부족하다는게 느껴질 때가 있었다. 회사에서 사용하는 스펙이 심각한 레거시라 생긴 문제인지, 아니면 정말 내가 뭔가를 모르고 있는 것인지는 공부 해봐야 아는 것이다.

[인강 및 프로그래밍 책 읽기]

게을리한 JPA, 알고리즘 코테 인강을 올해는 끝내고 그 이상으로 발전 해야겠다.

[이직]

회사 사정까진 모르겠고, 지금 회사에 머물 이유가 배울 수 있는 선임들 이였는데, 그 사람들이 지금 다 나갔다.
회사가 학교는 아니지만 개인의 성장에 많은 영향을 미친다고 생각하며, 그 성장에는 같이 일하는 동료들이 중요하다고 생각한다.
떠나신 그 세분을 내가 따라 갈 수 있을지는 모르겠고, 우선 적으로 회사 매출이 어떻든 개발팀의 조직이 8인 이상인 곳으로 이직하고싶다고 생각 했다.
이직의 결심은 22년에 "다른 선/후배/동료 개발자들과 생각을 교류하고/보고/배움으로써 개인이 성장할 수 있다"고 느낀게 가장 큰 것 같다.

[여행]

적어도 분기에 한번은 여행을 다녀와야겠다고 생각했다.
일 하면서 쌓인 생각이나 걱정들도 잠시 내려두고, 여행에서 마주하는 낯선 경험들이 나를 찾도록 해주는 것 같다.

[운동, 건강]

건강하지 않으면 공부도 할 수 없는 것 같다. 살로인해(?) 집중에 방해되는 것도 있고.
일단 1년 동안 10키로 빼는 게 목표로 지금 68키로다.

 
728x90
반응형

'커리어 디버깅' 카테고리의 다른 글

[면접 회고] W사  (0) 2023.02.27
[면접 회고] C사  (0) 2023.02.27
[코테 회고] 2022 10 01  (0) 2022.10.01
[채용 과제 회고] 2022 09 22 P사  (0) 2022.09.22
패션 쇼핑몰 1년 회고  (0) 2022.09.14

객체지향 → 역할, 책임, 협력을 투영하는 새로운 세계


토끼책에서 객체지향에 대해 가장 중요하게 여기는 개념은 오브젝트 사이의 메세지가 핵임이며 모든건 메세지 위주로 돌아가야한다는 점이다. 메세지가 곧 역할을 만들고 책임을 만들며 협력의 접점을 만들기 때문이다.

각 오브젝트는 결국 자기만의 역할, 책임을 분명하게 가지게끔 만들어야 하며, 협력을 하려 할때 오브젝트 A는 오브젝트 B의 역할, 책임 내부를 들여다보는(OOP의 패러다임을 깨버리는)순간 의존성이 강하게 걸리며 OOP의 사상과 멀어지게 된다. 오로지 내 입장에서 '무언가'를 하려한다는 메세지를 전파하는 것, 그 자체로 끝나야하며, 그게 좋은 구조의 OOP이고, 디커플링 된다.

현재 재직중인 회사의 개발 소스들은 역할과 책임, 협력 없이 한 프로세스에서 모든 역할을 하며 그러다 보니 파편화된 소스가 너무나도 많다. 그리고 그런 파편화로 인해 유지보수성에 어려움을 겪고, 많은 버그에 개발팀은 물론 운영 MD팀, CS팀, 배송팀까지 업무에 어려움을 겪고 있다. 이런 문제로 업무의 효율과 공수에 비효율이 생기고, 사용자들은 좋지 않은 사용 경험을 넘어 불쾌감을 느끼는 일도 허다하다.

소스 수정이 있을 때마다 개선을 한다고 해보지만 2014년부터 유지되오던 시스템의 방대함과 기한이라는 두개의 큰 벽앞에서 쉽지 않다. 그렇지만 당장의 시간 비용이 더 들어서 추후 비용을 덜 들일 수 있다면 어떤게 더 이득인지 생각해 볼 필요가 있다고 생각한다.


이 책을 읽고 역할, 책임, 협력을 나눠 잘 짜여진 구조의 시스템에 대한 목마름이 생겼다. OOP의 철학이 잘 녹아든 소스 위에서 일 하고싶다.

 
728x90
반응형

유지보수나 기능 개선프로젝트를 진행하면서 분기 처리 부분에서 가독성이 떨어지는 코드를 많이 보게 되었다.
종종 이런 코드는 가독성이 떨어지는건 물론이고 코드 작성자 본인도 가독성 문제로 오류를 만들어 내는 로직도 있었다.

 


연산자 우선 순위

좋은 분기분을 만들기 전에 언어별 연산자 우선순위를 알아야 한다.
결합 방법에 대해서는 언어별, 버전별 기준으로 정확하지 않으니 참고만 하면 된다.
언어별 연산자 우선순위는 사칙 연산에서 곱셈/나눗셈이 덧셈/뺄셈보다 먼저 이뤄지는 것처럼 이해하면 된다.

 


java 연산자 우선순위

우선순위 연산 기호 결합 방향
1 [], . >>>>
2 x++, x-- <<<<
3 ++x, --x,_x, -x, ~, !, (type) <<<<
4 *, /, % >>>>
5 +, - >>>>
6 <<, >>, >>> >>>>
7 <, >, <=, >=, instanceof >>>>
8 ==, != >>>>
9 & >>>>
10 ^ >>>>
11   >>>>
12 && >>>>
13    
14 ? a : b <<<<
15 =, +=, -=, *=, /=, %=, &=, ^=, !=, <<=, >>=, >>>= <<<<

 

javascript 연산자 우선순위

자바스크립트 연산자 우선순위(비트 연산자 제외)
순위 기능 연산자
1 괄호 ()          
2 증감/논리 연산자 not ++ -- !      
3 산술 연산자 곱셈 * / %      
4 산술 연산자 덧셈 + -        
5 비교 연산자 대소 < <= > >=    
6 비교 연산자 같음 == === != !==    
7 논리 연산자 and &&          
8 논리 연산자 or ||          
9 대입 연산자 = += -= *= /= %=

 

python 연산자 우선순위

우선순위 연산자 설명
1 (값...), [값...], {키: 값...}, {값...} 튜플, 리스트, 딕셔너리, 세트 생성
2 x[인덱스], x[인덱스:인덱스], x(인수...), x.속성 리스트(튜플) 첨자, 슬라이싱, 함수 호출, 속성 참조
3 await x await 표현식
4 ** 거듭제곱
5 +x, -x, ~x 단항 덧셈(양의 부호), 단항 뺄셈(음의 부호), 비트 NOT
6 *, @, /, //, % 곱셈, 행렬 곱셈, 나눗셈, 버림 나눗셈, 나머지
7 +, - 덧셈, 뺄셈
8 <<, >> 비트 시프트
9 & 비트 AND
10 ^ 비트 XOR
11    
12 in, not in, is, is not, <, <=, >, >=, !=, == 포함 연산자, 객체 비교 연산자, 비교 연산자
13 not x 논리 NOT
14 and 논리 AND
15 or 논리 OR
16 if else 조건부 표현식
17 lambda 람다 표현식

 


단축 평가 (Short-circuit Evaluation)

단축 평가는 and(&&) 연산자와 or(||) 연산자의 원리를 이해하면 쉽다.

    if( condition1 && condition2 && condition3 && condition3 )

위와 같이 && 연산자로 여러 boolean 값의 상황이 있을 때, && 연산자는 하나의 조건이라도 false면 결과가 false 이기 때문에,
condition1이 false라면 굳이 뒤에 있는 2, 3, 4를 확인하지 않는다.

    if( condition1 || condition2 || condition3 || condition3 )

마찬 가지로 || 연산자로 여러 boolean 값의 상황이 있을 때는 condition1이 true면 그다음 조건은 검사하지 않는다.
이런 단축 평가의 개념으로 boolean 값이 간단하게 나오는 상황을 앞 쪽에 적용하면 빠르게 처리할 수 있다.

 


가독성 높은 분기 처리 방법

중첩 if

일반적으로 개발할 시 긍정적(유효한) 상황을 염두하고 개발을 하는데,
지속적으로 유효성을 체크하는 로직이 들어갈 경우 if 문이 계층구조처럼 구성이 만들어지기도 함.

    Object getUserInfo() {
      Session session = getSession();
      if( session != null ) {
        User user = session.getAttribute("loginUser");
        if( user != null ) {
          String id = user.getId();
          if( id != null ) {
            // 처리할 로직
          }
        }
      }
    }

 

중첩 if - 개선

역으로 부정적(유효하지 않는) 상황을 염두하고 분기 처리를 하면, 가독성과 구조적으로 좋은 코드가 나옴.
실제 처리할 로직이 시작하기 전에 유효하지 않는 상황으로 분기되면 해당 메소드나 함수를 return이나 예외 처리로 벗어나는 것을 보호절 숙어 라고 함.

    Object getUserInfo() {
      Session session = getSession();
      if( session == null ) return;

      User user = session.getAttribute("loginUser");
      if( user == null ) return;

      String id = user.getId();
      if( id == null ) return;

      // 처리할 로직
    }

 

 


loop 내에서의 분기 처리

    String line;
    while( line = reader.readline() ) {
      if( line.startsWith('#') || line.isEmpty() )
        continue;

      //  처리할 로직
    }

 

 


가독성을 위한 if

좌변에 유동적인 값이나 표현을 넣고, 우변에 상수와 같은 고정 값을 넣어야 가독성이 좋아짐.

    if( 10 <= length )

    //  아래가 더 보기 편함.
    if( length >= 10 )

 

 


if/else 블록의 순서

  • 가능하다면 if 조건 안에는 긍정 조건을 넣어야 가독성이 좋음.
  • 단, if/else 처리 로직 중 간단한 로직을 먼저 if 절에 넣는 것이 가독성이 좋음.
  • 단, 보호절 숙어가 우선순위가 높음. 부정의 조건을 넣어서 계층 구조를 만들지 않을 수 있다면 이게 더 낫다는 의미.
  •   if( hasAuth ) {
        // 간단하고 긍정적인 내용
      } else {
        // 상대적으로 복잡하고 긴 내용
      }

 


삼항 연산자

  • 간단한 구문일 경우 : 삼항 연산자.
  • 복잡한 구문일 경우 : if/else.

삼항 연산자는 코드 한 줄로 가독성을 챙길 수 있으며, 한 줄로 처리하기 복잡할 경우에는 if/else를 사용하는 게 낫다.

  • 삼항 연산자가 이득인 경우
  • let timeType = hour < 12 ? 'am' : 'pm';
  • if/else가 이득인 경우
  •   let timeKor, timeEng;
      if( hour < 12 ) { 
          timeKor = '오전';
        timeEng = 'am';
      } else { 
          timeKor = '오후';
        timeEng = 'pm';
      }

 


복잡한 분기 추출

재사용되거나, 분기 절 내의 복잡한 내용을 메소드로 표현하게 되면 더 나은 가독성을 얻을 수 있다.

  • 기존
  •     if( user.id == post.registerId ) {
            // 사용자가 게시물의 작성자 이다.
        } else {
            // 사용자가 게시물의 작성자가 아니다.
        }
  • 개선
  •     boolean isEditable = isOwner( user, post );
        if( isEditable ) {
            // 사용자가 게시물의 작성자 이다.
        } else {
            // 사용자가 게시물의 작성자가 아니다.
        }
        boolean isOwner( User user, Post post ) { return user.id == post.registerId; }

 


드모르간 법칙

괄호 중첩이 적을수록 가독성이 좋다.

  • 기존
  • if( !(hasfile && !isPrivate) ) return false;
  • 개선
  • if( !hasFile || isPrivate ) return false;

 


복잡한 논리 가독성 향상

한 라인으로 논리를 표현하지 않고, 가독성을 위해 적절한 여러 라인으로 분리하여 보호절과 유사하게 한다.

  • 기존
  •   public class Range {
        private int bgn;
        private int end;
        // this의 bgn이나 end가 other의 bgn이나 end에 속하는지 확인
        private boolean isOverlapsWith( Range other ) {
          return ( this.bgn >= other.bgn && this.bgn < other.end )
              || ( this.end > other.bgn && this.end <= other.end )
              || ( this.bgn <= other.bgn && this.end >= other.end );
        } 
      }
  • 개선
  •   public class Range {
        private int bgn;
        private int end;
        // this의 bgn이나 end가 other의 bgn이나 end에 속하는지 확인
        private boolean isOverlapsWith( Range other ) {
          // this가 시작하기 전에 끝난다.
          if( other.end <= this.bgn ) return false;
          // this가 끝난 후에 시작한다.
          if( other.bgn >= this.end ) return false;
          // 겹친다.
          return true;
        }
      }

 


switch 문의 사용

if-else 문은 각 조건문을 iterate 하며 로직을 결정한다. N개의 if-else 구문이 있다면 N번의 조건 여부를 판단한다.
switch 문은 입력받은 케이스로 로직이 바로 넘어가게 된다.
일반적으로 4개 이상의 조건일 때 if-else 보다 switch 문을 사용하는 것이 성능에 좋다고 한다.

시간 복잡도

다음은 if-else와 switch의 시간 복잡도이다.

  • if-else : O(N)
  • switch : O(logN)
  int num = 5;
  int ret;

  if (num == 0)      ret = num;
  else if (num == 1) ret = num;
  else if (num == 3) ret = num;
  else if (num == 5) ret = num;
  else if (num == 7) ret = num;
  else               ret = num;

  System.out.println(ret);
  int num = 5;
  int ret;

  switch (num) {
    case 0: ret = num; break;
    case 1: ret = num; break;
    case 3: ret = num; break;
    case 5: ret = num; break;
    case 7: ret = num; break;
    default: ret = num; break;
  }
  System.out.println(ret);

 

 


참고자료 :

728x90
반응형

+ Recent posts