Monday, September 28, 2015

[How to become an open source contributor?] 2시간만에 컨트리뷰터 되기!

1. 준비되셨나요?

초보도 2시간만에 오픈소스 컨트리뷰터가 될 수 있는가?!
필요한 것: GitHub 계정, 초급 git 사용법, 발사이즈 토익점수, 근성

로직 등 코드에 기여하는 것은 상위 단계의 일이고(뛰기 전에 걸어야 한다는 격언을 생각합니다), 일단 코드 리뷰 수준의 기여를 하도록 합시다.

음 ... 뭐가 있을까 보다가 핫하고 핫한 도커docker를 한 번 보도록 합시다.


2. 오타 찾기

이제부터 오타를 찾을겁니다. 자주 틀리는 영어 표현을 보도록 하죠.
enviroment,
timout,
annotaion,
limitaion,
developement,
11st,
12nd,
2th,
3nd,
pubic,
positoin,
defualt,
seting,
mousenter,
gurantee,
lisence,
milis,
statmeent,
...
등등 자주 틀리는 표현은 많습니다!

근성을 갖고 찾아보도록 합시다. 하지만 쉽지 않을 수도 있습니다... ㅠ_ ㅠ


차...찾았다! 후..후후...후후후후후 인간은 실수의 동물


3. Pull Request(PR)

자, 이제 본격적으로 pull request를 위한 작업을 해보죠.

fork를 뜨고,

clone을 뜨고, (소스트리로 떠보았습니다)


코드 수정을 하기 전에...

웬만한 대형 repo에는 다 Developer Certificate of Origin나 Contributor License Agreement 같은 시스템이 있고, 컨트리뷰트 가이드가 있습니다. 이건 약관에 동의하는 거라고 생각하면 이해가 쉽습니다.
가이드대로 해야 한다! 중요하죠... 그렇지 않은 경우 merge를 할 수 없다는 메시지를 받게 될 겁니다 ^_^ 이슈로 다루길 원하는 repo도 있고, 주석 수정 등 작은 오타는 바로 PR해주길 바라는 repo도 있고, 이것은 해당 repo의 분위기(?)에 따라 다릅니다.

가이드대로 다음처럼 해 봅시다.




다음과 같이 오타를 수정 ^_^! timeout으로!

근데 이 때 주의해야 할 점! indentation이나 new line 타입, encoding을 깨서는 안된다는 것!
얌전하게 고칠것만 고칩시다. (쓰지맙시다 윈도우즈 메모장...ㅠㅠ)


이제 다시 원본 docker/docker repo로 가서,

New pull request에서 compare across forks,

fork한 repo를 선택하고,

create pull request를 합니다. 잡아먹지 않는답니다요! 아닐수도

영어는 못하지만 언어는 의사소통이라 하였더라. 애써 손짓발짓을 해봅니다.

그리고 지릅니다.


4. Pull Request 그리고 나서...

PR 날렸더니 ... 오잉 이게 모람. GordonTheTurtle 아저씨가 친절하게 뭔갈 알려줬다. 이대로 해봅시다.
아 ... 모든 커밋 메시지에 저게 들어가야 한다는 거구나;;
우...우렁거북이세여 ;; (사람이 아니고 봇같아요 거북이봇.)

흔한 거북의 예

아아 친절해 ㅜㅜ 집앞 맥도날드 알바분보다 더 ㅜㅜ




푸시하려면 빌드테스트를 하고 하는 것이 마땅하거늘, 요즘엔 travis-ci나 jenkins같은 빌드시스템이 이것을 관리해줍니다! 키야 주긴다잉


기다립니다.

오 사람이 나타났습니다!


vendor는 import된거기때문에 합치지는 않을거니까 docker/libkv로 가보랍니다. 귀여운 이모티콘과 함께..
무를 뺐으면 칼이라도 썰어야지!
가자!
갑니다.

똑같이 (이제는 amend를 빼먹지 말고... 적용된 모습이 보입니까? 물론 이건 repo 정책에 따라 다릅니다!)


빌드 성공!


또 기다립니다.

주의: 자다가 일어났는데 메일이 왔으면 설렐 수 있습니다.

아앗 머지됐어

드디어 메일이 왔습니다! LGTM(Looks good to me)!!!


