좋은 코드란 무엇인가?
좋은 코드?
좋은 코드란 무엇일까? 좋은 코드는 정해져있지 않다. 모두의 기준이 다 다르고 환경이 다르기 때문일것이다.
보통 사람들이 말하는 좋은 코드는 다음과 같다
- 읽기 쉬운 코드
- 중복이 없는 코드
- 테스트가 용이한 코드
- ...
사실 정해진 결론은 없다. 매 상황에 따라 알맞게 코드를 잘 작성하는것이 가장 좋은 것 같다.
- 코드 간의 의존성을 고민하자.
- 합의된 규칙으로 일관성있게 작성하자.
- 적절하게 확장 가능하도록 설계하자.
- 어쩔 수 없는 코드는 주석과 함께 격리하자.
- ...
객체지향 프로그래밍(OOP, Object Oriented Programming)
객체 지향 프로그래밍 이전의 프로그래밍 패러다임을 살펴보면, 중심이 컴퓨터에 있었다. 컴퓨터가 사고하는대로 프로그래밍을 하는 것이다. 하지만 객체지향 프로그래밍이란 인간 중심적 프로그래밍 패러다임이라고 할 수 있다.
즉 현실 세계를 프로그래밍으로 옮겨와 프로그래밍하는 것을 말한다. 현실 세계의 사물들을 객체라고 보고 그 객체로부터 개발하고자 하는 어플리케이션에 필요한 특징들을 뽑아와 프로그래밍 하는 것이다. 이를 추상화라 한다.
OOP로 코드를 작성하면 이미 작성한 코드에 대한 재사용성이 높다.
자주 사용되는 로직을 라이브러리로 만들어두면 계속해서 사용할 수 있으며 그 신뢰성을 확보 할 수 있다. 또한 라이브러리를 각종 예외상황에 맞게 잘 만들어두면 개발자가 사소한 실수를 하더라도 그 에러를 컴파일 단계에서 잡아낼 수 있으므로 버그 발생이 줄어든다.
또한 내부적으로 어떻게 동작하는지 몰라도 개발자는 라이브러리가 제공하는 기능들을 사용할 수 있기 때문에 생산성이 높아지게 된다.
객체 단위로 코드가 나눠져 작성되기 때문에 디버깅이 쉽고 유지보수에 용이하다. 또한 데이터 모델링을 할 때 객체와 매핑하는 것이 수월하기 때문에 요구사항을 보다 명확하게 파악하여 프로그래밍 할 수 있다.
단점-
객체 간의 정보 교환이 모두 메시지 교환을 통해 일어나므로 실행 시스템에 많은 Overhead가 발생할 수 있지만, 이는 하드웨어의 발전으로 많이 보완되었다.
객체 지향 프로그래밍의 치명적인 단점은 함수형 프로그래밍 패러다임의 등장 배경을 통해 알 수 있다. 바로 객체가 상태를 갖는다는 것이다. 변수가 존재하고 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되어 어플리케이션 내부에서 버그를 발생시킨다는것이다. 이런 이유로 함수형 패러다임이 주목받고있기도 하다.
객체 지향적 설계 원칙
1. SRP(Single Responsibility Principle) : 단일 책임 원칙
클래스는 단 하나의 책임을 가져야 하며 클래스를 변경하는 이유는 단 하나의 이유이어야 한다.
2. OCP(Open-Closed Principle) : 개방-폐쇄 원칙
확정에는 열려 있어야 하고 변경에는 닫혀 있어야 한다.
3. LSP(Liskov Substitution Principle) : 리스코프 치환 원칙
인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
4. ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
5. DIP(Dependency Inversion Principle) : 의존 역전 원칙
고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.
함수형 프로그래밍
함수형 프로그래밍의 가장 큰 특징 두가지는 immutable data와 first class citizen으로서의 function이다.
immutable vs mutable
immutable : 변경 불가능함을 의미한다. immutable 객체는 객체가 가지고 있는 값을 변경할 수 없는 객체를 의미하여 값이 변경될 경우, 새로운 객체를 생성하고 변경된 값을 주입하여 반환해야 한다. 이와는 달리, mutable 객체는 해당 객체의 값이 변경될 경우 값을 변경한다.
first-class citizen
함수형 프로그래밍 패러다임을 따르고 있는 언어에서의 함수는 일급 객체(first class citizen) 으로 간주된다. 일급 객체라 함은 다음과 같다.
- 변수나 데이터 구조 안에 함수를 담을 수 있어서 파라미터로 전달할 수 있고, 함수의 반환값으로 사용할 수 있다.
- 할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.
- 함수를 리터럴로 바로 정의할 수 있다.
Reactive Programming
반응형 프로그래밍(Reactive Programming)은 선언형 프로그래밍(Declarative Programming)이라고도 불리며, 명령형 프로그래밍(Imperative Programming)의 반대말이다. 또 함수형 프로그래밍 패러다임을 활용하는 것을 말한다.
반응형 프로그래밍은 기본적으로 모든 것을 스트림(Stream)으로 본다. 스트림이란 값들의 집합으로 볼 수 있으며 제공되는 함수형 메소드를 통해 데이터를 immutable하게 관리할 수 있다는 것이다.
RESTful API
정의
월드 와이드 웹(WWW)과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식으로 자원을 정의하고 자원에 대한 주소를 지정하는 방법 전반에 대한 패턴
REST란, REpresentational State Transfer의 약자이다. 여기에 ~ful 이라는 형용사형 어미를 붙여 ~한 API 라는 표현으로 사용된다. 즉, REST의 기본 원칙을 성실히 지킨 서비스 디자인은 'RESTful'하다 라고 표현할 수 있다.
REST가 디자인 패턴이다, 아키텍처다 많은 이야기가 존재하는데, 하나의 아키텍처로 볼 수 있다. 좀 더 정확한 표현으로 말하자면, REST는 Resource Oriented Architecture이다. API설계의 중심에 자원(Resource)이 있고, HTTP Method를 통해 자원을 처리하도록 설계하는 것이다.
REST 6 가지 원칙
- Uniform Interface
- Stateless
- Caching
- Client-Server
- Hierarchical system
- Code on demand
RESTfUL 하게 API를 디자인 한다는 것은 무엇을 의미할까?(요약)
- 리소스와 행위를 명시적이고 직관적으로 분리한다
- 리소스는 URI로 표현되는데, 리소스가 가리키는 것은 명사로 표현되어야 한다.
- 행위는 HTTP Method로 표현하고, GET(조회), POST(생성), PUT(기존 entity 전체 수정), PATCH(기존 entity 일부 수정), DELETE(삭제)를 분명한 목적으로 사용한다.
- Message 는 Header와 Body를 명확하게 분리해서 사용한다.
- Entity에 대한 내용은 body에 담는다.
- 어플리케이션 서버가 행동할 판단의 근거가 되는 컨트롤 정보인 API 버전 정보, 응답받고자 하는 MIME 타입 등은 header에 담는다.
- header 와 body 는 http header 와 http body 로 나눌 수도 있고, http body 에 들어가는 json 구조로 분리할 수도 있다.
- API 버전을 관리한다.
- 환경은 항상 변하기 때문에 API 의 signature 가 변경될 수도 있음에 유의하자.
- 특정 API를 변경할 때는 반드시 하위호환성을 보장해야 한다.
- 서버와 클라이언트가 같은 방식을 사용해서 요청하도록 한다.
- 브라우저는 form-data 형식의 submit으로 보내고 서버에서는 json 형태로 보내는 식의 분리보다는 둘다 json 또는 form-data 형식으로 통일한다
- 다르게 표현하자면 URI가 플랫폼 중립적이어야 한다.
어떤 장점이 존재할까?
- Open API 를 제공하기 쉽다.
- 멀티플랫폼 지원 및 연동이 용이하다.
- 원하는 타입으로 데이터를 주고 받을 수 있다.
- 기존 웹 인프라(HTTP)를 그대로 사용할 수 있다.
단점은 뭐가 있을까?
- 사용할 수 있는 메소드가 4가지 밖에 없다.
- 분산환경에는 부적합하다.
- HTTP 통신 모델에 대해서만 지원한다.
Reference
- REST API 제대로 알고 사용하기 - TOAST
- 바쁜 개발자들을 위한 RESTFul api 논문 요약
- REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁 - spoqa
TDD
TDD란 무엇인가?
Test-Driven Development(TDD)는 매우 짧은 개발 사이클의 반복에 의존하는 소프트웨어 개발 프로세스이다. 우선 개발자는 요구되는 새로운 기능에 대한 자동화된 테스트케이스를 작성하고 해당 테스트를 통과하는 가장 간단한 코드를 작성한다. 일단 테스트를 통과하는 코드를 작성하고 상황에 맞게 리팩토링하는 과정을 거치는 것이다.
Add a test
테스트 주도형 개발에선, 새로운 기능을 추가하기 전 테스트를 먼저 작성한다. 테스트를 작성하기 위해서, 개발자는 해당 기능의 요구사항과 명세를 분명히 이해하고 있어야 한다. 이는 사용자 케이스와 사용자 스토리 등으로 이해할 수 있으며, 이는 개발자가 코드를 작성하기 전에 보다 요구사항에 집중할 수 있도록 도와준다. 이는 정말 중요한 부분이자 테스트 주도 개발이 주는 이점이라고 볼 수 있다.
Run all tests and see if new one Fails
새로운 기능을 추가하면 잘 작동하던 기능이 제대로 작동하지 않는 경우가 발생할 수 있다.
이러한 경우를 방지하기 위해 테스트 코드를 작성해 새로운 기능의 점검과 기존 기능들의 점검을 테스트해보면 좋다.
Refactor code
'좋은 코드'를 작성하기란 쉽지 않다. 코드를 작성할 때 고려해야 할 요소가 한 두 가지가 아니기 때문이다. 가독성이 좋게 coding convention을 맞춰야 하며, 네이밍 규칙을 적용하여 메소드명, 변수명, 클래스명에 일관성을 주어야하며, 앞으로의 확장성 또한 고려해야한다. 이와 동시에 비즈니스 로직에 대한 고려도 반드시 필요하며, 예외처리 부분 역시 빠뜨릴 수 없다. 물론 코드 크기가 작다면 이런 저런 것들을 모두 신경쓰며 코드를 작성할 수 있지만 끊임없이 발견되는 버그들을 디버깅하는 과정에서 코드가 복잡해질 수 있다.
이런 이유로 코드 리팩토링을 하게 된다. 이때 테스트 주도 개발을 통해 개발을 해왔다면, 테스트 코드가 그 중심을 잡아줄 수 있다. 덩치가 커진 함수를 분리하는 과정에서 해당 기능에 문제가 생길 수 있지만, 간단히 테스트를 돌려봄으로써 이에 대한 안심을 하고 계속해서 리팩토링을 진행할 수 있는것이다.
결과적으로 테스트 주도 개발 내에선 리펙토링의 속도가 빨라지고 퀄리티의 향상도 기대할 수 있다.
코드 퀄리티 부분에선 좀더 객체지향적이고 확장 가능이 용이한 코드, 재설계의 시간을 단축시킬 수 있는 코드, 디버깅 시간이 단축되는 코드가 TDD와 함께 탄생하는것이다.
의문점. TDD는 항상 옳은가?
Q. 코드 생산성에 문제가 있지는 않을까?
일단, 작성하는 코드의 양이 늘어날 수밖에 없다. 비즈니스 로직, 각종 코드 디자인에도 시간이 많이 소요되는데 테스트코드까지 작성하기란 여간 벅찬 일이 아닐 것이다. 코드 퀄리티보다 빠른 생산성이 요구되는 시점에서 TDD는 큰 걸림돌이 될 수 있다.
Q. 테스트 코드를 작성하기가 쉬운가?
어떤 부분을 테스트해야할지, 어떻게 테스트해야할 지, 여러 테스트 프레임워크 중 어떤 것이 우리의 서비스와 맞을지 등 여러 부분들에 대한 고려와 학습이 필요하고 결코 이런 과정이 빨리 이루어질 수 없다. 그리고 팀에서 한명만 익숙해진다고 해결될 일도 아니다.
개발은 팀 단위로 수행되기 때문에 팀원 전체의 동의가 필요하고 팀원 전체가 익숙해져야 비로소 테스트 코드가 빛을 발하게 되는 것이다.
따라서 어느정도 진입장벽이 존재한다.
Q. 모든 상황에 대해서 테스트 코드를 작성할 수 있는가? 작성해야 하는가?
다양한 예외적인 상황에 모두 대응할 수 있을까? 이때의 테스트코드를 작성하는데 있어 어려움이 있지는 않을까?
테스트코드에 비중이 커지게되면 주객이 전도되는 상황이 발생할 수 있다. 실제 코드가 중심이 되어야 하는데, 테스트를 위해 코드의 구조를 바꿔야하나 라는 고민이 생길 수도 있다. 또한 발생할 수 있는 상황에 대한 테스트 코드를 작성하기 위해 배보다 배꼽이 더 커지는 경우가 허다하다.
실제 구현 코드보다 방대해진 코드를 관리하는게 쉽지만은 않을 것이다.
모든 코드에 대해서 테스트 코드를 작성할 수 없으며 작성할 필요도 없다. 또한 테스트 코드를 작성한다고 해서 버그가 발생하지 않는 것도 아니다. 애초에 TDD는 100% Coverage와 100% 무결성을 주장하지 않았다.
MVC 패턴이란 무엇인가?
Model, View, Controller
Model
컨트롤러가 호출할 때 요청에 맞는 역할을 수행한다. 비즈니스 로직을 구현하는 영역으로 응용프로그램에서 데이터를 처리하는 부분이다.
비즈니스 로직이란 업무에 필요한 데이터처리를 수행하는 응용프로그램의 일부라고 할 수 있다. DB에 연결하고 데이터를 추출하거나 저장, 삭제, 업데이트, 변환 등의 작업을 수행한다. 상태의 변화가 있을 때 컨트롤러와 뷰에 통보해 후속 조치 명령을 받을 수 있게 한다.
View
컨트롤러로부터 받은 모델의 결과값을 가지고 사용자에게 출력할 화면을 만드는 일을 한다.
만들어진 화면을 웹브라우저에 전송하여 웹브라우저가 출력하게 하는 것이다. 화면에 표시되는 부분으로 추출한 데이터나 일반적인 텍스트 데이터를 표시하거나 입력폼 또는 사용자와의 상호작용을 위한 인터페이스를 표시하는 영역이다.
Controller
일종의 조정자라고 할 수 있다.
클라이언트의 요청을 받았을 때, 그 요청에 대해 실제 업무를 수행하는 모델 컴포넌트를 호출한다.
또한 클라이언트가 보낸 데이터가 있다면, 모델에 전달하기 쉽게 데이터를 가공한다.
모델이 업무를 마치면 그 결과를 뷰에게 전달한다.
MVC 구동 원리
C/S(Client - Server)구조로 요청을 하면 그에 맞는 응답을 하는 구조를 기본으로 하고 있다.
- 웹 브라우저가 웹 서버에 웹 어플리케이션 실행을 요청한다. (MVC 구조가 WAS라고 보면 된다.)
- 웹 서버는 들어온 요청을 처리할 수 있는 서블릿을 찾아서 요청을 전달한다.(Matching)
- 서블릿은 모델 자바 객체의 메서드를 호출한다.
- 데이터를 가공하여 값 객체를 생성하거나, JDBC를 사용하여 데이터베이스와의 인터랙션을 통해 값 객체를 생성한다.
- 업무 수행을 마친 결과값을 컨트롤러에게 전달한다.
- 컨트롤러는 모델로부터 받은 결과값을 View에게 전달한다.
- JSP는 전달받은 값을 참조하여 출력할 결과 화면을 만들고 컨트롤러에게 전달한다.
- 뷰로부터 받은 화면을 웹 서버에게 전달한다.
- 웹 브라우저는 웹 서버로부터 요청한 결과값을 응답받으면 그 값을 화면에 출력한다.
해당 페이지의 포스트를 참고하여 블로그에 다시 정리하였습니다.
'ETC > CS' 카테고리의 다른 글
[컴퓨터구조] ch.2-4 MIPS (0) | 2020.10.26 |
---|---|
[컴퓨터구조] ch.2-3 MIPS (0) | 2020.10.25 |
[컴퓨터구조] ch.2-2 산술 동작 (0) | 2020.10.24 |
[컴퓨터구조] Ch.2-1 컴퓨터 언어 - Language of the Compute (0) | 2020.10.24 |
[컴퓨터구조] Ch.1 컴퓨터 추상화와 기술 - Computer Abstractions and Technology (0) | 2020.10.21 |
댓글