nGrinder에서 Groovy script 사용시 java.lang.UnsupportedOperationException 발생

nGrinder에서 Groovy Maven Project를 만들어 사용할 때, 특히 IntelliJ를 사용하려면 Import Groovy Maven Project in IntelliJ를 참조하면 된다.

잘 될 것 같았는데 Unit test에서 시작부터 아래와 같은 에러가 발생했다.

한참을 검색해본 결과 Eclipse의 경우 build 설정시 Groovy 라이브러리를 지우는 과정이 있다는 것을 알게 되었다.
혹시나 IntelliJ에서도 같은 문제일까 해서 Groovy libraries를 모두 지웠더니(File > Project Structure) 아무 문제 없이 잘 작동하기 시작했다.

Groovy를 사용하면 종종 예상치 못한 일을 만나게 된다고 하는데 – 예를 들어 “Using Groovy? Prepare for the unexpected!” – 이런 일을 겪을 때면 아무래도 이 언어의 ‘한계’ 같은 것이 느껴진다.

Java 7의 Project Coin 중 몇가지

Java 7 (그리고 8)에 포함된 Project Coin 중 유용하지만 (상대적으로) 자주 언급되지 않은 몇 가지.

Binary Literals

Java 7 이전에는 binary 값으로 무언가 하려 하면 ‘parseX’ 메소드를 써야 했다.
예를 들어 “1100110”을 십진수 102로 변수에 지정하려면 아래와 같았다.

하지만 Java 7 부터는 아래와 같다. (왠지 너무나 당연하다)

또다른 재미있는 것 하나는, 긴 숫자 사이에 ‘_’ (underscore)를 넣어 표현할 수 있다는 것이다. (Ruby에서 아이디어를 가져왔다고 한다)
이 ‘_’는 compiler가 나중에 다 지워버리기 때문에 상관없다.

아래 예를 보면 가독성이 확실히 차이남을 알 수 있다.

TWR(Try-with-resources)

Project Coin 쪽에 본 기능에 대한 제안이 도착했을 때 밝혀진 놀라운 사실 하나는, JDK 내 close()를 사용한 code 60% 이상이 bug를 내포하고 있었다는 것이다. (사실 사용한 resource를 100% 확실하게 close 하는 것이 쉽진 않다)

아래 내용은 TWGJD(The Well-Grounded Java Developer, 2013)에서 가져온 것이다.

코드를 보면 InputStream이나 File (즉 OutputStream) 어느 쪽에서도 뭔 일이 벌어질 수 있고, 특히 이런 식으로 exception이 엉켜있게 되면 문제가 생겼을 때 처리하기 여간 성가신 것이 아니다.

그래서, 아래와 같은 문법이 등장했다.
즉 exception이 발생하게 되면 자동으로 모든 열려있는 resource를 close 해준다.

한가지 주의할 점은, 아래와 같은 code는 ObjectInputStream 생성 중 에러가 발생할 경우 FileInputStream을 close 하지 못할 수 있다.

해결책은, 좀 덜 멋있더라도(?) 분리해놓으면 된다.
아래와 같이.

생산성을 갉아먹는 메신저 프로그램 (Collaborative software)

New York Times의 ‘Meet the Life Hackers‘란 기사를 보면 interruption 이후 다시 본래 task로 돌아가는데 약 25분이 소요된다고 한다.


When Mark crunched the data, a picture of 21st-century office work emerged that was, she says, “far worse than I could ever have imagined.” Each employee spent only 11 minutes on any given project before being interrupted and whisked off to do something else. What’s more, each 11-minute project was itself fragmented into even shorter three-minute tasks, like answering e-mail messages, reading a Web page or working on a spreadsheet. And each time a worker was distracted from a task, it would take, on average, 25 minutes to return to that task. To perform an office job today, it seems, your attention must skip like a stone across water all day long, touching down only periodically.

꽤나 유명한 논의였던만큼 해당 수치에 대해 이런 저런 반론도 있었지만, 그런 건 차치하고라도 원래 작업에 복귀하는데 드는 에너지가 상당한 것은 경험으로 아는 사실이다.

특히나 요즘은 메신저 프로그램 – 정확히 말하면 Collaborative software – 때문에 거의 신경쇠약 직전이다.
팀에서는 Flowdock을 쓰는데, ‘Mute’를 해놓지 않으면 거의 업무가 불가능하다. Slack, HipChat, Flowdock 등 많은 서비스들이 ‘생산성’을 이야기하는데 그건 정말 한 단면만 보고 이야기하는 것이다. 즉, ‘방해를 하는 사람’ 입장에서의 생산성이지 ‘방해를 받는 사람’ 입장에서는 정말이지, 지옥 같다. (신경이 갈갈이 찢어지는 느낌)

이번에 신규로 채용한 Backend 개발자들에게는 그래서 일부러 계정을 만들어 주지 않았다.
결국 그들은 아무런 방해 없이 주어진 업무에만 집중할 수 있었고 무리 없이 일정대로 마칠 수 있었지만, Integration Test 시 UK에 있는 Client 개발자가 여기 Germany에 있는 Backend 개발자와 제때 제때 feedback을 주고 받지 못해 심한 병목현상이 발생했다.