이러면 저도 14명의 컨트리뷰터 중 한 명!(;;)
(물론 전 아직도 잡아먹히지 않았습니다.)

위와 관련하여 좋은 말씀이 있어 나누고자 합니다.(?)
Naver Labs 이형규님의 "Contributing to Docker": http://www.slideshare.net/HyeongKyuLee/docker-contribution-slideshare-38684955


5. 마치며

참 쉽죠??
이러한 주석 수정 등의 활동이 오픈 소스 활동으로 인정받을 수 있느냐라는 논란이 제기되곤 합니다. 그리고 위는 뭔가 꼼수를 부린 것 같이 찝찝한 느낌이 들 수도 있다고 생각합니다.
하지만 천 리 길도 한 걸음부터라고 하듯, 사소한 움직임이 변화의 시작!입니다. (게다가 대부분의 커미터들은 좋아합니다. 물론 예를 갖추어 ... 커미터는 컨트리뷰터를 무조건 좋아해!는 도끼병입니다)
이런 소소한 활동이 세상의 소프트웨어와 여러분들의 일상에 변화를 줄 수 있기를 바랍니다. ^_^

김태희, http://github.com/KimTaehee


Monday, September 21, 2015

[Unit testing] 2. Play JUnit~!

JUnit을 시작해보자 ^_^

* 개발환경: OS X Yosemite / Android Studio 1.3.2

1. 프로젝트 생성

기본 옵션으로 Blank Activity 프로젝트를 생성한다.

2. Unit Test 폴더 구조 생성

Junit 테스트의 경우, src/test/java를 기본 테스트 폴더로 인식한다. 그렇기 때문에 폴더명을 수정해준다~! 마우스 우클릭 > Refactor > Rename > "androidTest"를 "test"로 수정

* 테스트 폴더가 안보인다면 좌측 상단을 Project로 선택해주면 된다

3. 빌드 스크립트 수정

app의 build.gradle 파일을 열어서 dependency에 testCompile 구문을 추가해준다. 그 다음, Sync now 클릭!

4. Test Artifact 설정

좌측 하단 Build Variant 탭을 클릭한 후 Test Artifact를 Unit Tests로 설정해 준다. 그러면 아래와 같이 폴더 아이콘이 초록색으로 변경된다~!

여기까지 성공했다면, 환경설정 끝!

5. Unit Test 코드 작성

정상적으로 작동하는지 알아보기 위해 간단히 Calculator 클래스를 만들어서 두 정수를 더하는 메소드를 테스트 해보자 ^_^! 아래와 같이 Calculator랑 CalculatorTest 클래스를 생성하고 코드를 써준다~~

클래스 생성해주고

테스트 코드를 작성해준다! ^_^!

6. 테스트 하기~~

테스트 java 폴더에서 우클릭하여 Run 'All Tests' 클릭하여 테스트 해준당!

끄읏~~~~~

덧.

내 환경에서는 위와 같이 했을 때 다음과 같이 fail이 2개가 생겼다 ㅜ_ㅜ

로그 내용
java.lang.RuntimeException: Method setUp in android.test.ApplicationTestCase not mocked. See http://g.co/androidstudio/not-mocked for details. at android.test.ApplicationTestCase.setUp(ApplicationTestCase.java) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
java.lang.RuntimeException: Method setUp in android.test.ApplicationTestCase not mocked. See http://g.co/androidstudio/not-mocked for details. at android.test.ApplicationTestCase.setUp(ApplicationTestCase.java) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:86) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

이럴 경우 app의 build.gradle 스크립트에 다음과 같이 testOption을 추가해주면 된다.

Sync now를 해주고 다시 Run'All Test'를 하면!

All Tests Passed! 진짜 끝~~~~~~^_^

다음 글에서는 robolectric에 대해 알아보자!

참고 논문 및 사이트

1. TDD/JUnit 조금 더 알기 http://www.slideshare.net/WonchangSong1/abouttddj-unit

2. Android Studio에서 Junit 기반 단위 테스트(Unit Test) 환경 구축하기 http://xinics.tistory.com/101#recentTrackback

3. Android Developer https://developer.android.com/training/testing/unit-testing/local-unit-tests.html

4. Android Tools Project Site http://tools.android.com/tech-docs/unit-testing-support

Saturday, September 19, 2015

[AndroidAnnotations structure analysis] How to make custom annotation processor_01

