라이브러리에 익숙치 않으면 발생할 수 있는 문제
아래는 무작위 수를 백만 개를 생성한 다음, 그중 중간 값보다 작은 게 몇 개인지를 출력하는 코드다.
static Random rnd = new Random();
static int random(int n) {
return Math.abs(rnd.nextInt()) % n;
}
public static void main(String[] args) {
int n = 2 * (Integer.MAX_VALUE / 3);
int low = 0;
for (int i = 0; i < 1000000; i++) {
if (random(n) < n/2) {
low++;
}
}
System.out.println(low);
}
괜찮은 듯 보여도 적지않은 문제를 내포하고 있다.
- n이 그리 크지 않은 2의 제곱수라면 얼마 지나지 않아 같은 수열이 반복된다.
- n이 2의 제곱수가 아니라면 몇몇 숫자가 평균적으로 더 자주 반환된다. n 값이 클수록 이 현상은 더 두드러진다.
- 무작위 수를 백만개를 선택한 다음, 그중 중간 값보다 작은 게 몇개인지 출력하는 테스트를 진행했다.
random 메서드가 이상적으로 동작한다면, 약 50만 개가 출력돼야 하지만, 실제로 돌려보면 무작위로 생성된 수 중에서 2/3 가량이 중간값보다 낮은 쪽으로 쏠려 666,666에 가까운 값을 얻는다.
- 무작위 수를 백만개를 선택한 다음, 그중 중간 값보다 작은 게 몇개인지 출력하는 테스트를 진행했다.
- 지정한 범위 '바깥'의 수가 종종 튀어나올 수 있다.
rnd.nextInt()
가 반환한 값을Math.abs
를 이용해 음수가 아닌 정수로 매핑하기 때문에 지정한 범위의 바깥 수가 반환될 수 있다.nextInt()
가Integer.MIN_VALUE
를 반환하면,Math.abs
도Integer.MIN_VALUE
를 반환하고, 나머지 연산자(%)는 음수를 반환해버린다.
그럼 이 문제들을 어떻게 해결해야 할까?
표준 라이브러리의 이점
위 결함들을 해결하려면 의사난수 생성기, 정수론, 2의 보수 계산 등에 조예가 깊어야 한다.
하지만, 이미 Random.nextInt(int)
메서드가 이런 문제를 해결해주고 있기 때문에 우리가 직접 해결할 필요는 없다.
표준 라이브러리를 사용하면 그 코드를 작성한 전문가의 지식과 앞서 사용한 다른 프로그래머들의 경험을 활용할 수 있다.
이것이 가능한 이유는 이 알고리즘에 능통한 개발자 및 전문가 들이 설계부터 검증까지 해놓았기 때문이다. 그리고 혹시 버그가 발겨노디더라도 다음 릴리스에서 수정될 것이다. 이처럼 표준 라이브러리를 사용하면 그 코드를 작성한 전문가의 지식과 앞서 사용한 다른 프로그래머들의 경험을 활용할 수 있다.
핵심적인 일과 크게 관련 없는 문제를 해결하느라 시간을 허비하지 않아도 된다는 것이다.
프로그래머들은 하부 공사를 하기보다는 애플리케이션 기능 개발에 집중하고 싶어한다.
따로 노력하지 않아도 성능이 지속해서 개선된다.
사용자가 많고, 업계 표준 벤치마크를 사용해 성능을 확인했기 때문에 표준 라이브러리 제작자들은 더 나은 방법을 꾸준히 모색할 수 밖에 없을 것이다. 이런 환경에서 자바 플랫폼 라이브러리의 많은 부분이 수 년에 걸쳐 지속해서 다시 작성되고, 성능이 극적으로 개선되기도 한다.
기능이 점점 많아진다.
라이브러리에 부족한 부분이 있다면 해당 라이브러리를 사용하는 개발자들의 커뮤니티에서 이야기가 나올 것이고, 그 부분에서 논의된 후 다음 릴리스에 해당 기능이 추가되기도 한다.
내가 작성한 코드가 많은 사람에게 낯익은 코드가 된다.
표준 라이브러리를 사용하게 되면 자연스럽게 다른 개발자들이 더 읽기 좋아지고, 유지보수하기 좋고, 재활용하기 쉬운 코드가 될 것이다.
그럼에도 불구하고 직접 구현하는 이유
이렇게 많은 이점을 가진 표준 라이브러리가가 있지만, 실상은 많은 프로그래머가 직접 구현해 쓰고 있다.
왜 그럴까?
대부분 이유는 라이브러리에 그런 기능이 있는지 모르기 때문이다.
메이저 릴리스마다 주목할 만한 수많은 기능이 라이브러리에 추가되고 있다.
이렇게 라이브러리가 너무 방대하면 모든 API 문서를 공부하기는 벅찰 수 있다.
그럼 어느 정도까지 알아야 할까?
책에서는 자바 프로그래머라면 적어도 java.lang
, java.util
, java.io
와 그 하위 패키지는 알아두길 권장하고 있다.
이후, 다른 라이브러리들을 필요할 때마다 익히는 것을 함께 권장하고 있다.
라이브러리가 필요한 기능을 충분히 제공하지 못하는 경우
때때로 라이브러리가 필요한 기능을 충분히 제공하지 못할 수 있다. 더 전문적인 기능을 요구할수록 이러한 현상은 더 자주 발생할 것이다. 이때는 우선은 라이브러리를 사용하려고 시도해보고, 해당 라이브러리가 원하는 기능이 아니라 판단되면 그때 대안을 사용하도록 하는 것이 좋다. 어떤 라이브러리든 제공하는 깅은 유한하다. 이땐 항상 구멍이 존재하기에 자바 표준 라이브러리 또한 원하는 기능이 없을 수 있다. 그럼 그다음 선택지는 고글의 구아바 라이브러리 같은 고품질의 서드파티 라이브러리에서 대안을 찾아보도록 하자.
정리
바퀴를 다시 발명하지 말자. 나만의 특별한 기능이 아니라면 누군가 이미 라이브러리 형태로 구현해놓았을 가능성이 크다. 이러한 라이브러리 코드는 일반적으로 우리가 작성한 코드보다 품질이 좋고, 개선의 가능성 또한 크기에 바퀴를 다시 발명하기 전에 있는 지 먼저 찾아보도록 하자.