Java - Comparable (Feat. Effective Java)

이미지
순서를 고려해야 하는 값 class 를 작성한다면 꼭 Comparable Interface 를 구현해서, 해당 인스턴스들을 쉽게 정렬하고, 검색하고, 비교 기능을 제공하는 컬렉션과 어우러지도록 해야 한다. compareTo 메서드에서 필드의 값을 비교할 때 < 와 > 연산자는 쓰지 말자. 대신, 박싱된 기본 타입 클래스가 제공하는 정적 compare 메서드나 Comparator Interface 가 제공하는 비교자 생성 메서드를 사용하자. 먼저, compareTo 를 구현할 때 3가지 규약을 살펴보자. equals 규약과 비슷하다. 1. 대칭성 - 두 객체 참조의 순서를 바꿔 비교해도 얘상한 결과가 나와야 한다. 2. 추이성 - 첫 번째가 두 번째보다 크고 두 번째가 세 번째보다 크면, 첫 번째는 세 번째보다 커야 한다. 3. 반사성 - 크기가 같은 객체들끼리는 어떤 객체와 비교하더라도 항상 같아야 한다. 반사성에서 한 가지 주의할점은 equals 와 compareTo 를 일관되게 구현해야 된다는 점인데, 일관되지 않을 경우, Collection 을 사용할 때 의도와 다르게 작동할 수 있다. Bigdecimal 의 예를 보자. 아래의 javadoc 을 살펴보자. 두 객체의 equals 메서드의 경우 다르다고 나온다. 왜냐면 equals 메서드가 scale 여부까지 비교한다. 하지만, compareTo 는 값이 같은지 비교하기 때문에, 같다고 나온다. 따라서 이와 같이 BigDecimal 을 사용할 때, 주의하지 않으면 의도치 않은 버그가 발생할 수 있다. 더욱이, 아래와 같이 Collection 을 사용할 경우, 더욱이 주의해야 한다. HashSet 은 equals 를 기반으로, TreeSet 의 경우 compareTo 를 기반으로 비교하기 때문에, 이와 같은 결과가 나타난다. https://stackoverflow.com/questions/6787142/bigdecimal-equals-versus-compareto https://docs.or...

Build Docker image NodeJS App (Express) using Dockerfile, .dockerignore, Layer Caching

이미지
 이번 글에서는 Dockerfile 과 .dockerignore 파일을 이용하여 express 프레임워크를 사용한 node JS application 을 build 하고 Dockerfile 작성 시 Image layer 캐싱에 대하여 간단하게 정리해보겠다. 우선, 정말로 간단한 express application 이다.  https://expressjs.com/ko/starter/installing.html user-service-api 라는 directory 를 생성하고, npm 을 통해 express 를 사용할 수 있도록 하였다. index.js 를 아래와 같이 작성했다. 3000 port 로 서빙한다. / path 접근 시 정적으로 name, email 을 형식의 object 를 array 로 내려준다. 이제 Dockerfile 을 작성해보자. node 최신 이미지를 base image 로 사용하고, /app 을 working directory 로 설정한다. 그리고 현재 user-service-api directory 밑에 모든 파일을 /app 밑에 ADD 한다. 그리고 npm 명령어를 통해서 의존성을 설치하고, CMD 를 통해 container 가 run 할 때 index.js 를 실행한다. docker -t user-service-api:latest . 를 통해서 build 한다. npm install 명령어를 하게 되면 package.json 의 dependencies 를 node_modules 밑에 설치하게 된다. 설치된 의존성에 대한 snapshot 이 package-lock.json 파일에 남는다. 따라서 image 를 빌드할 시점에 node_modules 밑에 있는 의존성은 추가될 필요가 없다. 그래서 .dockerignore 파일을 작성하여 제외시키도록 하자. 또한 Dockerfile 및 .git 아래에 있는 해당 레포지토리에 대한 정보들 또한 build 에 필요없는 정보라서 같이 제외시킨다. 이외에도 build 에 필요하지...

Docker -v option, --volumes-from option Using Nginx Image

이미지
아래의 두 가지 예제를 nginx 이미지를 통해서 간단하게 정리해보겠다. 1.  Docker -v 옵션을 통해서 host machine 의 directory 를 컨테이너의 directory 에 mount 시키는 예제 2. Docker --volumes-from 옵션을 통해서 여러 컨테이너가 host machine 의 directory 를 공유하는 예제 환경은 MacOS 이고 Docker 는 이미 설치되었다는 전제이다. 1. 우선 website 라는 directory 를 공유할 경로에 생성하고, 해당 경로안에 index.html 을 간단하게 생성한다. 아래와 같이 정말 간단한 태그 하나 작성한다. 2. docker run -v 옵션을 이용하여 index.html 이 있는 경로 {호스트 머신 경로}:/user/share/nginx/html 을 통해서 컨테이너를 run 한다. 아래의 차이점은 마지막에 :ro 를 붙여줬는데, ro 는 readOnly 을 줄인것이다. 즉, 해당 컨테이너 안에서 해당 경로를 읽기용으로만 사용할 수 있다는 말이고 쓰기는 불가능하다는 말이다. 브라우저에서 8080 포트 접근 시 생성했던 index.html 이 서빙 되는것 확인. docker ps 커맨드로 컨테이너 확인. 다음은, --volumes-from 옵션을 통해서 host machine 의 같은 경로를 공유해보겠다. -p 옵션을 통해서 8081 포트를 사용했다. --volumes-from 옵션에서는 이미 앞서 생성했던 컨테이너 이름을 사용하여 같은 경로를 공유하도록 설정했다. 브라우저에서 8081 포트 접근 시 동일하게 서빙 되는것 확인. docker ps 커맨드를 통해서 2개의 컨테이너가 각각 8080, 8081 포트를 사용하고 있는것을 확인.

