cs 스터디 - (1) 개발상식

Yuri JI·2022년 8월 29일
0

cs스터디

목록 보기
1/9

📒 개발상식

1) 좋은 코드란?

https://jbee.io/etc/what-is-good-code/ 해당 블로그 글을 참고하여 작성하였습니다.
좋은 코드란 무엇인지 생각해본 뒤 왜 좋지 않은 코드가 생산되는지, 그리고 좋은 코드를 생성하기 위한 방법은 무엇인지 알아보자.

📌 좋은 코드란 무엇인지?

  • 읽기 쉬운 코드 ?
    - 주석을 이용하면 변수 및 함수를 언제 사용해야할지, 함수의 인자는 무엇인 빠르게 파악이 가능하다.
    - 하지만, 주석은 메타데이터이기 때문에 주석의 내용과 함수의 실제 동작이 일치한다고 보장할 수 없다.
  • 테스트가 용이한 코드 ?
    - 테스트가 용이한 코드라는 것은 무엇인지? 이에 대한 좀 더 근본적인 정의가 필요하다.
  • 중복이 없는 코드 ?
    - 중복을 제거하기 위한 코드 추출(Extraction)은 무엇을 기준으로 해야할까?

📌 왜 좋지 않은 코드가 생산되는가?

우리는 새로운 로직에 대한 코드를 작성하기도 하지만 기존의 코드를 수정해야할 경우가 있다.

  • 쓰이지 않는 코드
    - 더 이상 쓰지 않는 코드(Dead code)
    : 코드가 어디에 쓰이는지 알 수 없어 함부로 삭제하기도 어려운 코드
  • 응급처치를 한 코드
    - 응급처치가 몇 번 이루어진 함수는 누구도 알아보기 어렵다. 이런 코드는 우리가 고민하는 좋은 코드라고 할 수 없다.
  • 기술부채
    - 당장 제공하고있는 서비스에서 발생하는 버그를 잡아야 한다면, 전체적인 구조 리팩토링을 할 수 없기때문에 응급처치는 그 당시에 옳은 선택이었다.
    - 하지만, 이런 응급처치한 코드들은 기술 부채로 쌓이고, 기술 부채가 많아질 수록 그 코드를 유지보수 하는데 더 큰 비용이 들어가기때문에 문제 해결과 기술 부채 사이의 적정선을 찾는 것 또한 중요하다.

📌 좋지 않은 코드 줄이기

좋지 않은 코드가 생성되는 이유를 알아보았으니, 이런 코드를 개선하는 방법을 알아보자.

  • 코드의 분리
    - 비즈니스 요구사항을 맞추다 보면 어쩔 수 없이 복잡한 코드가 작성될 수도 있다.
    - 좋지 않은 코드가 생산되는 것을 완전히 차단할 수 없다면 제대로 관리될 수 있도록 격리해야한다.

  • 추출이 아닌 추상화하기

    • 추출(Extraction)
      - 우리가 별도의 함수 또는 파일로 추출하는 이유는 재사용하기 위함일 수도 있고, 단지 파일이 커져서 분리하기도 한다. 하지만 단순히 중복된 코드 덩어리를 추출하면 재사용하기 어렵다. 잘못 추출하면 함수 간 의존 관계를 파악하기 위한 비용이 더 들어간다.
      - 따라서 함수를 분리할 때는 그 함수의 역할을 인지하고 하나의 역할만 정의해야한다. 즉, 의존성을 드러내기 위함이 추출의 목적이 되어야 한다.
    • 추상화(Abstraction)
      : 하나의 목적(역할)을 가지고 의미 있는 추출(추상화)를 해야한다.
  • 일관성있는 코드 작성하기
    - 최소한의 가독성을 보장하는 방법은 일관성(합의된 규칙)있는 코드를 작성하는 것이다.

    1. Naming convention
    변수명 및 함수명을 일관된 규칙으로 작성하면 코드를 파악하는데 큰 도움이 된다.
    2. Directory 구조
    일관된 디렉토리 구조는 전체적인 구조를 파악하는데 큰 도움이 되고 컴포넌트 간의 관계를 팡가하는데에도 도움을 준다.
    코드의 역할에 따라 디렉토리를 분리할 수도 있고, 페이지(도메인 영역)에 따라, Featured based하게 .. 등등 작성할 수 있다.
    3. 확장성 있는 코드
    확장에 너무 많이 열려있어도 생기는 문제가 있기때문에 적정선을 찾아가는 것이 무엇보다 중요하다.

