Github 2015년말~2016년말 매일매일 코딩 기록 프로그래밍

2015년 말에 어쩌다보니10여일간 거의 연속으로 코딩을 한 적이 있다.
그래서 시작한 김에 1년간 해볼까? 하고 계속 진행했다. 나의 Github.



위는 2015년 11월말부터 2016년 11월 26일까지의 기록이다. 휴가기간에도 노트북을 들고가서 쉬는시간에 짬을내어 무엇인가를 코딩해서 올렸다.
10월달에 회식자리에서 집에갔더니 12시가 넘어서 딱 한 번 빼먹었다.

1년간 회고를 해보자면,

좋은 점은 꾸준한 학습에 나름 많은 도움이 됐다. 무언가를 하루도 거르지 않고 할 수 있다는 그 자체가 사실 큰 의미를 주고, 나도 할 수 있다는 자신감으로 다가온다.

하지만 문제가 있다.
공부가 제일 쉬웠어요. - 사실 공부가 제일 쉽다. 올 1년을 제외한 그 전의 나의 Github 활동은 세상에 없던 것들을 만드는데 많이 할애 되었었으나, 매일 매일 코딩을 시작한 뒤에는 Github이 거의 남의 것을 학습하고 그 것을 기록하는 용도로 변형 되었다. 매일매일 코드를 남기는데는 이게 훨씬 편하다. 스스로 생각하고 창조하다보면 시간이 너무 많이 가고 실제 코딩량은 현저히 줄게 된다.

나 정도 경력자가 되면 공부도 공부지만 창조를 해야한다. 내가 블로그에 글을 쓰면서도 언제부터인가 원칙으로 삼는 것이 있는데, 바로 남의 것을 번역하거나 정리해서 전달하지 말고, 혹은 현재 트렌드를 소개하는 식의 글을 지양하고 나만의 무언가를 글로 남기자는 것이다(그 때문에 글쓰는 양이 현저히 줄어들었다).

2017년에도 계속해서 할 수 있는 데까지 매일매일 코딩을 하겠지만, 휴가 기간은 이제 편히 쉬는데 집중하고, 또한 학습 코딩 비중을 낮추고 비록 허접하더라도 세상에 없는 나만의 무엇인가를 만드는데 집중할 수 있도록 노력해야겠다.

FindBugs 적용 후 흔히 발생하는 버그 패턴들 프로그래밍

회사의 모든 프로젝트는 FindBugs 지표 수집을 하게 돼 있는데 이를 SonarQube를 통해 프로젝트 건강성 지표로만 삼고 있었다(findbugs, jacoco code coverage, checkstyle, pmd 등을 수집한다).
하지만 지표는 참조일뿐 강제가 아니고, 바쁘면 바쁘다는 핑계로 무시하게 마련이다.

그러다가 팀원들과 팀 프로젝트에서 FindBugs 의 버그 탐지를 단순 지표가 아닌 build 실패로 간주하도록 (빌드가 실패하면 당연히 배포 불가이다) 하기로 논의하여 결정하고 적용했더니 매주 1~2건씩은 배포 전에 버그를 탐지해 막아주고 있다(물론 이 버그들은 코드 Coverage 100%의 테스트를 했다면 발생하지 않았겠지만 그건 다음에...).
물론 Build 행위는 Jenkins + Gradle 조합으로 이뤄지며 Jenkins의 FindBugs 플러그인으로 FindBugs 의 버그가 탐지되면 빌드 실패로 간주하고 배포를 불가능하게 설정하였다.

FindBugs는 가급적 단순 지표가 아닌 실제 배포 가능 여부를 가늠하는 도구로써 버그 탐지시에는 실질적으로 컴파일이 안 된 것과 마찬가지로 취급하는 것이 좋겠다.

지금까지 내가 본 흔히 나오는 버그 패턴은 다음과 같다(컴파일은 되지만 100% 버그이므로 따라하면 안됨!!).

1. null 체크해놓고 그 객체 호출하기(보통은 logging 시에 실수로 호출함)
if (a == null) {
....
    log.debug("a.something {}", a.getSomething()); // 로깅 코드에서 null pointer exception이 발생해서 로그도 안남고 에러가 남.
}


2. 서로 다른 타입간의 equals 호출
Integer a = ..;
Long b = ..;
if (a.equals(b)) { // 언제나 false
...
}


또한 흔한게 enum 과 String 비교.
String enumValue = "..";
if (SomeEnum.ENUMVALUE.equals(enumValue)) { // 언제나 false
...
}


enum은 아예 equals()를 사용하지 말고 == 비교를 하는 게 낫다.

3. 숫자 Wrapper 객체 동일성 == 비교
Integer a = new Integer(1);
Integer b = new Integer(1);
if (a == b) { ... } // false이다.


Wrapper 객체는 equals() 로 비교해야 한다.

4. List/Map 등 컬렉션에서 엉뚱한 객체로 get 하기
안타깝게도 List.indexOf()와 Map.get()은 인자로 지정된 Generic Type을 받는게 아니라 Object를 받는다. 이로 인해 버그가 발생한다(이렇게 한 이유가 있겠지...).
List<Integer> integers = ...;
Long someLongValue = 1L;

// Integer 1 값이 리스트에 있어도 올바로 판단 못함
if (integers.indexOf(someLongValue) >= 0) { // false이다.
...
}


Map.get()도 마찬가지이다. 특히 이 경우의 버그가 많이 발생한다.
Map<Integer,String> map = new HashMap<>();
map.put(1, "하나");
map.put(2, "둘");

System.out.println(map.get(1L)); // null


예제에서는 단순화하려고 값을 직접 넣었지만 대부분은 메소드 파라미터로 받았기 때문에 코드의 호출부에서는 파라미터의 타입이 눈에 안 띄어서 버그여부를 인지하기가 쉽지 않다.

위에서 보다시피가장 많은 버그는 메소드의 인자가 Object 일 때 발생한다(equals, List.indexOf, Map.get). 컴파일 에러가 안나기 때문이다.

FindBugs 가 정착이 다 되면, 이후에는 다음과 같은 것도 해볼까 생각중.
  1. Jenkins JaCoCo Plugin 을 통해 현 시점의 코드 커버리지를 임계치로 설정하고 임계치보다 떨어지면 빌드 실패하게, 그리고 1주일에 1%씩 임계치 증가시키키(아무튼 최소한 커버리지를 떨어뜨리지는 못하게)
  2. Jenkins CheckstyleJenkins PMD 적용하고 임계치를 서서히 증가시키기

위 툴들은 우리회사에서는 이미 SonarQube를 통해 지표 수집은 다 하고 있는 것들이다. 거기에 강제성을 부여하는 것만 더 하고 싶은 것.


마지막으로.. FindBugs가 버그를 찾아줬으니 버그가 없다는 착각 따위는 하지 말 것. 결국은 열심히 단위 테스트를 해야 한다..

단점 : 빌드 시간이 너무 길어져서 배포 시간이 증가했다... ㅜㅜ


1 2 3 4 5 6 7 8 9 10 다음