Slack Integration with Gitlab (Gitlab & Slack 연동하기)

It’s super easy way to enable Slack Integration, first you have to create new channel and then create an Incoming WebHooks on slack.

Create Webhook URL

Go into this following link with your teamdomain on Slack :

https://your_teamdomain.slack.com/services/new/incoming-webhook

Select your channel or create new channel that you want to send notifications and Click Add Incoming WebHooks integration.

You can get Webhook URL for sending data to Slack and also change curtomize name or icon.

These steps are all on Slack for integrating Gitlab. And now you have to use webhook url which gets from slack.

Enter the Webhook URL

Open your Gitlab and find Services right top of menu.

You can find Slack among the project services at the bottom.

Make Active checked and input webhook url from Slack and username, channel that you want. Save changes.

Finally, you will get this notification on your Slack chaneel.

failed to find target with hash string ‘android-XX’ in Jenkins CI

compileSdkVersion, minSdkVersion, and targetSdkVersion

First of all, read this ‘Picking your compileSdkVersion, minSdkVersion, and targetSdkVersion’ to know what these mean for building your project.

compileSdkVersion, minSdkVersion, and targetSdkVersion come in: they control what APIs are available, what the required API level is, and what compatiblity modes are applied, respectively. – Ian Lake’s blog

I’ve updated android latest compileSdkVersion, targetSdkVersion and buildToolsVersion on my Android project a couple of days ago, installing the latest version of the Android platform as android-24 and buildTools as 24.0.1.

android {
    compileSdkVersion 24
    buildToolsVersion '24.0.1'

    defaultConfig {
        targetSdkVersion 24
….

What went wrong :

But Jenkins gives this error through slack-plugin as below.

Jenkins Bot Message on Slack

Check Console Output on Jenkins

It failed to find android sdk 24 in android-sdk-linux directory because compileSdkVersion sets 23 to the newest API 24. So you can check list installed SDK package so far via command line.

$ cd /opt/android-sdk-linux/platforms
$ ls
android-10  android-15  android-16  android-17  android-18  android-19  android-20  android-21  android-22  android-23  android-8

You will understand it’s no android-24 folder, to compile app by API level 24 so let’s add android-24 to platforms and also Android SDK Build-tools, version 24.0.1. See the package list for Android SDK Tools, Android SDK Platform-Tools, Android SDK Build-tools, Google Play services, Google Admob and etc.

How To Update SDK

$ cd /opt/android-sdk-linux/tools
$ ./android list sdk --all
Packages available for installation or update: 156
   1- Android SDK Tools, revision 25.1.7
   2- Android SDK Tools, revision 25.2.1 rc1
   3- Android SDK Platform-tools, revision 24.0.1
   4- Android SDK Build-tools, revision 24.0.1
   5- Android SDK Build-tools, revision 24
   6- Android SDK Build-tools, revision 23.0.3
   7- Android SDK Build-tools, revision 23.0.2
   8- Android SDK Build-tools, revision 23.0.1

………

  29- SDK Platform Android 7.0, API 24, revision 2
  30- SDK Platform Android 6.0, API 23, revision 3
  31- SDK Platform Android 5.1.1, API 22, revision 2
  32- SDK Platform Android 5.0.1, API 21, revision 2
  33- SDK Platform Android 4.4W.2, API 20, revision 2
  34- SDK Platform Android 4.4.2, API 19, revision 4
  35- SDK Platform Android 4.3.1, API 18, revision 3

……….

 108- Google APIs, Android API 23, revision 1
 109- Google APIs, Android API 22, revision 1
 110- Google APIs, Android API 21, revision 1

Now we need to install No.29, ‘SDK Platform Android 7.0, API 24, revision 2’, to build in Jenkins successfully. So try to install by commend line as below.

$ sudo ./android update sdk -a -u -t 29

Try build it again in Jenkins. Finally, the problem was fixed and build was finished successfully.

CachePot으로 Activity 또는 Fragment 사이 간단한 데이터 통신

Java에서 흔히 객체로 데이터 통신 하기 위해 객체에 Serializable 인터페이스를 상속 받은 뒤 직렬화된 객체를 바이트 단위로 분해하여 전송한다. Android에서도 마찬가지로 Serializable을 사용하긴 하지만 보다 Parcelable을 많이 사용하고 있다. 하지만 Parcelable을 사용하기 위해서는 객체에 선언된 데이터가 추가 될 때마다 writeToParcelreadFromParcel을 통해 Parcel 객체에 읽고 쓰는 작업을 추가해야 데이터 전송이 가능하다. CachePot은 간단한 앱을 만들거나 Intent를 통한 다른 애플리케이션과 통신이 없다면 간단하게 데이터 캐시를 할 수 있는 인스턴스가 있으면 좋겠다고 생각되어 Generic을 사용해 간단하게 만든 안드로이드 라이브러리이다.

Download

현재 Gradle을 사용하는 중이라면 build.gradle에 아래를 추가하자.

repositories {
      jcenter()
}

dependencies {
      compile 'com.github.kimkevin:cachepot:1.0.0'
}

How To Use?

동기식 데이터 전달하기

  • Between Activity and A ctivity
  • Between Activity and Fragment
  • Between Fragment and Fragment

데이터가 메모리에 올라가기 때문에 결국은 사용자 인테페이스를 구성하는 Activity와 Fragment 등 아무대서나 동기적으로 데이터 전달이 가능하다.

1. Model 객체 전달

새로운 화면 생성 전 데이터 저장하기

KoreanFood foodItem = new KoreanFood(1, "Kimchi", "Traditional fermented Korean side dish made of vegetables");
CachePot.getInstance().push(foodItem);

새로운 화면 생성 후 데이터 가져오기

public class MainFragment extends Fragment{
    private KoreanFood foodItem;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        foodItem = CachePot.getInstance().pop(KoreanFood.class);
    }
}

2. Collection 또는 Map 객체 전달

새로운 화면 생성 전 데이터 저장하기

List<KoreanFood> foodItems = new ArrayList<>();
foodItems.add(new KoreanFood(1, "Kimchi", "Traditional fermented Korean side dish made of vegetables"));
foodItems.add(new KoreanFood(2, "Kkakdugi", "A variety of kimchi in Korean cuisine"));
CachePot.getInstance().push(foodItems);

새로운 화면 생성 후 데이터 가져오기

List<KoreanFood> foodItems = CachePot.getInstance().pop(ArrayList.class);

ArrayList나 HashMap, Stack, LinkedList 등과 같이 구현 클래스도 일반적인 모델 데이터를 전달하는 것과 같은 방식으로 데이터 전송이 가능하다.

비동기식 데이터 전달하기

ViewPager에서 position별로 Fragment에 객체 전달

요즘 앱에서 흔하게 ViewPagerFragmentStatePagerAdapter를 사용하고 있다. 그리고 Adapter에서는 getItem(int position)이 호출 될 때 Fragment를 생성하게 되는데 새로운 Fragment가 생성되고 CachePot 인스턴스에 저장된 데이터를 가져오기 전에 새로운 데이터를 캐시하게 되어 데이터를 가져올 때 오류가 발생하게 된다. 이를 방지하기 위해서 Fragment의 postiion을 함께 저장할 수 있는 기능을 제공한다.

Framgnet 생성 전에 position과 데이터 저장하기

private class PagerAdapter extends FragmentStatePagerAdapter {
    ...
    public Fragment getItem(int position) {
        CachePot.getInstance().push(position, foodItems.get(position));
        return FoodFragment.newInstance(position);
    }
}

생성된 Fragment에서 데이터 가져오기

public static FoodFragment newInstance(int position) {
    FoodFragment fragment = new FoodFragment();
    Bundle args = new Bundle();
    args.putInt(ARG_POSITION, position);
    fragment.setArguments(args);
    return fragment;
}
...
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        final int position = getArguments().getInt(ARG_POSITION);
        koreanFoodItem = CachePot.getInstance().pop(position);
    }
}