📌 결론

  • 코드 간의 의존성을 고민하자
  • 합의된 규칙으로 일관성있게 작성하자
  • 적절하게 확장 가능하도록 설계하자
  • 어쩔 수 없는 코드는 주석과 함께 격리하자

2) 객체지향프로그래밍

이전에는 컴퓨터가 사고하는대로 프로그래밍을 했다.하지만, 객체지향 프로그래밍은 인간 중심적으로 프로그래밍하는 것을 말한다. 현실 세계를 프로그램이으로 옮겨오는 것이다. 현실 세계의 사물들을 객체라고 보고, 그 객체로부터 개발하고하자는 애플리케이션에 필요한 특징들을 뽑아와 프로그래밍하는 것을 말하고. 이를 추상화라고 한다.

📌 OOP의 장점

  • 이미 작성한 코드에 대한 재사용성이 높다.
  • 객체 단위로 코드가 나눠져 작성되기 때문에 디버깅이 쉽고 유지보수에 용이하다.

📌 객체 지향적 설계 원칙

  • SRP 단일 책임 원칙 : Single Responsibility Principle

    • 한 클래스는 하나의 책임만 가져야한다.
    • 하지만 책임이라는 것이 모호하다 (책임의 크고 작음, 문맥과 상황에 따라 다름)
      • 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이다.
  • OCP 개방 폐쇄 원칙 : Opne/Closed Principle 🤨

    • 소프트웨어 요소는 확장에서는 열려있으나 변경에는 닫혀있어야 한다.
    • 다형성을 활용
    • 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현 …. !
    • 문제점
      public class MemeberService {
      	MemberRepository m = new MemoryMemberRepository(); // 기존코드
      	MemberRepository m = new JdbcMemberRepository(); // 변경코드
      }
      • 구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다… !
      • 다형성은 사용했지만, OCP 원칙을 지킬 수 없다.
    • 해결방법
      - 객체를 생성하고, 연관관계를 맺어주는 별도의 조합, 설정자가 필요하다.
  • LSP 리스코프 치환 원칙 : Liskov substitution principle

    • 악셀을 밟으면 앞으로 가 > 근데 내가 뒤로 가라고 클래스를 만들었어 > 컴파일 오류는 안 난다. → LSP 위반 ! 느리더라도 앞으로만 가면 LSP 지키는 것
    • 하지만 ! 리스코프 치환 원칙은 컴파일 성공하는 것을 넘어서,
    • 다형성에서 하위 클래스는 인터페이스 규약(엑셀을 밟으면 앞으로 간다)을 지켜야 한다.
    • why? 인터페이스를 구현한 구현체를 믿고 사용하기 위해서, 다형성 지원을 위한 원칙이다.
  • ISP 인터페이스 분리 원칙 : Interface segregation principle

    • 특정 클라이언트를 위한 인터페이스가 여러 개가 범용 인터페이스 하나보다 낫다.
    • 자동차 인터페이스 → 운전 인터페이스, 정비 인터페이스로 분리
    • 사용자 클라이언트 → 운전자 클라이언트, 정비사 클라이언트로 분리
    • 왜? 분리하면 정비 인터페이스 자체가 변해도 운전자 클라이언트에 영향을 주지 않음
    • 인터페이스가 명확해지고, 대체 가능성이 높아진다. (덩어리가 작으면 편하다 ~)
  • DIP 의존 관계 역전 : Dependency inversion principle

    • 추상화에 의존해야지, 구체화에 의존하면 안된다. = 의존성 주입
    • → 구현 클래스에 의존하지 말고, 인터페이스에 의존하다.
    • → 클라이언트는 인터페이스만 바라보면 된다.
    • → 역할(Role)에 의존해야한다.
    • 왜? 클라이언트가 인터페이스에 의존해야 유연하게 구현체를 변경할 수 있다. 구현체에 의존하면 변경이 어려워진다.

