전체 글

전체 글

    매개변수가 유효한지 검사하라 - [8장. 메서드(아이템49)]

    메서드나 생성자를 작성할 때면 그 매개변수들에 어떤 제약이 있을지 생각해야 한다. 이를 위한 원칙 2가지를 살펴보자. 📙 1. 원칙 1 : 오류는 가능한 한 빨리 (발생한 곳에서) 잡아야 한다. 오류를 발생한 즉시 잡지 못하면 해당 오류를 감지하기 어려워지고, 감지하더라도 오류의 발생 지점을 찾기 어려워진다. 매개변수 검사를 제대로 하지 못하면 아래와 같은 문제가 발생할 수 있다. 메서드가 수행되는 중간에 모호한 예외를 던지며 실패할 수 있다. 메서드가 잘 수행되지만 잘못된 결과를 반환할 수 있다. 메서드는 문제없이 수행됐지만, 어떤 객체를 이상한 상태로 만들어놓아서 미래의 알 수 없는 시점에 이 메서드와는 관련 없는 오류를 만들 수 있다. 이러한 문제를 예방하고자 public과 protected 메서드..

    스트림 병렬화는 주의해서 적용하라 - [7장. 람다와 스트림(아이템48)]

    📙 1. 자바의 동시성 프로그래밍 자바는 동시성 프로그래밍 측면에서 항상 앞서갔다. 처음 릴리스된 1996년 스레드, 동기화, wait/notify 지원 자바 5 동시성 컬렉션인 java.util.concurrent 라이브러리와 실행자(Executor) 프레임워크 지원 자바 7 고성능 병렬 분해(parallel decom-position) 프레임워크인 포크-조인(fork-join) 패키지 추가 자바 8 parallel 메서드만 한 번 호출하면 파이프라인을 병렬 실행할 수 있는 스트림 지원 이처럼 자바로 동시성 프로그램을 작성하기가 점점 쉬워지고 있다. 하지만, 동시성 프로그래밍을 할 때는 안전성(safety)과 응답 가능(liveness) 상태를 유지하기 위해 애써야 한다. 병렬 스트림 파이프라인 프로그..

    반환 타입으로는 스트림보다 컬렉션이 낫다 - [7장. 람다와 스트림(아이템47)]

    📙 1. 원소 시퀀스 반환 타입 비교 일련의 원소(원소 시퀀스)를 반환하는 메서드는 수없이 많다. 이런 메서드의 반환 타입으로 Collection, Set, List와 같은 인터페이스, Iterable, 배열, 스트림이 존재한다. 이 중 가장 적합한 타입은 컬렉션 인터페이스다. 만약, API를 스트림만 반환하도록 짜놓으면 반환된 스트림을 for-each로 반복하길 원하는 사용자는 당연히 불만을 토로할 것이다. 스트림을 반복하기 위해서는 아래와 같은 우회 방법을 선택해야 한다. for (ProcessHandle ph : (Iterable) ProcessHandle.allProcesses()::iterator) { ... } 작동은 하지만 실전에 쓰기에는 너무 난잡하고 직관성이 떨어진다. 그래서 아래와 같이..

    스트림에서는 부작용 없는 함수를 사용하라 - [7장. 람다와 스트림(아이템46)]

    📙 1. 스트림의 핵심 스트림은 그저 또 하나의 API가 아닌, 함수형 프로그래밍에 기초한 패러다임이다. 스트림 패러다임의 핵심은 계산을 일련의 변환(transformation)으로 재구성하는 부분이다. 이때 각 변환 단계는 가능한 한 이전 단계의 결과를 받아 처리하는 순수 함수여야 한다. 순수 함수란 오직 입력만이 결과에 영향을 주는 함수다. 다른 가변 상태를 참조하지 않고, 함수 스스로도 다른 상태를 변경하지 않아야 한다. 이를 위해서는 (중간 단계든 종단 단계든) 스트림 연산에 건네는 함수 객체는 모든 부작용(side effect)이 없어야 한다. 그렇다면 만약 부작용(side effect)이 발생하면 어떻게 될까? 아래와 같은 문제점이 발생하게 된다. 가독성 Stream을 사용한 순간 데이터의 변..

    스트림은 주의해서 사용하라 - [7장. 람다와 스트림(아이템45)]

    📙 1. 스트림의 특징 다량의 데이터 처리 작업(순차적이든 병렬적이든)을 돕고자 자바 8에 스트림 API가 추가되었다. 스트림의 특징은 아래와 같다. 스트림 안의 데이터 원소들은 객체 참조나 기본 타입 값(int, long, double)이다. 스트림 파이프라인은 소스 스트림에서 시작해 종단 연산(terminal operation)으로 끝나며, 그 사이에 하나 이상의 중간 연산(intermediate operation)이 있을 수 있다. 각 중간 연산은 스트림을 어떠한 방식으로 변환할 수 있다. 예를 들어, 각 원소에 함수를 적용하거나 특정 조건을 만족 못하는 원소를 걸러낼 수 있다. 스트림 파이프라인은 지연 평가(lazy evaluation)된다. 평가는 종단 연산이 호출될 때 이뤄지며, 종단 연산에 ..

    엘라스틱서치(Elasticsearch) 적용 후기

    📙 1. 엘라스틱서치(Elasticsearch)를 사용하게 된 계기 프로젝트를 진행하면서 상대적으로 크기가 큰 동물 데이터(130만 건의 데이터)를 사용할 일이 있었다. 필요한 작업은 '동물의 계층적 분류를 나타내는 값에서 특정 계층이 있는 동물을 조회하는 것'이었다. 이러한 과정에서 어떻게 하면 조회 시간을 단축시킬 수 있을까 고민하였고 그 결과 엘라스틱서치(Elasticsearch)를 사용하게 되었다. 작업에 대해서 조금 더 자세하게 살펴보도록 하자. 원하는 동작은 '동물의 계층적 분류(higherClassification)에서 특정 계층(포유류, 양서류, 조류,...)이 존재하는 동물들을 가져오는 것'이다. 데이터는 아래와 같이 구성되어 있다. { ... "higherClassification": ..

    테스트 커버리지 100% 달성 후기

    이 글은 테스트 커버리지 100%를 달성하는 과정과 그 과정에서 느낀 점을 기록한 글입니다. 📚 1. 계기 아래 2가지 이유와 함께 '테스트 커버리지 100%를 달성해 보자!'라는 목표가 생겼다. 📗 1. 로버트 C. 마틴(a.k.a Uncle Bob)의 클린 코더 클린 코더에 다음과 같은 내용이 있다. 얼마만큼의 코드를 자동화한 단위 테스트로 계산해야 할까? 대답할 필요조차 없다. 모조리 다 해야 한다. 모. 조. 리! 100% 테스트 커버리지를 권장하냐고? 권장이 아니라 강력히 요구한다. 작성한 코드는 한 줄도 빠짐없이 전부 테스트해야 한다. 군말은 필요 없다. - 클린 코더 (로버트 C. 마틴 저) - 개발자가 아닌 사람이 위의 내용을 본다면 '너무 당연한 거 아니야?'라고 생각할 거 같다. 하지만..

    표준 함수형 인터페이스를 사용하라 - [7장. 람다와 스트림(아이템44)]

    📙 1. 함수형 인터페이스 자바가 람다를 지원하면서 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 메서드 패턴의 매력이 크게 줄었다. 이를 대체하는 방법으로 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 방법이 있다. 즉, 함수 객체를 매개변수로 받는 생성자와 메서드를 더 많이 사용하는 것이다. LinkedHashMap의 removeEldestEntry를 살펴보자. removeEldestEntry를 다음과 같이 재정의하면, 맵에 원소가 100개가 될 때마다 가장 오래된 원소를 하나씩 제거한다. // 기존 public class LinkedHashMap extends HashMap implements Map { ... protected boolean removeEldestEntry..

    서버에서 연결을 끊어 소켓을 말소한다. - [Ch 02. TCP/IP의 데이터를 전기 신호로 만들어 보낸다.]

    지금까지 '소켓 작성, 서버에 접속, 데이터 송수신' 과정을 알아보았다. 마지막으로 '연결 끊기'를 살펴보면서 데이터 송·수신에 관한 일련의 움직임을 마무리해보자. 📙 1. 데이터 보내기를 완료했을 때 연결을 끊는다. 데이터 송·수신을 종료하는 것은 애플리케이션이 송신해야 하는 데이터를 전부 송신 완료했다고 판단했을 때다. 송신을 완료한 측이 연결 끊기 단계로 들어가는데, 어디에서 데이터 송·수신 동작이 끝나는지는 애플리케이션에 따라 다르다. 서버 측에서 연결 끊기 단계에 들어가는 것으로 간주한다면 그 과정은 아래와 같다. 서버 측의 애플리케이션이 먼저 Socket 라이브러리의 close를 호출한다. 서버 측의 프로토콜 스택이 TCP 헤더를 만들고, 여기에 연결 끊기 정보를 나타내는 FIN 비트를 1로 ..

    데이터를 송·수신한다. - [Ch 02. TCP/IP의 데이터를 전기 신호로 만들어 보낸다.]

    이전 글을 통해 서버에 접속하는 방법을 알아보았다. 이번에는 서버에 접속을 완료하고 connect에서 애플리케이션에 제어가 되돌아온 후의 데이터 송·수신 동작을 알아보도록 하자. 📙 1. 프로토콜 스택에 HTTP 리퀘스트 메시지를 넘긴다 첫 번째 동작은 애플리케이션이 write를 호출하여 송신 데이터를 프로토콜 스택에 건네주는 것이다. 프로토콜 스택은 데이터를 곧바로 송신하는 것이 아니라 일단 자체의 내부에 있는 송신용 버퍼 메모리 영역에 저장하고, 애플리케이션이 다음 데이터를 건네주기를 기다린다. 만약 받은 데이터를 곧바로 보낸다면 작은 패킷을 많이 보낼 수 있다. 하지만, 이렇게 한다면 네트워크의 이용 효율이 저하되므로 어느 정도 데이터를 저장하고 나서 송·수신 동작을 한다. 그렇다면 어느 정도 저장..

    람다보다는 메서드 참조를 사용하라 - [7장. 람다와 스트림(아이템43)]

    람다가 익명 클래스보다 나은 점 중에서 가장 큰 특징은 간결함이다. 그런데, 자바에는 함수 객체를 심지어 람다보다도 더 간결하게 만드는 방법이 있는데, 그것이 바로 메서드 참조(method reference)다. 이번 글에서는 람다와 메서드 참조를 비교해 보고 언제 어떤 것을 쓰면 좋은지 알아보도록 하자. 📙 1. 람다와 메서드 참조 public static void main(String[] args) { Map map = new HashMap(); int myKey = 1; int myValue = 3; map.merge(myKey, myValue, (count, incr) -> count + incr); System.out.println(map.get(myKey)); // 3 myValue = 5; ..

    서버에 접속한다. - [Ch 02. TCP/IP의 데이터를 전기 신호로 만들어 보낸다.]

    이전 글을 통해 소켓을 작성하는 것을 알아보았다. 이번에는 작성된 소켓을 이용하여 서버에 접속하는 것을 알아보자. 📙 1. 접속의 의미 서버에 접속을 한다는 것은 통신 상대와 제어 정보를 주고받아 소켓에 필요한 정보를 기록하고 데이터 송·수신이 가능한 상태로 만드는 것을 의미한다. 제어 정보란 IP 주소나 포트 번호와 같이 데이터 송·수신 동작을 제어하기 위한 정보다. 또한, 데이터 송·수신 동작을 실행할 때는 송·수신하는 데이터를 일시적으로 저장하는 메모리 영역(=버퍼 메모리)이 필요한데, 버퍼 메모리의 확보도 접속을 할 때 실행된다. 📙 2. 맨 앞부분에 제어 정보를 기록한 헤더를 배치한다. 제어 정보는 'TCP 헤더에 기입되는 정보'와 '소켓(프로토콜 스택의 메모리 영역)에 기록되는 정보'로 나뉜다..