학교에서 알려주지 않는 17가지 실무기술 책 메모
- 해커와 화가라는 책을 읽다가 너~무 재미없어서 책을 변경했다. (너무 옛날 이야기같기도 하고, 지루했다.)
벌써 6권째 전자책 완독이다! 리디북스 베스트 셀러에 보이길래 목차보고 흥미로워서 구매했다.
책 제목처럼 정말 학교에서는 배우지 않은 내용들이지만 업무하면서 어디선가 필요한 내용이었다. 나같은 기초가 부족한 주니어 개발자 혹은 취준생이 읽으면 아주 좋을 것 같다.
물론 책에서 해당 내용에 대해 깊게 설명하진 않지만, 해당 기술이 어디서 필요한지, 실무에선 어떻게 사용하는 것이 좋을지, 심화적으로 공부해보면 좋을 것을 소개해주고 있어 가볍게 보기 좋은 것 같다.
파이썬을 통해 예제 또한 제공하여 이해를 돕고있다.
특히 HTTPS, OAuth 부분은 직접 깊게 찾아보지 않는 이상 잘 정리된 내용을 접하기 힘든데, 쉽고 빠르게 설명해주어서 흥미롭게 읽었다!!
문자열 인코딩
UTF - 8
- 오늘날 가장 많이 사용하는 문자열 인코딩(최소 1바이트, 최대 6바이트, 대부분 4바이트 이내로 처리)
- 아스키 코드와 호환 가능
- JSON은 UTF-8 인코딩만 사용한다.
MySQL에서 UTF-8과 완벽히 호환되는 문자 집합을 쓰고 싶다면 utf8mb4를 써야한다.
날짜와 시간
- 서버 개발자라면 ETCD나 주키퍼를 사용해보는 것도 좋다.
정규표현식
- 특수문자를 찾을 때는 프로그래밍 언어가 한 번, 정규식 표현식이 한 번 문자를 이스케이프해서 해석할 수 있도록 역슬래시 두 개를 사용해야 한다.
- 정규표현식 검사로 인해 처리속도가 늦어질 수 있다. 성능을 생각한다면 parser 라이브러리를 사용하는 것이 좋다.
범용 고유 식별자
- UUID는 충돌 가능성이 낮아서 범용적인 고유 식별자로 사용하기 좋다. 하지만 16바이트나 필요하고 UUID만으로는 정보를 식별하기 어렵다.
해시 함수
해시 함수는 임의의 입력값을 고정된 길이의 해시 값으로 변환하는 함수다.
암호학적으로 안전한 해시 함수는 다음의 조건들을 만족해야한다.
- 해시 값으로 입력 값을 복원하는 방법이 불가능해야 한다.
- 서로 다른 입력값으로 같거나 비슷한 해시 값을 찾는 방법이 불가능해야 한다.
대규모 사용자를 기반으로 한 서비스를 개발할 때는 SHA-2 해시 함수를 사용하는 대신 멀티 코어를 사용할 수 있는 Blake2b 해시 함수를 사용해야 한다. (SHA-256 또는 SHA-512 해시함수는 비밀번호와 같은 민감한 데이터를 안전하게 저장할 수 있으나, 해시 값을 계산하는 비용이 매우 크다)
거의 모든 경우 클라이언트에서 평문으로 된 비밀번호를 보내고, 서버에서 가능한 빨리 해시 값으로 변환한 후 사용하는 게 이상적이다. 평문으로 된 비밀번호가 유출되는 상황은 높은 수준의 암호화 방식을 적용한 HTTPS를 사용하는 것으로 쉽게 방지할 수 있다.
JSON
- JSON은 숫자, 문자, 참 또는 거짓 등 여러 형태 데이터를 키와 값으로 구조화 된 객체에 담아 처리하는 규격이다.
- JSON 메시지가 예측할 수 없는 외부 (사용자 입력, HTML 폼요청 등)로부터 온 데이터인 경우에는 앞서 본 예제 코드와 같이 읽기 전에 키가 존재하는지 검사하는 게 좋다.
- JSON 객체와 배열을 읽을 때는 객체 내부 또는 배열 요소가 정렬됐다는 가정을 하지 않는게 좋다.
- 실무환경에서 JSON 메시지를 만들 때 null을 사용하지 않는 게 좋다. (그 키가 어떤 데이터를 담고있는지 알수 없다)
- JSON 규격의 데이터는 읽기 쉽지만, 텍스트 기반이기 때문에 데이터를 표현하는데 비용이 크다는 단점이 있다.
YAML
- JSON과 비슷하지만 YAML만의 고유한 특징으로 차세대 설정 파일 표준 규격으로 영역을 넓히고 있음
- 주석지원, 앵커, 별칭 기능
- 앵커는 & 으로 시작하는 식별자, 별칭은 * 로 시작하는 식별자
- YAML은 텍스트 기반 데이터 규격으로 읽기 쉬우면서 중괄호나 큰 따옴표를 사용하지 않음. 바이너리 규격에 비해 비효적임
XML
- 웹에서 규격화된 데이터를 효율적으로 주고받기 위해 만든 마크업 언어
- 데이터 직렬화를 위한 규격이 필요하고 반드시 xml을 써야할 이유가 없다면 JSON 또는 바이너리 기반 프로토콜 버퍼를 고려할 것.
- 애플리케이션 설정 파일을 만들기 위한 규격이 필요하면 YAML을 고려할 것
프로토콜 버퍼
- 구글에서 만든 데이터 직렬화 규격
- 바이너리 기반 규격이기 때문에 더 빠르고 효율적으로 데이터 가공, 처리 가능
- 메시지를 받은 소프트웨어도 데이터를 가공하고 보낸 곳과 같은 메시지 규격을 사용해야만 메시지 복원, 읽기 가능
- 인터페이스 코드 : 컴파일러가 스키마를 읽어 만들어낸 결과물. 모든 프로그램은 이 코드를 통해서만 데이터 직렬화/역직렬화 가능
- 프로토콜 버퍼는 메시지만 정의하면 검증, 누락과 관련된 인터페이스를 자동으로 생성하기 때문에 관리의 필요성이 줄어든다. 메시지 크기도 작고 빠름.
Base64
- 바이너리 데이터를 아스키 코드 일부와 일대일로 매칭되는 문자열. 단순 치환하는 인코딩 방식
- 바이너리 데이터를 문자열 기반 데이터로 취급할 수 있어 많은 곳에서 사용됨.
- Base64는 XML, JSON, RESTfull API 처럼 문자열을 기반으로 데이터를 주고 받는 환경에서 바이너리 데이터를 취급할 떄 사용.
- HTTP로 큰 파일을 보내야한다면 HTTP 멀티파트 기능을 살펴보는 게 도움이 된다.
zlib
- zip파일을 압축할 때는 DEFLATE 알고리즘 사용 (INFLATE는 압축 해제)
- 데이터 크기가 가변적인 환경에서는 모든 데이터를 압축하지 않는 게 좋다.
- 웹 서비스의 경우 브라우저가 DEFLATE를 지원하지 않을 수 있음. 일반적으로 Nginx와 같은 서버가 알아서 처리하겠지만 웹소켓, HTTP 서버에서 항상 DEFLATE를 사용하지 않게 설정해두는 것이 좋다.
HTTP
- 서버와 클라이언트가 텍스트, 이미지, 동영상 등의 데이터를 주고 받을 때 사용하는 프로토콜
- 데이터를 안전하게 주고받기 위해 HTTP에 전송계층보안 TLS을 더해 만든 HTTPS를 사용함.
- HTTP는 요청 메시지를 보내기 직전까지 대상 컴퓨터가 연결 가능한지 메시지를 응답할 수 있는 상태인지 알 수 없다.(stateless 프로토콜)
- TCP는 HTTP 보다 빠르지만 연결상태를 직접 관리해야해서 로직이 복잡함. (TCP는 실시간 멀티플레이 게임이나, 금융서비스처럼 메시지 처리시간이 로직 처리보다 오래걸리는 경우에만 사용하는 것이 좋음)
- HTTP요청
- GET : 웹 브라우저가 서버에 웹 페이지를 요청할 때 사용
- POST : 클라이언트에서 서버로 데이터가 포함된 요청을 보낼 때 사용
- DELETE, PUT : DELETE는 데이터 삭제, PUT은 이미 존재하는 데이터의 업데이트 요청을 의미하며 기술적으로는 POST와 큰 차이는 없다.
- URL과 달리 URI는 특정 문서, 영상 등과 같은 자원의 위치를 가리킬 때 사용하는 용어임. (XML에서도 사용)
- 로드밸런스 서비스는 사용자가 접속했을 때 부하가 가장 적은 웹 서버로 연결해주고 동작하지 않는 서버를 발견하면 서버 목록에서 자동으로 제외됨.
- 스티키 세션 : 하나의 브라우저는 하나의 웹 서버에만 연결하게 됨
- 교차 출처 리소스 공유(CORS) : HTTP 서버의 웹 페이지, 이미지 파일이나 API 등을 특정 호스트로 접속한 웹 브라우저만 사용할 수 있게 제현하는 정책
- 동일 출처 정책 : 사전에 정의하지 않은 다른 곳에서 웹 페이지, API와 같은 리소스 요청을 차단하는 방어 장치 (다른 웹사이트에서 이미지, 동영상과 같은 리소스를 무단으로 가져가는 상황을 방지할 수 있음 - 다른 도메인간 리소스 공유가 필요한 경우 있기 때문에 CORS가 생김)
- 웹서버는 요청 처리 외에도 정적 파일 캐시, 로드 밸런스, 압축 및 보안 기능 등 고려해야할 것이 많음
- HTTP 표준에서 정의하는 기능을 바로 사용할 수있는 웹서버 소프트웨어가 있음
- Nginx : 아파치 보다 뛰어난 성능과 가벼운 구조로 인기를 끌고 있다.
- Nginx는 단일 스레드와 이벤트 기반으로 동작하고, 아파치보다 많은 사용자를 처리할 수 있다. (사용 권장)
- 비동기 통신을 지원하는 표준은 HTTP 2.0과 웹소켓이 있음. HTTP 2.0은 하나의 요청에 대한 응답을 병렬로 보내는 데 초점. 웹소켓은 웹상에서 TCP처럼 데이터를 양방향으로 주고받음
RESTful API
- 서버와 클라이언트가 메시지를 주고 받을 때 가장 많이 사용하는 통신 규격
- 요청 주소와 메서드(GET,POST 등) JSON 규격을 이용하여 API를 정의하고 읽기 쉬운 형태임
- 정해진 표준이나 규격이 없기 때문에 커뮤니티나 기업에서 제공하는 관례를 따르자.
- API를 사용하는 입장에서 호환성을 고려할 수있도록 API 버전을 명시하자.
- 대상을 어떻게 할 것인지는 메서드로 결정하자. (POST, PUT, PATCH, DELETE 등) (객체의 행동을 요청 주소에 정의하면 메서드 역할이 축소된다. 좋은 디자인이라고 볼 수 없음)
- GET은 HTTP 표준에 따라 메시지 바디를 사용할 수 없는데, RESTful API에서 요청 주소 경로에 식별자를 넣는 것이 관례이다
- 조회 시 단일 객체, 복수 객체 조회를 구분하지 않고 같은 형식으로 응답 메시지를 구성하면 API를 만드는 입장, 사용하는 입장 모두 유지보수가 쉬워진디. (재사용 가능)
- API를 만들 때는 인수받는 방법 과 응답 규격을 최대한 일관성 있게 만들어 모두 재사용이 쉽게 하자
HTTPS
- 안전하게 메시지를 주고 받기 위해 만든 프로토콜. TLS 프로토콜 기반으로 하는 HTTP
- TLS이 등장하기 전까진 보안 소켓 계층 SSL 을 사용했음. SSL은 많은 취약점으로 더 이상 사용하지 않지만, SSL의 이름을 계속 사용중임
- HTTPS를 사용하면 서버와 클라이언트가 주고 받는 메시지를 암호화한다. 메시지를 암호화 복호화하는 키는 HTTPS로 메시지를 주고 받는 두 컴퓨터만 안다.
- HTTPS는 TLS를 기반으로하여 TLS버전에 따라 사용가능한 암호화 목록과 안정성이 달라진다.
- HTTPS 통신을 하기 위해서는 반드시 인증서가 필요함.
- 클라이언트는 키를 교환하기 전에 이 서버가 신뢰할 수 있는 서버인지 검증하는 작업이 필요한데, 클라이언트는 이 과정에서 서버가 보내는 인증서를 통해 검증함.
- HTTPS를 소프트웨어 프레임워크에서 설정하는 것보다 Nginx나 아파치와 같은 웹서버에서 설정하는것이 안전함.
OAuth 2.0
- OAuth는 데이터를 간편하고 안전하게 주고받기 위해 만들어진 표준.
- ID와 비밀번호 대신 엑세스 토큰 기반으로 사용자 식별. 토큰은 API를 제공하는 리소스 서버만 발급.
- 엑세스 토큰을 요청할 때 가능하면 유효 기간을 짧게 설정하고 자주 갱신하는 게 좋음.
- 엑세스 토큰으로 RESTful API를 사용할 때는 반드시 HTTPS를 사용하는 지 확인해야 보안 위협을 방지할 수 있다.
- JSON Web Token(JWT)을 사용하면 인가 서버를 통해 토큰을 검증하는 대신 인가 정보를 포함해 사용하기 때문에 인가 서버의 부하를 줄일 수 있음.