Item60에서는 정확한 계산을 할 때에는 float과 double을 피하라 말한다 대표적인 예로 금융과 관련된 계산을 할 때는 아래 세 경우를 고려해야 한다 1. 최대 21억 근사치까지 사용한다면 메모리 리소스까지 고려하여 int 사용 2. 약 1800경까지의 값이 필요하다면 long 사용 3. 이 마저도 초과한다면 성능을 깎아먹더라도 정확성을 위해 BigDecimal 사용 처음 단정밀도, 배정밀도 실수에 대해 봤을 때 단순하게 float은 정밀도가 6~7이고 double은 약 15~17 정도 구만 하고 넘어갔는데 최근에 컴퓨터 구조를 공부하면서 호기심이 생겨 좀 더 찾아봤다 1. 단정밀도 https://bahasa.wiki/ko/Single-precision_floating-point_format 2..
Item59에서는 라이브러리를 익히고 사용하라 말한다 예시로 Java의 Random 클래스의 random 메서드를 들었는데 내부 구현의 허점으로 이상적으로 동작하지 않는다고 한다 약 2/3 정도가 중간 값보다 낮은 쪽으로 쏠린다고 한다 다행히도 Random.nextInt() 메서드는 이를 보완해서 나왔고 일반적인 상황에서는 충분히 사용 가능하다 더 나아가 자바7 이상부터는 ThreadLocalRandom을 사용하라 한다 ThreadLocalRandom은 ThreadLocal과 Random을 짬뽕해 만들었다고 하고 Random보다 더 나은 성능을 보인다고 한다 또한 Fork-Join Pool을 사용해 병렬 처리를 할 때는 SplittableRandom을 사용하라 한다 그럼 ThreadLocalRandom ..
item58에서는 fori 보다 iter를 사용하라 말한다 fori는 무엇인가, fori를 치면 생성되는 좌측의 코드 블록을 의미한다, 전통적인 for문 / for-loop라고 한다 iter는 무엇인가? iter를 치면 생성되는 우측의 코드 블록을 의미한다, 향상된 for문 / foreach-loop라고 한다 향상된 for문이라 부르는 이유는 성능 측면이 아닌 가독성 측면에서의 향상을 의미한다 특별한 이유가 있거나 학습의 목적이 아니라면 iterator()를 얻어서 iterator.next()로 순회하는 코드를 작성할 일은 거의 없으니 패스하자 for-loop과 foreach-loop는 반복 형태의 구조를 다룬다는 점에서 동일하다 가장 큰 차이는 for-loop은 외부에서 인덱스를 가지고 조작한다는 점에..
Item57에서는 지역변수의 범위를 최소화하라 말한다 왜일까? 변수의 범위를 줄이면 가독성과 유지보수성이 좋아지기 때문이란다 이 조언을 정면으로 들이박는 형태가 있는데 메서드나 코드 블록에서 변수를 한 무더기 선언해놓고 그 아래에서 선언한 변수를 사용하는 방식을 옛날 옛적 C를 사용할 때 그렇게 했었다고 한다 다행히도 아직까지는 실무에서 변수촌을 만들어놓고 아무데서나 막 가져다 쓰는 코드는 보지 못 했다 이펙티브 자바의 예는 약간 극단적이라 갸우뚱하긴 하다, iterator()로 직접 돌리는 코드도 본 적이 없고 자바8 이후로 성능이 정말 중요한 경우가 아니고서야 enhanced-for도 stream으로 대체 가능하니 더욱 그렇다 자바8의 stream, Function 등을 배우고 나면 기존의 코드를 싹..
Item56에서는 공개된 API 요소에는 항상 문서화 주석을 작성하라 말한다 사실 언어나 프레임워크, 공개 라이브러리 작성자가 아니라면 지키지 않아도 될 조언이긴 하다 다만 구멍가게를 벗어나 네이버와 같이 하나의 회사지만 여러 계열사로 나뉘고 그 안에서 공통적으로 사용할 모듈을 개발한다면 의무는 아니어도 javadoc 형태로 작성해두면 사용하는 이들에게 좋다 나는 수습 과제로 만든 작은 사이드 프로젝트에 주석을 적어놓기도 했다 클린 코드에 미친 사람이라면 주석 자체가 쓰레기 같겠지만 분명한 건 코드를 짜는 순간부터 레거시가 되고 자신이 평생 유지보수할 수는 없다는 것이다 그렇다면 다음 사람이 이를 맡아서 유지보수를 해야 하는데 도메인 지식이라고도 하고, 배경지식이라고도 하는 특정 비지니스 로직을 모르고 ..
Item55에서는 옵셔널 반환을 신중히 하라 말한다 참고 글에서는 옵셔널이 보기만큼 쉬운 녀석이 아니라고 하며 무언가를 사용할 때 왜 만들어졌는지, 어떤 방식으로 테스트되었는지를 반드시 확인하라 한다 위 글에는 Optional의 여러 API들을 사용하는 방법과 best-practice를 안내하고 있으니 시간이 있다면 읽어보자 Optional에 대해 자바 설계자 브라이언 고츠는 아래와 같이 정의한다 많은 이가 사용하는 라이브러리 메서드는 값이 없는 경우 null을 반환하면 에러 발생 가능성이 높아지니 대안으로 값이 없다는 것을 제한된 방식으로 나타내기 위해 만들어졌다고 한다 Optional이라는 컨테이너를 만들고 그 안에 값이 있든 없든 반환하고 클라이언트 쪽에서 값이 있는 경우와 없는 경우를 고려해 사용..
Item54에서는 null이 아닌 빈 컬렉션이나 배열을 반환하라 말한다 생각해보면 어떤 객체든 값이 없는 경우 null 반환 때리면 간단한데 왜 하지 말라는 걸까? null 만든 사람조차 10억 달러짜리 실수라 말했기 때문이다 어떤 메서드든 null을 반환하면 클라이언트 측에서 null check가 필요하다 만약 something 객체가 인스턴스 변수로 참조 타입을 가지고 있고 그 참조를 사용하려 한다면 null check 한방 더 들어간다 if (something != null) // 로직 수행 if (something == null) throw new 어쩌구Exception(); null check로 콜백 지옥과 같은 형태로 뎁스가 쭉쭉 늘어나 진짜 중요한 비즈니스 로직을 가리게 될 수 있고 실수로 ..
Item53에서는 가변 인수는 신중히 사용하라 말한다 가변 인수를 사용할 때 주의점은 아래 글을 참고하자 [Item32] varargs는 신중히 varargs란 메서드 인수의 개수를 클라이언트 측에서 결정할 수 있다는 점에서 개꿀이다 인수를 여러 개 넘기면 내부적으로는 배열을 만들어 담아두고 사용한다 바로 이 부분에서 문제가 되는데 ryumodrn.tistory.com 가변 인수를 사용하면 매개변수의 개수가 정해지지 않은 상태로 클라이언트에게 매개변수를 몇 개 넘길지에 대한 책임을 넘겨 클라이언트가 필요한 만큼 넘길 수 있도록 한다는 점에서 유연한 API 설계가 가능하다 다만 varargs는 위험하다, 가변인수를 받는 메서드는 런타임에 새로운 배열이 생성되어 인수를 처리한다 어차피 사용하고 GC로 처리되..
Item52에서는 다중 정의를 신중히 사용하라 말한다 책의 나온 예제 코드만 보면 매개변수에 따라 다른 값이 출력될 것 같지만 실제로는 Collection 타입으로 인식되어 세 번 다 "Collection"만 나오게 된다 public class CollectionClassifier { public static String classify(Set s) { return "Set"; } public static String classify(List s) { return "List"; } public static String classify(Collection s) { return "Collection"; } public static void main(String[] args) { Collection[] col..
Item51에서는 메서드 시그니처를 신중히 설계하라 한다 규모가 큰 프로젝트를 진행할 때 절실히 깨달을 수 있다 개념적으로 유사한 행위를 하는 메서드의 이름이 다를 때, 하나하나 구현 부분을 찾아가 봐야 하고 어떤 기능을 하는지 뭐가 다르길래 이름의 뉘앙스가 다른지를 파악해야 한다 메서드를 작성하는 입장에서는 아주 명확하다고 생각하고 작성했더라도 메서드를 사용하는 입장에서도 과연 그런지 고민해볼 필요가 있다 나의 경험으로는 클린 코드를 읽고 서술적인 메서드명에 꽂혀서 표현력 있는 메서드를 작성했다고 뿌듯해했었는데 코드 리뷰에서 개념적 유사성을 고려한 메서드명을 지으라는 피드백을 받은 적이 있다 도메인 엔티티를 수정할 때, 어떤 메서드는 changeXX를 사용하고 어떤 메서드는 editXX을 사용했었다 작..
이전 글에서는 SecurityConfig 구성과 OAuth Login으로 받아온 유저 정보 처리 방법을 알아봤다 이번 글에서는 Security 설정 중 JWT와 관련된 부분을 알아보고 로그인 이후의 흐름을 살펴보자 JWT 설정은 내용이 많지는 않지만 따로 클래스로 빼내 구성하고 있다 현재 프로젝트에서는 OAuth2 로그인 시에는 구글에서 발급해준 ID & Access Token을 그대로 이용하고 애플리케이션 자체 로그인 시에는 직접 발급한 ECC 알고리즘 기반 ID & Access Token을 이용한다 일반적으로 Access & Refresh Token으로 묶겠지만 로그인, 토큰 발급 과정의 개념적인 통일을 위해 살짝 번거롭더라도 ID 토큰으로 사용자의 정보를 파싱 한다, 따라서 ID Token이 JWT..
스프링 부트 프로젝트에 OAuth2를 적용하는 것 자체는 쉽다 그러나 한발 더 나아가 흐름을 이해하고 어떻게 동작하는지 알아보려면 그다지 쉽지 않을 것이다 본 글은 OAuth2에 대한 이해를 도와줄 수는 있으나 친절한 설명이 될 것 같진 않다 스텝 바이 스텝으로 따라오게 만들 정도의 글 솜씨가 아니라 그렇다 내가 이해한 바를 바탕으로 어떻게 적용했는지를 보여줄 것이다 OAuth2 입문자에겐 매우 불친절한 자료가 될 예정이고 예제를 따라 적용을 해본 사람에겐 도움이 될 수 있을 것이다 글 하단에 참고 블로그를 첨부했다, 난 저 자료들 외에도 수 많은 자료들을 참고했는데 제일 잘 정리된 글들만 추렸다 개념 정리는 이해하는게 제일 중요하니 원서보다 한글로 된 자료를 보는 것을 추천한다 영어가 된다면 공식 문서..
약 3개월 간 OAuth2 연동 프로젝트를 진행하고 마무리 단계에 들어 그동안의 작업을 정리할 겸 남긴다 angular git convention을 따랐고 병합 전략은 squash-and-merge로 하여 연관된 작업을 한눈에 보기 쉽게 정리했다 아래는 깃 컨벤션을 참고했던 블로그다 [Git] 커밋 메시지 규약 정리 (the AngularJS commit conventions) the AngularJS commit conventions를 번역한 것입니다. 공부하면서 번역했습니다. 입맛대로 번역된 부분이나 오역이 있을 수 있습니다. velog.io angular convention을 따를 때 인텔리제이에서 사용할 수 있는 꿀 플러그인이 있다 인텔리제이 2022.01 버전에서도 사용 가능하므로 사용을 추천한..
Item50에서는 적시에 방어적 복사본을 만들라 한다 defensive copy를 만들어야 하는 이유는 미성숙한 & 악의적인 클라이언트의 잘못된 접근을 막기 위함이다 secure coding의 한 종류로써 사용하는 쪽에서 무슨 짓을 하든 객체의 불변성, 안전성이 위협 받지 않도록 하는 것이다 상식적으로 보면 이런 일이 과연 일어날까 싶지만 대규모 프로젝트의 경우 초기 인원들이 끝까지 남아 소프트웨어 생명주기 전체를 관리하는 일은 흔치 않을 것이다 그렇다면 작성한 사람과 관리하는 사람이 다를 것이고 어떤 의도로 코드를 작성했을지 알 길이 없다 책에 등장하는 Date를 인스턴스 변수로 가지는 Period의 예로 보면 Date 자체가 불변을 보장하지 못 하는 클래스라 단순하게 Date에 setXX 메서드를 이..
item49는 매개변수가 유효한지 검사하라 말한다 메서드나 생성자에 적용해야 하는 규칙으로써 이를 지키지 않으면 실패 원자성을 깨부술 수 있기 때문이다 실패 원자성이란 쉽게 생각해서 잘못 됐을 때 바로 터져야 함을 의미한다 매개변수가 유효하지 않음으로 인해 바로 그 순간에 예외가 터지는게 아닌 로직을 타고 흘러 흘러 어딘지도 모를 엉뚱한 곳에서 예외가 터진다면 실패 원자성이 깨진 상태다 웹 개발을 하는 경우 입력 유효성을 하는 대표적인 상황은 Controller에서 매개변수를 받는 상황일 것이다 이 역시 여러 방법으로 처리가 가능한데 @Valid @RequestBody를 이용해 객체를 매핑 받아 사용하고 바인딩이 실패하는 경우, 실패 원인을 담고 있는 BindingResult도 받아서 추가 처리도 가능하..
Item48에서는 스트림 병렬화를 주의하라 말한다 병렬화란 단어에는 엄청난 성능 효과가 있을 것 같은 느낌이 든다 특히 자바는 컬렉션 등의 데이터 소스에 stream() 대신 parallelStream()으로 간단하게 병렬로 만들 수 있는 것이 함정이다 왜 함정인고 하니 병렬 스트림은 순차 스트림 보다 빠른 경우가 드물고 더 느린 경우가 많다 개념적으로 쉽게 와닿지 않을 수 있다 하나의 스레드가 큰 뭉탱이 하나 처리하는 것이 어떻게 여러 스레드가 작은 뭉탱이를 처리하는 것보다 느릴 수 있을까? 그 이유는 이전 글 Item45에 간략하게 정리해뒀다 [Item45] Stream vs For-Loop Item45에서 스트림은 주의해서 사용하라 말한다 Stream API는 다량의 데이터 처리 작업을 돕고자 Ja..
Item47에서는 반환 타입으로 스트림 보다 컬렉션이 낫다고 한다 개발을 하면서 스트림을 반환 타입으로 메서드를 작성한 적이 없어 문득 궁금해졌다 스트림 반환과 관련해서 밸덩과 스택오버플로우 글을 찾아봤다 - https://www.baeldung.com/java-return-stream-collection - https://stackoverflow.com/questions/24676877/should-i-return-a-collection-or-a-stream 컬렉션 반환은 data structure에 접근하는 것이고 스트림 반환은 data storage 안의 data source에 접근하는 것이다 어느 상황에 Stream을 반환해야 하는가에 대해서 스택오버플로우에 꽤나 정확한 답변이 있다 개발에서의 대..
Item46에서 스트림에는 부작용 없는 함수를 사용하라 말한다 스트림은 함수형 프로그래밍에 기초한 패러다임이라는데 그럼 함수형 프로그래밍이라는 패러다임은 무엇인가? 깔끔하고 유지 보수하기 쉬운 코드를 만들기 위한 코드 작성 방식이란다 OOP와 대치되는 개념이 아니고 둘이 짬뽕시켜 쓸 수 있다 함수형 프로그래밍은 모던 프로그래밍에서 대세가 되어가는 중인데 절차형, 객체지향, 함수형 중 함수형이 가장 먼저 나왔으나 그동안 많이 쓰이지 못했던 것은 불변 객체와 side-effect를 다루는 문제 때문이다 객체가 불변이라면 다른 값이 필요한 경우에 기존 객체를 변경할 수 없으니 항상 새로운 객체를 생성해야 한다 side-effect를 만들지 않으려면 외부 변수를 변경하지 못하고 모든 변경은 새로운 값으로 대체해..
Item45에서 스트림은 주의해서 사용하라 말한다 Stream API는 다량의 데이터 처리 작업을 돕고자 Java8부터 추가되었고 짜잘한 for, if문을 스트림으로 대체할 수 있다 Stream API의 핵심은 책을 참고해보면 다음과 같다 1. Stream 데이터 소스로부터 오는 유한 또는 무한의 흐름 2. Stream Pipeline 데이터 소스를 돌리면서 수행하는 연산의 단계 (중간 연산과 종단 연산으로 나뉜다) Stream이란 이름에서부터 알 수 있듯이 데이터가 흐르고 있고 중간 연산을 활용해 변환(mapping)하거나 걸러낸다(filtering) 쌩으로 출력하거나 다른 파일에 쓰는 경우가 아니라면 무언가 가공이 필요한 데이터이므로 중간 연산이 들어갈 것이다 파이프라인이라는 단어에서 유추할 수 있듯..
Item44는 표준 함수형 인터페이스를 사용하라 말한다 람다 등장 이전에 구현체마다 다른 행동을 지정하기 위해 사용하는 방법으로 템플릿 메서드 패턴이 있었다 상위 클래스의 메서드를 오버라이딩해 동작을 변경할 수 있는데 아래와 같은 형태다 public abstract class Animal { void yahoo() { System.out.println("YAHOO"); } } public class Cat extends Animal { @Override void yahoo() { System.out.println("CAT YAHOO"); } } public static void main(String[] args) { Animal animal = new Cat(); animal.yahoo(); } 실제 동..