Angular - Build Docker Image Using Github Action ( Feat. ECR )

이미지
 얼마전까지 백엔드만 겁나 파서 백엔드 마스터가 되어야지! 라고 생각했다. 근데 요즘들어서 다시 백엔드만 해가지고는 개발 실력 성장에 한계를 느껴서 또 다시 생각이 바뀌고 있다. 그리고 역시 프론트는 재미있구나,,! 몇년 전까지만 해도 React, Angular, Vue 가 삼대장이라 불리는 만큼 강세였는데, 요즘에는 또 춘추전국 시대 같다. Svelte 니 lit-element 니, Stencil 이니 하믄서 처음 보는 것들이 계속 나온다. ㅎㅎ  이제 겨우 React, Angular, Vue 기초만 잠깐 맛보았는데 ㅎㅎ  예전의 3대장을 맛보다가, Angular 에 꽂혔는데, 이유는 바로 TypeScript 다. Angular 는 TypeScript 기반이다.  JS 자체가 워낙 Type 이 약하다 보니, 이게 number 인지 string 인지 참... 곤란한 경험을 한 적도 많다. Interface 설계 시 정확한 Type 계약을 하지 않고, 더욱이 JS 를 잘못 사용하면 지옥이 열리는 것을 경험해서 그런가 더욱이 TypeScript 가 내겐 끌렸다. ㅎㅎ Angular 로 프론트를 개발하고, Spring Boot 로 백엔드를 개발을 요즘하고 있다. 개발하고 테스트하고 운영하려면 배포를 해야되는데, 음.. 어떻게 하는것이 좋을까 고민도 많이 했다. 그러다가, AWSKRUG 에다가 아래와 같이 조언을 구해보았다. 친절한 twkiiim 님이 나의 질문에 너무너무 친절하게 도움을 주셨다. ㅎㅎ 나의 질문에서 알 수 있듯이, 일단 수동으로 ng build --prod 를 통해서 dist 밑에 static files 들을 Spring Boot resources/static 밑에 우겨놓고 Jenkins 에서 Spring Boot 만 jar 로 build 해서 배포하는 반수자동(?) 을 했었는데..  이러한 상황에서 좋은 방법을 찾아야했다. twkiiim 님의 답변을 정리해보자면 아래와 같다. 1. Only CSR...

Java - Exception ( Feat. Effective Java)

이미지
이전 글  에서 Error 와 Exception 에 대해서 정리해보았다. 이번 글에서는 Java 개발자라면 읽어야 한다는 Effective JAVA Third Edition 기준으로 예외 핸들링에 대해서 정리해보겠다. 책에서는 이렇게 말하고있다.  "예외를 제대로 활용한다면 프로그램의 가독성, 신뢰성, 유지보수성이 높아지지만, 잘못 사용하면 반대의 효과만 나타낸다." 그렇다면, 제대로 활용하는 방법에 대해서 책이 알려주는 내용을 정리해보겠다. 예외는 진짜 상황에만 사용하라 책에서는 운이 없다면 언젠가 다음과 같은 코드를 마주할지 모른다고 한다. 나는 운이 없는가 보다.. ㅎㅎ 해당 코드를 보고 무슨 일은 하는 코드인지 알기 어렵다. 전혀 직관적이지 않다. 해당 이유만으로 코드를 이렇게 작성하면 안된다는 이유가 분명하다. 해당 코드를 분석하면, 아주 끔찍한 방식으로 배열을 순회하고 있다. 무한루프를 돌다가 배열의 끝에 도달하여 ArrayIndexOutOfBoundsException 이 발생하면 끝이 난다.  해당 코드를 표준적인 관용구대로 작성했다면 바로 이해할 수 있을것이다.  왜 예외를 써서 끔찍한 코드를 만들어 냈을까?  책에서는 잘못된 추론을 근거로 성능을 높이려 시도할 경우 발생할 수 있다고 한다. 나의 개인적인 생각으로는 아마 해당 코드 작성자가 정확한 배열 순회 메커니즘을 이해하지 못한다거나, 혹은 겉멋(?)이 들어서가 아닐까 의심이 된다. ArrayIndexOutOfBoundsException 을 사용한 코드가 표준 관용구보다 성능이 안좋다. try-catch 블록 안에 코드를 넣으면 JVM 이 적용할 수 있는 최적화가 제한 된다. try catch block 사용은 소량의 데이터 케이스에서 성능 차이는 미비하여, 하드웨어 성능으로 어느정도 커버가 가능하다고 말할 수 있다.  하지만 제일 중요한 점은 가독성을 해치는 것이라고 나는 생각한다. 이는 유지보수에 상당한 어려움을 유발한다. try cat...