오늘 회사 채팅창에 데이터 바인딩 라이브러리 이야기가 잠깐 나와서 살펴봄..

(도대체.. 이게 소개된 게 Android Plugin for Gradle 1.5.0-alpha1 이후 부터인데 이제야..)


사내 프로젝트에서는 버터나이프조차도 쓰는 일이 없어서, 어떤 것인가 살짝 맛만 봄...


(참고 사이트)

구글 개발자 문서

https://developer.android.com/topic/libraries/data-binding/index.html#build_environment


박상권님의 블로그 - basic, butterknife, data binding 3개의 코드를 비교해 놓은 샘플이 보기 좋음

http://gun0912.tistory.com/71



(결론)

findViewById() 없이 xml의 View를 자동으로 Binding 해 준다.

그래서 실제 로직과 관계없는 바인딩 코드를 없애줘서 소스의 가독성이 높아진다.

반응형

설정

트랙백

댓글

[PKI] 보안에서 말하는 PKI의 기본 개념 간단 설명


PKI 에 대해서 간단히 잘 설명해 놓은 글이 있어 기억해 둠...


반응형

설정

트랙백

댓글

아니다. 단지 GC의 성능을 나쁘게 만들 뿐이다.

 

아래의 예를 보자.

 

Main.java

public class Main {

    Outer outer;

 

void alloc() { outer = new Outer(); }

void free() { outer = null; }

}

 

Outer.java

public class Outer {

    Inner inner = new Inner();

 

public class Inner {

}

}

 

 

non-static inner 클래스는 outer 클래스에 대한 암묵적인 레퍼렌스를 가진다.

Main 클래스의 alloc() 메소드와 free() 메소드를 차례대로 실행시키면

객체들은 아래와 같은 레퍼런스를 가지게 될 것이다.

 

 

 

 

먼 옛날(?) Inner Class가 처음 소개되던 JDK 1.1 시절에 쓰여진 글들을 보면

메모리 릭을 발생시킬 수 있다는 글들이 있다.

outer와 inner가 서로의 레퍼런스를 가지고 있어 레퍼런스 카운트가 0이 되지 않아

GC가 메모리를 해제할 수 없다는 생각이 었던 것 같다.

(JDK 1.1 초기에는 실제로 그렇게 동작했을지도 모르지만,

 JDK 1.1을 설치해서 확인하고 싶은 생각까지는 없는 관계로... Pass)

 

하지만 Garbage Collector는 Unreachable object에 대해서 메모리를 해제한다.

메모리가 할당된 object들의 연관 관계를 그래프로 표현한다고 생각해보자.

 

레퍼런스 카운트가 0인 object는 쉽게 찾을 수 있지만,

레퍼런스 카운트가 0보다 큰 object인 경우는,

그래프의 시작 노드에서 모든 노드를 방문했을 때 방문하지 않은 노드를 찾아서

메모리를 해제해야 하기 때문에 Grabage Collector의 성능이 떨어질 수 밖에 없다.

 

이것을 보여주는 적절한 예제를 작성하려 했는데 시간 관계상 패스.

http://stackoverflow.com/questions/20380600/gc-performance-hit-for-inner-class-vs-static-nested-class

위 링크를 참고해 보시라.

 

 

결론:

inner 클래스를 가지는 객체가 빈번하게 만들어지도 버려진다면, (만들어진 객체에

대한 레퍼런스를 유지하지 않는다는 의미. 로컬 메소드에서만 사용되는 것 처럼)

non-static static으로 inner 클래스를 구현하는 것이 어플리케이션 성능을 좋게 만들 것이다.

 

추가로 outer 클래스에 대한 암묵적인 레퍼런스를 없앨 수 있으므로 메모리 절약에도

약간 도움을 줄 수 있을 것이다. (물론 실제로는 아닐 가능성이 더 클것 같다. 

WeakReference를 사용해야 할 경우가 있을 수도 있고, outer 클래스에 직접 접근이

불가능 하므로 필요한 멤버 변수를 추가로 가지고 있어야 할 수도 있다)

 

 

 

다음 글은 이 글을 쓰게 된 동기인 Android의 lint 이슈인 HandlerLeak에 대해서 알아보겠다.

반응형

설정

트랙백

댓글

안드로이드 프로젝트에서 유닛 테스트에 사용할 만한 Test Frame은 Mockito, PowerMock, Roboletric 정도가 있다. 여기에서는 이 셋의 차이점을 알아보고 언제 무엇을 사용할 것인가를 제안하려 한다.