결국 Backend 개발자들도 Flowdock을 쓰도록 했지만, 아직도 맞는 판단인가 아직도 의구심이 든다. 사실, 정답이 있기는 있는 문제인가 싶기도 하고.
방해 받는 사람은 되고 싶지 않지만, 업무의 (빠른) 진행을 위해 방해 하는 사람이 될 필요가 있기 때문이다.
사용 규칙을 만들 수도 있지만, 가뜩이나 복잡도가 높은 소프트웨어 개발 업무 와중에 이런 저런 규칙까지 지키라고 주문하기는 부담스럽다.

최적의 Solution이 나오기 까지는 계속 관찰할 필요가 있을 것 같다.

Google Test 빌드 및 설정

1. gtest 빌드하기

gtest-1.6.0.zip 다운로드 후 적당한 곳에 압축을 푼다.
아래 설명은 D:\gtest-1.6.0 에 위치하고 있다고 가정하고 있다.

이제 *.lib를 만들어내야 하는데 README를 보면 CMake를 이용하기를 권장하고 있다.
cross-platform 하게 makefile 또는 project 파일을 만들어낼 수 있으니 멋지긴 한데, 귀차니즘이 발동하면 D:\gtest-1.6.0\msvc 에 있는 solution 파일들을 그냥 사용해도 된다.

해당 폴더에는 두개의 solution 파일이 있는데, gtest-md.sln은 Microsoft runtime libraries의 DLL versions을 이용하는 반면 gtest.sln은 Microsoft runtime libraries의 static versions을 이용한다.
중요한 것은, gtest를 build 시 내 프로젝트(향후 테스트를 적용할)의 C++ Code Generation setting과 정확히 맞아야 한다는 것이다. (Project 속성 > 구성 속성 > C/C++ > 코드 생성 에서 ‘런타임 라이브러리’ 확인)
나는 보통 static versions of the runtime libraries를 이용하며 /MT 또는 /MTd로 주로 셋팅한다. 즉 gtest.sln을 사용해야 한다.

하지만, 결국 CMake를 이용했는데 상기 방법을 이용시 $(TargetName) 등으로 인한 warning이 발생했기 때문이다. (warning을 아주 싫어한다)
수정해서 진행할까 하다가 그냥 공식적인 방법을 쓰기로 결정했다. (어렵지도 않다)

20120808_gtest_1

상기 화면과 같이 순서대로 처리 후 D:\gtest-1.6.0\lib\gtest.sln을 더블클릭 하여 VS를 연 다음 ‘솔루션 빌드’를 한다. D:\gtest-1.6.0\lib\Debug에 가면 gtest.lib와 gtest_main.lib가 만들어져 있는 것을 볼 수 있다.

2. gtest 내 sample 테스트

gtest-1.6.0\samples 에 보면 멋진 sample들이 있다. 그중 첫번째 sample을 선택해서 VS 내에 구성해보기로 했다.

20120808_gtest_2

먼저 ‘Google Test’란 solution을 만들고 그 안에 Example이란 프로젝트와 ExampleTest란 프로젝트를 구성했다.
최종구현물이 될 프로젝트에 unit test part가 섞여 있으면 너무 복잡해지고 별로 보기도 안 좋기 때문에 Eclipse에서 JUnit 사용할 때 같이 따로 분리를 하였다.
sample1.cc은 Example 내에, sample1_unittest.cc는 ExampleTest에, sample1.h는 양쪽에 모두 지정했다. (소스 보면 알겠지만 두 *.cc가 모두 참조한다)
ExampleTest에 main()이 필요한데 이는 gtest-1.6.0\src\gtest_main.cc를 copy하면 된다. 이 소스 안에 보면 RUN_ALL_TESTS() 매크로가 있는데 이 친구가 모든 테스트를 알아서 다 돌려주기 때문이다.

이제 각 프로젝트의 속성을 변경해야 한다. Example에서는 별로 할 것이 없는 반면, ExampleTest에서는 몇가지 신경 쓸 것들이 있다.

Example에서,

  • 구성 속성 > 일반 내 ‘구성 형식’을 ‘정적 라이브러리(.lib)’로 한다. sample1.cc가 main()을 가지고 있지 않은 library 프로젝트이기 때문이다.
  • 구성 속성 > C/C++ > 코드 생성 내 ‘런타임 라이브러리’가 /MTd 로 되어 있는 지 확인한다. 앞서 gtest를 이 방식으로 빌드했기 때문이다.

ExampleTest에서,

  • 공용 속성 > 프레임워크 및 참조 로 가서 ‘Example’을 추가한다.
  • 구성 속성 > C/C++ > 일반 내 ‘추가 포함 디렉토리’에 D:\gtest-1.6.0\include; 를 추가한다.
  • 구성 속성 > C/C++ > 코드 생성 내 ‘런타임 라이브러리’가 /MTd 로 되어 있는 지 확인한다.
  • 구성 속성 > 링커 > 일반 내 ‘추가 라이브러리 디렉토리’에 D:\gtest-1.6.0\lib\Debug; 를 추가한다.
  • 구성 속성 > 링커 > 입력 내 ‘추가 종속성’에 gtest.lib;gtest_main.lib; 를 추가한다.
  • (옵션 사항) 구성 속성 > 빌드 이벤트 > 빌드 후 이벤트 내 ‘명령줄’에 “$(TargetDir)$(TargetFileName)” 를 입력한다. (겹따옴표를 잊지 말도록) 이렇게 설정하면 빌드 직후 출력창에 테스트가 곧장 실행되는 것을 확인할 수 있다.

빌드 하면 아래와 같이 빌드 직후 unit test가 실행되는 것을 볼 수 있다.

추가로,

  • 빌드 시 exe를 못찾겠다고 불평할 때가 있다. 이 경우, 구성 속성 > 일반 내 ‘출력 디렉토리’를 ‘$(SolutionDir)$(ProjectName)\$(Configuration)\‘로 변경해본다.
  • 출력창에서 보면 더 보기 좋게 출력결과가 나온다. 이를 위해 빌드 직후 Ctrl-F5로 곧장 실행하면 Unit Test 수행 하자마자 곧바로 창이 닫혀버리는 문제가 있다. 이를 위해 gtest_main.cc를 살짝 고쳤다.

결과는 아래와 같다.

20120808_gtest_3

TomorrowNow

TomorrowNow 판결이 난 지도 이틀이 지났는데 상대적으로 조용하다.
금액이 워낙 황당해서 – $1.3B, 즉 1조 5천억원 – 아무래도 여파가 길 줄 알았는데, 직원들에게 부담은 없을 것이라는 사내메일을 빠르게 보내는 등 조기에 수습하려는 듯. (하긴 SAP 한 회사의 revenue만도 전 세계 GDP rank(nominal) 중간을 간다)

이슈 자체가 X팔리는 것이라 그럴 수도 있겠다. 하지만 래리의 대응을 보면 피해자라기보다 끊임없이 적만 양산하는 듯 하다. 별로 더 나아보이진 않는다. 쯧쯧.

Reference

C++을 자주 쓸 일이 없어 그런지 아직도 이따금 헷갈리는 reference. 몇가지만 적어두자.

  • 호출부가 call-by-value와 똑같다. (이것때문에 call-by-value 함수와 헷갈리기도 한다)
  • 함수 원형이 plusref2(int &a) 식으로 레퍼런스를 받는다. 함수 본체 내에서는 call-by-value로 받은 마냥 전달받은 인수를 사용한다. 예를 들어 구조체를 받으면 -> 로 억세스하는 것이 아니라 . 으로 한다.

아래는 구조체 호출의 예이다.

STL에서 배열의 값을 find를 써서 찾을 때는 다음과 같다.

find의 first, last 인자와 리턴이 같은 타입의 iterator라는 것을 고려하면 배열에 대해 find를 사용할 때 int *prt = find(&a[0], &a[5], 849); 로 했는지 이해가 간다. (&a[0]는 a[0], 즉 첫번째 값의 주소)가

assert

종종 assert를 쓸까 말까 고민할 때가 있다. 아래 내용을 늘 기억하도록.

  • if 문을 써서 프로그램을 exit 해도 되지만 왜 그렇게 되었는지는 assert를 쓰는 것이 더 명확하다. (NetWeaver에서는 Dump 화면과 똑같이 보이기 때문에 좀 시껍하긴 하다)
  • debugger를 통해서도 오류를 알 수 있지만 assert를 쓰면 문제가 발생한 시점과 원인을 명확히 드러낼 수 있다.
  • 많이 써도 성능에는 상관없다.
  • 절대로 발생해서는 안되는 조건에 대해서 사용하는 것이지 정상적인 에러 상황을 처리하는 문장이 아니니 오용하지는 말자.

사실 assert는 OOP에서 쓰기에 좀 문제가 있다. 이에 대한 해결방안으로 Design by contract가 있겠지만 – C#의 Code Contracts 같은 – ABAP에서는 아직 지원되지 않고 있는 듯 하다.

Event handing in ABAP Object

아래는 SAP Help에서 가져온 예제이다.

정리하면, 3가지 역할이 필요하다. 즉, 1) Event를 등록하고 2) Event를 발생(Raise)하고 3) 발생된 Event를 handling 하는 것. 여기서는 ‘Event Trigger’ 클래스에서 1)과 2)를, ‘Event Handler’ 클래스에서 3)을 처리하는 방식을 취하고 있다.

구체적으로 보면,

  • SET HANDLER 구문은 handler table를 만든다. 이 테이블은 ① handler methods의 이름과 ② 그 handler를 갖고 있는 클래스 인스턴스의 reference로 구성되어있다.
  • 상기 클래스 인스턴스는 초기화 되더라도 garbage collection 대상이 되지 않는다. Handler table에 등록되어 떡 버티고 있기 때문이다.
  • For static events, the system creates an instance-independent handler table for the relevant class.