‘Where is CEO?’ == ‘사장 어딨노?’ 사내 해커톤 후기

얼마전 플리토 사내에서 첫 번째 해커톤을 열었다. 보통 해커톤에 참여 할 경우에는 한 달 전부터 만들어 보고 싶은 것들을 꼭 팬으로 노트에 낙서하듯 적어본다. 딱히 이유는 없지만 팬으로 적었을 때에는 머리 속에서 더 오래 남아있는 것 같은 느낌이 들어서다.

그래서 이번은 회사 프로젝트는 아니지만 만들면 재밌을 것 같았던 ‘Where is Simon(CEO)?’로 결정했다. 플리토 청담 오피스는 현재 40명에 가까운 인원이 총 3개의 층을 사용하고 있고 사내 메신저로 가끔 누가 어디에 있는지 묻는 경우가 있어서 이를 확인할 수 있는 페이지가 있으면 좋겠다고 생각했었다. 가장 빈번히 찾는 대상은 어느 회사에서나 공공의 타겟 바로 대표님이다. 기본 아이디어는 ‘층마다 있는 무선 공유기(AP)에 접속한 직원들을 층별로 보여주자‘로 시작했다.

1. Mornitoring Agent – 층별 AP에 접속한 직원들 리스트 가져오기

가장 기본적으로 먼저 AP에 접속한 단말기의 정보를 가져와야 프로젝트가 시작될 수 있기 때문에 여러 방법들을 시도했다.

ipTIME 관리자 페이지로 리스트 가져오기

가장 먼저 iptime의 관리자 페이지에서 내부 네트워크의 접속 주소 정보를 리스트로 가져올 수 API가 있을까 했지만 실패다. 그래도 AP에 접속한 직원들의 MAC 주소 리스트를 쉽게 만들 수 있었다.

특정 AP에 접속한 기기정보 명령어로 가져오기

해커톤이 있는 전날 밤, 어떻게 직원들의 리스트를 가져올 수 있을지 찾아보다가 페이스북에 글을 남겼고 Bruce Lee님이 여러 링크를 댓글로 남겨주셨다.

그 중 하나가 AP에 연결된 클라이언트들의 리스트를 가져 올 수 있는 arp 명령어를 발견 했다.

$arp -a
? (192.168.2.1) at 90:9e:33:38:d3:98 on en0 ifscope [ethernet]
? (192.168.2.13) at (incomplete) on en0 ifscope [ethernet]
? (192.168.2.20) at c:8b:fc:b1:bd:ea on en0 ifscope [ethernet]
? (192.168.2.43) at d0:53:29:c7:8a:4b on en0 ifscope [ethernet]
? (192.168.2.54) at (incomplete) on en0 ifscope [ethernet]
? (192.168.2.63) at 44:12:10:b7:12:22 on en0 ifscope [ethernet]
? (192.168.2.71) at 28:5a:eb:a2:ed:94 on en0 ifscope [ethernet]
? (192.168.2.83) at d8:1c:72:d9:ce:e on en0 ifscope [ethernet]
? (192.168.0.112) at (incomplete) on en0 ifscope [ethernet]

첫 번째는 AP에서 할당한 내부 IP정보와 할당 받은 MAC 주소를 가져올 수 있다. PC뿐만 아니라 스마트폰, 태블릿이 AP에 접속하면 리스트에 포함이 된다. 여기에서 리스트의 가장 상단에 있는 192.168.7.1은 AP의 MAC 주소이다. 하지만 arp 명령어로 테스트를 해보면서 몇 가지의 이슈가 발생했다.

  1. AP의 2.4G, 5G는 MAC 주소가 다르다.
  2. MackBook은 얼마 후 ‘incomplete’상태로 변경되어 리스트에서 없어지고 Windows 노트북은 계속해서 유지된다.
  3. arp에 나오는 기기정보들은 내 MacBook이 AP에 접속한 후에 접속한 기기들만 포함된다.

해커톤은 24시간 내 개발을 해야하기 때문에 완벽함보다는 가능성이 있는 부분을 더욱 구체화 시키는 편이 더 좋다. 그래서 추후에 위의 3가지 이슈를 해결할 수 있는 다른 방법은 실제로 서비스할 수 있을 때 찾아서 수정하기로 한다.

