티스토리 툴바


닭고기 vs 치킨

국어 2012/01/19 18:40
내가 어렸을 때는 '치킨'이라는 말 보다는 '닭고기', '통닭' 같은 말이 일반적으로 사용됐다. 닭고기를 튀겨 파는 가게는 통닭집이라 불렀다. 그런데 언제부터인지 '치킨'이란 말이 사용되기 시작하더니 이제는 '닭고기'를 뜻할 때는 의례 '치킨'이란 말을 사용한다. 우리말을 올바르게 사용하는 데 앞장서야 할 방송사도 마찬가지다. 드라마, 쇼 프로그램, 뉴스 할 것 없이 모두 '치킨'이란 외국어를 사용한다.

우리말은 빠른 속도로 영어로 오염되고 있다. 사람들은 '팩트'가 어쩌구 저쩌구 말하고, '고객의 니즈'가 어쩌구 저쩌구 말하며, '리얼리티'가 어떻다고 말하기도 한다. '팩트'는 '사실'로, '니즈'는 '필요'로, '리얼리티'는 '사실성'으로 쓴다고 해서 원래 말하려는 뜻을 나타내기가 어려울까? 예를 들자면 끝도 없을 것이다.

'닭고기' 또는 '통닭'이라고 말하면 왠지 촌티나는 것 같고 '치킨'이라고 해야 있어 보인다고 생각하는 사람들이 늘어나는 것 같다. 그래서 바보상자에 나오는 정치인들이 '사실'이라고 말해도 되는데 굳이 '팩트'라고 말하는지도 모르겠다. 좀더 유식해보이고 싶어서, 좀더 잘나 보이고 싶어서.

예전에는 국한문을 혼용하거나 적어도 병기해야 한다고 주장하는 사람들이 있었다. 국어 단어의 70%가 한자어로 되어 있기 때문에 한자로 써놓지 않으면 이해하기가 어렵다는 것이었다. 아직도 이렇게 생각하고 있는 사람들이 있는지는 모르겠지만, 지금 상태로라면 한 세대쯤 지난 다음에 국영 혼용 또는 병기를 해야 한다고 주장하는 사람들이 생길지도 모르겠다. 국어 단어의 OO%가 영어 단어로 되어 있으니 영어를 병기하지 않고는 정확한 뜻을 이해하기 어렵다고 할지도 모를 일이다.

분별없이 영어 단어를 섞어쓰며 말하는 것은 별로 멋있어 보이지 않는다. 그저 잘난척 하는 재수없는 인간으로만 보일 뿐이다.
저작자 표시 비영리 변경 금지
Posted by ntalbs

NoSuchMethodError

programming 2011/08/12 22:54
CI서버에서 대략 삼분의 일 정도의 테스트가 실패하고 있었다. 로그를 확인해보니 어이없게도 실패하는 테스트에서 NoSuchMethodError가 발생했고, 모두 Google의 컬렉션 라이브러리를 사용하는 부분이었다. 이클립스에서 테스트를 실행시킬 때는 아무런 문제가 없는데 CI 서버에서는 실패하는 것이었다.

에러 이름으로 보자면 메서드를 찾지 못해 생기는 문제다. 컴파일할 때와 실행할 때 클래스패스에 차이가 있다면 이런 문제가 발생할 수 있다. 그러나 문제가 생기는 라이브러리는 guava-r09.jar 파일에 있는 것으로, 가져다 쓰는 것이고, 컴파일 할 때나 실행할 때 같은 파일을 클래스패스에 추가했기 때문에 이런 문제가 생기는 이유를 알 수 없었다.

조금 더 확인을 해보니, 내 PC에서도 Ant 태스크로 JUnit 테스트를 돌릴 때 동일한 문제가 발생한다는 것을 알게 되었다. 이클립스에서 그냥 돌릴 때와 Ant로 돌릴 때의 차이점이 무엇일까? 아무리 생각해도 알 수 없었다. 혹시 guava 라이브러리가 클래스패스에 중복해 존재하는지 확인하기 위해 클래스패스의 모든 jar 파일을 확인하기도 했다. 분명 클래스패스에 중복된 클래스가 있고, 클래스 로더가 내가 원하는 클래스가 아닌 다른 클래스를 로딩해 발생한 문제인 것은 알겠는데, 그 이상 나아갈 수가 없었다.

이렇게 어제 하루를 날렸다. 오늘 아침에 다시 구글로 검색을 하다가 귀중한 정보를 찾았다. JVM 파라미터 중에 로딩되는 클래스 정보를 표시하도록 하는 옵션이 있다는 것이다.
 java -verbose:class <other args=>
옵션을 추가해 테스트를 실행해보니 문제를 바로 확인할 수 있었다. com.google.common.collect.Maps 클래스를 내가 의도한 guava-r09.jar가 아닌 checkstyle-5.3-all.jar에서 로딩하고 있는 것이었다. 허거덕! 결국 이클립스에서 테스트를 실행시킬 때와 Ant로 돌릴 때와의 차이점은, Ant로 돌릴 때 정적 분석을 위해 클래스패스에 추가한 몇몇 jar 파일이었다. Checkstyle의 jar 파일에 Google 컬렉션 라이브러리 클래스가 함께 들어있어 이 때문에 문제가 생기리라고는 상상도 하지 못했다.

물론 이건 설정을 잘못한 문제다. 테스트를 실행할 때 checkstyle-5.3-all.jar가 클래스패스에 있어야 할 이유는 전혀 없다. checkstyle-5.3-all.jar는 Checkstyle을 돌릴 때만 필요하다. 빌드 스크립트를 만들 때 클래스패스를 구분하기 귀찮아 그냥 하나의 변수에 몰아넣고 아무데서나 이 변수를 참조해 쓴 게 잘못이다.

구글에서 NoSuchMethodError로 검색했을 때 상위에 나오는 국내 블로그 글들은 문제에 대한 설명은 있지만 해결하는 방법에 대한 설명은 부족해 보인다. 그냥 중복된 jar 파일이 있는지 확인해 지우니 잘 되더라 하는 정도다.

정확한 문제 해결 방법을 정리하자면 다음과 같은 정도가 될 것 같다:
java를 실행시킬 때 -verbose:class 옵션을 주어 에러가 발생하는 클래스가 원하는 jar 파일(또는 클래스패스)에서 로딩되었는지를 확인한다.

저작자 표시 비영리 변경 금지
Posted by ntalbs
Hudson에서 JsTestDriver를 이용해 커버리지 분석 설정에서 JsTestDriver로 작성한 테스트에 대해 커버리지를 어떻게 볼 수 있는지 설명했다. 그런데 이렇게 테스트 커버리지를 분석할 때 한 가지 문제가 있다. JavaScript로 프로그램을 작성할 때 외부 라이브러리를 사용하는 경우가 많은데, 커버리지 분석 리포트에 외부 라이브러리 코드까지 포함되어 전체 커버리지 낮게 나온다는 점이다.

그런데 이 문제도 의외로 간단하게 해결할 수 있다. (아래 내용은 옆팀 동료가 알려준 것이다.) JsTestDriver의 coverage 플러그인은 JsTestDriver 실행시 지정한 testOutput 디렉터리에 LCOV 포맷의 <config filename>-coverage.dat 파일을 생성하는데, 이 파일은 텍스트 파일이며 다음과 같은 형식으로 되어 있다.
SF:/.../.../.../src1.js
DA:10,1
DA:11,1
DA:12,1
...
end_of_record
SF:/.../.../.../src2.js
DA:12,1
DA:13,1
DA:16,1
...
end_of_record
...
각 파일에 대한 커버리지 정보를 가지고 있는데, SF:{파일경로+파일이름}으로 시작하고 end_of_record로 끝났다. 따라서 간단한 프로그램을 짜서 불필요한 파일에 대한 정보를 날린 다음 커버리지 리포트를 만들면, 제외하고 싶은 파일을 제거한 상태의 커버리지 리포트를 만들 수 있다.

이런 작업은 스크립트 언어로 처리하면 쉬울 것 같다. 회사 CI 서버에 python이 깔려 있어 python으로 간단하게 작성해봤다. (다듬을 여지가 많이 있다. 예를 들어 input_file을 명령행 인수로 받도록 처리할 수도 있겠다.)
import shutil
excludeList = open('exclude_coverage.txt').readlines()
input_file = '/.../.../jsTestDriver.conf-coverage.dat'
output_file = '/.../.../excluded.dat'

input = open(input_file, 'r')
output = open(output_file,'w')

skip = False
for l in input:
    if l.startswith('SF:'):
        jsName = l.split('/').pop()
        if excludeList.count(jsName) > 0:
            skip = True
    if not skip:
        output.write(l)
    if l.startswith('end_of_record'):
        skip = False

input.close()
output.close()

shutil.move(output_file, input_file)
exclude_coverage.txt 파일에 커버리지 분석에서 제외하고 싶은 파일 이름을 넣으면, 이 프로그램이 JsTestDriver의 커버리지 데이터 파일(...-coverage.dat)을 읽어 exclude_coverage.txt에 기술한 파일을 제외한다. exclude_coverage.txt 파일은 다음과 같은 식으로 작성하면 된다.
 
external-lib1.js
external-lib2.js
external-lib3.js
...
그리고 CI서버에서 genhtml을 실행하기 전에 위에서 작성한 python 프로그램을 실행하도록 설정한다.


빌드해보면 JavaScript 커버리지 리포트에 제외하고 싶었던 파일에 대한 커버리지가 빠져 있는 것을 확인할 수 있다.

참조

저작자 표시 비영리 변경 금지
Posted by ntalbs