결론부터 말하면 기본적으로 Mockito를 이용하자.

그리고 Mockito의 제한으로 인해 static method 혹은 private method를 테스트 해야 한다면 PowerMock을 이용하자.

가능하다면 Roboletric은 이용하지 말자.

아래에는 각 툴에 대해 살펴보고 이렇게 결론을 내린 이유를 적어본다.



Mockito


mock 객체를 쉽게 만들 수 있게 해주는 도구들 중에는 EasyMock, jMock, Mockito 등이 있으나 현재는 Mockito가 대세이다. 이것은 구글 트렌드에서 확인할 수 있다.



 

http://kwon37xi.egloos.com/4126439 블로그 링크를 보면,  jMock 과 EasyMock을 비교하는데 결론은 엉뚱하게도 Mockito 였다. 글이 2009년에 작성된 글이라 지금은 크게 의미가 없는 내용이긴 하지만 글 마지막에 왜 Mockito로 트렌드가 바뀌었는지에 대한 힌트를 얻을 수 있다. 


그 이유가 Mockito가 마틴 파울러가 이야기한 Mocks aren't Stubs의 원칙을 지키는 프레임워크이기 때문이라고 한다.

(원문글: http://martinfowler.com/articles/mocksArentStubs.html
번역글: http://so-blog.net/2016/05/09/mock_stub/
http://testing.jabberstory.net/)


그리고 여기에 대해 추가로 '왜 Mockito가 좋은가'에 대해 작성한 글이 있는데
http://kwon37xi.egloos.com/4165915 도 참고하면 좋을 것 같다.


Mockto 사용법에 대해서는
공식문서(영문): http://static.javadoc.io/org.mockito/mockito-core/2.2.7/org/mockito/Mockito.html
혹은 누군가 한글로 정리해 둔 아래 링크를 참고하자.
http://bestalign.github.io/2016/07/08/intro-mockito-1/
http://bestalign.github.io/2016/07/10/intro-mockito-2/


하지만 Mockito에는 몇 가지 제약이 있다. 

(https://github.com/mockito/mockito/wiki/FAQ 의 limitation 항목 참고)

그 중 테스트 케이스를 작성하는 데 가장 문제가 되는 부분이 private method와 static method에 대한 mock 을 만들 수 없는 것이다.


static method에 대한 mock을 제공하지 않는 이유에 대해 Mockito팀은 static method는 object orient 와 dependency injection을 사용하는 것이 좋다는 입장이라 구현하지 않는다고 한다. 만약 레거시 코드의 테스트 케이스 작성에 이용하고 싶다면 PowerMock 같은 툴을 이용하라고 한다. 

(static method 관련해서는 Mockito에도 작업중이라는 메일링 리스트의 답글이 있긴 하다)


private method에 대한 mock을 제공하지 않는 이유에 대해서는 아래와 같이 이야기 한다.
1. 기술적으로 추가 작업이 필요하고
2. protected나 package로 메소드의 접근자를 변경하는 간단한 work-around도 있고
3. 담당할 사람도 부족하고 이미 그것을 구현한 PowerMock이라는 툴도 있다.
4. 마지막으로 private method를 mock으로 만들어야 한다면 그것은 OO 측면에서 뭔가 잘못되어 간다는 신호라는 뜻이다.

(https://github.com/mockito/mockito/wiki/Mockito-And-Private-Methods 참고)

 

 

PowerMock

일반적으로 Mockito의 제약을 해결하기 위해 PowerMock을 이용한다.

다만!!! PowerMock 설명에 따르면 PowerMock은 unit testing 에 대해 전문적인 지식을 가진 사람을 위한 것이고, 익숙하지 않는 개발자에게는 좋은 점보다 나쁜 점이 더 많을 수 있다고 한다. (https://github.com/jayway/powermock)

아마도 객체 지향 원칙을 지키지 않아도 되도록 만든다는 측면이 있어서 그렇다고 생각된다.


그럼에도 불구하고 레거시 코드에 대한 테스트 코드를 작성해야 한다거나, 일정상 OO 측면을 조금 무시하고 작성한 코드에 대한 테스트 코드를 작성하려 할 때 PowerMock을 이용하면 되겠다.


정확하게는 우리가 이용할 클래스는 PowerMockito 클래스이다.
PowerMock은 EasyMock과 Mockito에 새로운 feature를 추가한 것이라 생각하면 되고, 

PowerMock 클래스는 EasyMock 을 기반으로 한 것이고,
PowerMockito 클래스는 Mockito 을 기반으로 한 것이다.

현재의 대새는 Mockito라고 하니 PowerMockito를 주로 이용하면 될 것으로 생각된다.


PowerMockito는 아직 Mockito 2.0 베타버전 기반이기에 Mockito 최신 버전의 기능과 혼용해서 사용할 경우 문제가 발생할 수 있다. (PowerMockito에 Mockito의 새로운 버전을 통합하는 작업이 쉽지는 않은 듯 하여 PowerMockito가 기반으로 삼은 Mockito 버전은 최신 Mockito버전과 다를 수 있으니 Mockito 최신 기능 사용시 주의가 필요하다.)


실제 사용 방법은 아래의 링크에서 확인해 볼 수 있다.


static method mocking 예제 파일:
https://github.com/jayway/powermock/tree/master/modules/module-test/mockito/testng/src/test/java/samples/powermockito/testng/staticmocking


Using PowerMock with Mockick:
https://github.com/jayway/powermock/wiki/mockitousage#a-full-example-of-partial-mocking-of-a-private-method



 

Roboletric

Mockto가 익숙하지 않다면 가능하면 이용하지 말자.
Roboletric을 잘못 이용하여 작성한 테스트 케이스는 실제 테스트 결과를 assertion 하지 않는 Code coverage만 늘어날 것이다.


Roboletric의 기본적인 컨셉은 실제 디바이스에서 해야하는 테스트를 JVM 상에서 테스트 할 수 있도록 해 주는 것이다. 실제 디바이스에서 실행하는 것 보다는 시간적으로 물리적으로 이점이 많지만, 비지니스 로직을 테스트 하기 위해서라면 테스트에 걸리는 시간이  많이 소요되고 결국 Mockito 등의 도움이 없으면 assertion하기 힘들다. 

그리고 테스트 케이스 코드 리뷰를 하다보면 Roboletric으로 테스트를 작성한 테스트 케이스는 타겟 메소드가 아닌 Roboletric 코드에 의존적인 assertion을 하는 경우가 많았다. 비지니스 로직은 가능한 Mockito 만으로 작성하도록 노력하자.


Roboletric을 이용하기에 적절한 테스트는 UI 동작을 테스트 하는데 이용하는 것이다.
http://robolectric.org/ 에서 보여주는 예제를 보고 생각해 보자. 

(http://robolectric.org/writing-a-test/ 도 UI 동작 테스트 예제이다)


하지만 Roboletric 만으로 UI 동작을 테스트 하는 코드를 작성하기에는 Roboletric에 대한 신뢰가 아직 부족한 듯 한다. 즉, 테스트가 실패 했을 때, 테스트 케이스가 문제인지,  나의 코드가 문제인지 Roboletric이 문제인지에 대해 확인이 어렵다는 것이다. 그리고 만들더라도 실제 디바이스와 Roboletric의 동작이 다를 가능성도 있다.


그리고 Android Framework 버전의 업데이트 속도를 바로 따라가지 못한다. 얼마전 까지만 해도 현재 sdk version 21까지만 지원하고 있었다. 그리고 최신 버전의 android support 라이브러리류 또한 문제가 있을 가능성이 높다.


단점만 쭉 적어 놓긴 했는데, Roboletric을 이용하는게 좋을 때도 있다.
특히 단위 테스트가 아닌 UI 동작 테스트 라던가, 멀티쓰레드 코드를 테스트 할 때는 도움이 된다고 하는 듯 하다.


반응형

설정

트랙백

댓글

다른 사람이 코멘트한 코드리뷰를 보다가 위와 같은 의문이 생겨서
조금 더 생각해보고 인터넷 검색하여 다른 사람의 생각을 찾아보았다.

그리고 내가 내린 결론을 말하자면 대부분의 경우에 "YES" 라고 하겠다.

가장 큰 이유를 말하자면 단순한 스트링은 그 스트링이 의미하는 것을 정확히 설명하지 못한다는 것이다.

예를들면 특정 앱에 할당된 ID를 생각 해보자.
우리앱에 할당된 ID는 "lkjq2oifw2" 이다.
이걸 전체 프로젝트에서 한 번만 사용한다고 하더라도 이 스트링의 의미를 명확하게 표현하는 이름의
Contant로 사용하는게 낫지 않을까?

스트링 뿐만이 아니라 단순한 숫자값의 경우도 마찬가지이다.
그리고 여러번 사용되는 경우 라면 더더욱 말할 것도 없고...

내가 생각한 예외적인 경우는,
로그 스트링 정도? 아니면 SQL 문법의 키워드 같은 것도 괜찮을 꺼 같다.

 

반응형

설정

트랙백

댓글

Technical Debt의 개념에 대한 글을 찾아 보다가 '리팩토링'의 저자 마틴 파울러가 쓴 글을 찾았다.

팀에 공유하고 싶어 번역을 할까 싶었는데 다른 분이 먼저 번역한 것이 있어서 냉큼 트랙백을 걸었다.


원문:

http://www.martinfowler.com/bliki/TechnicalDebt.html


번역문:

http://jinson.tistory.com/entry/%ED%95%9C%EA%B8%80%ED%99%94-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-3-%EA%B8%B0%EC%88%A0%EB%B6%80%EC%B1%84




추가로 Technical Debt에 대한 다른 글도 링크를 남겨본다.


조대협님의 블로그: Technical Debt 에 대한 영문 위키 버전의 내용과 비슷.

http://bcho.tistory.com/811


지디넷 기사:

http://www.zdnet.co.kr/column/column_view.asp?artice_id=20140609092502





기술적 부채를 갚는 것은 비개발 조직 입장에서 보면 하등 쓸데없는 짓인데,

이러한 비유가 개발자의 고충을 이해하는 데 도움이 되었으면...


결국 빚을 갚아야 하는 건 개발자인데,

문제는 개발조직의 장으로 있는 사람도 이런 것에 관심이 없다는거...

반응형

설정

트랙백

댓글

참고링크: http://operationwritehome.org/the-abcs-of-color-basic-color-theory/


안드로이드의 Layout Resource 를 작성하다 보면 ImageView 에 tint 항목이 있다.

이게 정확히 뭘하는 건지 궁금해서 찾아본 결과..

아래와 같은 이미지로 의미를 한 눈에 알 수 있었다.





하지만!!!

위의 이미지에서 의미하는 tint 와 ImageView 에 지정하는 tint 는 다르다.

위 이미지에서는 원래 컬러에 흰색을 더하는 것이라고만 되어 있지만,

ImageView 의 tint 는 tint color 값을 지정한다.

또한 tintMode 를 통해 tint color 를 섞는 방법도 지정할 수 있다.



반응형

설정

트랙백

댓글

Blogger로 이동합니다. T* 타입 (포인터의 vector 정렬에 대해 궁금하시다면 아래로...)


https://ommokazza.blogspot.com/2020/10/stl-vector-object-pointer.html



반응형

설정

트랙백

댓글

원래 Windows 환경에서 사용할 만한 컴파일러와 IDE 에 대한 이야기를 쓰려다가,

msys 에서 아래와 같은 에러가 발생하여, 여기에 대한 내용부터 기록에 남긴다.


*** Couldn't reserve space for cygwin's heap (0xXXXXXXXX <0xXXXXXXX>) in child, Win32 error 0


집에서는 잘 되는데, 회사에선 항상 저런 메시지를 내면서 msys 의 대부분의 실행 파일들이 동작하지 않는다.


간단하게 결론부터 말하면 child process 가 fork() 될 때,

dll 파일이 로드되는 메모리 주소가 서로 다르게 되어 fork() 가 실패하기 때문이다.

( 이게 무슨 말이냐 라고 묻는다면, 납득할 만하게 설명할 자신은 없다. -_-;;

  좀 더 자세한 설명을 원한다면 아래 포스트를 읽어보라.

  http://old.nabble.com/Re%3A-fork-problem-on-Windows-XP-64-bit-p31154393.html )

( 예전에는 cygwin 에서도 이러한 에러 메시지를 본 기억이 있는데,

  최근에는 cygwin setup 시에 dll 파일들의 base address 를 재설정 한다고 하는 듯하다. )


이리저리 구글링 좀 해 본 결과, 아직까지 근본적인 해결방법은 없는듯 한데,

실제로 msys 의 릴리즈 노트를 봐도 저 문제를 해결하지는 못하고

다만 rebase 되는 상황을 최소화 하기 위해 msys-1.0.dll 파일의 base address 를 바꾸었다고 되어있다.

( 분명 Windows 는 dll 파일을 로드할 때, 주소 충돌이 생기면 base address 를 알아서 조정한다고 했던거 같은데, 

 왜 msys 에서는 안되는지 잘 모르겠다. dll 파일 자체에 해당 기능을 enable 하는 플래그가 있다고 본 거 같다.

 하지만 더 구체적인 근거를 찾기엔 시간도 부족하고... 해서 패스 )


어쨌든 저러한 문제가 생기면 msys 에 포함된 dll 파일들의 base address 를 바꾸어 주어야 하는데,

이 때 사용하는 프로그램이 rebase 프로그램이다.

문제는 msys 에 포함된 rebase 를 실행하기 위해서는 msys-1.0.dll 이 필요하다는 거.

그래서 msys-1.0.dll 이 의존적이지 않는, Win32 native binary 가 필요한데,

직접 빌드하려 소스를 열어보니 익숙치 않은 autoconf, automake 조합으로 빌드되도록 되어있다.

하지만 나와 같은 (그리고 이런 문제를 만난 다른 많은 사람들과 같은) 생각을 가진 분이

이미 빌드해 놓은 파일이 있었다.


소스: http://repo.or.cz/w/msysgit.git/tree/322c42c780833a52bd7cd0358a562ab243ecfbce:/src/rebase

바이너리: http://repo.or.cz/w/msysgit.git/history/76920dc49da361257cbccb02ea63b3e5357fe353:/bin/rebase.exe


위 툴을 받아, msys 의 bin 디렉토리에 복사를 한다. (보통 C:\MinGW\msys\1.0\bin 일 것이다.)

그리고 해당 디렉토리에서 cmd 창을 열고 아래와 같이 입력한다.

C:\MinGW\msys\1.0\bin>rebase -b 0x30000000 msys-1.0.dll

새로운 Base 주소는 각자 적당히 찾아서 적으면 될듯 하다.

그리고 이제 다른 dll 파일들에 대하여 rebase 작업을 한다.

이제 MinGW Shell 을 열어도 에러가 뜨지 않으니, MinGW Shell 을 열고,

$ mingw-get install msys-rebase

를 실행한다. 위 명령을 성공적으로 실행되면, MinGW Shell 을 닫고,

탐색기에서 msys 의 bin 디렉토리로 이동하여 dash 를 실행한다.

그리고 아래와 같이 입력한다.

/bin/rebaseall

만약 에러 메시지가 출력된다면, (예를 들면 read-only 속성이 걸려 있다던가...)

에러 메시지를 보고 적절한 조치를 취해 준 뒤 다시 실행한다.


마지막으로

/bin/peflagsall

을 해주면,

(위에서 이야기 했던) dll 파일에 dynamicbase flag 를 set 한다고 되어 있다.

dash 에서는 현재 환경을 MinGW32 로 인식하고 있어서 별 다른 작업을 하지는 않는데,

실제 문제가 되는 건 msys 기 때문에 스크립트 파일의 Platform 환경변수를

강제로 바꾸어 주어야 되는지는 잘 모르겠다.

써 보다가 문제가 생긴다면 고려해 봐야할 듯.


P.S

아무래도 생각해도 이 에러가 발생한 건,

회사의 보안 프로그램이 해당 영역을 이미 차지하고 있기 때문이라는 생각이 든다.


반응형

설정

트랙백

댓글

In Code::Blocks can set programs arguments in IDE ("Project > Set programs' arguments...")

But in windows version, the redirection is not working.


How to make it enable?


The problem is the 'cb_console_runner.exe'.

That use CreateProcess() function to start the child process.

Unfortunately, CreateProcess() CAN'T handle redirections.

Why does 'cb_console_runner.exe' use this function?


It is written in source code.

    //Windows's system() seems to not be able to handle parentheses in
    //the path, so we have to launch the program a different way.

( See this svn log. )


So I complied the 'cb_console_runner.exe' using system() instead of CreateProcess().

In my windows7, It works well and it seems that there is no problem about parentheses.

( That was modified in 2006. Now does it fixed?. I don't know. )


Anyway I replaced the 'cb_console_runner.exe' with my own build.

If anyone having a redirection problem in windows version of Code::Blocks, try this one.

cb_console_runner.exe

(Just copy to where Code::Blocks installs and replace original file with this)


Or you can build it easely with just a few modification. (That's why I didn't attach soruce code.)

I modified and built this in Code::Block. ;)


P.S

영어로 쓰고 나니 진에 빠져서, 한글로 내용을 다시 쓰는건 패스.

도대체 구글링 해도 시원하게 답해주는 사람이 없어서,

직접 원인을 찾아서 수정한 버전을 사용하기로 함.

반응형

설정

트랙백

댓글