AP에 접속한 단말 정보 주기적으로 가져오기
$arp -a | awk '{print $2, $4}' | sed -e 's/(/''/g' | sed -e 's/)/''/g'
192.168.2.1 90:7e:32:33:d2:x1
192.168.2.13 incomplete
192.168.2.20 c:8b:fc:b1:bd:ea
192.168.2.43 d0:53:29:c7:8a:4b
192.168.2.54 incomplete
192.168.2.63 44:12:10:b7:12:22
192.168.2.71 28:5a:eb:a2:ed:94
192.168.2.83 d8:1c:72:d9:ce:eg
192.168.0.112 incomplete

필요한 데이터를 추출한 다음에 incomplete된 Mac 주소와 AP의 Mac 주소를 제외하고 웹 서버에 층 정보와 Mac 주소 리스트를 등록한다. 그리고 새로운 기기가 Wifi가 연결될 때 자동으로 웹 서버에 등록할 수 없기 때문에 setInterval 로 10초당 한번씩 확인해서 갱신되었을 때마다 웹 서버에 등록을 시켜주면서 최신으로 업데이트하도록 구현하면 된다.(사실 깊게 생각 안 했고 cronJob으로도 가능할 듯)

Mornitoring Agent에서 층 구별하기

ap = {
"90:7e:32:33:d2:x1" : "6",
"90:8f:31:33:d1:93" : "7"
}

층 정보는 arp 명령어의 결과에서 받은 ‘192.168.2.1 90:7e:32:33:d2:x1’의 MAC 주소와 Agent에 등록된 AP MAC 주소를 비교해서 몇 층에 위치한 모니터링 서버인지 구별할 수 있다. 위를 비교해보면 결과물은 6층 AP임을 알 수 있다.

2. Express for Node.js – 웹 서버 만들기

이번 프로젝트는 간단한 Rest API와 웹 서버가 필요했기 때문에 빠르게 구현할 수 있는 Express를 사용했다.

직원들이 사용하는 단말의 MAC 주소 리스트 미리 등록하기
flittorians = {
"78:31:c0:c3:e4:13" : "김케빈",
"54:4d:80:94:7e:c1" : "김케빈 아이폰",
...
}

웹 서버에서는 직원들의 Mac 주소 리스트를 가지고 있으므로 층 별로 모니터링 하는 Agent에서 변화를 알려주면 층 별로 매칭되는 직원들의 최신 리스트를 가지고 있을 수 있게 된다. 그리고 이 정보가 필요할 땐 JSON으로 보내준다.

Slack Bot 연동하기

Bruce Lee님의 이번 주제는 ‘슬랙봇 만들기’이다. 새벽이 되었을 때 층 별 API를 요청을 하셨고, 간단한 작업이라 만들어 드렸더니 본인이 만들던 슬랙봇에 연결을 했다. 서로 말하고 시작한 프로젝트가 아니였는데 재밌다. 때로는 독립적인 작은 덩어리가 서로 연결되어 큰 덩어리가 된다. 이런게 바로 개발의 행복 그리고 소소한 재미를 느낄 수 있었다.

3. ejs & bootstrap 으로 웹 페이지 만들기

웹 프론트 작업은 새벽 4시정도 부터 시작할 수 있었는데 이번 해커톤은 혼자지만 생각보다 진행이 잘되어 발표시간(12시)까지는 8시간을 남겨놓은 상태라 여유로운 편이다. 웹페이지는 express 만들 때 탬플릿으로 ejs를 설정했기 때문에 간단하게 bootstrap을 사용하여 간단한 table로 구성했다. 처음에는 스타일 없이 작업을 하고 시간적 여유가 있다면 간단히 스타일을 주는건 결과물을 보는 청중에게 더욱 인정받는 결과물이 된다. 여기에서 table은 bootstap-table을 사용해서 간단히 스타일을 적용했다.

정리하면서..

그리고 국내에서든, 국외에서든 모든 해커톤에서는 시간 관리가 제일 중요하다. 아무리 뛰어난 아이디어라고 하더라도 발표 때 결과물이 없다면 또는 만들었지만 정상적으로 동작하지 않는다면 심사위원들에게 인정 받지 못하기 때문에 심사위원에게 무엇을 어떻게 어필할지 있을지 마지막까지 고민해야한다. 즉, 시간이 걸리는 작업은 되도록 나중에 하는 것이 낫다라는게 개인적인 생각이다. 새로운 팀빌딩으로 작업을 하기 때문에 밤새하지 않더라도 적어도 프로토타입을 보여줄 수 있을 정도면 충분한 것 같다

SlidingIconTabLayout 탭에 아이콘 넣기

구글에서는 현재 많은 샘플 코드들을 개발자가 전반적인 프로젝트 구조나 리소스, 코드 파일들을 볼 수 있도록 제공해주고 있다. 그 중에서 Material Design이 안드로이드 5.0에서 소개되면서 UI관련 소스들을 많이 추가되었고 많은 프로젝트에서 SlidingTabLayoutSlidingTabStrip를 사용한다.

프로젝트에서 ViewPager를 이용하게 되면 페이지의 이름을 보여주기 위한 레이아웃이 필요하게 되는데, 만약 탭의 이름을 텍스트로 보여주고 싶다면 구글에서 제공해주는 위의 두 파일로 충분히 구현할 수 있다. 하지만 텍스트를 사용할 경우, 다국어 지원을 하게 되면 여러가지 이슈가 발생하게 되는데 예를 들면, 한국어를 영어로 바꿀 경우에는 대부분 글자수가 많아진다. 이를 해결하기 위해서 흔히 탭의 이름을 아이콘으로 대체하고 ActionBar의 타이틀에 페이지의 이름을 노출하고 있다. 텍스트와 아이콘을 모두 지원하기 위해서 SlidingTabLayout에 아이콘도 추가할 수 있도록 간단한 인터페이스를 추가해서 오픈소스 SlidingIconTabLayout로 만들었다.

SlidingIconTabLayout

Download

repositories {
  jcenter()
}

dependencies {
  compile 'com.github.kimkevin:slidingicontablayout:1.0.0'
}

SlidingTabLayout.TabIconProvider 추가하기

