이전 아이템에서 Generics를 꼭 써야 한다는 것을 배웠다 다만 어떤 기술이든, 어떤 언어든 무언가를 도입함에 따라 장단점이 따라오게 되어있다 새로운 기술은 도입할 때의 장단점을 저울질해 이전의 장단점들을 상쇄하고 남을 효용이 생기면 도입해야 한다 Generics 장점으로 type-safety를 지켜주어 번거로운 형 변환이 필요 없고 잘못된 값이 들어갈 일이 없다는 점이 있다 단점으로 수 많은 unchecked-call이 뜰 수 있다는 것인데 잘 생각해보면 이건 장점이다 사용자 입장에서 타입 체크를 제대로 안 했기 때문에 친절한 IDE가 컴파일 전에 미리 뿜어내 주는 것이다 IDE에서 문법 오류나 구식 for문을 향상된 for문으로 바꿔주는 것과 같은 자동 수정은 지원하지 않으나 비검사 경고가 뜬다는..
옛날 옛적, Generics 도입 이전엔 List, Set, Map 같은 컬렉션에 특정 타입이고 나발이고 아무거나 집어넣고 멍 때리던 시절이 있었다 Java5부터 type-safety를 지원하려 구원자 Generics가 오셨다 raw type 을 쓰는 게 왜 문제인가? 당연 타입 안정성을 지원해주지 못하기 때문이다 Generics로 타입을 명시하지 않은 경우 기본적으로 컬렉션에 들어가는 요소를 Object로 간주한다 어떤 값을 넣든 Object 형태로 받아버리기 때문에 막상 꺼내서 쓰려고 할 때 Object로 사용할 것이 아니라면 원래 넣은 형태로 캐스팅을 해줘야 한다 1~2개 사용하고 개발자가 타입을 꿰차고 있는 경우엔 아무 상관없다만 조금 더 현실적으로 생각해보면 말 같지도 않은 상황이 펼쳐지는 것이..
톱 레벨 클래스는 한 파일에 하나만 담으라는데 이 말을 듣기 전에도 무의식적으로 수행하고 있었다 얼마 전 Kotlin in action을 깔짝 보고 top-level function을 써봤는데 Item25를 읽으면서 자바는 왜 안 되는지 궁금해졌다 그 이유는 자바의 초기 설계와 관련이 깊은데 자바에서는 모든 것이 객체다 다른 말로 하자면 모든 것이 객체 안에 있어야 한다 그렇기 때문에 톱 레벨에는 클래스를 두고 그 안에 변수나 메서드를 둬야 한다 비록 그 클래스가 아무런 의미 없이 컨테이너 역할을 하더라도 말이다 코틀린에서는 아마 이런 불필요한 껍데기를 두는 게 꼴 뵈기 싫어서 톱 레벨에 변수나 함수를 선언할 수 있도록 만든 거 같은데 JVM 언어이고 자바와의 상호 운용성을 제일로 치기 때문에 컴파일 시..
멤버 클래스를 왜 static으로 만들어야 하는가, 그전에 멤버 클래스는 왜 필요한가? 책에서는 멤버 클래스를 가지고 있는 클래스에서만 쓰여야 한다고 한다 Oracle 문서에서는 다음과 같이 설명한다 한 곳에서만 쓰일 녀석들을 논리적으로 묶기 위함 & 캡슐화, 가독성, 유지보수성 향상 즉 outer class 와 함께 쓰일 때만 의미 있는 클래스로써 도우미 역할을 한다 예를 들어 outer class에서 쓰일 상수 클래스가 있을 때, outer class 외에 쓰일 일이 전혀 없으면 top-level로 빼기엔 애매하다 더욱이 유지 보수를 위해서 개념적으로 가깝다면 물리적으로 가까이 두는 것이 좋다 이런 경우 inner class로 두면 응집력이 높고 결합도가 낮은 형태로 만들 수 있다 중첩 클래스엔 네 ..
요즘 내가 자주 시도하는 객체지향적 사고는 어떻게 하면 공통된 부분을 뽑아내 여러 곳에서 재사용할 수 있을 지다 작성한 지 꽤 지났는데 어떻게 공통된 부분을 뽑아냈고 이를 재사용할 수 있는지 고민했던 글이다 고수가 보면 콧방귀를 뀔 코드일 수 있으나 초보라면 참고해보면 괜찮을 거라 생각해 첨부한다 [OAuth2] SpringBoot OAuth2 적용기 & 깨지는 테스트 살리기 개인 프로젝트에 OAuth2를 적용해봤다 Spring Security를 이용한 로그인, 회원가입 과정을 대체하기 위해서는 아니고 학습 목적이다 학습 목적이라 해보고 싶은 것 다 하려고 google, facebook, github, naver, ryumodrn.tistory.com 저 코드도 아쉬운 부분이 많다 switch 난사로 더..
Interface는 언제 그리고 왜 쓸까? 행동에 제약을 걸기 위한 추상화로만 사용하자 책의 예제는 상수 인터페이스를 보여주는데 얼핏 보면 괜찮은 생각처럼 보일 수도 있다 상수 인터페이스를 구현한 모든 클래스에서 이 상수들을 이용하면 편할 거 같은데 두 가지 문제가 있다 첫번째는 타입 정의를 위해 사용해야 할 인터페이스를 올바르게 사용하지 않은 것이다 관례와 규칙을 따르지 않은 방식이므로 본인은 편하게 사용할지 몰라도 해당 코드를 본 대부분의 사람은 의문을 품게 될 것이다 둘째, 바이너리 호환성 인터페이스에서 상수를 공개했으므로 이를 사용하는 쪽에서 상수에 강하게 결합된다 상수를 수정할 일이 있을 때 인터페이스에서만 바꾸고 끝이 아니라 클라이언트 코드까지 전부 컴파일 해줘야 한다 게다가 인터페이스에서 상..
당연한 말이지만 인터페이스는 구현하는 쪽을 생각해 설계해야 하고 클래스는 사용하는 쪽을 생각해 설계해야 한다 코드를 작성한다는 것은 작게 보면 어떤 기술을 사용해 멋진 프로그램을 만들어내느냐 지만 크게 보면 결국 요구사항을 충족시키는 프로그램을 어떻게 만들어내느냐 이기 때문이다 클라이언트 혹은 액터라고 부르는 이해 관계자는 인터페이스나 클래스에 기대하는 행위가 있다 개발자는 그 기대에 부응할 의무가 있다 Java8부터 인터페이스에 default method를 추가할 수 있게 됐다, 이는 엄청난 축복이지만 저주가 될 수도 있다 위에서 말한 내용 때문인데 클라이언트는 인터페이스에 기대하는 행위가 있는데 수많은 구현체들에서 이 기대가 올바르게 작동하리라는 보장이 없기 때문이다 책에서는 apache.common..
Item20의 핵심은 한 줄로 요약된다 자바에서는 다중 상속이 되지 않기 때문에 추상 클래스보다는 인터페이스를 사용해야 한다 다중 상속을 허용하게 되면 다이아몬드 상속 문제를 피할 수 없다 그럼 다이아몬드 상속 문제가 무엇일까? 아하 Super1, Super2를 다중 상속받았을 때 어떤 놈의 메서드가 우선순위를 가져야 하는지 정하지 못하기 때문이로구나 어떤 계층이 위에 있는지, 어떤 놈이 먼저 나오는지 ex) extends Super1, Super2 이면 Super1의 메서드 상속 식으로 풀어도 되긴 하지만 결국 복잡성이 올라가는 문제를 안고 있다, 애초에 될 수 없게 하는게 간단하다 그럼 여러개를 가질 수 있는 방법이 없단 말인가? 다중 상속은 안 되지만 다중 구현은 가능하다 implements Sup..
Item19는 일반 개발자에게는 생소한 내용이 담겨있다, 물론 나에게도 그렇다 작성하는 클래스가 상속용인지 아닌지 결정하라는 것인데 이 것이 중요한 이유는 라이브러리 사용자에게 상속했을 때 신경 써야 할 부분을 알려주기 위함이다 이전 아이템에서 나온 HashSet 상속 시 발생할 수 있는 문제는 명세를 꼼꼼히 살펴봤다면 일어나지 않았을 것이다 이전 아이템은 아래 글 참고 [Item18] extends 멈춰 자바에서 extends를 이용해 상위 클래스를 상속 받으면 코드 복붙이 필요 없다 상위 클래스의 private 변수, 메서드를 제외한 모든 속성을 내려주기 때문이다 이런 편리함을 제공하는데도 상속 보다 ryumodrn.tistory.com Javadoc까지 완벽하게 작성할 것이 아니라면 @implSpe..
객체지향, 자바 & 스프링을 올바르게 공부하고 있는 건가 싶은 의문이 든다면 아래 동영상을 한번 보자 얼마 전 팀장님과 잠깐 나눴던 대화 중 앉아만 있다고 공부하는 것이 아니라는 말씀을 해주셨다 난 2021.02 기준으로 개발 공부를 시작했고 그때부터 약간은 강박적으로 공부에 매달렸다 이전 회사에서도 그랬고 지금도 퇴근 후 적어도 4시간 이상은 하고 주말에 약속이 없다면 거진 10시간 정도를 하는데 그래서 난 공부를 오래 하고, 정말 열심히 한다는 생각을 했던 것 같다 팀장님의 말씀과 위 동영상을 보고나니 의식적인 연습이 부족했구나 하는 생각이 든다 그렇게 긴 시간을 공부하더라도 무의식적인 공부라면 코드 따라 치기 일 뿐이고 잘 봐줘도 API 사용법 학습일 뿐이다 위 동영상에서 말한 것과 팀장님께서 해주..
자바에서 extends를 이용해 상위 클래스를 상속 받으면 코드 복붙이 필요 없다 상위 클래스의 private 변수, 메서드를 제외한 모든 속성을 내려주기 때문이다 이런 편리함을 제공하는데도 상속 보다는 합성을 이용하란다, 왜일까? 어허어허, 구현 상속은 캡슐화를 깨트려서고만 protected는 내부 구현을 감춰뒀다는 환상을 준다고라 캡슐화의 핵심은 이전에 제공했던 public interface 대로 동작만 가능하면 아무 걱정 없게 해주기 때문이구만 만약 변경이 필요하면 인터페이스를 구현한 클래스에서만 신경 써주면 되니까 편하겠구먼 그런데 상속을 사용해 protected로 내려주면 상속 받은 녀석들까지 모두 신경 써야 하니까 귀찮아지고 이는 캡슐화가 깨졌음을 의미하는 것이로구나 OOP에서 복잡성을 관리하..
가변과 불변에 대한 좋은 글이 있다, 읽고 시작하자 Just Enough FP: Immutability Kyle Shevlin is a software engineer who specializes in JavaScript, React and front end web development. kyleshevlin.com 객체를 가변과 불변으로 만드는 절대적 기준은 딱히 없고 어떤 부분에 중점을 둘 것인지에 따라 달렸다 즉 애플리케이션을 만들 때 모든 객체를 가변으로 만들어도 되고 불변으로 만들어도 된다 다만 그 대가로 극심한 난이도의 유지보수성이나 지하로 곤두박질 친 성능이 따라올 수 있다 가변 객체는 귀요미 프로젝트일 땐 상관 없지만 며칠에 걸쳐 소스를 봐도 구조를 파악할 수 없을 때 문제된다 프로그램 작..
객체지향의 달인이 되려면 뭐든 간에 잘 숨겨야 한다, 객체지향을 처음 배울 땐 이 개념에 의문이 들었다 어차피 외부에서 쓰려고 만드는 건데 왜 숨겨야 하는가? 결합도를 낮추고 응집도를 높이기 위해서라는 말로는 이해하기 부족했다 불변 객체가 아니라면 인스턴스 변수들은 final이 아닐 것이고 변경 가능하다 접근 제한자까지 public이라면 어디서든 값을 변경할 수 있다 이는 엄청난 자율성을 주지만 시간이 지나면 참혹한 대가가 따른다 H/W, S/W 성능 향상으로 인해 변하지 않을 코드는 없다 이 정도면 기가 막히구만 하고 짰더라도 다음 버전에서 그 성능을 한참 앞지르는 알고리즘이 나올 수도 있고 절차 지향에서 객체지향으로, 객체지향에서 리액티브로 패러다임이 바뀌어버릴 수도 있다 가장 흔한건 역시 클라이언트..
객체지향의 핵심은 풀어 설명하면 한도 끝도 없지만 간단하게 보면 캡상추다로 요약된다 1. 캡슐화 2. 상속 3. 추상화 4. 다형성 이 중 캡슐화에 해당하는 내용이 Item15에 나오는데 외부에서의 접근 권한을 최소화하는 것이다 개인적으로는 컴포넌트의 손발 자르기라고 생각해 불호에 가깝지만 기술적으로 보면 맞는 말이기 때문에 따라야 한다 프로그램 유지보수의 난이도는 변경이 어디까지, 얼마나 전파되느냐에 따라 달라지기 때문이다 변경의 영향을 최소한으로 줄이기 위해 setter를 막아두고 특별한 이름의 메서드를 만들어 사용해야 한다 사실 setter를 열어두거나 필드를 public으로 열어두면 유연성이 향상된다 혼자 만드는 프로젝트라면야 세터를 열어두든 퍼블릭으로 다 열어두든 누가 뭐라하겠는가? 특히 내가 ..
Item14의 핵심은 작성하는 클래스가 순서가 필요하다면 Comparable을 구현하라는 것이다 모던 자바 인 액션에서 스트림의 다양한 사용법을 배우는데 그때 Comparable을 사용하는 코드도 많다 당시엔 단순 사용법만 익히느라 어떤 원리로 돌아가는지 몰랐는데 이번에는 깊게 읽어봤다 왜 Comparable을 구현하라고 했을까? 보통 알파벳, 숫자, 연대 같이 순서를 가진 값 클래스를 이용하는 과정에 유용하게 쓰일 수 있기 때문이다 책에서는 전화번호를 지역번호, 앞자리, 뒷자리로 잘라서 표현하는 클래스를 작성하는데 비지니스 로직에 따라 지역번호 별 정렬, 앞자리 별 정렬 등이 필요한 경우가 있을 수 있다 또한 자연적인 순서를 가지고 있다면 Arrays.sort()를 이용해 간단히 정렬시킬 수도 있다 C..
자바 툴로 인텔리제이를 사용한다면 개인 프로젝트라도 코드 스타일을 맞추는 걸 추천한다 국내에서는 보통 구글 혹은 네이버의 스타일을 따르는 것 같다 나는 구글 스타일을 선택했고 웬만하면 커스텀 옵션을 주지 않고 사용하고 있다 GitHub - google/styleguide: Style guides for Google-originated open-source projects Style guides for Google-originated open-source projects - GitHub - google/styleguide: Style guides for Google-originated open-source projects github.com 위 깃허브에 접속해 xml 파일을 긁어다 저장하면 된다 Copy ..
Cloneable은 mixin interface라고 한다, 믹스인 인터페이스가 무엇일까? Item20에서 자세히 설명되어 있는데 A라는 클래스가 있다면 Cloneable과 같은 mixin interface를 구현하게 하면 A 클래스가 가진 본연의 기능에 다른 기능을 덧붙이기 때문에 (mix-in) 믹스인이라고 한다 두 번째 코멘트를 보자 자바에서는 인터페이스에 상태나 코드를 가질 수 없어 믹스인 인터페이스란 건 없다고 하며 추상 클래스를 이용했다면 다중 상속을 지원하지 않기에 모든 조건을 만족할 수 없다고 했다 자바8 이후로 인터페이스에서 메서드 구현이 가능하므로 이제는 믹스인 인터페이스가 존재할 수 있다 그럼에도 Cloneable은 정상적인 믹스인 인터페이스라고 할 수 없는데 clone() 메서드를 직..
Object 조상님에서 toString()은 ClassName@hashCodeByHex 를 던져주신다 이 값은 딱히 궁금하지 않았는데.. 그러므로 인스턴스에 대한 야무진 정보를 제공해주려면 toString()도 재정의해줘야 한다 조슈아 형님은 사용하기에 즐겁고 디버깅 하기 쉽기 때문에 반드시 구현하라고 하셨다 그에 앞서 클래스에 대한 야무진 정보가 문자열 형태로 왜 필요한가부터 고민할 필요가 있다 System.out.println()으로 인스턴스를 찍어보는 자바 연습 단계를 지났다면 toString이 도대체 왜 필요한가? 나는 지금껏 프로젝트에서 toString() 메서드를 요긴하게 사용해 본 적이 없어 열심히 찾아봤다 마크씨가 남겨준 답변과 그 아래 달린 코멘트를 유심히 보자 인스턴스에 대한 문맥 제공..
Item11은 equals 재정의할 때 hashCode도 반드시 재정의하라는 내용이다 equals를 직접 작성하고 싶어서 안달이 난 게 아니라면 그냥 롬복이 제공하는 걸로 쓰자 자바는 안 그래도 boiler plate 때문에 코드 길이가 긴 놈인데 코드 흥선대원군 마냥 롬복을 쓰지 않겠다면 프로젝트 코드가 금세 팔만대장경 뺨 칠 수준이 될 것이다 특히 이는 알고리즘 문제 풀 때 C++, python과 비교해보면 코드 길이 차이가 체감이 된다 한 달 전쯤 잠깐 코틀린 인 액션 한 바퀴 돌리면서 코틀린 좀 핥아봤는데 많은 문제가 개선된 것 같다 아직까지는 대규모 프로젝트에 도입하기엔 이른 감이 없지 않은데 네카라쿠배당토가 힘내서 레퍼런스 뿌려주면 좋겠다 이전 장에서 @EqualsAndHashCode 사용할 ..
equals를 재정의 하고 싶다면 일반 규약을 지켜야 한다 일반 규약은 다음과 같다 1. 반사성, reflexibility x가 null이 아닐 때 모든 x에 대하여 x.equals(x)는 true 2. 대칭성, symmetry null이 아닌 두 값 x, y가 있을 때, x.equals(y) == y.equals(x)가 true라면 그 반대도 성립해야 한다 3. 추이성, transitivity null이 아닌 세 값 x, y, z가 있을 때, x.equals(y) == true, y.equals(z) == true면 x.equals(z) == true 4. 일관성, consistency x, y의 값이 변하지 않을 때 x.equals(y) == true라면 언제 호출하더라도 false로 변해선 안 된다..