1. 개요

AndroidAnnotations 프레임워크 분석을 위해 나만의 커스텀 annotation processor를 따라 만들어보자.


2. 환경

Android Application는 Android Studio를 사용하고, AndroidAnnotations 프레임워크는 IntelliJ를 사용한다. 4.0-SNAPSHOT의 develop 브랜치에 따라가는 것임을 밝힌다.
앞으로 분석을 위해 만들 custom annotation processor는 동일한 구조를 본딸 것이다. 이에 앞서, 어떤 방식으로 이 annotation processor가 import될 수 있는지 보자.

AndroidAnnotations의 최신 버전(develop 브랜치에서 개발중)인 4.0-SNAPSHOT이다. 어플리케이션에서 이 프레임워크를 사용하기 위해서는, 어플리케이션에 빌드 스크립트가 들어가 있어야 한다.
mavenCentral에 올라간 것을 사용하는 것이 아니라, 직접 빌드한 결과물을 로컬에서 가져오기 위해 아래와 같이 mavenLocal을 선언하였다. (4.0-SNAPSHOT 버전은 아직 릴리즈되지 않았기 때문이다.)
아래와 같이 annotation processor를 선언하고, 해당 annotation processor에 알맞는 api 라이브러리를 선언해준다.


그러면 이제 다음과 같은 예쁜 소스코드를 사용할 준비가 완료된 것!


3. AndroidAnnotations 프레임워크 구조 분석

AndroidAnnotations의 프로젝트 구조는 다음과 같다.

core는 EActivity 등 AndroidAnnotations의 필수요소들을 담고 있으며, 나머지 Rest 등 다른 요소들은 필요시 옵션으로 부착할 수 있게 되어있다. core를 보면 다음과 같이 annotation processor와 core가 사용하는 api로 구성되어 있다. (테스트는 다음에 다루자.)

위 라이브러리들은 maven을 통해 다음과 같이 jar로 추출된다. 이 중 javadoc과 sources를 제외하고 필수 요소만으로도 사용할 수 있다.



4. AndroidTannotations 프레임워크 및 테스트 어플리케이션 생성

이제 나만의 custom annotations processor를 만들어보자. 내 이름은 김태희니까 태노테이션이라고 해보았다. 팀원들은 어이가 없는 모양이지만 그냥 이렇게 할거다.
앞서 언급한 대로 Android Studio로 Android Application을 만들어보자.(저는 1.3.2) (남아있는 소스는 그냥 찌꺼기니 신경쓰지 않으셔도 좋다.)


그리고 나서, IntelliJ로 Java Application을 만들어보자.(저는 15 EAP) (남아있는 소스는 그냥 찌꺼기니 신경쓰지 않으셔도 좋다2.)

원래 있던 main()을 없애고, [Project Structure -> Artifacts -> +로 JAR를 추가]로 설정하여 실행하면 main()이 실행되는 게 아니라, 실행되지 않는 jar가 생성되도록 설정해주자. 그러면 이제 라이브러리로 사용할 프로젝트가 완성되었다. (원래는 maven 빌드로 만들지만 원리를 파악하기 위함이니까 그렇게까지는 하지 않습니다.) 여기까진 기본이져...

이렇게 하면 준비 끝~ 이 아니고 그 전에! annotation processor를 만드는 방법을 알아야 한다. 다음 장에 계속...


Thursday, September 17, 2015

[Unit testing] 1. What is JUnit?

1. 단위 테스트란? - What is Unit test?

* 사전적 의미 ^_^

단위
1) 사물의 길이, 넓이, 무게 등을 수치로 나타낼 때, 기본이 되는 기준
2) 하나의 집단 조직 등을 구성하는 기본적인 한덩어리.

테스트
1) 제품의 성능이나 상태 따위를 일정한 기준에 따라 검사함
2) 일정한 기준에 따라 검사하다.

* 위키 백과 ^_^

유닛 테스트(unit test)는 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차다.
즉, 모든 함수와 메소드에 대한 테스트 케이스(Test case)를 작성하는 절차를 말한다.
이를 통해서 언제라도 코드 변경으로 인해 문제가 발생할 경우, 단시간 내에 이를 파악하고 바로 잡을 수 있도록 해준다.

이미지출처: http://martinfowler.com/bliki/UnitTest.html

