2020년 7월 12일 일요일

젠킨스 자동배포 연습해보기

까먹지말자. 메모!


CI/CD?

  • 애플리케이션 개발 단계를 자동화하여 새로운 코드 통합으로 인한 문제를 해결할 수 있다.
  • 빌드, 테스트, 배포 프로세스에 대해 자동화와 모니터링이 가능하다.

CI란? (Continuous Integration)

  • 지속적 통합
  • 개발한 소스를 특정 시점에 통합(빌드, 테스트 등)하는 것이 아닌, 지속적으로 통합을 진행한다. (자동화 프로세스!)
  • 어플리케이션을 변경할 때 자동으로 빌드 및 테스트 가능
  • 유명한 CI 툴은 Jenkins 가 있다.

CD란? (Continuous Deploy or Delivery)

  • 지속적 배포
  • 변경사항을 저장소에서 테스트서버나 운영서버에 자동으로 반영한다.

Travis VS Jenkins

Travis
  • 장점

    • 전용 서버가 필요하지 않다. (자체 호스팅)
    • github과 연동이 편하다.
  • 단점

    • 제한된 옵션 제공
    • 느린 속도
    • private 유료

Jenkins
  • 장점

    • 많은 플러그인 제공
  • 단점

    • 별도의 서버가 필요함
    • 젠킨스에 대한 관리 필요

  • 간단히 혼자 해보기는 travis가 재미있을 것 같지만, 학습과 실습이 목적이니 Jenkins를 선택한다!

  • 일단 로컬로 도커를 이용해서 연습해보자.

  • 학습목적이니 일단 내장서버를 이용해서 실행해보자

    Once the spring-boot plugin has been applied to your project it will automatically attempt to rewrite archives to make them executable using the bootRepackage task. You should configure your project to build a jar or war (as appropriate) in the usual way.

    // build.gradle 에 다음 내용을 추가해준다.
    // plugin, 생성할 war명 과 실행할 메인 클래스 명을 넣는다.
    apply plugin: 'war'
    
    
    ...
    
    
    war {
        baseName = 'NoN'
        version =  '0.0.1-SNAPSHOT'
        manifest{
            attributes(
                    'Main-Class': 'com.edu.EduApplication'
            )
        }
    }
    


설치과정 메모


  • 도커에 jenkins 설치하기

    • 명령어로 설치할 수 도 있지만, Docker가 제공해주는 관리도구(Kitematic)로 쉽게 설치할 수 있다.


    • 도커 설치 중..


    • 설치 후 다음 명령어로 어떤 포트로 실행되고있는 지 볼 수 있다.


    • 물론 Kitematic에서도 확인 가능


    • 중간에 패스워드 입력화면은 Kitematic 로그 자세히 보면 패스워드가 있다. 그걸 입력하자.

      • 못봤다면... 도커에서 비밀번호에서 확인해보자

        docker exec -it jenkins /bin/bash
        
        
        cat /var/jenkins_home/secrets/initialAdminPassword

    • localhost:32819 로 접속 (잘 모를때는 추천 플러그인을 설치해보자)


    • 플러그인들이 모두 설치실패한다?


    • 젠킨스 버전 문제라고한다. 높은 버전으로 변경하자.

      docker exec -it -u 0 jenkins bash
      
      
      wget http://updates.jenkins-ci.org/download/war/2.235.1/jenkins.war
      
      
      mv ./jenkins.war /usr/share/jenkins/
      
      
      chown jenkins:jenkins /usr/share/jenkins/jenkins.war
      
      
      도커 젠킨스 재시작

    • 새로운 Item 클릭 


    • 소스관리 탭에서 자신의 프로젝트 git 주소와 Credentials - Add 자신의 git 정보를 입력한다.


    • build 유발 - GitHub hook trigger for GITScm polling 체크


    • 빌드 후 배포를 하기위해 다음 작업을 추가한다. Build - Add build step - Execute Shell - 다음 쉘 추가


  • 현재 젠킨스를 도커에 띄웠으므로 접속주소가 localhost 이다. github에서 요청을 보내야한다. 외부에서 로컬에 접속가능하게 하기 위해 ngrok 을 사용한다.

    • 설치 후 다음 명령어로 사용 가능

      ngrok http 32819
      
      
      // 세션만료 없애기 (기본 8시간), AuthToken 은 ngrok 홈페이지에서 로그인 후 받을 수있다.
      ngrok http 32819 --authtoken={AuthToken}
      
    • 생성된 주소를 사용하면 된다!!


  • Github에 이벤트가 있을 때 젠킨스로 요청을 보내야하므로 Webhooks를 설정해준다.

    • Gibhub - Settings - Webhooks - Add Webhook
    • 젠킨스 주소 뒤에 /github-webhook/ 를 붙여준다. (ngrok에서 생성된 주소 사용하면 됨)

  • README.md 파일에 build 상태 보여주기

    • 젠킨스 플러그인에서 Embeddable Build Status Plugin 다운로드
      • Item - Embeddable Build Status - MarkDown 부분 복사 - github README.md 파일에 입력

      • 다음과 같이 README.md 파일에 표시되는 것을 확인할 수 있다! (빌드상태가 계속 반영된다. 다만, ngrok을 사용하고 있기때문에 주소가 자꾸 바뀐다. 별도의 젠킨스 서버가 필요할 듯하다.)

  • 이제 저장소에 푸시가 있을 때 젠킨스가 자동으로 빌드하는 것을 볼 수 있다. 이를 활용해서 서버에 설치하고 배포작업을 상세화, 단계화하여 적용하면 될 것 같다. (실무에선 어떤 프로세스로 사용할까? ㅠ)


참고

2020년 7월 8일 수요일

학교에서 알려주지 않는 17가지 실무기술 책 메모

학교에서 알려주지 않는 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)을 사용하면 인가 서버를 통해 토큰을 검증하는 대신 인가 정보를 포함해 사용하기 때문에 인가 서버의 부하를 줄일 수 있음.

2020년 5월 8일 금요일

일 잘하는 사람은 단순하게 합니다 책 메모

일 잘하는 사람은 단순하게 합니다

쉬어가는 책으로 출근 중 지하철에서 간단하게 읽은 책이다. 
책에서는 기획, 보고서, 언어소통, 관계 의 네 가지 영역에서 일 잘하는 방법에 대해 설명하고 있다. 
현재 내가 하고있는 것과는 관련이 없을 수 있지만 분명 도움이 되는 내용이었고, 나중에 활용할 수 있는 내용도 많았다. 
특히 무엇인가를 보고해야할 때나 설명할 때 횡설수설하는 경우가 많았는데, 이 책의 내용을 읽고 내가 했던 말들을 되돌아보는 계기가 되었다.


  • 생각하는 대로 살지 않으면, 사는 대로 생각하게 된디.

  • 기획자는 다음의 세 가지에 꼭 대답할 수 있어야한다.

    • 목표는 무엇인가?
    • 목표를 가로막는 진짜 문제는 무엇인가?
    • 문제를 해결하고 ,원하는 미래를 달성하기 위해 할 수 있는 실현 가능한 최적의 행동은 무엇인가?
  • 단순하게 일하는 사람은 화려한 현황보다는 무엇을, 왜 해야 하는지를 분명히 보여준다.

    • 탄탄한 기획안도 회사 방향과 맞지 않으면 무용지물이다.
  • 일 잘하는 사람은 상대방이 궁금해 하는 내용과 자기가 이야기하고 싶은 내용을 가능한 한 짧게 말하는데 선수입니다.

  • 무엇을 하려고 하는지, 보고서의 핵심은 무엇인지, 무슨 얘기를 하는지, 30초 안에 깔끔히게 설명할 수 있는 습관을 길러야 한다.

  • 기획이란 어떤 대상에 대해 그 대상의 변화를 가져올 목적을 확인하고, 그 목적을 성취하는 데에 가장 적합한 행동을 설계하는 것을 의미한다.

    • 모든 기획은 '왜'부터 시작해야한다.
  • SWOP이나 4P 등의 프레임워크는 고민 과정에서 활용하되 직접적인 언급은 지양하는 것이 좋다.

  • 덩어리를 묶을 때 각 항목끼리는 독립적이어야하고, 항목을 합치면 전체가 되야한다.

  • 좁쌀 서 말 굴리는 것보다 호박 한 개 굴리는 게 낫다

    • 굵직한 기획을 진행해야한다
  • 정보의 홍수 속에서 단순하게 글을 쓰려면 '왜 쓰는지' 처음부터 알고 써야 덜 고생스럽다.

  • 하고 싶은 얘기가 아니라, 듣고 싶어할 얘기를 쓰자

  • 작성자의 설명을 들어야 이해되는 보고서는 실패다.

    • 전체 요약 박스와 소제목별 요약 한 줄은 아무리 심오한 보고서라도 직관적으로 이해할 수 있게 한다.
  • 메시지를 위한 글쓰기에서는 하나의 핵심 키워드를 찾는 일이 관건이다.

    • 스토리들은 모두 핵심 키워드를 향하고 있어야 한다.
  • 모든 사람에게 똑같은 의미를 가진 단어는 없다.

  • '중간보고'는 서로의 의도와 방향을 조절하는 기술이다.

    • 중간보고는 필요하다. 그래야 오해가 있더라도 다시 방향을 맞출 수 있다.
  • 지시할 때 가능한 한 정확하게 설명해주자. 지시하는 사람이 5분 더 쓰면, 실행하는 사람은 하루 이상의 시간을 절약할 수 있다.

  • 두괄식으로 시작해서 30초안에 하고 싶은 얘기를 모두 끝내야한다.

  • A를 물어보면 정확히 A를 대답하자. 비슷한 대답말고.

  • 회사의 공식적인 커뮤니케이션에서는 '매우, 곧, 상당히, 최선을 다해, 심각하게, 신중히' 유의 언어는 쓰지 않는 게 좋다.

    • 오해만 불러일으킬 수 있다.
  • 숫자에 해석을 함께 곁들이면 단순하고 강력한 메시지가 된다.

  • 직장에서 최고의 평판 관리는 '상사를 승진시키는 사람'이다.

  • 생각을 끄고 켜는 연습은 내가 현재에 살도록 도와준다.

2020년 4월 19일 일요일

예외처리 핸들러 테스트

예외처리 핸들러 테스트

  • 토이프로젝트의 예외처리를 어떻게 할까 고민하다 검색과 백기선님 웹MVC강의에 예외처리 부분을 복습하였다. (회사소스에 존재하는 ExceptionHandler에는 로그만 남기도록 되어있었다.)
  • MVC에서 요청을 처리하다가 에러가 발생하거나 자바에서 지원하는 예외가 발생했을 때 정의한 핸들러로 그 예외를 어떻게 처리할지?, 어떤응답을 만들지를 정의할 수 있다.
      @ExceptionHandler
      public String RuntimeExceptionHandler(RuntimeException e, Model model){
        model.addAttribute("message", "runtime error");
        return "error"
      }
    
    • 예외처리를 핸들러를 전역 컨트롤러에 선언할 수 있다. (모든 컨트롤러에 적용됨)
      // 모든 컨트롤러 적용
      @ControllerAdvice("com.edu.controller")
      public class CommonExceptionHandler {
        ...
      }
    
    
      // 다수의 특정 컨트롤러 지정 가능
      @ControllerAdvice(assignableTypes = {EventController.class, EventApi.class})
      public class CommonExceptionHandler {
        ...
      }
    
    
      // 패키지 지정 가능
      @ControllerAdvice("com.edu.controller")
      public class CommonExceptionHandler {
        ...
      }
    
  • @RestControllerAdvice 는 @ResponseBody 가 붙은거 라고 생각하면될듯!

내가 테스트해본 것

아쉬운 점 : 그냥 잘못된 값을 던지고 해당 메서드에서 exception이 발생하였을 때 처리하는 테스트를 하였는데, 테스트 시 예외를 강제로 줘서 테스트를 하고 싶었는데 못하였음 ㅠㅠ(의미가 없으려나??)
  • CommonExceptionHandler.java