3) RESTful API

📌 RESTful의 의미

  • REST + ~ful = REST한 API라는 표현이다. 즉, REST의 기본 원칙을 성실히 지킨 서비스 디자인을 'RESTful'하다고 표현한다.
  • REST는 Resource Oriented Architecture이다.
    : API 설계의 중심에 자원(Resoucr)가 있고, HTTP Method를 통해 자원을 처리하도록 설계하는 것이다.

📌 REST 6가지 원칙

  • Client-Server
    - 사용자 인터페이스에 대한 관심과 데이터 저장에 대한 관심을 분리함으로써 클라이언트의 이식성과 서버의 규모확장성을 개선한다.
  • Stateless
    - 클라이언트와 서버의 통신에는 상태가 없어야한다. 상태를 저장할 필요가 없어졌기때문에, 모든 요청은 필요한 모든 정보를 담고 있을 수 있게되면서 규모 확장성이 개선된다.
  • Cache
    - 모든 서버 응답은 캐시 가능한지 아닌지 알 수 있어야한다.
  • Uniform Interface
    - 구성 요소(클라이언트, 서버 등) 사이의 인터페이스는 균일해야한다.
  • Layered System
    - 계층으로 구성이 가능해야하며, 각 레이어에 속한 구성요소는 인접하지 않은 레이어의 구성요소를 알 수 없어야 한다.
  • Code-On-Demand (Optional)
    - 서버가 네트워크를 통해 클라이언트에 프로그램을 전달하면 그 프로그램이 클라이언트에서 실행될 수 있어야한다. (Java applet이나 Javascript 같은 것을 말함) 다만 이 제약조건은 필수는 아니다.

📌 RESTful API 디자인 한다는 것은?

  • 리소스와 행위를 명시적으로 직관적으로 분리한다.
    리소스URI명사로 표현한다.
    행위HTTP Method로 표현하고, GET(조회), POST(생성), PUT(기존 entity 전체 수정), PATCH(기존 entity 일부 수정), DELETE(삭제)을 분명한 목적으로 사용한다.
  • Message 는 Header 와 Body 를 명확하게 분리해서 사용한다.
    Header에는 API 버전 정보, 응답받고자하는 MIME 타입등을 담는다.
    Body에는 Entity에 대한 내용을 담는다.
  • API 버전을 관리한다.
    API의 signature가 변경될 수 있음을 유의하고, 특정 API를 변경할 때는 반드시 하위호환성을 보장해야 한다.
  • 서버와 클라이언트가 같은 방식을 사용해서 요청하도록 한다.
    브라우저는 form-data 형식의 submit 으로 보내고 서버에서는 json 형태로 보내는 식의 분리보다는 json 으로 보내든, 둘 다 form-data 형식으로 보내든 하나로 통일한다.
    다른 말로 표현하자면 URI 가 플랫폼 중립적이어야 한다.

4) TDD

📌 TDD란

  • Test-Driven Development(TDD)는 매우 짧은 개발 사이클의 반복에 의존하는 소프트웨어 개발 프로세스이다.

📌 Add a test

  • TDD에서는 새로운 기능을 추가하기 전 테스트를 먼저 작성한다. 개발자는 이를 위해 해당 기능의 요구사항과 명세를 분명하게 이해하고 있어야한다.

📌 Run all tests and see if new on fails

  • 어떤 기능을 추가할 때, 새로운 기능이 제대로 작동함과 동시에 기존의 기능들이 잘 작동하는지 테스트를 통해 확인할 수 있다.

📌 Refactor code

  • 끊임없이 발견되는 버그들을 디버깅하는 과정에서 코드의 양이 많아지며 리팩토링을 하게된다. 이 때 TDD를 해왔다면, 테스트 코드가 그 중심을 잡아줄 수 있다.
  • 테스트에 대한 부분에 대한 문서도 만들어야 한다. 그 부분을 자동으로 해주면서, 코드 작성에 도움을 주는 것이 TDD 인 것이다.

