-
블로그 이사갑니다!카테고리 없음 2022.08.22 04:14
안녕하세요! 티스토리에서 벨로그로 이전했습니다!ㅎㅎ 아직 모든 글을 다 옮기진 않았지만, 남은 글들은 내용 수정도 하고 앞으로 공부할 내용이랑 합쳐서 올리려고 해요! https://velog.io/@wisdom-one wisdom-one (wisdom) - velog SQL vs NoSQL RDB는 관계형 데이터 모델을 기초로 두고, 모든 데이터를 2차원 테이블 형태로 표현하는 데이터베이스를 말한다.구성된 테이블이 다른 테이블들과 관계를 맺고 모여있는 집합체이며, velog.io 블로그 이사 이유 티스토리는 다양한 커스텀이 가능하다는 장점이 있지만, 저에게는 직접 커스텀을 해야 한다는게 꽤 번거로운 작업으로 느껴졌어요. 요즘 부쩍 정리할 게 많아서.. 최대한 빠르고 간단하게 정리할 수 있는 블로그가 저한..
-
[Effective Java] 아이템35: ordinal 메서드 대신 인스턴스 필드를 사용하라Java 2022.08.15 12:01
✔️ ordinal 메서드란? 대부분의 열거 타입 상수는 하나의 정숫값에 대응된다. 그리고 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 메서드를 제공하는데, 이 메서드가 ordinal 메서드다. ✔️ ordinal의 잘못된 사용 언뜻 보면 굉장히 편리한 메서드처럼 보이고, 이 메서드를 이용하고 싶은 유혹에 빠지기 쉽다. 하지만 아이템 이름에서도 알 수 있듯이 사용하지 않는 것이 좋다. 연주자가 1명인 솔로(solo)부터 10명인 디텍트(dectet)까지 정의한 열거 타입 예제를 보자. public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public in..
-
[Spring Data JPA] 기본 사용법 정리Spring Boot 2022.08.12 03:41
전에 공부했던 Spring Data JPA의 기본 사용법을 정리하고자 한다. ✔️ Dependency build.gradle 파일의 dependencies 부분에 다음을 추가하자. implementation ‘org.springframework.boot:spring-boot-starter-data-jpa’ ✔️ 공통 인터페이스, JpaRepository 적용 Spring Data JPA는 JpaRepository 라는 공통 인터페이스를 제공한다. 이 인터페이스는 기본적인 CRUD와 페이징 등 유용한 기능을 제공해주며, 적용하는 방법도 간단하다. JpaRepository를 상속하는 인터페이스를 구성하면 된다. T: 엔티티 타입 ID: 식별자 타입 public interface EntityRepository..
-
[Effective Java] 아이템34: int 상수 대신 열거 타입을 사용하라Java 2022.08.11 19:31
✔️ 열거 타입 (Enum Type) 📌 열거 패턴의 한계 자바에서 열거 타입을 지원하기 전에는 정수 열거 패턴(int enum pattern)을 사용하곤 했다. public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int GRAPE_NAVEL = 0; public static final int GRAPE_TEMPLE = 1; public static final int GRAPE_BLOOD = 2; 정수 열거 패턴에는 단점이 많다. 타입 안전을 보장할 수 없다. 표현력이 좋지 않다. 정수 열거..
-
[Effective Java] 아이템33: 타입 안전 이종 컨테이너를 고려하라Java 2022.08.10 18:11
✔️ 타입 안전 이종 컨테이너 패턴 제네릭은 컬렉션과 단일원소 컨테이너에 흔히 쓰인다. 이때 매개변수화되는 대상은 원소가 아닌 컨테이너 자신이다. 따라서 하나의 컨테이너에서 매개변수화할 수 있는 타입의 수가 제한된다. 하지만 더 유연한 수단이 필요할 때도 종종 있다. 예를 들어, 데이터베이스의 행은 임의 개수의 열을 가질 수 있는데 모두 열을 타입 안전하게 이용할 수 있다면 멋질 것이다. Q. 하나의 컨테이너에서 매개변수화할 수 있는 타입 개수를 제한하지 않고 사용할 수 있는 방법은 없을까? 해법은 컨테이너 대신 키를 매개변수화한 다음, 컨테이너에 값을 넣거나 뺄 때 매개변수화한 키를 함께 제공하는 것이다. 이러한 설계 방식을 타입 안전 이종 컨테이너 패턴(type safe heterogeneous co..
-
[Effective Java] 아이템32: 제네릭과 가변인수를 함께 쓸 때는 신중하라Java 2022.08.09 19:31
✔️ 가변인수 메서드와 제네릭 가변인수(varargs, variable arguments) 메서드와 제네릭은 자바 5 때 함께 추가되었으니 서로 잘 어우러지리라 기대하겠지만, 그렇지 않다. 가변인수 메서드를 호출하면 가변인수를 담기 위한 배열이 자동으로 하나 만들어지며, 이 배열은 클라이언트에게 노출된다. 그 결과 varargs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 알기 어려운 컴파일 경고가 발생한다. 제네릭과 varargs를 혼용하면 타입 안전성이 깨지게 된다. 따라서 제네릭 varargs 배열 매개변수에 값을 저장하는 것은 안전하지 않다. 그렇다면 제네릭 배열을 프로그래머가 직접 생성하는 건 허용하지 않으면서 제네릭 varargs 매개변수를 받는 메서드를 선언할 수 있게 한 이유는 무엇일까..
-
[Effective Java] 아이템31: 한정적 와일드카드를 사용해 API 유연성을 높이라Java 2022.08.06 09:34
아이템 28에서 이야기했듯 매개변수화 타입은 불공변(invariant)이다. 즉 서로 다른 타입 Type1과 Type2가 있을 때 List은 List의 하위 타입도 상위 타입도 아니다. 하지만 때론 불공변 방식보다 유연한 무언가가 필요하다. 유연성을 높이기 위해, 원소의 생산자(producer)나 소비자(consumer)용 입력 매개변수에 와일드카드 타입을 사용하자. ✔️ PECS 팩스(PECS) 란, producer-extends, consumer-super 를 의미한다. 매개변수화 타입 T가 생산자라면
-
[Effective Java] 아이템30: 이왕이면 제네릭 메서드로 만들라Java 2022.08.06 09:33
클래스와 마찬가지로 메서드도 제네릭으로 만들 수 있다. 📌 단순한 제네릭 메서드 두 집합의 합집합을 반환하는 메서드를 예시로 보자. 로 타입 사용 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); result.addAll(s2); return result; } 위의 코드는 컴파일은 되지만 경고가 두 개 발생한다. 경고를 없애기 위해서는, 메서드를 타입 안전하게 만들어야 한다. 세 집합의 원소 타입을 타입 매개변수로 명시하고, 메서드 안에서도 이 타입 매개변수만 사용하게 수정하자! 제네릭 메서드 public static Set union(Set s1, Set s2) { Set result = new HashSet(s1); res..
-
[Effective Java] 아이템29: 이왕이면 제네릭 타입으로 만들라Java 2022.08.06 09:32
아이템7에서 다룬 스택 코드는 원래 제네릭 타입이어야 마땅하다. 다음과 같이 타입 매개변수 E를 추가하고, Object를 적절한 타입 매개변수로 바꾸어준다. public class Stack { private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { // 컴파일 오류. 실체화 불가 타입으로는 배열을 만들 수 없다. elements = new E[DEFAULT_INITIAL_CAPACITY]; } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (si..
-
[Effective Java] 아이템28: 배열보다는 리스트를 사용하라Java 2022.07.30 02:29
✔️ 배열 vs 제네릭 타입 1. 배열은 공변(covariant)인 반면, 제네릭은 불공변(invariant)이다. Sub가 Super의 하위 타입이라면 배열 Sub[]는 배열 Super[]의 하위 타입이 되지만, List은 List의 하위 타입도 아니고 상위 타입도 아니다. 2. 배열은 실체화(reify)된다. 배열은 런타임에도 원소의 타입을 확인한다. 즉, 런타임에 예외가 발생할 수 있다. 반면, 제네릭은 타입 정보가 런타임에는 소거된다. 원소 타입을 컴파일타임에만 검사하며 런타임에는 알 수조차 없다. 💡 위와 같은 차이로 인해, 배열과 제네릭은 잘 어우러지지 못한다. 예를 들어, 배열은 제네릭 타입(new List[]), 매개변수화 타입(new List[]), 타입 매개변수(new E[])로 사용할..
-
[Effective Java] 아이템27: 비검사 경고를 제거하라Java 2022.07.29 19:08
✔️ 할 수 있는 한 모든 비검사 경고를 제거하라. 모두 제거한다면 그 코드는 타입 안전성이 보장된다. 즉, 런타임에 ClassCastException이 발생할 일이 없다. ✔️ 경고를 제거할 수는 없지만 타입 안전하다고 확신할 수 있다면 @SuppressWarning("unchecked") 애너테이션을 달아 경고를 숨기자. 안전하다고 검증된 비검사 경고를 숨기지 않고 그대로 두면, 진짜 문제를 알리는 새로운 경고가 나와도 눈치채지 못할 수 있다. 단, 경고를 무시해도 안전한 이유를 항상 주석으로 남겨야 한다. ✔️ @SuppressWarning 애너테이션은 항상 가능한 한 좁은 범위에 적용하자. @SuppressWarning 애너테이션은 개별 지역변수 선언부터 클래스 전체까지 어떤 선언에도 달 수 있다..
-
[Effective Java] 아이템26: 로 타입(raw type)은 사용하지 말라Java 2022.07.29 16:29
✔️ 제네릭 타입과 로 타입 클래스와 인터페이스 선언에 타입 매개변수가 쓰이면 제네릭 클래스 혹은 제네릭 인터페이스라고 하며, 두 가지를 통틀어 제네릭 타입(generic type)이라고 한다. 로 타입(raw type)이란 타입 매개변수가 없는 제네릭 타입을 말한다. 예를 들어, List의 로 타입은 List다. 로 타입은 타입 선언에서 제네릭 타입 정보를 전부 지워진 것처럼 동작하는데, 제네릭이 도래하기 전 코드와 호환되도록 하기 위한 궁여지책이라 할 수 있다. ✔️ 컬렉션의 로 타입 컬렉션 로 타입을 사용할 경우, 엉뚱한 타입을 넣어도 오류 없이 컴파일되고 실행될 수 있다. 이 경우, 형변환 시 ClassCastException을 던지게 된다. 📍 컬렉션의 로 타입 → 좋지 않은 예! private..
-
[Effective Java] 아이템25: 톱레벨 클래스는 한 파일에 하나만 담으라Java 2022.07.23 00:06
소스 파일 하나에 여러 개의 톱레벨 클래스를 선언하더라도 자바 컴파일러는 불평하지 않는다. 하지만 아무런 득이 없을 뿐더러 심각한 위험을 감수해야 한다. 한 클래스를 여러 가지로 정의할 수 있으며, 그 중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하느냐에 따라 달라지기 때문이다. 💡 예제 Main.java public class Main { public static void main(String[] args) { System.out.println(Utensil.NAME + Dessert.NAME); } } Utensil.java // 두 클래스가 한 파일(Utensil.java)에 정의되었다. - 따라 하지 말 것! class Utensil { static final String NAME = "..
-
[Effective Java] 아이템24: 멤버 클래스는 되도록 static으로 만들라Java 2022.07.22 23:42
✔️ 중첩 클래스(nested class)란? 중첩 클래스는 '다른 클래스 안에 정의된 클래스'를 말한다. 자신을 감싼 바깥 클래스에서만 사용되어야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 💡 종류 (4가지) 정적 멤버 클래스 비정적 멤버 클래스 익명 클래스 지역 클래스 첫 번째를 제외한 나머지(비정적 멤버 클래스, 익명 클래스, 지역 클래스)는 모두 내부 클래스(inner class)에 해당한다. ✔️ 정적 멤버 클래스 다른 클래스 안에 선언되고, 바깥 클래스의 private 멤버에도 접근할 수 있다. 흔히 바깥 클래스와 함께 쓰일 때만 유용한 public 도우미 클래스로 쓰인다. private 정적 멤버 클래스는 흔히 바깥 클래스가 표현하는 객체의 한 부분, 즉 구성요소로 나타..
-
[Effective Java] 아이템23: 태그 달린 클래스보다는 클래스 계층구조를 활용하라Java 2022.07.18 12:10
✔️ 태그 달린 클래스 📍 예시 class Figure { enum Shape { RECTANGLE, CIRCLE }; // 태그 필드 - 현재 모양을 나타낸다. final Shape shape; // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다. double length; double width; // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다. double radius; // 원용 생성자 Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // 사각형용 생성자 Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = len..
-
[Effective Java] 아이템22: 인터페이스는 타입을 정의하는 용도로만 사용하라Java 2022.07.16 01:10
인터페이스는 자신을 구현할 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 인터페이스는 오직 이 용도로만 사용해야 한다. ✔️ 상수 인터페이스 - 잘못된 사용 예시 인터페이스를 타입을 정의하는 용도로 사용하지 않은 대표적인 예로 상수 인터페이스를 들 수 있다. 상수 인터페이스란, 메서드 없이 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. 📍 상수 인터페이스 안티패턴 // 상수 인터페이스 안티패턴 - 사용금지! public interface PhysicalConstants { // 아보가드로 수 (1/몰) static final double AVOGADROS_NUMBER = 6.022_140_857e23; // 볼츠만 상수 (J/K) static final double..
-
[Effective Java] 아이템21: 인터페이스는 구현하는 쪽을 생각해 설계하라Java 2022.07.14 15:47
자바 8 전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 방법이 없었으나,자바 8 부터는 디폴트 메서드가 소개되면서 기존 인터페이스에 메서드를 추가할 수 있게 되었다. 그러나 이렇게 추가된 디폴트 메서드가 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. ✔️ 디폴트 메서드 추가 시 주의사항 1️⃣ 디폴트 메서드는 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으킬 수 있다. 흔한 일은 아니지만, 일어나지 않으리라는 보장도 없다. 2️⃣ 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 한다. 추가하려는 디폴트 메서드가 기존 구현체들과 충돌하지 않을지 심사숙고해야 한다. 또한, 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 ..
-
[Effective Java] 아이템20: 추상 클래스보다는 인터페이스를 우선하라Java 2022.07.09 09:02
✔️ 인터페이스 vs 추상 클래스 자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스 2가지다. 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만을 지원하므로, 추상 클래스 방식은 새로운 타입을 정의하는 데 커다란 제약을 안겨준다. 반면 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 또한 기존 클래스에도 손쉽게 새로운 인터페이스를 구현해넣을 수 있다. (인터페이스가 요구하는 메서드를 추가하고, 클래스 선언에 implements 구문을 추가하기만 하면..
-
[Effective Java] 아이템19: 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라Java 2022.07.09 09:01
✔️ 상속을 고려한 문서화와 설계 문서화 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지 문서로 남겨야 한다. 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다. * 재정의 가능 메서드: public과 protected 메서드 중 final이 아닌 모든 메서드. @implSpec 태그 메서드 주석에 붙여주면 자바도 도구가 "Implementation Requirements"로 시작하는, 메서드의 내부 동작 방식을 설명하는 절을 생성해준다. 이 태그를 활성화하려면 명령줄 매개변수로 -tag "implSpec:a:Implementation Requirents:"를 지정해주면 된다. protected 메서드 및 필드 클래스의 내부 동작 과정 중간에 끼어들 수 있는 ..
-
[따라하며 배우는 도커와 CI환경] 9. 복잡한 어플을 실제로 배포해보기(테스트 & 배포 부분)Docker 2022.07.05 00:24
이제 소스코드를 테스트한 후 테스트 성공 시, AWS를 통해 배포하는 부분을 추가할 것이다. 애플리케이션을 배포하는 과정은 다음과 같다. Travis CI에서 바로 AWS Elastic Beanstalk으로 전달하지 않고, Docker Hub에 빌드된 이미지를 보관함으로써 이미지를 한 번만 빌드하도록 한다. ✔️ Github 에 소스코드 업로드 1️⃣ github에서 repository 생성하기 2️⃣ 로컬 git 저장소 만들기 $ git init 3️⃣ .gitignore 파일 추가 node_modules mysql_data 4️⃣ 커밋하기 $ git add . $ git commit -m "first commit" 5️⃣ remote 저장소에 push 하기 처음에는 remote 저장소를 추가한 후, ..
-
[Effective Java] 아이템18: 상속보다는 컴포지션을 사용하라Java 2022.07.02 04:45
이번 아이템에서 논하는 상속은 클래스가 다른 클래스를 확장하는 구현 상속을 말한다. 클래스가 인터페이스를 구현하거나 인터페이스가 다른 인터페이스를 확장하는 인터페이스 상속과는 무관하다. ✔️ 상속의 위험성 메서드 호출과 달리 상속은 캡슐화를 깨뜨린다. 상위 클래스가 릴리스 때 내부 구현이 달라지면, 그 여파로 하위 클래스가 오동작할 수 있다. 메서드를 재정의하는 대신 새로운 메서드를 추가하더라도, 문제가 발생할 수 있다. 상위 클래스의 새 메서드와 시그니처가 같고 반환 타입이 다르다면, 컴파일 오류가 발생한다. 시그니처와 반환 타입 모두 같을 경우, 상위 클래스의 메서드를 재정의한 것이 된다. 새로 추가한 메서드가 상위 클래스의 메서드가 요구하는 규약을 만족하지 못할 가능성이 크다. ✔️ 컴포지션 (Co..
-
[Effective Java] 아이템17: 변경 가능성을 최소화하라Java 2022.06.29 16:00
✔️ 자바 플랫폼 라이브러리의 불변 클래스 String 기본 타입의 박싱된 클래스들 ex) Integer, Long, Double BigInteger BigDecimal→ ✔️ 불변 클래스 만들기 위한 규칙 (5가지) 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다. 클래스를 확장할 수 없도록 한다. → 2가지 방법이 있다. (클래스 상속 방지하는 방법 참고) 모든 필드를 final로 선언한다. 모든 필드를 private으로 선언한다. 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 생성자, 접근자, readObject 메서드 모두에서 방어적 복사를 수행하라. ✔️ 불변 클래스 예시: 복소수 클래스 // 불변 복소수 클래스 public final class Complex { priv..
-
[Effective Java] 아이템16: public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라Java 2022.06.24 23:55
class Point { public double x; public double y; } 위의 클래스는 데이터 필드를 직접 접근할 수 있어, 캡슐화의 이점을 제공하지 못 한다. API를 수정하지 않고는 내부 표현을 바꿀 수 없고, 불변식을 보장할 수 없으며, 외부에서 필드에 접근할 때 부수 작업을 수행할 수도 없다. class Point { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public double getY() { return y; } public void setX(double x) { this.x = x..
-
[따라하며 배우는 도커와 CI환경] 8. 복잡한 어플을 실제로 배포해보기(개발 환경 부분)Docker 2022.06.22 21:01
지난 포스트에서는 리액트 컨테이너 하나만 실행하는 싱글 컨테이너 애플리케이션을 만들어보았다. 이번엔 프론트엔드 뿐만 아니라 백엔드 서버, 데이터베이스까지 사용하도록 다음과 같은 풀스택(멀티 컨테이너) 애플리케이션을 만들 것이다. ✔️ Multi Container 애플리케이션을 위한 설계 Multi Container 애플리케이션을 설계하는 방법 2가지를 알아보자. 1️⃣ Nginx의 Proxy를 이용한 설계 장점 Request를 보낼 때 URL 부분을 host 이름이 바뀌어도 변경시켜주지 않아도 된다. 포트가 바뀌어도 변경하지 않아도 된다. axios.get('/api/values') 단점 nginx 설정, 전체 설계가 다소 복잡하다. 2️⃣ Nginx는 정적파일을 제공만 해주는 설계 장점 설계가 다소 간..
-
[Effective Java] 아이템15: 클래스와 멤버의 접근 권한을 최소화하라Java 2022.06.22 11:57
잘 설계된 컴포넌트는 모든 내부 구현을 완벽히 숨겨, 구현과 API를 깔끔히 분리한다. 오직 API를 통해서만 다른 컴포넌트와 소통하며 서로의 내부 동작 방식에는 전혀 개의치 않는다. 이러한 정보 은닉 혹은 캡슐화라고 하는 개념은 소프트웨어 설계의 근간이 되는 원리다. ✔️ 정보 은닉의 장점 시스템 개발 속도를 높인다. 여러 컴포넌트를 병렬로 개발할 수 있기 때문이다. 시스템 관리 비용을 낮춘다. 각 컴포넌트를 더 빨리 파악하여 디버깅할 수 있고, 다른 컴포넌트로 교체하는 부담도 적기 때문이다. 정보 은닉 자체가 성능을 높여주지는 않지만, 성능 최적화에 도움을 준다. 완성된 시스템을 프로파일링해 최적화할 컴포넌트를 정한 다음, 다른 컴포넌트에 영향을 주지 않고 해당 컴포넌트만 최적화할 수 있기 때문이다...
-
[Effective Java] 아이템14:Comparable을 구현할지 고려하라Java 2022.06.20 13:20
이번에는 Comparable 인터페이스의 유일한 메서드인 compareTo에 대하여 알아보자. compareTo 는 두 가지만 빼면 Object의 equals와 같다. 첫 번째, compareTo 는 단순 동치성 비교에 더해 순서까지 비교할 수 있다. 두 번째, compareTo 는 제네릭하다. Comparable을 구현했다는 것은 그 클래스의 인스턴스들에는 자연저인 순서(natural order)가 있음을 뜻한다. 그래서 Comparable을 구현한 객체들의 배열은 손쉽게 정렬할 수 있다. Arrays.sort(a); 또한, 검색, 극단값 계산, 자동 정렬되는 컬렉션 관리도 쉽게 할 수 있다. String이 Comparable을 구현하였기 때문에 다음 예제는 명령줄 인수들을 (중복 제거하고) 알파벳순으..
-
[Effective Java] 아이템13: clone 재정의는 주의해서 진행하라Java 2022.06.16 00:37
Cloneable은 복제해도 되는 클래스임을 명시하는 용도의 '믹스인 인터페이스(mixin interface, 아이템 20)'지만, 의도한 목적을 제대로 이루지 못했다. 가장 큰 문제는 clone 메서드가 선언된 곳이 Cloneable이 아닌 Object이고, 그 마저도 protected라는 것이다. 그래서 Cloneable을 구현하는 것만으로는 외부 객체에서 clone 메서드를 호출할 수 없다. 이러한 여러 문제점에도 불구하고 Cloneable 방식은 널리 쓰이고 있어 잘 알아두는 것이 좋다. 이번 아이템에서는 clone 메서드를 잘 동작하게끔 해주는 구현 방법과 언제 그렇게 해야 하는지, 그리고 가능한 다른 선택지에 관해 논의할 것이다. ✔️ Cloneable 인터페이스 먼저 메서드 하나 없는 Clo..
-
[따라하며 배우는 도커와 CI환경] 7. 간단한 어플을 실제로 배포해보기(테스트 & 배포 부분)Docker 2022.06.13 16:09
이번에는 지난 포스트에서 생성한 애플리케이션을 배포해보자! 다음의 순서대로 애플리케이션을 테스트 및 배포할 것이다. Github에 소스 코드 업로드 Travis CI 연동 AWS Elastic Beanstalk 환경 구성 배포 ✔️ Github에 소스 코드 업로드 먼저 Github에 애플리케이션의 소스 코드를 올려야 한다. 1️⃣ Repository 생성 깃허브에서 새로운 repository를 생성한다. 나는 docker-react-app 이라는 이름으로 repository를 생성하였다. 강의에서는 public은 무료, private 유료라고 했다. 그러나 나는 private으로 설정해도 별도의 요금은 부과되지 않았다. 2️⃣ 로컬 git 저장소 만들기 $ npm init 우리는 처음에 npx creat..
-
[Effective Java] 아이템12: toString을 항상 재정의하라Java 2022.06.10 21:56
Object의 기본 toString 메서드가 작성한 클래스의 적합한 문자열을 반환하는 경우는 거의 없다. 이 메서드는 단순히 클래스_이름@16진수로_표시한_해시코드 를 반환할 뿐이다. toString의 일반 규약에 따르면 '간결하면서 사람이 읽기 쉬운 형태의 유익한 정보'를 반환해야 한다. 또한, toString의 규약은 '모든 하위 클래스에서 이 메서드를 재정의하라'고 한다. equals와 hashCode 규약만큼 대단히 중요하진 않지만, toString 을 잘 구현한 클래스는 사용하기 훨씬 즐겁고, 디버깅하기 쉽다. 그렇다면 이제부터 toString을 재정의할 때 유의할 점을 알아보자. ✔️ 실전에서 toString은 그 객체가 가진 주요 정보 모두를 반환하는 게 좋다. 만약 객체가 거대하거나, 객체..
-
9. 값 타입 (2)JPA 2022.06.10 14:06
5. 값 타입 컬렉션 (Collection Value Type) 값 타입을 하나 이상 저장하려면 컬렉션에 저장하면 된다. 이때 2가지 어노테이션이 필요하다. @ElementCollection: 값 타입 컬렉션을 사용하는 속성에 표시한다. @CollectionTable: 컬렉션을 위한 추가 테이블을 매핑한다. 생략 가능하며, 기본값으로 {엔티티 이름}_{컬렉션 속성 이름} 테이블과 매핑한다. 위의 다이어그램에서 favoriteFoods는 기본값 타입 컬렉션이고, addressHistory는 임베디드 타입 컬렉션이다. 관계형 데이터베이스 테이블의 컬럼 안에 컬렉션을 포함할 수 없기 때문에, 두 가지 값 타입 컬렉션 모두 별도의 테이블을 추가하고, 추가한 테이블을 매핑해야 한다. favoriteFoods 와 ..
-
9. 값 타입 (1)JPA 2022.06.09 12:05
JPA의 데이터 타입을 크게 분류하면 엔티티 타입과 값 타입으로 나눌 수 있다. 엔티티 타입은 @Entity로 정의하는 객체이고, 값 타입은 int, Integer, String 처럼 단순한 값으로 사용하는 자바 기본 타입이나 객체를 말한다. 값 타입은 기본값 타입(basic value type), 임베디드 타입(embedded type), 컬렉션 값 타입(collection value type) 3가지로 나눌 수 있다. 값 타입은 식별자가 없고 추적할 수 없는 정보라고 볼 수 있다. 지금부터 값 타입에 대하여 알아보자. 1. 기본값 타입 (Basic Value Type) 예제 코드) @Entity public class Member { @Id @GeneratedValue private Long id; ..
-
8. 프록시와 연관관계 관리JPA 2022.06.07 11:01
1. 프록시 엔티티를 조회할 때 연관된 엔티티들이 항상 사용되는 것은 아니다. 사용하지 않는 연관된 엔티티까지 데이터베이스에서 함께 조회해두는 것이 효율적이지 않다. JPA는 이런 문제를 해결하기 위해, 엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법인 지연 로딩을 제공한다.지연 로딩 기능을 사용하려면 실제 엔티티 객체 데신에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요하고, 이것을 프록시 객체라 한다. 📌 참고! JPA의 지연 로딩 JPA 표준 명세는 지연 로딩의 구현 방법을 JPA 구현체에 위임했다. 이후의 내용은 하이버네이트 구현체에 대한 내용이다. 1.1. 프록시 기초 JPA에서 식별자로 엔티티 하나를 조회할 때는 EntityManager.find() 를 사용한다. 이 메소..
-
[Effective Java] 아이템11: equals를 재정의하려거든 hashCode도 재정의하라Java 2022.06.05 00:11
equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 해당 클래스의 인스턴스를 HashMap이나 HashSet 과 같은 컬렉션의 원소로 사용할 때 문제를 일으킬 것이다. ✔️ hashCode 에 관한 규약 다음은 Object 명세에서 발췌한 규약이다. equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메서드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 한다. 단 애플리케이션을 다시 실행한다면 이 값은 달라져도 상관없다. equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 한다. equals(Object)..
-
[Effective Java] 아이템10: equals는 일반 규약을 지켜 재정의하라Java 2022.06.04 16:53
equals 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있다. 따라서 재정의가 필요하지 않은 경우에는 재정의하지 않는 것이 최선의 선택이다. ✔️ equals를 재정의하지 않는 것이 좋은 상황 1️⃣ 각 인스턴스가 본질적으로 고유한 경우 값을 표현하는 게 아니라 동작하는 개체를 표현하는 클래스. Thread 와 같은 클래스가 좋은 예시다. 2️⃣ 인스턴스의 '논리적 동치성'을 검사할 일이 없는 경우 3️⃣ 상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는 경우 4️⃣ 클래스가 private 이거나 package-private 이고, equals 메서드를 호출할 일이 없는 경우 참고❗️ equals가 실수로라도 호출되는 걸 막고 싶다면 다음처럼 구현하자. @Override ..
-
[따라하며 배우는 도커와 CI환경] 6. 간단한 어플을 실제로 배포해보기(개발 환경 부분)Docker 2022.05.30 14:56
이번 시간부터는 간단한 애플리케이션를 배포하면서 도커를 배워보자. ✔️ 리액트 환경 세팅 리액트를 사용하려면 node를 반드시 설치해야 한다. $ npx create-react-app ./ node 설치 후, 위의 명령어를 통해 리액트 앱을 위한 환경을 세팅한다. 명령어가 실행되면 다음과 같은 파일들이 생성된다. ✔️ 도커로 리액트 앱 실행 이제 도커를 통해 리액트 앱을 실행해보자. 도커로 리액트 앱을 실행하기 위해서는 다음과 같은 과정을 수행해야 한다. 1️⃣ 도커 파일 생성 및 빌드 다음과 같이 도커 파일을 생성하자. Dockerfile.dev FROM node:alpine WORKDIR /usr/src/app COPY package.json ./ RUN npm install COPY ./ ./ CM..
-
[Effective Java] 아이템9: try-finally 보다는 try-with-resources 를 사용하라Java 2022.05.30 01:19
자바에는 InputStream, OutputStream, java.sql.Connection과 같이 close 메서드를 호출해 직접 닫아줘야 하는 자원이 많다. 그런데 자원 닫기는 클라이언트가 놓치기 쉬워 성능 문제로 이어질 수 있다. 그렇다면 자원이 제대로 닫히도록 보장할 수 있는 방법은 무엇일까? 전통적으로 자원이 제대로 닫힘을 보장하는 수단으로 try-finally가 쓰였다. ✔️ try-finally static String firstLineOfFile(String path) throws IOException { BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br..
-
[Effective Java] 아이템8: finalizer와 cleaner 사용을 피하라Java 2022.05.30 00:39
자바는 두 가지 객체 소멸자를 제공한다. 1️⃣ 첫 번째는 finalizer 다. finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로 불필요하다. 2️⃣ 두 번째는 cleaner 다. finalizer는 오동작, 낮은 성능, 이식성 문제가 있었기 때문에, 자바 9에서 deprecated API로 지정되었고 finalizer의 대안으로 cleaner가 소개되었다. cleaner는 finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고, 성능이 느리고, 일반적으로 불필요하다. 그렇다면 지금부터 finalizer와 cleaner의 문제점을 알아보자. ✔️ 불확실성 (수행 미보장) finalizer와 cleaner는 즉시 수행된다는 보장이 없다. 객체에 접근할 수 없게 된 후 f..
-
[따라하며 배우는 도커와 CI환경] 5. Docker ComposeDocker 2022.05.23 17:11
📌 Docker Compose 란, 다중 컨테이너 도커 애플리케이션을 정의하고 실행하기 위한 도구 이다. 정의만 보아서는 어떤 도구인지 감이 잘 오지 않을 것이다. Node.js와 Redis를 이용한 애플리케이션을 만들어보면서 Docker Compose에 대하여 알아보자. 지난 강의에서 Node.js를 사용하여 간단한 애플리케이션을 만들어보았다. 그렇다면 Redis란 무엇일까? ✔️ Redis 란? Redis(REmote Dictionary Server)는 메모리 기반의 키-값 구조 데이터 관리 시스템으로, 모든 데이터를 메모리에 저장하고 빠르게 조회할 수 있는 비 관계형 데이터베이스(NoSql)이다. Redis를 사용하는 이유 메모리에 저장하기 때문에 Mysql 같은 데이터베이스에 데이터를 저장하고 불..
-
[따라하며 배우는 도커와 CI환경] 4. 도커를 이용한 간단한 Node.js 어플 만들기Docker 2022.05.22 15:33
이제부터 매우 간단한 Nodejs 앱을 도커 환경에서 실행해보자. ✔️ 아주 간단한 Node.js 앱 만들기 도커 실습을 위한 것이기 때문에 앱은 최대한 간단하게 만들어보자! Nodejs 프로젝트를 생성해주고 다음과 같이 파일을 추가한다. package.json { "name": "nodejs-docker-app", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "start": "node server.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "express": "^..
-
[Effective Java] 아이템7: 다 쓴 객체 참조를 해제하라Java 2022.05.21 03:21
가비지 컬렉션 언어에서는 메모리 누수를 찾기가 아주 까다롭다. 가비지 컬렉터는 객체 참조 하나를 살려두면 그 객체 뿐만 아니라 그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체...)를 회수해가지 못한다. 그래서 단 몇 개의 객체가 매우 많은 객체를 회수되지 못하게 할 수 있고, 잠재적으로 성능에 악영향을 줄 수 있다. 스택을 구현하는 다음의 코드를 보자. public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = new Object[DEFAULT_INITIAL_CAP..
-
[Effective Java] 아이템6: 불필요한 객체 생성을 피하라Java 2022.05.21 02:16
똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. ✔️ String 인스턴스 String s = new String("bikini"); // 1, 따라하지 말 것! String s = "bikini"; // 2 1번 코드의 경우, 실행될 때마다 String 인스턴스를 새로 만든다. 생성자에 넘겨진 "bikini" 자체가 이 생성자가 만들어내는 String과 기능적으로 완전히 똑같으므로, 완전히 쓸데없는 행위이다. 2번 코드는 1번 코드를 개선한 것이다. 새로운 인스턴스를 매번 만드는 대신에 하나의 String 인스턴스를 사용한다. 이 방식은 같은 가상 머신 안에서 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 사용함이 보장된다. ✔️ 불변 클래스의 정적 팩..
-
[Effective Java] 아이템5: 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라Java 2022.05.21 00:24
많은 클래스가 하나 이상의 자원에 의존한다. 이런 클래스는 정적 유틸리티 클래스로 구현하거나 싱글턴으로 구현할 수 있는데, 둘 다 그리 좋지 않은 방법이다. 다음의 예시를 보자. // 정적 유틸리티 public calss SpellChecker { private static final Lexicon dictionary = ...; private SpellChecker() {} // 객체 생성 방지 public static boolean isValid(String word) {...} public static List suggestions(String typo) {...} } // 싱글턴 public calss SpellChecker { private static final Lexicon dictionar..
-
[따라하며 배우는 도커와 CI환경] 3. 직접 도커 이미지 만들기Docker 2022.05.17 01:23
✔️ 도커 이미지 생성 순서 도커 이미지를 생성하는 과정은 다음과 같다. 1. 도커 파일을 작성한다. 2. 도커 파일에 입력된 값들을 클라이언트에 전달한다. 3. 도커 서버에서 도커 클라이언트에 전달된 모든 중요한 작업들을 수행한다. 4. 이미지를 생성한다. 이제부터 도커 이미지 생성 과정을 더 자세하게 알아보자. ✔️ Dockerfile 만들기 Docker file이란? - 도커 이미지를 만들기 위한 설정 파일 - 컨테이너가 어떻게 행동해야 하는지에 대한 설정들을 정의하는 곳이다. 베이스 이미지(Base Image)란? - 도커 이미지의 기반이 되는 부분 - 참고) 도커 이미지는 베이스 이미지와 레이어들로 구성되어 있다. 도커 파일을 만드는 순서 1. 베이스 이미지를 명시한다. (파일 스냅샷에 해당) ..
-
[따라하며 배우는 도커와 CI환경] 2. 기본적인 도커 클라이언트 명령어Docker 2022.05.16 16:41
기본적인 도커 명령어를 알아보자! ✔️ 이미지 내부 파일 시스템 구조 보기 이미지 내부 파일은 어떻게 확인할 수 있는지 알아보자. $ docker run ls 위의 명령어를 통해 내부 파일 목록을 확인할 수 있다. 각각의 의미를 살펴보자. docker: 도커 클라이언트 언급 run: 컨테이너 생성 및 실행 이미지 이름: 이 컨테이너를 위한 이미지 ls: 원래 이미지가 가진 시작 명령어 대신 이 커맨드가 실행됨 기본적으로 docker run 을 실행하면 이미지가 가지고있는 시작 명령어가 실행된다. 그러나 이미지 이름 뒤에 ls 와 같이 커맨드를 추가하여 docker run 를 실행하면, 시작 명령어를 무시하고 커맨드를 실행하게 된다. alpine 이라는 이미지의 내부 파일 구조를 확인해보자. ex) $ d..
-
[Effective Java] 아이템4: 인스턴스화를 막으려거든 private 생성자를 사용하라Java 2022.05.14 02:17
이따금 단순히 정적 메서드와 정적 필드만을 담은 클래스를 만들고 싶을 때가 있을 것이다. 이렇게 정적 멤버만 담은 클래스는 인스턴스로 만들어 쓰려고 설계한 것이 아니다. 따라서 이러한 클래스의 인스턴스화를 막아야하는데, 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 생성자를 만들어준다는 문제가 있다. 그렇다면 어떻게 클래스의 인스턴스화를 막을 수 있을까? 그 방법은 private 생성자를 추가하는 것이다. 다음의 코드를 참고하자. public class UtilityClass { // 기본 생성자가 만들어지는 것을 막는다 (인스턴스화 방지용) private UtilityClass() { throw new AssertionError(); } ... // 나머지 코드는 생략 } 이렇게 구현하면, 명시적 ..
-
[Effective Java] 아이템3: private 생성자나 열거 타입으로 싱글턴임을 보증하라Java 2022.05.14 00:58
싱글턴(Singleton) 이란? 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. 싱글턴의 전형적인 예로는 함수와 같은 무상태(stateless) 객체나 설계상 유일해야 하는 시스템 컴포넌트를 들 수 있다. 싱글턴을 만드는 방식은 3가지가 있다. public static final 필드 방식 (private 생성자 사용) 정적 팩터리 방식 (private 생성자 사용) 열거 타입 방식 이제 각각의 방식을 알아보자. 1. public static final 필드 방식 public calss Elvis { public static final Elvis INSTANCE = new Elvis(); private Elvis() { ... } public void leaveTheBuilding() { ....
-
[Effective Java] 아이템2: 생성자에 매개변수가 많다면 빌더를 고려하자Java 2022.05.13 23:39
정적 팩터리와 생성자에는 똑같은 제약 사항이 하나 있다. 바로 선택적 매개변수가 많을 때 적절히 대응하기 어렵다는 점이다. 선택 매개변수가 많을 때 취할 수 있는 대안을 알아보자. 선택 매개변수가 많을 때 활용할 수 있는 대안 1. 점층적 생성자 패턴(Telescoping Constructor Pattern) 먼저 점층적 생성자 패턴이 있다. 이 패턴은 필수 매개변수만 생성자부터, 필수 매개변수와 선택 매개변수 1개를 받는 생성자, 선택 매개변수 2개까지 받는 생성자, ... 형태로 선택 매개변수를 전부 받는 생성자까지 늘려가는 방식이다. 점층적 생성자 패턴은 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기가 어렵다는 문제가 있다. 코드를 읽을 때, 각 값의 의미가 헷갈리고, 매개변수가 몇 개..
-
[Effective Java] 아이템1: 생성자 대신 정적 팩터리 메서드를 고려하라Java 2022.05.13 15:17
✔️ 정적 팩터리 메서드(Static Factory Method) 란? 그 클래스의 인스턴스를 반환하는 단순한 정적 메서드 참고) 정적 팩터리 메서드는 디자인 패턴에서의 팩터리 메서드 (Factory Method)와 다르다. 디자인 패턴 중 이와 일치하는 패턴은 없다. ✔️ 장점 1. 이름을 가질 수 있다. 생성자에 넘기는 매개변수와 생성자 자체만으로는 반환될 객체의 특성을 제대로 설명하지 못한다. 반면, 정적 팩터리 메서드는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다. BigInteger(int, int, Random) vs BigInteger.probablePrime '값이 소수인 BigInteger를 반환한다'는 의미를 어느 쪽이 더 잘 설명하고 있는지는 누구나 알 것이다. 2. ..
-
[따라하며 배우는 도커와 CI환경] 1. 도커 기본Docker 2022.05.10 12:08
✔️ 도커(Docker) 란 무엇인가? 도커는 컨테이너를 사용하여 응용프로그램을 더 쉽게 만들고 배포하고 실행할 수 있도록 설계된 도구 이며 컨테이너 기반의 오픈소스 가상화 플랫폼이자 생태계 이다. 도커를 이해하기 위해서는 먼저 컨테이너의 개념을 알고 있어야 한다. 컨테이너의 개념을 먼저 알아보고, 도커 이미지에 대하여 알아보자. 컨테이너 컨테이너는 코드와 모든 종속성을 패키지화하여 응용 프로그램이 한 컴퓨팅 환경에서 다른 컴퓨팅 환경으로 빠르고 안정적으로 실행되도록 하는 소프트웨어의 표준 단위 이다. 즉 컨테이너는 도커에서의 실행 단위로써, 격리된 공간에서 프로세스가 동작하는 기술을 의미한다. 도커 이미지 도커 이미지는 코드, 런타임, 시스템 도구, 시스템 라이브러리 및 설정과 같은 응용 프로그램을 실..
-
7. 고급 매핑JPA 2022.05.03 15:50
1. 상속 관계 매핑 관계형 데이터베이스에는 상속이라는 개념이 없다. 대신 객체의 상속 개념과 가장 유사한 슈퍼타입 서브타입 관계라는 모델링 기법을 사용할 수 있다. 슈퍼타입 서브타입 논리 모델을 실제 물리 모델인 테이블로 구현하기 위한 방법은 3가지가 있다. 1. 각각의 테이블로 변환: JPA에서는 조인 전략이라 한다. 2. 통합 테이블로 변환: JPA에서는 단일 테이블 전략이라 한다. 3. 서브타입 테이블로 변환: JPA에서는 구현 클래스마다 테이블 전략이라 한다. 1.1. 조인 전략 (Joined Strategy) 엔티티 각각을 모두 테이블로 만들고, 자식 테이블이 부모 테이블의 기본 키를 받아서 기본 키와 외래 키로 사용하는 전략이다. 예제 코드 @Entity @Inheritance(strateg..