@ControllerAdvice
public class CommonExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(CommonExceptionHandler.class);

    public static final String DEFAULT_ERROR_VIEW = "exception";

    @ExceptionHandler(value = RuntimeException.class)
    public ModelAndView defaultRuntimeErrorHandler(HttpServletRequest req, RuntimeException e) {
        logger.debug("RuntimeException: " + e);
        logger.debug("url: " + req.getRequestURL());

        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);

        return mav;

    }
}
  • LectureControllerTest.java
public class LectureControllerTest extends BaseControllerTest {

/* 전역 Exception Handler 설정
CommonExceptionHandler 에서 처리하기 위한 셋팅: standaloneSetup, setControllerAdvice 지정

지정 파라미터를 다른 값으로 변경하면 CommonExceptionHandler에 안들어온다.
하지만 아예 이 부분을 제거해도 CommonExceptionHandler에 옴.
 */
    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders
                .standaloneSetup(lectureController)
                .setControllerAdvice(new CommonExceptionHandler())
                .build();
    }

  ...


    @Test
    @Description("Exception 발생 테스트")
    public void exceptionTest() throws Exception{

        // Given
        String userId = "admin2";

        // When (실패함. 어떻게 사용하는 지 더 찾아볼 것)
        //when(lectureController.checkedLecture(anyString(),anyString(),anyString())).thenThrow(new Exception("테스트입니다."));

        // Then
        mockMvc.perform(post("/lecture/checkedLecture")
                .param("userId", userId)

        ).andDo(print())
                .andExpect(status().is2xxSuccessful())
                .andExpect(view().name("exception"))
                .andExpect(model().attributeExists("exception"))
        ;

    }
}

Error, Exception 참고

  • Error : 개발자가 미리 예측하여 처리할 수 없는 경우 (JVM 자원 부족 등의 문제?)
    • 관례적으로 Error에 대해서는 Custom Class를 만들지 않는다
  • Exception : 개발자가 구현한 로직에서 발생하기 때문에 미리 예측하여 처리할 수 있음
    • RuntimeException
      • 처리를 강제하지 않음(동작하다 exception 발생)
      • 하위 Exception: NullPoint, IllegalArgument, IndexOutOfBound, System)
      • Custom UnChecked Exception 을 만들 경우 RuntimeException 클래스를 상속하여 만든다.
    • CheckedException
      • 반드시 예외처리를 해야함(처리안하면 컴파일 오류)
      • RuntimeException을 제외한 모든 클래스
      • Custom checked Exception을 만들 경우 Exception 클래스를 상속하여 만든다.
  • 예외처리 팁
    • 아무것도안하는 에러처리는 피하기 : catch 영역에 아무 동작도 안하면 예외 발생 시 추적하기 힘들어짐. 처리를 못한다면 로그라도 남길 것
    • exception.printStackTrace()는 쓰지 말 것 : 에러가 발생한 원인에 대한 Stack Trace를 추적하여 개발자에게 디버깅할 수 있는 힌트를 제공해주지만, 운영 시 성능을 생각한다면 지양해야한다. java reflection을 사용하여 trace를 추적하기 때문에 오버헤드가 발생한다고한다.
    • 반복문 내에서 Checked Exception에 대한 처리는 지양할 것 : 반복문 내에서 Checked Exception에 대한 예외처리 구문이 들어가게 되면 성능은 2배 3배 떨어지게 된다.

2020년 3월 8일 일요일

클린 코드 책 메모

클린코드