* 장점 ^_^

1. 프로그램의 결함을 찾기 쉽다
단위 테스트의 목적은 프로그램의 각각의 부분이 정확하게 잘 동작하는지 확인하는 것.
즉, 프로그램을 작은 단위로 쪼개서 각 단위가 정확하게 동작하는지 검사하고 이를 통해 문제 발생 시 정확하게 어느 부분이 잘못되었는지를 재빨리 확인할 수 있게 해준다!
=> 따라서 프로그램의 안정성이 높아진다.
단위 테스트는 개발 시간을 증가 시키는 것처럼 보인다.
하지만 잘 이용한다면, 개발 기간 중 대부분을 차지하는 디버깅 시간을 단축시킴으로써 여유로운 프로그래밍을 가능케 한다!

2. 변경이 쉽다
리팩토링은 알다시피 기능을 유지하므로, 리팩토링을 진행하고 나서 자신이 변경한 코드가 리팩토링 전 처럼 의도한 대로 작동하고 있음을 단위 테스트를 통해서 확실하게 알 수 있다!
이를 회귀 테스트(Regression testing)라고 한다.
어떻게 코드를 수정해도 문제가 되는 부분을 빠르게 확인 할 수 있고, 수정한 코드가 잘 동작하는지 바로 알 수 있기 때문에 리팩토링에 있어서 안정적으로, 그리고 맘편하게 코드 수정을 할 수 있도록 도와준다~!

3. 통합이 간단하다
단위 테스트는 쪼개어진 단위에서 그 자체의 불확실성을 제거해주므로 상향식(bottom-up) 테스트 방식에서 유용하다.
먼저 프로그램의 각 부분을 검증하고 그 부분들은 합쳐서 다시 검증하는 통합 테스트에서 더욱 더 빛을 발한다.

* 왜 단위테스트를 써야 하지?

두 말할 것 없다!!! "신뢰!"
단위 테스트는 프로그램의 쪼개진 단위마다 테스트 결과가 매우 명확하다.
그렇기 때문에 개발 조직에서 개발자와 개발자간의 코드에 대한 신뢰를 형성한다.
개발 조직과 테스트 팀간의 신뢰 또한 ㅎㅎ!
그리고 우리의 목적인 오픈소스 - 다른 개발자와 코드로 소통을 해야한다.
이 때, 다른 개발자에 대한 최소한의 신뢰를 갖기에 단위테스트가 매우 적절하다!
단위 테스트라는 것을 했고, 그 결과가 명확하기 때문에 그 관계에서 "신뢰" 가 형성될 수 있다 ^_^!!!!

2. JUnit이란?

* 정의?

Java에서 독립된 단위 테스트를 도와주는 framework! (편의성! 자동화!)

* 어떻게?

기대값과 결과값을 비교!
위에서 설명한 바와 같이 단위 테스트란 잘게 쪼갠 소스 코드의 어떠한 모듈이 의도한 대로 정확히 작동하는지 검증하는 것이다.
즉, 모든 함수와 메소드에 대한 테스트 케이스(Test case)를 작성하는 절차를 말한다.
해당 모듈이 동작하길 기대하는 값과 실제로 동작 후 나온 결과 값을 비교하며 테스트를 진행한다.

* 참고~ JUnit은 컴파일 시에 JAR로서 링크된다.
JUnit 3.8과 그 이전 버전에서는 프레임워크의 junit.framework 패키지 하위에 있고, JUnit 4와 그 이후 버전에서는 org.junit 패키지 하위에 있다.

다음 포스팅에서는 JUnit 사용법을 알아보자~

참고 논문 및 사이트

1. 시작하자 단위테스트 - http://www.slideshare.net/youngeunchoi12/springcamp2014-35347399

2. 위키백과 - 유닛 테스트 - https://ko.wikipedia.org/wiki/유닛_테스트

3. 왜 단위 테스트를 해야 하는가? - http://blog.powerumc.kr/265

4. Wikipedia - JUnit - https://en.wikipedia.org/wiki/JUnit

[AndroidAnnotations_Build] 5. AndroidAnnotations 4.0 SNASHOT maven build