SlidingIconTabLayout.TabIconProvider는 안드로이드 화면상에 노출되는 다수의 Fragment를 관리하기 위한 어답터이다. Fragment에 필요한 데이터나 리소스를 위치(Position)에 맞게 그려주기 위해서 FragmentPagerAdapter를 상속 받아야 하기 때문에 이때 아이콘을 텍스트 대신에 보여주기 위한 인터페이스가 필요하다.

public interface TabIconProvider {
    int getPageIconResId(int position);
}

SlidingTabLayout 수정

TabIconProvider를 상속받고 있다면 텍스트 대신 아이콘을 사용할 수 있다.

if (TextView.class.isInstance(tabTitleView)) {
    ((TextView) tabTitleView).setText(adapter.getPageTitle(i));
} else if (ImageView.class.isInstance(tabTitleView) && adapter instanceof TabIconProvider {
    TabIconProvider mTabIconProvider = (TabIconProvider) adapter;
    tabTitleView.setBackgroundResource(mTabIconProvider.getPageIconResId(i));
}

사용할 FragmentTabIconProvider를 추가해서 필요한 아이콘을 추가해주면 해당 Tab의 아이콘으로 노출된다.

모알보알 스쿠버다이빙, 삶의 균형을 위한 중성부력

새로운 도전! 스쿠버다이빙

scuba_diving_01

올해 8월 초, 5일간 필리핀 세부를 다녀왔다. 예전부터 꼭 하고 싶었지만, 2년 전 아일랜드 호핑으로 느꼈던 세부의 짠물에 대한 공포때문에 미뤄두고 있었던 스쿠버다이빙, 오픈워터에 도전하기로 마음 먹었다. 장소는 세부시티에서 가까운 막탄보다는 깨끗해서 투명한 바다, 많은 종류의 산호초와 사람만한 거북이, 화려한 색감의 열대어를 볼 수 있는 다이빙 포인트로 유명한 모알보알이다. 강사 말로는 예전에는 고래상어가 출몰해서 섬을 몇 바퀴 돌면서 머물다가 갔다고 했다.

막탄 공항에 도착하다

scuba_diving_02

막탄 공항을 빠져나와 택시타고 서부터미널로 향했다. 택시비는 약 500페소 정도면 갈 수 있다. 택시를 이용할 때는 잔돈이 있는게 좋다. 기사 아저씨들은 돈만 받으면 잔돈이 없다는 뻔한 말들을 하기 시작한다. 그래도 택시에 내리지 말고 버티다 보면 슬그머니 돈을 꺼내기 시작하면서 재미가 쏠쏠한 밀당이 시작된다. 터미널 안은 매표소가 별도로 없고 버스타고 출발하면 아저씨가 표를 주는데, 버스 이용요금은 116페소 한국돈으로 3300원 정도다. 만약 터미널이나 공항에서 벤이나 택시를 이용하게 되면 한국돈으로 6만원 ~ 10만원 든다고 한다. 여행하면서 로컬 버스를 타보는 것도 좋은 경험이 될 것 이라고 생각한다면 이것은 고생이다. 이동 시간이 4시간이라는 것만 빼고는… 세부시티로 돌아오는 길에는 약5시간 가까이 걸렸던 것 같다.

수심 30m에서 찾아온 나의 균형

scuba_diving_03

나에게 있어서 여행은 휴가, 휴식의 의미보다는 여행을 통한 배움을 위해서다. 그래서 꼭 1년에 한번 이상은 국내나 해외를 여행한다. 그럼 이번 오픈워터를 통해서는 무엇을 배웠을까? 이번 오픈워터 도전을 통해서 배운건 다른 여행보다 의미가 컸다. 스타트업 로켓에 탑승하기 전까지, 방세를 내며 여름 방학동안 공모전 공장을 운영해봤었고, 개발자에게는 좋은 근무환경을 제공하는 IT회사에서 근무도 해봤었다. 그리고 짧은 시간이었지만 미국에서 스타트업을 경험도 해보았다. 짧다면 짧고 길다면 긴 시간동안 많은 경험을 했던 만큼 나 자신에 대해 고민하고 생각해보면서 내놓은 결론이 있다. 삶에 있어서 가족, 친구, 지인, 회사, 꿈도 중요하지만 모든 곳에서 꼭 있어야 하는 무엇보다 중요한 바로 균형이라고 생각한다. 그것을 몸으로 느껴볼 수 있었던 경험이 바로 하루 3 ~ 5시간씩 물 속에서 있을 때였다.

두려움을 극복하라

scuba_diving_04

스쿠버다이빙에서 중성부력이라는 용어가 있다. 부력(위로 올라가려는 힘) 중력의 힘(아래로 내려가려는 힘)이 동일한 상태로, 물 속에서 뜨지도 가라 앉지도 않는 상태이며, 다이빙을 하면서 이 상태로 자신의 호흡만으로 즉, 폐 안의 공기를 이용해 수심을 유지하는 방법이다. 밸트에 납 때문에 중력으로 쉽게 밑으로 내려갈 수 있고, 부력조절기(BC)로 불리는 조끼같이 생긴 장비 때문에, BC에 공기를 넣어 중력의 반대의 힘 부력을 만들 수 있다.

스쿠버다이빙을 편하고 즐겁게 하기 위해서는 중성부력을 맞추지 못하면 다이빙하고 있는 수심이 낮아졌다 높아졌다하면서 이퀄라이징을 자주 해야하기 때문에 귀에 무리가 가고 귀가 아프기도 한다.

이런 이유보다 쉽게 중성부력을 잡지 못하는건 바로 내 마음속에 있는 두려움 때문이다. 두려움이 내 몸에 힘이 들어가게 만들고 힘이 들어가면 호흡이 가빠지다 보니 불안해지기 때문에 상황대처능력도 떨어지며 바로 앞에 있는 아름다운 바다를 보는 시야도 줄어들게 된다.

두려움 이겨내는 중성부력

scuba_diving_05

하루에 2 ~ 3시간 동안 바다 안에 있으면서 두려움을 잊기 위해서 많은 시도를 해봤지만 언제 어디서 나올지 모를 상어에 대한 걱정(강사도 실제로 큰 상어를 본적은 없다고 한다), 언제 마스크가 벗겨질지 모를 상황에 대한 걱정, 강사를 놓치진 않을까 하는 걱정, 아픈 귀에 대한 걱정, 공기통에 남은 공기의 양에 대한 걱정 등 물속에서 생각해야하는 것들이 많았다. 여러 환경적 요소들로 인해서 몸에는 힘이 잔득 들어가고 그로 인해 몸은 가라앉고, BC에 공기를 넣었다 빼는데 바빴던 것이다. 앞을 볼 시간은 줄어들었고 집중력은 떨어졌다. 즉 내가 보고 싶은 바다를 편안하게 보기 위해 필요했던건 바로 균형이었다.

그리고 문득 바다속에서 내가 처한 상황이 우리의 상황과 비슷하다는 생각이 들었다. 정신적으로 여유를 가지고 몸에는 힘을 뺀채로 넓은 시야로 눈 앞에 있는 문제들을 해결해야 하는데, 사소한 문제들로 인해서 균형이 깨져서 힘들어 하고 있진 않을까? 그게 금전적 문제, 직업, 직장이든 말이다.

직장인이라면 누구나 불안함을 지니고 산다. 하지만 생각해보면 그 불안감은 자기 자신이 만드는 것이다. 옆에서 상어가 오진 않을까 강사를 놓치진 않을까, 결국 나 자신이 만든 불안감으로 부터 시작되었다. 외부적 요인이 몸에 힘이 들어가게 했고 바다속으로 가라 앉도록 했던 것이다. 결국 부력(여유)이 중력(불안감)을 받쳐주지 못하기 때문이다. 자신이 여유를 생산하고 불안을 잘 컨트롤 할 수 있다면 그게 바로 균형일 것이다. 우리가 재미있고 행복하게 지내기 위해 가장 필요한 것은 균형을 맞추기 위한 중성부력이 아닐까 생각한다.

리얼포스 & 해피해킹 오사카 키보드 구매기

지난 주말, 해피해킹 키보드를 구매했다. 2년전 첫 번째 키보드는 기계식 레올포드 FC700R 중고를 구매하면서 부터다. 구매전에는 리얼포스, 해피해킹, 레오폴드, DECK등 많은 키보드들을 알아보았지만 처음에는 가장 무난한 FC700R의 적축으로 사용했다. 기계식 키보드에는 적축, 갈축, 청축, 흑축이 있는데, 타건을 해보면 축마다 특유의 차이점이 있다. 구매전 리더스키레오포들 사이트를 자주 들어가보면서 가격과 재고를 자주 확인하기도 했었고 만약 직접 타건을 해보고 싶으면 용산역 리더스키에 가서 키보드를 직접 사용해볼 수 있다.

FC700R

FC700R

첫 번째 키보드를 구매할 때 가장 좋고 비싼 해피해킹이나 리얼포스를 살까라고 생각했지만, 한국에서 구매하기엔 부담스러운 가격이라 FC700R 중고를 구매해서 사용해보기로 했다. 첫 번째 기계식 키보드 FC700R은 나에게 대만족이었다.

그리고 작년 9월, 미국에서 만난 일본 친구들을 보기 위해 오사카를 여행을 계획했고, 이왕 가는김에 키보드 구매를 결심했다. 검색으로 여기저기 돌아다니며 블로그 구매후기도 찾아 읽어보고가 덴덴타운에 대한 단서를 찾을 수 있었다. 20만원 정도에 구매를 했다는 후기를 보았던 것 같다.

리얼포스

Real Force

작년 오사카에서 리얼포스를 구매했다. 오사카 난바역에서 Nippombashi St을 찾아 걷다보면 오타쿠 천국이라고 불리는 거리를 볼 수 있게 된다. 길 양쪽으로는 게임, 피규어, 만화, 전자기기등 용산전자상가같은 느낌으로 길게 나열된 스토어들이 있다. 일본 만화나 피규어, 게임을 좋아한다면 하루도 충분히 보낼 수 있다. 지금까지 한번도 피규어를 사본적 적도 관심도 없던 나였지만 리얼포스를 사러 가던길에 피규어 샵에 들러서 구경하다 보니, 나도 모르게, 정말 나도 모르게 스토어를 나올 땐 내 손에는 두 개의 피규어가 있었다.

많은 스토어들을 찾아 들어가 리얼포스의 행방을 물었지만 87키가 없을 뿐더러 제품을 찾기는 어려웠다. 처음에는 1’s라는 가게를 모르고 모든 곳을 찾아다니면서 가격을 비교해봤고 가장 저렴하게 판매되던 곳이 1’s였던 것으로 기억한다. 덴덴타운에서는 리얼포스 파는 곳이 3~4곳은 있었던 것 같다.

1’s

1’s(one’s) PCワンズ Google Maps

가게에 도착해서 아래 계단으로 내려가면 다양한 키보드가 나열되어 있고, 올 해에는 작년에 보지 못한 레올폴드 FC660C도 봤는데 일본에서는 리얼포스보다 비싼 가격이었다. 리얼포스 가격은 작년 내가 구매한 20,980엔으로 변함이 없었다. 텍스프리를 작년 리얼포스 구매할 때 알았다면 이보다는 훨씬 싼가격으로 구매했을 텐데 사기전에 잘 알아보고 구매하는 것이 현명하다. 예상하기론 1’s에서도 텍스프리로 구매가 가능하겠지만, 만약 되지 않는다면 요도바시카메라나 다른 스토어에서 사는게 더 저렴할 수 있을 것 같다. 그리고 차등을 구매해서 물어보지 않아서 균등, 저소음 차등은 구매가 가능한지는 모르겠다.

Realforce Price

사용후기는 FC700R을 반년 정도 사용하다가 리얼포스로 바꾸니 처음에는 묵직한(?) 느낌으로 오히려 손가락에 부담이 되는거 같았지만, 일주일 정도 개발을 하다보니 어느새 리얼포스가 더 부드럽고 타건 재미에 빠졌다.

해피해킹 프로2 – 요도바시 카메라

Happy Hacking Pro2

지난주 일본 친구의 결혼식으로 다시 한번 오사카를 방문했다. 비행기 티켓 예약보다 먼저 구글 검색에 해피해킹 프로2 구매관련 키워드를 입력을 하고 있었다. 한 분의 구매기를 읽었더니 19,800엔 정도로 오사카에서 구매를 했다는 글을 읽고 구매를 결심했다. 작년에 리얼포스를 구매했던 곳(one’s)에서 구래를 할 수 있을 거라 생각하고 오사카 도착 후 일본친구와 함께 one’s를 갔지만 아쉽게도 해피해킹은 판매하지 않았다.

검색이 필요한 타이밍이다. 글 보다는 댓글에 초점을 맞추었다. 댓글 중에서 우메다 역에 있는 요도바시카메라에서 구매한 사람을 발견하고 교토를 가기전에 우메다역에 있는 요도바시카메라를 잠시 들러서 찾아보았다.

Happy Hacking Pro2

해피해킹 프로2 가격은 약 24,000엔. 분명 어제 보았던 글에서는 분명 19,800엔으로 봤던거 같은데 싸게 산 사람을 글을 읽고 났더니 구매의욕이 떨어졌다. 하지만 일본친구가 점원을 불러 이야기를 하더니 TAX FREE로 싸게 살 수 있다고 한다. 가격은 2개에 39,600엔, TAX FREE를 왜 몰랐을까라는 생각은 잠시 점원이 VISA카드로 결제하면 6% 할인을 더 해주겠다고 한다. 추가 할인이 가능하고 했을 경우 2개에 37,236엔, 하나에 18,600엔 정도 되는 가격으로 해피해킹 프로2를 구매할 수 있었다.

Happy Hacking Pro2 Price

아직까지 어떤 키보드를 살지 구매를 고민하고 있다면 일단 구매하고 사용해 보면 돈이 아까운 생각은 들지 않는다. 자신이 사고 싶은 키보드를 빨리 구매해서 그 시간만큼 열심히 개발하자.

Keyboard

Twitter Flock Seoul 2015 – Fabric

Awesome ! Twitter Flock Seoul 2015

백앤드 개발자들을 통해 빌드 및 배포 자동화를 위해 fabric을 사용하고 있다는 이야기를 들은 적이 있다. 그리고 얼마전 알고 지내는 스타트업에서 fabric을 통해 배포 직전인 앱을 사람들의 이메일 등록을 통해 배포하는 것을 보았다. 물론 앞서 말한 두 개의 fabric은 서로 다른 이야기다. 이번 Twitter Flock 행사는 한국에서는 처음 열렸고, 모바일 개발자들에게 도움될 만한 주제들이 많았다.

먼저 패브릭(fabric)은 모바일 개발자들이 트위터에서 제공해주는 툴을 사용해 더 안정된 앱을 만들 수 있도록 도와주고 있다. 앱 개발에서의 안정성, 사용자 확보, 수익성, 사용자 인증 등을 해결하기 위해 여러가지 툴(Kit)를 내놓았고, Crashlytics, MoPub, Twitter Kit Answers 등이 있다.

App Stablilty(안정성)
  • Crashlytics : 모바일 충돌(오류) 감지 및 분석
  • Beta for Crashlytics : 앱 베타 오픈 테스트 관리
Identity(사용자 인증)
  • Digits : 전화번호를 통해 서비스 로그인
  • Log in with Twitter : 트위터 인증 로그인
Distribution(사용자 확성)
  • Twitter Kit : 네이비트 트윗 임베드, 드윗 컴포저 기능 제공
Mobile Analytics(사용자 분석)
  • Answers : 실시간으로 앱 최적화를 위한 분석
Monetization(수익성)
  • MoPub : 모바일 앱 개발자들을 위한 최고의 광고 플랫폼

더 자세한 사항은 패브릭(fabric)소개 에서 읽어 볼 수 있다.


행사 등록 (오후 13:00 ~ 14:00)

Flock은 개발자 컨퍼런스를 뜻하고, Fabric은 작년 10월 Twitter Flight 개발자 컨퍼런스에서 앱 제작을 지원하는 모듈식 개발 도구 모음이다. 장소는 학동역 부근 Patio9이었고 네임택을 받고 입장했을 때는 해외 기업 컨퍼런스라 그런지 다른 컨퍼런스와는 달리 클럽 조명과 음악으로 분위기가 더 좋았던 것 같다. 마치 2년전 샌프란시스코 TechCrunch를 갔었던 느낌이다. 세션 대부분은 Fabric 개발 도구를 만든 엔지니어, 개발자들의 세션이었고, 정보와 지식을 공유하기 위한 자리였다.

기조 연설, 데모, 파트너 성공 사례 (오후 14:00 ~ 15:00)

Twitter 코리아 대표가 나와 기조 연설을 했고, 왜 Fabric을 만들게 되었으며, 왜 사용해야하는지에 대해서 이야기를 들을 수 있었다. 그리고 이어서 파트너 성공 사례로 한국 스타트업의 개발 담당자들이 패널로 참석해 정보를 공유하는 자리를 가졌다.

현재 스타트업에서 Fabric 개발 도구 중 무엇을 어떻게 사용하고 있으며, 어떤 장점을 가지고 있는지 정보를 들을 수 있었고, 왜 스타트업에서 Fabric을 사용하면 좋은지에 대해서 들을 수 있는 자리였으며 ‘Between’을 개발한 VCNC, Flitto, ‘배달의 민족’의 우아한 형제들, ‘알람몬’의 말랑스튜디오 개발자 분들이 직접 앞에 나와 트위터 코리아 소영선 대표와 서로 질문과 답변식으로 대화를 나누었다. 사실 Fabric의 장점만 나열되는 것 같아 조금 아쉬운 질의응답 시간이었던 것 같다. 더 궁금하면 직접 실행으로 옮기자! 게을러지지 말자!

Digits: A Better Way to Login (오후 15:00 ~ 15:30)

우리가 대부분의 앱을 처음 사용할 때 거치는 첫 번째 단계는 회원 가입이다. 지루한 가입 단계로 인한 유입율을 높이기 위해서 대부분의 기업에서 페이스북, 트위터, 구글+ 로그인을 사용해서 수 십초 이내에 앱의 첫 화면을 볼 수 있도록 해주고 있다. 여기에 트위터는 더 좋은, 더 쉬운, 더 빠른 로그인 방법인 휴대폰 번호를 위한 인증을 내놓았다. 휴대폰 번호를 통한 인증은 보통 본인 인증때 우리가 사용하는 방식으로, 그 방법을 이용해서 회원 가입을 하도록 새로운 방안을 제시했다. 휴대폰 번호만 있으면 회원 가입이 가능하도록 하며 간편하고 그 만큼 안전하다고 한다. 무엇보다 개발자가 이를 개발하기 위한 단계도 굉장히 심플하게 만들었다. Fabric을 맥에 설치하면 상단 메뉴를 통해서 가이드와 관리를 할 수 있도록 제공해주고 있다.

Crashlytics: Quality First (오후 15:45 ~ 16:15)

대부분 현재 서비스하고 있는 기업이라면 Flurry, BugSense, Google Analytics 등을 통해 광고, 분석, 버그 추적 등을 하고 있을 것이다. 기본적으로 이를 사용하는 이유는 버그를 가진 앱을 배포했을 때 발생하는 피해, 앱 순위 하락과 좋지 못한 리뷰로 상처를 덜?받기 위해서(덜 받아도 상처는 상처) 그리고 개발 시간을 보다 단축시키기 위해서 사용한다. 이에 Twitter에서는 Crashlytics라는 도구를 만들었고 무료로 기업들이 사용할 수 있도록 배포하고 있다는 점, 또한 정말 사용하기 쉽도록 구현되어 있다는 것이다. 간단한 코드에 키를 등록해주면 자사 서비스와 연동이 되도록 만들어져 있다.

TwitterKit: Tap Into the Pulse of the Planet (오후 16:15 ~ 16:45)

예전에는 트윗을 임베드하기 위해서는 네이티브에 별도의 구현을 해야하기 때문에 비용이 많이 들었다. 이에 Twitter Kit은 코드 몇 줄을 통해 트윗 임베드를 편리하게 할 수 있도록 다양한 기능을 제공해주고 있다. 또한 트윗 컴포저는 앱 내에서 사용자가 트위터 팔로우들에게 사용자 자신만의 경험을 편리하게 공유할 수 있도록 제공해주는 기능이다. 디자인 또한 앱의 테마에 맞도록 커스텀하게 변경이 가능하여 스타일을 변경할 수 있다. 이 중에서 가장 필요했던 기능은 트위터 로그인(Log in with Twitter)인데, 기존의 트위터 로그인 인증시 사용자의 이메일을 알지 못했다. 이제는 사용자 동의를 통해서 사용자의 이메일을 수집할 수 있도록 기능을 제공해준다고 한다.

앞서 말한 모든 툴은 트위터에서 무료로 제공한다. 베타 버전 준비부터 서비스 오픈, 서비스 버그 관리, 사용자 분석, 개별 광고까지 모두 하나의 툴에서 할 수 있다는 점은 정말 놀랍다. 전화번호 인증, 크래시리틱스, 트위터의 타임라인 가쟈오기, 트위터로 공유하기, 앱에서 테마 수정 등 이 모든 툴을 사용하기 위해 필요한 것은 단 코드 몇줄이면 가능했다. 맥북 오른쪽 상단에 있는 패브릭 아이콘을 이용해서 베타 버전 배포를 위한 테스터 이메일 등록 후 배포, 툴을 사용하기 위핸 API 문서부터 코드까지 관리를 해주었고 코드를 복사/붙여넣기로 간단하게 개발할 수 있도록 되어 있었다. 패브릭은 개발자가 사용하는 개발 비용을 줄여주고 편리하게 개발할 수 있도록 정말 많은 노력을 기울였다는 생각이 들었고 많은 준비를 한 것 같다. 모바일 앱 개발자를 위한 정말 좋은 툴 하나가 나온 것 같다.

패브릭은 개발자 여러분이 사용하는 엑스코드(Xcode), 이클립스(Eclipse), 안드로이드 스튜디오(Android Studio), 인텔리제이(IntelliJ) 등의 IDE와 연동되어 있습니다. 패브릭은 또한 자동화된 코드 빌더와 테스트 툴과도 연동되어 있습니다. 덕분에 개발자 여러분은 키트의 업데이트에 대해 걱정할 필요가 없습니다. 패브릭이 업데이트가 올라올 때마다 여러분에게 알림을 줄 것이기 때문입니다. from 트위터 블로그

AWSome Day 한정판? 티셔츠와 수료증 받기

얼마전에 AWSome Day를 행사에 참여했다. AWSome Day는 아마존 클라우드 웹 서비스에서 지원하는 교육 프로그램으로 1년에 한번 열린다. 작년 행사 시기에 해외에 있었기 때문에 참여하지 못했고, 이번 행사때는 회사에서 지원해준 덕분에 출근 대신에 코엑스로 향했다. 회사 바로 앞이 코엑스라는 점, 사실 출근과 비슷하다.

평일이기 때문에 등록을 위한 줄을 선 분들은 모두 직장인들일 것이다. 많은 회사에서 AWS 교육을 지원하고 있는 것으로 보였고 네임택을 봐서나 경품 추천 때 불려지는 근무 중인 회사 이름은 대부분 우리가 알고 있는 대기업이었다. 등록은 이미 SNS로 보내준 태그로 쉽게 확인이 가능했고 경품 추천을 위해 명함을 한 부를 경품통에 넣고 입장했다. 이번 행사의 경품은 무선 마우스와 킨들로 나름 저번 자바 컨퍼런스에서 경품으로 주었던 리얼포스 키보드에 비해 소홀하다. 지금까지 경품을 받아본 이력은 사실 없다…

마련된 좌석이 부족할 정도로 많은 사람들이 행사에 참여했고, 모든 교육이수 후 한정판(?) 티셔츠를 준다는 Ash Willis의 환영사로 행사가 시작되었다. 환영사에서 행사의 개요와 일정은 다음과 같다.

첫 번째 스피커는 이국희 팀장님으로 AWS의 소개와 AWS 관리 콘솔의 간단한 사용법, 관리 콘솔의 보안 관련 기능 및 보안 기본 원칙에 대해서 이야기 해주셨고, 스피치에 비유를 빗대어 설명을 해주셔서 이해하는데 흥을 돋구었다. 클라우드가 나오기 전과 후를 비교하자면 전기, 수도와 같이 혁신적이다고 말했다. 또한 AWS 웹서비스를 컴퓨터와 비유하자면 CPU+RAM은 Amazon EC2, HDD는 EBS, 웹하드는 S3와 같다고 한다. 현재 회사에서 AWS를 사용하고 있기 때문에 설명을 이해하는데 어렵지는 않았다. 물론 스피커 분들이 설명을 아주 쉽게 자세히 설명해주었기 때문에 서비스를 처음 접해 보는 사람도 이해할 수 있을 것 같았다

가장 대표적인 서비스 EC2에 대해서는 검색을 해본다면 더욱 자세한 자료를 얻어 볼 수 있지만, 현재 교육 수료자인 본인이 직접 기억하는 바로는 용량 조절이 가능한 가상 서버이며 컴퓨터 리소스에 대한 제어가 가능한 인스턴스이다. 서버 인스턴스를 획득하여 부팅하는데 필요한 시간을 수분내로 단축시킴으로써 개발자가 개발 환경 구축을 위한 시간을 줄일 수 있다. 실제로 이미 t1.micro를 사용해본 경험상 쉽게 인스턴스 즉 서버를 만들고 실행하는데 수분내로 가능하다. 또한 운영체제의 선택과 운영 요금의 경우 사용자 본인이 선택할 수 있으며 사용하지 않을 경우는 잠시 꺼두어 절약이 가능하다. 예를 들어 말하자면 수도꼭지를 잠그지 않고 외출을 한다면 한달 후 통지서에 폭탄을 맞은 금액을 받아 볼 수도 있으니 사용하지 않을 땐 반드시 잘 잠그어야 한다고 충고를 덧붙여주셨다.

2교시는 양승도 수석님이 S3에 대해서 설명해주셨고 시작전 “AWS 스토리지는 빨간색 표현한다” 이것만 기억해달라는 당부의 메시지도 전했다. S3를 간단히 설명하자면 우리가 흔히 사용하는 HTTP나 HTTPS로 액세스가 가능한 스토리지이며 오브젝트로 저장, 조회가 가능하다. 특히 기억나는 것은 내구성이다. Eleven Nine을 강조하셨는데 11개의 9 소수점까지의 내구성을 보장한다고 한다. 예를 들면 10000개의 오브젝트트를 100만년 저장한다면 1개를 잃어버릴 확률이 이에 해당한다. 이외에도 오브젝트를 담기 위한 버킷을 만들기 위해서는 유일한 이름을 지정해주어야 한다고 당부했다.

행사에 참여해서 기록한 교육 내용은 이곳에서 모두 설명하기엔 많으므로 1교시와 2교시에 대해 간단히 이야기를 했고 나머지는 네트워킹과 데이터베이스 마지막으로 관리 및 배포를 수강했다. 이 강의가 좋은 점은 바로 설명을 중간에 스피커 분들이 직접해주시는 시연이다. 직접 관리 콘솔에서 하나씩 설명을 덧붙여 클릭으로 실행해주셔서 이해하는데 도움이 되었다.

현재 AWS 웹서비스에서 제공하는 서비스들이 무수히 많기 때문에 대표적인 몇 가지에 대해서만 자세히 설명을 해주었고 이외에 필요한 정보들은 http://aws-training-apac.com 에 접속하여 동영상과 자료를 볼 수 있다고 한다. 이렇게 5교시 까지 모든 세션 교육과정이 끝이난다.

마치 하루 동안 5개의 대학 수업을 들은 느낌이 들었지만, 실제로 하나씩 다 사용해보고 싶은 생각이 들었다. 바로 이것이 이 교육이 추구하는 목표가 아닐까라는 생각을 하면서 문을 나서는데 눈앞에 보이는 것은 바로 수료증과 한정판(?) 티셔츠를 받기 위한 긴 줄이다. 6교시가 남은 기분이다. 교육도 교육이지만 무엇보다 직접 해보는 것만한 것은 없다. 만약 신규 회원 가입을 하게 되면 1년간 일정량씩 모든 서비스를 사용해 볼 수 있는 기회가 주어진다. 그 기회를 이용해 관리 콘솔에서 직접 해보는 것이 가장 큰 공부가 아닐까 생각한다.

[Andorid] Gradle Test Case 개발시 겪은 에러

이전 글 처럼 우연히 TDD에 대해서 알게되었고, 그에 관해 공부해보고 싶은 마음에 시작했다. TDD란 의미는 테스트를 기반으로 한 개발방법론이기 때문에 현재 내가 진행중인 프로젝트에 적목해 보기가 쉽지 않았다. 그로 인해 기본 프로젝트에 맞는 Test Case 개발을 진행해 보면서 겪은 문제점들에 대해서 적으려고 한다.

ActionBarActivity 사용시 겪은 에러

@Test
public void createAdapter() throws Exception{
    MainActivity activity = Robolectric.buildActivity(MainActivity.class).create().get();
    assertThat(activity, notNullValue());

MainActivity를 생성하는 과정에서 NullPointerException 에러가 발생한다. 그 이유는 MainActivity가 ActionBarActivity를 상속을 받고 있기 때문이었고 Activity를 상속 받게 되면 에러는 발생하지 않았다. 이를 위한 해결책으로 activity를 생성하고 사용하는 함수들 위에 @Test와 마찬가지로 @Config(reportSdk = 10)을 다음과 같이 선언해 주어야 한다.

@Test      @Config(reportSdk = 10)
public void createAdapter() throws Exception{
        MainActivity activity = Robolectric.buildActivity(MainActivity.class).create().get();
        assertThat(activity, notNullValue());

이유를 명확히 하기 위해서 찾아보았지만 자세한 이유에 대해 찾기가 어려웠다. 이후에 자세히 알게 된다면 다시 적을 예정.