취업 전 도서관에서 클린코드를 빌려서 읽어본적이 있었다. 물론 2장 중간에 포기하고 반납을 했었다.
그때는 무슨 소리를 하는 지 이 책은 왜이리 어려운 책인가 하고 바로 반납을 해버렸지만....
이번엔 3일만에 읽어버렸다. (물론 저자가 직접 리팩토링하면서 설명하는 부분은 좀 빠르게 읽었다)
작년에 회사 업무시간 전 차곡차곡 읽을 생각으로 산 이후로 방치되었었는데, 이번주에는 조금 시간이 넉넉하여 업무시간을 활용하였다.
지금 읽어보니 정말 쉽게 설명되어있고, 기본적으로 코드를 짤 때 필요한 내용이어서 너무 재미있게 읽었다.
왜 우아한형제 기술블로그에서 이 책의 제목이 자주 언급되는 지에 대해서 조금은 알 것 같았다.
반성도 많이하게 되고, 머리에 꽂히는 것도 많은 책이다.
꼭 다시 한번 더 읽으리라~~~ (입사,이직 전 한번 읽으면 엄청 좋을 듯!!)
이 책을 모두 정리한다는 것은 어려울 것 같다. 모든 내용이 중요해보였고, 나에게 필요해 보인다.
밑의 내용은 그냥 읽으면서 체크한 내용을 메모한 것이다.

1장 깨끗한 코드

  • 자신이 짠 쓰레기 코드를 보고 나중에 정리하겠다고 다짐하지만, 나중은 결코 오지 않는다.
  • 나쁜 코드의 위험을 이해하지 못하는 관리자 말을 그대로 따르는 행동은 전문가답지 못하다.

2장 의미있는 이름

  • 의도가 분명하게 이름을 지으라

3장 함수

  • 작게 만들어라!
  • 함수는 한 가지를 해야한다.
  • 인수를 줄이자
  • 부수효과를 일으키지 마라!
  • 반복하지 마라
  • 함수를 작게 만든담녀 간혹 return, break, continue를 여러 차례 사용해도 괜찮다. 오히로 때로는 단일 입/출구 규칙보다 의도를 표현하기 쉬워진다. 반면 goto문은 큰 함수에서만 의미가 있으므로, 작은 함수에서는 피해야만 한다.
  • 소프트웨어를 짜는 행위는 여느 글짓기와 비슷하다. 먼서 생각을 기록한 후 읽기 좋게 다듬는다. 초안은 대개 서투르고 어수선하므로 원하는 대로 읽힐 때까지 말을 다듬고 문장을 고치고 문단을 정리한다.

4장 주석

  • 코드로 의도를 표현하라 : 코드로 대다수의 의도를 표현할 수 있다. 많은 경우 주석으로 달려는 설명을 함수로 만들어 표현해도 충분하다.

5장 형식 맞추기

  • 오늘 구현한 기능이 다음 버전에서 바뀔 확률은 아주 높다. 그런데 오늘 구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다. 오랜 시간이 지나 원래 코드의 흔적을 더 이상 찾아보기 어려울 정도로 코드가 바뀌어도 맨 처음 잡아놓은 구현 스타일과 가독성 수준은 유지보수 용이성과 확장설에 계속 영향을 미친다.
  • 변수는 사용하는 위치에 최대한 가까이 선언한다.

6장 객체와 자료구조

  • 디미터 법칙 : 모듈은 자신이 조작하는 개체의 속사정을 몰라야 한다. 객체는 조회 함수로 내부 구조를 공개하면 안된다.
  • 시스템을 구현할 떼, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적절하다. 다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료구조와 절차적인 코드가 더 적합하다. 우수한 소프트웨어 개발자는 편견없이 이 사실을 이해해 직면한 문제에 최적인 해결책을 선택한다.

7장 오류 처리

  • null을 반환하지 마라 : null을 반환하는 코드는 일거리를 늘릴 뿐만 아니라 호출자에게 문제를 떠넘긴다. 누구 하나라도 null 확인을 빼먹는다면 애플리케이션이 통제 불능에 빠질지도 모르다.

8장 경계

  • 외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자. 새로운 클래스로 경계를 감싸거나 아니면 ADAPTER 패턴을 사용해 우리가 원하는 인터페이스를 패키지가 제공하는 인터페이스로 변환하자. 어느 방법이든 코드 가독성이 높아지며, 경계 인터페이스를 사용하는 일관성도 높아지며, 외부 패키지가 변했을 때 변경할 코드도 줄어든다.

