🏠 인터페이스는 타입을 정의하는 용도로만 사용하라. 인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 즉 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에게 얘기하는 것이다. 인터페이스는 오직 이 용도로만 사용해야한다. 💊 잘못된 예시 ( 상수 인터페이스 ) 상수 인터페이스 안티패턴은 인터페이스를 잘못 사용한 예시다. 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아닌, 내부 구현에 해당한다. 때문에 상수 인터페이스를 구현하는 것은 해당 내부 구현을 클래스의 API로 노출하는 행위이다. 이는 혼란을 줄 수 있을 뿐만 아니라, 클라이언트 코드가 내부 구현에 해당하는 상수들에 종속될 수 있다. 이로서 더는 쓰지 않게 되더라고,..
🏠 equals 는 일반 규약을 지켜 재정의하라. equlas 메서드는 재정의하기 쉬워 보이지만 곳곳에 함정이 도사리고 있어 자칫하면 끔찍한 결과를 초래한다. 만약 다음과 같은 상황 중 하나에 해당한다면 재정의하지 않는 편이 낫다. 각 인스턴스가 본질적으로 고유하다. 인스턴스의 논리적 동치성을 검사할 필요가 없다. 상위 클래스에서 재정의한 equals 가 하위 클래스에도 딱 맞는다. 클래스가 private 이거나 package-private 이고 equals 를 호출할 일이 없다. 다음과 같은 상황에 해당되지 않고,객체 식별성이 아닌 논리적 동치성을 확인해야 한다면 equals 를 재정의할 필요가 있다. 주로 값 클래스들이 해당된다. Integer, String 처럼 객체가 같은지가 아닌 값이 같은지를 ..
🏠 상속보다는 컴포지션을 사용하라 상속은 코드를 재사용하는 강력한 수단이지만, 항상 최선인 것은 아니다. 이번 챕터에서 말하는 상속이란 클래스가 인터페이스를 구현하거나, 인터페이스가 다른 인터페이스를 확장하는 상속은 제외한다. 챕터에서 소개하는 상속은 클래스가 다른 클래스를 확장하는 구현상속을 가르킨다. 일반적으로 패키지 경계를 넘어 상속하는 일은 위험하다고 한다. 💧 상속은 캡슐화를 깨뜨린다. 즉 상위 클래스가 어떻게 구현되냐에 따라 하위 클래스의 동작에 이상이 생길 수 있다는 뜻이다. 캡슐화란 객체의 상태와 행동을 하나의 단위로 묶고, 외부에는 상태를 감추고 행동만을 노출시키는 것이다. 하지만 상속은 하위 클래스가 상위 클래스의 구현에 의존하게 되어, 상위 클래스의 구현이 변경되면 하위 클래스도 영향..
🏠 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 어플리케이션 오늘날 많은 어플리케이션은 계산 중심에서 데이터 중심적으로 변했다. 더이상 CPU 성능이 아닌 데이터의 양, 복잡도, 변화 속도에 어플리케이션이 영향을 받는다는 뜻이다. 때문에 이제부터 개발자는 어플리케이션 개발자 뿐만 아니라 설계자여야 한다. 엔지니어링 관점에서 소프트웨어 시스템에서 중요하게 여기는 3가지를 자세하게 살펴보자 신뢰성 확장성 유지보수성 🔥 신뢰성 하드웨어나 소프트웨어 결험, 인적 오류같은 역경에 직면하더라도 시스템은 지속적으로 올바르게 동작해야한다. 즉, 무엇가 잘못되더라도 지속적으로 올바르게 동작함을 신뢰성의 의미로 이해할 수 있다. 소프트웨어 관점에서 잘못될 수 있는 일을 결함이라고 부르며, 결함을 예측하고 대처할 수 있..
🏠 Comparable 을 구현할지 고려하라 이번 아이템은 Comparable 인터페이스의 메서드인 compareTo 에 대해서 알아보는 챕터이다. compareTo 메서드는 Object 의 equals 메서드와 달리 순서까지 비교할 수 있으며, 제네릭하다. 때문에 Comparable 을 구현했다는 것은 해당 클래스의 인스턴스들에는 자연적인 순서가 있음을 뜻한다. 사실상 자바 플랫폼 라이브러리의 모든 값 클래스와 열거형 타입은 Comparable 을 구현했다. 알파벳, 숫자, 연대 같이 순서가 명확한 값 클래스를 작성한다면 반드시 Comparable 인터페이스를 구현하자. 🔥 Comparable 의 compareTo 메서드의 규약 Comparable 인터페이스를 구현할 때 따라야하는 compareTo 규..
🏠 불필요한 객체 생성을 피하라 같은 기능의 객체를 매번 생성하기 보다는, 객체 하나를 재사용하는 편이 나을 때가 많다. String s = new String("bikini"); //호출될 때마다 String 인스턴스 생성 String s = "bikini"; //하나의 인스턴스를 사용하며 JVM 안에서 같은 객체를 재사용함이 보장됨 생성자를 통해, 매번 새로운 객체를 생성하는 것보다는, 정적 팩터리 메서드를 사용해 불필요한 객체 생성을 피하는 것이 좋다. 🔥 생성 비용이 아주 비싼 객체도 있다. static boolean isRomanNumeral(String s) { return s.matches("^ ~)" + "(X[CL ~"); } 위 메서드의 문제점은 String.matches 를 사용하는데..
🏠 생성자에 매개변수가 많다면 빌더를 고려하라. 클래스를 설계하다보면 어떤 인스턴스임에 따라 필드 값이 필수일수도, 필요하지 않을 수도 있다. 이에 대해 모든 걸 고려해서 설계하다보면 생성자가 감당하기 힘들 정도로 많아진다. Builder 패턴이 나오기 전에는 점층적 생성자 패턴을 즐겨 사용했다고 한다. 💊 점층적 생성자 패턴이란 ? 점층적 생성자 패턴(Telescoping Constructor Pattern)은 생성자 오버로딩을 이용하여 객체를 생성하는 패턴이다. 이 패턴은 매개변수가 많은 객체를 생성할 때 유용하지만 매개변수가 많아질수록 코드의 가독성이 떨어지고, 실수할 가능성이 높아진다. public class Pizza { private int size; private boolean cheese;..
이전에 LocalCache 를 사용해서 Cache 서비스를 구현한 적이 있었습니다. 이번에는 이후에 MSA 서비스 확장성을 고려해서 Global Cache 를 사용하자는 요구사항이 나와서 Redis 를 사용해 Global Cache 를 구현해보겠습니다. Local 환경에 Redis 설치와 실행이 끝났다는 가정하에 쓴 글입니다. 아직 설치가 되지 않았다면 해당 블로그를 참고해주세요. (mac) https://wlswoo.tistory.com/44 🧤 Config build.gradle implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot..