이 글은 깃허브에 올라온 글을 바탕으로 제가 그대로 타이핑한 글입니다. 더 자세하고 정확한 정보를 보시려면
아래 링크를 참조해 주세요.
Link
Part 1. 전산 기초
개발 상식 Link
- 좋은 코드란?
- 객체 지향 프로그래밍이란?
- RESTFul API?
- TDD란? 어떠한 장점이 있는가?
- 함수형 프로그래밍?
- MVC 패턴이란?
- Git, GitHub란?
좋은 코드란 무엇일까?
Clean Code? Efficient Code? Short Code?
읽기 쉬운 코드?
- 주석을 쓰면 되지 않을까?
- 그렇지만, 기본적으로 메타데이터이고, 주석의 내용과 실제 동작이 일치하는지는 어떻게 알아?
나한테만 읽기 쉬운 코드?
- 내 코드가 한 번 작성되고, 이 다음에 수정될 일이 없다고 누가 그래?
읽기 쉽기만 하면 되는거야?
- 읽기 쉬운데 전혀 효율적이지 못하고, 버그를 유발하는 각종 암덩어리가 숨어 있으면?
테스트가 용이한 코드?
- 테스트가 용이한 코드가 좀 더 신뢰성 있지만
- 그 신뢰성을 계속 믿다간 큰 코를 다칠거야.
- 또, 테스트가 용이 하다는 것이 무슨 의미지?
중복이 없는 코드?
- 동일 로직에 대한 공통적인 처리가 있으면,
- 한가지로 모으는 작업은 거의 필수적이지.
- 수정할 일이 생겼을 때, 그 한 가지만 수정하면 되니까!
- 하지만 그 중복을 추출하는 과정을 어떻게 거쳐야 될까?
좋지 않은 코드
- 쓰이지 않는 코드
- 거리
- 코드가 동작하는 곳과 정의된 곳 간의 물리적 거리가 멀면 파악하기 힘들지.
- 보고 있는 코드가 일정 범위에서만 사용된다는 확신이 있으면 그 범위만 확인 후 사용하지 않는 코드라는 확신을 얻을 수 있어.
- 순수하지 않은 함수
- 함수 외부의 어떤 값을 기반으로 동작하는 함수는 그 side effect를 제어하기 힘들지.
- 함수의 입출력만 확인하여 함수 내부를 수정할 수 없다면 수정하기 까다로워.
- 응급 처치를 한 코드
- 중복으로 빼뒀지만 사용하는 곳에서 다른 로직을 추가해줘야 할 때
- 이 때 수정으로 인한 Side effect가 두려워 함수에 입력을 추가하던가, 옵션 값을 추가하여 내부에서 억지로 처리할 때 좋지 않은 코드가 된다.
- 기술 부채
- 응급처치가 무조건 나쁘다는 말이 아니지. 당장 문제를 해결하는 데에 이만큼 빠른 대응이 없지만, 전체적인 구조 리팩터링을 할 수가 없어.
- 응급처치 코드들은 부채가되고 상환의 의무를 져야 해.
좋지 않은 코드를 줄이기
추출이 아닌, 추상화
추출 Extraction
- 밖으로 끌어내
추상화 Abstraction
- 먼 개념을 이끌어내
의존성을 드러내기 위한 추상화
다른 곳에서 재사용하기 위해 분리하고
파일이 커져서 분리하고
단순히 중복된 코드 덩어리(chunk)에 대해 추출하면 재사용하기 어렵지.
오히려 함수 간 의존 관계를 파악하기 위해 비용이 들어가게 되는거야.
함수를 분리할 때는 그 함수의 역할을 인지하고 하나의 역할만 정의해야 해.
의존성을 드러내기 위함이 추출의 목적이 되야하는거지.
한 파일에 여러 로직이 얽혀 있을 때 각 코드 조각 중 서로 관계에 있는 것들을 추출해야 해.
추상화가 된 함수는 하나의 목적(역할)을 갖게 되고 의미 있는 추출(추상화)이 가능하게 되는거지.
Object Oriented Programming
학교에서 배웠던 대로, 인터넷에서 봐왔던 대로,
현실 세계의 사물을 객체(Object)로 보고, 그 객체로부터 개발하고자 하는 애플리케이션에 필요한 특징들을 뽑아와 프로그래밍하여 하는 것(Abstraction)이지.
OOP로 코드를 작성한다면
- 작성한 코드에 대한 재사용성이 높아.
- 자주 사용되는 로직을 라이브러리로 만들어두어 계속 사용할 수 있어.
- 라이브러리를 각종 예외 상황에 맞게 만들어둔다면 개발자가 사소한 실수를 하더라도 그 에러를 컴파일 단계에서 잡아낼 수 있어.
- 내부적으로 어떻게 동작하는지 몰라도 개발자는 라이브러리가 제공하는 기능들을 사용할 수 있어 생산성이 높아져
- 객체 단위로 코드가 나눠져 작성되기 때문에 디버깅이 쉽고 유지보수에 용이해
- 데이터 모델링을 할 때 객체와 매핑하는 것이 수월해 요구사항을 보다 명확하게 파악하여 프로그래밍 할 수 있어.
하지만
- 객체간의 정보 교환이 모두 메시지 교환을 통해 일어나게 되어, 실행 시스템에 많은 overhead가 발생하게 될 수 있어.
- 킹치만, 하드웨어의 발전으로 보완되고 있지
- 객체간의 정보 교환이 모두 메시지 교환을 통해 일어나게 되어, 실행 시스템에 많은 overhead가 발생하게 될 수 있어.
객체가 상태를 갖게 되고, 변수가 존재하여, 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되는 거지.
- 애플리케이션 내부에서 버그를 발생해
- 이로 인해 함수형 패러다임이 주목받고 있지.
객체 지향적 설계 원칙
- SRP : Single Responsibility Principle, 단일 책임 원칙
- 클래스는 단 하나의 책임을 가져야 하며, 클래스를 변경하는 이유는 단 하나의 이유이어야 한다.
- OCP : Open-Closed Principle, 개방-폐쇄 원칙
- 확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다.
- LSP : Liskov Subsitution Principle, 리스코프 치환 원칙
- 상위 타입의 객체를 하위 타입의 객체로 치환해도, 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.
- ISP : Interface Segregation Principle, 인터페이스 분리 원칙
- 인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
- DIP : Dependency Inversion Principle, 역전 의존 원칙
- 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.
RESTFul API
REST란, REpresentational State Transfer의 약자야. 여기에 ~ful 이라는 형용사형 어미를 붙여 REST한 API라는 표현으로 사용되는 거지.
REST는 디자인 패턴인지, 아키텍처인지 확실치는 않지만, 어떻게 보면 하나의 아키텍처로 볼 수 있지.
API 설계의 중심에 자원이 있고, 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 형태로 보내는 것보다, 방식을 하나로 통일하는 것이 좋아.
- URI가 플랫폼 중립적이어야 한다는것
어떠한 장점?
- Open API 제공이 쉬워
- 멀티플랫폼 지원 및 연동이 용이해
- 원하는 타입으로 데이터를 주고 받을 수 있어
- 기존 웹 인프라(HTTP)를 그대로 사용할 수 있어
어떠한 단점?
- 사용할 수 있는 메소드가 4가지 밖에 없어
- 분산환경에는 부적합해
- HTTP 통신 모델에 대해서만 지원해
Reference
- REST API 제대로 알고 사용하기 - TOAST
- 바쁜 개발자들을 위한 RESTFul api 논문 요약
- REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁 - spoqa
TDD
TDD란?
Test-Driven Development는 매우 짧은 개발사이클의 반복에 의존하는 소프트웨어 개발 프로세스야.
- 개발자는 요구되는 새로운 기능에 대한 자동화된 테스트케이스를 작성하고 해당 테스트를 통과하는 가장 간단한 코드를 작성해
- 테스트 통과하는 코드를 작성하고, 상황에 맞게 리팩토링 과정을 거치는 거지.
- 테스트가 코드 작성을 주도하는 개발방식이야
Add a test
- 새로운 기능을 추가하기 전 테스트를 먼저 작성해
- 테스트를 작성하기 위해 개발자는 해당 기능의 요구사항과 명세를 분명히 이해하고 있어야 해
- 사용자 케이스와 사용자 스토리 등으로 이해할 수 있고, 이는 개발자가 코드를 작성하기 전보다 요구사항에 보다 집중할 수 있도록 도와줘
Run all tests and see if new one fails
- 어떤 새로운 기능을 추가하면 잘 작동하던 기능이 제대로 작동하지 않는 경우가 발생할 수 있어.
- 더 위험한 경우는 개발자가 이를 미처 인지하지 못하는 경우야
- 이러한 경우를 방지하기 위해 테스트 코드를 작성하는 거지.
- 새로운 기능을 추가할 때 테스트 코드를 작성함으로써, 새로운 기능이 제대로 작동함과 동시에 작동하는 기존의 기능들이 잘 작동하는지 테스트를 통해 확인할 수 있어.
Refactor code
'좋은 코드'를 작성하는 것은 정말 어려워.
- 코드를 작성할 때 고려해야 할 요소가 정말 다양하기 때문이지.
- 가독성, Naming Rule, 확장성, 비즈니스 로직, 예외처리 등등
코드량이 방대해지면서 리팩토링은 거의 필수적으로 수행되어지게 되는거야.
이 때 테스트 주도 개발을 통해 개발을 해왔다면, 테스트 코드가 그 중심을 잡아줄 수 있지.
- 뚱뚱해진 함수를 여러 함수로 나누는 과정에서 해당 기능이 오작동을 일으킬 수 있지만, 간단히 테스트를 돌려봄으로써 이에 대한 안심을 하고 계속해서 리팩토링을 진행할 수 있어.
- 결과적으로 리팩토링 속도도 빨라지고, 코드의 퀼리티도 그만큼 향상되게 되는거야.
- 보다 객체지향적이고, 확장 가능이 용이한 코드, 재설계의 시간을 단축시킬 수 있는 코드, 디버깅 시간이 단축되는 코드가 TDD와 함께 탄생하는 것이지
의문점들
Q. 코드 생산성이 문제가 있지 않을까?
- 테스트 코드만큼 코드량이 늘어나고, 비즈니스 로직, 각종 코드 디자인에도 시간이 많이 소요되는거지. 코드 퀼리티보다는 빠른 생산성이 요구되는 시점에서 TDD는 큰 걸림돌이야.
Q. 테스트 코드를 작성하기 쉬워?
TDD라는 개발 방식을 적용하기에 큰 걸림돌이지. 진입 장벽이 분명 존재해.
- 어떤 부분을 테스트해야 할지
- 어떻게 테스트해야 할지
- 여러 테스트 프레임워크 중 어떤 것이 우리의 서비스와 맞는지 등
여러 부분들에 대한 학습이 필요하고 익숙해지는데도 시간이 걸려.
또, 한 명이 익숙해진다고 되는 일이 아니라, 개발은 팀 단위로 수행되는 거니까 팀원 전체에 대한 동의가 필요하고, 팀원 전체가 익숙해져야 하는거야.
Q. 모든 상황에 대해 테스트 코드를 작성할 수 있어야 해?
세상에는 다양한 사용자가 존재하고, 생각지도 못한 예외 케이스가 존재할 수 있어.
만약 테스트를 반드시 해봐야 하는 부분에 있어서 테스트 코드를 작성하는데 어려움이 발생한다면?
- 주객이 전도하는 상황이 발생하는거야
실제 코드가 더 중심이 되어야 하는데 테스트를 위해서 코드의 구조를 바꿔야 하는 고민이 생기거나 발생할 수 있는 상황에 대한 테스트 코드를 작성하기 위해 배보다 배꼽이 더 커지는 경우가 허다해.
모든 코드에 대해서 테스트 코드를 작성할 수 없고, 작성할 필요도 없어. 그리고 테스트 코드를 작성한다고해서 버그가 발생하지 않는 것도 아니야.
함수형 프로그래밍
함수형 프로그래밍의 가장 큰 특징 두가지는 immutable data와 first class citizen으로서의 function이야.
immutable vs mutable
- immutable이란 말 그대로 변경 불가능함을 의미해
- immutable 객체는 객체가 가지고 있는 값을 변경할 수 없는 객체를 의미하여 값이 변경될 경우, 새로운 객체를 생성하고 변경된 값을 주입하여 반환해야 해.
- 이와 달리 mutable 객체는 해당 객체의 값이 변경될 경우 값을 변경해.
first-citizen
함수형 프로그래밍 패러다임을 따르고 있는 언어에서의 함수는 일급 객체로 간주돼.
- 변수다 데이터 구조 안에 함수를 담을 수 있어서 함수의 파라미터로 전달할 수 있고, 함수의 반환값으로 사용할 수 있어.
- 할당에 사용된 이름과 관계없이 고유한 구별이 가능해.
- 함수를 리터럴로 바로 정의할 수 있어.
Reactive Programming
반응형 프로그래밍은 선언형 프로그래밍이라고도 불리고, 명령형 프로그래밍의 반대말이야.
- 또, 함수형 프로그래밍 패러다임을 활용하는 것을 말해.
- 반응형 프로그래밍은 기본적으로 모든 것을 스트림(stream)으로 봐.
- 스트림이란 값들의 집합으로 볼 수 있고, 제공되는 함수형 메소드를 통해 데이터를 immutable하게 관리할 수 있어.
Reference
- 함수형 프로그래밍 소개
- 반응형 프로그래밍이란 무엇인가
- What-I-Learned-About-RP
- Reactive Programming
- MS 는 ReactiveX 를 왜 만들었을까?
MVC 패턴이란 무엇인가?
그림과 함께 설명하는 것이 더 좋다고 판단하여 포스팅으로 대체한다.
Git 과 GitHub 에 대해서
Git 이란 VCS(Version Control System)에 대해서 기본적인 이해를 요구하고 있다.
Git 을 사용하기 위한 각종 전략(strategy)들이 존재한다. 해당 전략들에 대한 이해를 기반으로 Git 을 사용해야 하기 때문에 면접에서 자주 물어본다. 주로 사용되는 strategy 중심으로 질문이 들어오며 유명한 세 가지를 비교한 글을 첨부한다.
많은 회사들이 GitHub 을 기반으로 협업을 하게 되는데, (BitBucket 이라는 훌륭한 도구도 존재합니다.) GitHub 에서 어떤 일을 할 수 있는지, 어떻게 GitHub Repository 에 기여를 하는지 정리한 글을 첨부한다.