9장 단위 테스트

  • 테스트는 유연성, 유지보수성, 재사용성을 제공한다.
  • F.I.R.S.T : 꺠끗한 테스트는 다음 다섯가지 규칙을 따른다.
    • Fast 빠르게 : 테스트는 빨리 돌아야한다.
    • Independent 독립적으로 : 각 테스트는 서로 의존하면 안된다.
    • Repeatable 반복가능하게 : 테스트는 어떤 환경에서도 반복 가능해야한다.
    • Self-Validating 자가검증하는 : 테스트는 성공아니면 실패라고 결과를 내야한다. (성공여부루를 알려고 로그를 읽게 만들어선 안된다.)
    • Timely 적시에 : 테스트는 적시에 작성해야한다.

10장 클래스

  • 클래스 체계 : 표준 자바 관례에 따르면, 가장 먼저 변수 목록이 나온다. static public 상수가 있다면 맨 처음에 나온다. 다음으로 정적 private 변수가 나오며, 이어서 비공개 인스턴스 변수가 나온다. 변수 목록 다음에는 공개 함수가 나온다. 비공개 함수는 자신을 호출하는 공개 함수 직후에 넣는다. 즉, 추상화 단계가 순차적으로 내려간다. 그래서 프로그래램은 신문기사처럼 읽힌다.
  • 단일 책임 원칙(SRP) : 클래스는 책임, 즉 변경할 이유가 하나여야 한다.
  • 규모가 어느 수준에 이르는 시스템은 논리가 많고도 복잡합하다. 이런 복잡성을 다루려면 체계적인 정리가 필수다. 그래야 변경을 가할 때 직접 영향이 미치는 컴포넌트만 이해해도 충분하다.
  • 큰 클래스 몇 개가 아니라 작은 클래스 여럿으로 이뤄진 시스템이 더 바람직하다.
  • 시스템의 결합도를 낮추면 유연성과 재사용성도 더 높아진다. 결합도가 낮다는 소리는 각 시스템 요소가 다른 요소로부터 그리고 변경으로부터 잘 격리되어 있다는 의미다.

11장 시스템

  • 의존성 주입 : 사용과 제작을 분리하는 강력한 메커니즘. 의존성 주입은 제어의 역전 기법을 의존성관리에 적용한 메커니즘이다. 제어 역전에서는 한 객체가 맡은 보조 책임을 새로운 객체에게 전적으로 떠넘긴다. 새로운 객체는 넘겨받은 책임만 맡으므로 딘일 첵임 원칙을 지키게 된다. 의존성 관리 맥락에서는 객체는 의존성 자체를 인스턴스로 만드는 책임을 지지 않는다. 대신에 이런 책임을 다른 '전담' 메커니즘에 넘겨야만 한다. 그렇게 함으로 써 제어를 역전한다.
  • AOP에서 관점이라는 모듈 구성 개념은 "특정 관심사를 지원하려면 시스템에서 특정 지점들이 동작하는 방식을 일관성 있게 바꿔야한다" 라고 명시한다. 프로그래머는 영속석으로 저장할 객체와 속성을 선언한 후 영속성 책임을 영속성 프레임워크에 위임한다. 그러면 AOP 프레임워크는 대상 코드에 영향을 미치지 않는 상태로 동작방식을 변경한다.
  • 프로그래머는 설정파일이나 API를 사용해 피룻적인 애플리케이션 기반구조를 구현한다. 여기에는 영속성, 트랜잭션, 보안, 캐시, 장애조치 등과 같은 횡단관심사도 포함된다.
  • 시스템을 설계하든 개별 모듈을 설계하든, 실제로는 돌아가는 가장 단순한 수단을 사용해야 한다는 사실을 명심하자.

12장 창발성

  • 단순한 설계 규칙 네 가지
    • 모든 테스트를 실행한다.
    • 중복을 없앤디.
    • 프로그래머 의도를 표현한다.
    • 클래스와 메서드 수를 최소로 줄인다.

13장 동시성

  • 동시성 코드가 일으키는 문제로부터 시스템을 방어하는 원칙과 기술
    • 단일 책임 원칙 : 동시성 코드는 다른 코드와 분리하라
    • 자료범위를 제한하라 : 자료를 캡슐화하라. 공유 자료를 최대한 줄여라.
    • 자료 사본을 사용하라
    • 스레드는 가능한 독립적으로 구현하라 : 독자적인 스레드로, 가능하면 다른 프로세서에서, 돌려도 괜찮도록 자료를 독립적인 단위로 분할하라.
    • 자바에서 synchronized 키워드를 사용하면 락을 설정한다. 락은 스레드를 지연시키고 부하를 가중시킨다. 그로므로 synchronized 문을 남발하는 코드를 바람하지 않다. 반면, 임계영역은 반드시 보호해야한다. : 동기화하는 부분을 최대한 작게 만들어라
    • 스레드 코드 테스트하기 : 문제를 노출하는 테스트 케이스를 작성하라. 프로그램 설정과 시스템 설정과 부하를 바꿔가며 자주 돌려리. 테스트가 실패하면 원인을 추적하라. 다시 돌렸더니 통과하더라는 이유로 그냥 넘어가면 절대 안된다.

14장 점진적인 개선

  • 깨끗한 코드를 짜려면 먼저 지저분한 코드를 짠 뒤에 정리해야 한다.

15장 JUnit 들여다보기

16장 SerialDate 리팩터링

17장 냄새와 휴리스틱

  • 저자가 코드를 짜면서 사용하는 기교와 휴리스틱을 나열해놓았다. 꼭 다시 한번 볼 것!!
  • 주석
    • 부적절한 정보
    • 쓸모 없는 주석
    • 중복된 주석
    • 성의 없는 주석
    • 주석 처리 된 코드
  • 환경
    • 여러 단계로 빌드해야 한다
    • 여러 단계로 테스트해야 한다
  • 함수
    • 너무 많은 인수
    • 출력 인수
    • 플래그 인수
    • 죽은 함수
  • 일반
    • 힌 소스 파일에 여러 언어를 사용한다
    • 당연한 동작을 구현하지 않는다
    • 경계를 올바로 처리하지 않는다
    • 안전 절차 무시
    • 중복
    • 추상화 수준이 올바르지 못하다
    • 기초 클래스가 파생클래스에 의존한다
    • 과도한 정보
    • 죽은 코드
    • 수직 분리
    • 일관성 부족
    • 잡동사니
    • 인위적 결합
    • 기능 욕심
    • 선택자 인수
    • 모호한 의도
    • 잘못 지운 책임
    • 부적절한 static 함수
    • 서술적 변수
    • 알고리즘을 이해하라
    • If/Else 혹은 Switch/Case 문보다 다형성을 사용하라
    • 표준 표기법을 따르라
    • 매직 숫자는 명명된 상수로 교체하라
    • 정확하라
    • 관례보다 구조를 사용해라
    • 조건을 캡슐화하라
    • 부정 조건을 피하라
    • 함수는 한 가지만 해야한다
    • 일관성을 유지하라
    • 경계조건을 캡슐화하라
    • 설정 정보는 최상위 단계에 둬라
    • 추이적 탐색을 피하라
  • 자바
    • 긴 Import 목록을 피하고 와일드 카드를 사용하라
    • 상수는 상속하지 않는다
    • 상수 대신 Enum
  • 이름
    • 서술적인 이름을 사용하라
    • 적절한 추상화 수준에서 일므을 선택하라
    • 가능하다면 표준 명명법을 사용하라
    • 긴 범위는 긴 이름을 사용하라
    • 인코딩을 피하라
    • 이름으로 부수 효과를 설명하라
  • 테스트
    • 불충분한 테스트
    • 커버리지 도구를 사용하라
    • 사소한 테스트를 건너뛰지 마라
    • 무시한 테스트는 모호함을 뜻한다
    • 경계조건을 테스트하라
    • 버그 주변은 철저히 테스트하라
    • 실패 패턴을 살펴라
    • 테스트 커버리지 패턴을 살펴라
    • 테스트는 빨라야 한다