📌 TDD에 관해 생각해볼 점

  • 코드 생산성이 무조건 향상되는가?
    TDD는 코드의 양이 늘어난다. 비즈니스 로직, 각종 코드 디자인에 테스트코드까지 작성하기란 벅찰 수도 있다. 코드 퀄리티보다는 빠른 생산성이 요구되는 시점에서 TDD는 걸림돌이 될 수 있다.
  • 테스트 코드를 작성하기 쉬운가?
    테스트 코드 작성에는 진입장벽이 존재한다. 어떤 부분을, 어떻게 테스트할지, 여러 테스트 프레임워크가 서비스에 맞는지 등 여러 부분에 대한 고려가 필요하다. 또한 팀에서 한 명만 익숙해진다고 해결될 일이 아니다. 개발은 팀 단위로 수행되기 때문에 팀원 전체가 테스트 코드 작성에 익숙해져야 TDD의 장점을 누릴 수 있다.
  • *모든 상황에 대해서 테스트 코드를 작성해야하는가?
    모든 코드에 대해서 테스트 코드를 작성할 수 없으며 작성할 필요도 없다. 또한 테스트 코드를 작성한다고 해서 버그가 발생하지 않는 것도 아니다. 애초에 TDD 는 100% coverage 와 100% 무결성을 주장하지 않았다.

5) 함수형 프로그래밍

📌 함수형 프로그래밍을 배워야하는 이유

  • 다른 방식으로 사고하는 법을 배우기 위함이다.
    함수형 프로그래밍은 기존 절차적 프로그래밍과 객체 지향형 프로그래밍과는 다른 새로운 방식이다. 다양한 사고방식으로 프로그래밍을 바라보면 유연한 문제 해결이 가능하다.

📌 함수형 프로그래밍의 특징

  1. 순수함수 (Pure function)
  2. 비상태, 불변성(Stateless, Immutability)
  3. 선언형 함수 (Expressions)
  4. 1급 객체와 고차함수(First-class, Higher-order functions)

📌 함수형 프로그래밍의 장단점

  • 장점
    • 높은 수준의 추상화를 제공한다.
    • 함수 단위의 코드 재사용이 수월하다.
    • 불변성을 지향하기 때문에 프로그램의 동작 예측이 쉬워진다.
  • 단점
    • 순수함수를 구현하기 위해서 코드의 가독성이 좋지 않을 수 있다.
    • 반복이 for문이 아닌 재귀를 통해 이루어 지는데, 재귀적 코드 스타일은 무한 루프에 빠질 수 있다.
    • 순수함수를 사용하는 것은 쉬울 수 있지만 조합하는 것은 쉽지 않다

6) MVC 패턴

📌 각 컴포넌트의 역할 <Who, When, What>

  • Controller
    - 조정자
    - 클라이언트의 요청을 받았을 때, 그 요청에 대한 실제 업무를 수행하는 모델 컴포넌트를 호출한다.
    - 클라이언트가 보낸 데이터가 있다면, 모델에 전달하기 쉽게 데이터를 가공한다. 모델이 업무를 마치면 그 결과를 뷰에게 전달한다.
  • Model
    - 컨트롤러가 호출할 때, 요청에 맞는 역할을 수행한다.
    - 비즈니스 로직을 구현하는 영역으로 데이터를 처리하는 부분이다.
    - DB에 연결하고 데이터를 저장, 삭제, 업데이트, 변환 등의 작업을 수행한다. 상태의 변화가 있을 때 컨트롤러와 뷰에게 통보해 후속 조치 명령을 받을 수 있게 한다.
  • View
    - 컨트롤러부터 받은 모델으리 결과값을 가지고 사용자에게 출력할 화면을 만드는 일을 한다.
    - 사용자와 상호작용을 위한 인터페이스를 표시하는 영역이다.

🔖 참고한 사이트 목록

https://jbee.io/etc/what-is-good-code/

https://jongminfire.dev/%ED%95%A8%EC%88%98%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80

profile
안녕하세요 😄

0개의 댓글