시작하기에 앞서 AndroidAnnotaions가 4.0 SNAPSHOT 버전에서 보면 3.3.2 버전과 매우 다르게 프로젝트 구조가 격변했음을 알 수 있었다. 따라서 해당 프로젝트를 빌드하기 위해 처음에 Eclipse인줄만 알고(원래 3.3.2 까지 eclipse에서 작업을 했었다)작업을 했지만 정상적으로 수행되지 않았고, 열심히 Contributer에게 Gitter로 건의한 결과 Intellij에서 개발하는 환경 구축 방법을 얻을 수 있었다. 수행 해본 결과 Build에 성공하였고 이에 따라 로컬에 jar파일도 생성되어서 이미 구성해둔 Project에 import도 가능하게 되었다.:) 아래는 AndroidAnnotations 에 대한 4.0 SNAPSHOT 빌드 방법과 프로젝트 전체 구성방식에 대한 설명이다.

1. AndroidAnnotations 4.0 SNAPSHOT 빌드

빌드 환경은 InstallingEnvironment 에서 확인 가능하며, Maven Build 방식을 가지고 있다. Maven 에 대한 설명은 Build Label의 4번을 참고해도 되고 더 많은 정보는 구글링을 통해 찾아보면 된다. 여기서 나온 환경과 같이 해당 프로젝트를 빌드 하기 위해서는 3가지 조건이 필요하다.

빌드 환경 구성에 대한 내용에서는 Fork를 받으라고 되어있지만 해당 페이지는 Contributing에 관한 이야기이기 때문에 굳이 Fork를 받지 않아도 상관없습니다. 따라서 그냥 Clone을 내 저장소에 받으면됩니다. (저는 컨트리뷰팅이 목적임으로 Fork를 받고 Clone을 받았습니다. 아래 사진과 같이 SourceTree에서)

다음은 Console 창을 활성화 시킨뒤 Clone을 한 Repostiory로 이동하여 mvn install 을 작성하여 줍니다. 해당 명령어를 작성하게 되면 빌드가 실패가 되거나 정상적으로 수행되거나 둘중하나가 되게됩니다. 빌드가 성공하게 되면 다음과 같은 화면이 뜨게 됩니다. (수행하게되면 Maven에 명시된 모든 build가 수행됨으로 unittest케이스에 대한 실행도 모두 되게 됩니다.)


1.1. [BUG] JAVA_HOME 이 지정되있지 않은경우

환경변수에 JAVA_HOME 가 지정이 되어있지 않은 경우 정상적으로 install 되지 않을 수 있습니다. 빌드 실패시 로그가 눈에 보이기 때문에, 명령 오류에 따른 수정을 하면되지만 혹시라도 모르는 사람이 있을수도있기 때문에 환경변수 추가에 대한 내용을 적어두었습니다. 환경변수에 JAVA_HOME을 추가하면 되고 보통 oracle에서 받은 java를 설치할경우 설치 Driectory는 다음과 같습니다. "C:\Program Files\Java"

설치경로를 확인한뒤 환경변수에 다음과 같이 JAVA_HOME을 지정해주면 됩니다.

Window
------
변수 이름(N) : JAVA_HOME
변수 값(V) : C:\Program Files\Java\jdk1.7.0_76

1.2. [BUG] Android SDK 가 지정되있지 않은 경우

Android SDK 또한 ANDROID_PATH에 대한 것이 Path에 지정되어 있지 않다면 빌드가 정상적으로 이루어지지 않는다. 따라서 이 역시 환경변수에 추가해주어야 한다.

Window
------
변수 이름(N) : ANDROID_HOME
변수 값(V) : C:\Development\android_sdk

변수 이름(N) : Path
변수 값(V) : ...;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools;...


Linux
------
export ANDROID_HOME=/home/francis/Android/Sdk
export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

1.3. [BUG] Android SDK 16이 없는 경우

Android SDK 16 platform을 설치하면 됩니다. SDK Manager 를 활성화 시키고 아래의 화면과 같은 부분이 install 되어 있으면 됩니다.

2. AndroidAnnotations Maven Build 구조 분석

생각했던것 보다 엄청난 Maven 상속 구조를 가지고 있었습니다. 실제로 이런 프로젝트 빌드와 배포를 수행해 보지 않았기 때문에 빌드에 성공한뒤 프로젝트에 대한 구성 내용에 대한 파악을 진행해 보았습니다.

추후 업데이트 예정...