아직 정확히 어떤 기능을 하는지 확인되지 않고 있음

android:freezesText

If set, the text view will include its current complete text inside of its frozen icicle in addition to meta-data such as the current cursor position. By default this is disabled; it can be useful when the contents of a text view is not stored in a persistent place such as a content provider.

Must be a boolean value, either "true" or "false".

This may also be a reference to a resource (in the form "@[package:]type:name") or theme attribute (in the form "?[package:][type:]name") containing a value of this type.

This corresponds to the global attribute resource symbol freezesText.

android:inputType

The type of data being placed in a text field, used to help an input method decide how to let the user enter text. The constants here correspond to those defined by InputType. Generally you can select a single value, though some can be combined together as indicated. Setting this attribute to anything besides none also implies that the text is editable.

Must be one or more (separated by '|') of the following constant values.

ConstantValueDescription
none0x00000000There is no content type. The text is not editable.
text0x00000001

멀티라인을 지원하지 않아서 키보드에서 Enter 키 입력이 무시된다.
Just plain old text. Corresponds to 

TYPE_CLASS_TEXT |TYPE_TEXT_VARIATION_NORMAL.
textCapCharacters0x00001001Can be combined with text and its variations to request capitalization of all characters. Corresponds to TYPE_TEXT_FLAG_CAP_CHARACTERS.
textCapWords0x00002001Can be combined with text and its variations to request capitalization of the first character of every word. Corresponds toTYPE_TEXT_FLAG_CAP_WORDS.
textCapSentences0x00004001Can be combined with text and its variations to request capitalization of the first character of every sentence. Corresponds toTYPE_TEXT_FLAG_CAP_SENTENCES.
textAutoCorrect0x00008001Can be combined with text and its variations to request auto-correction of text being input. Corresponds to TYPE_TEXT_FLAG_AUTO_CORRECT.
textAutoComplete0x00010001Can be combined with text and its variations to specify that this field will be doing its own auto-completion and talking with the input method appropriately. Corresponds toTYPE_TEXT_FLAG_AUTO_COMPLETE.
textMultiLine0x00020001

문자 입력시 멀티 라인입력이 가능하다.
Can be combined with 

text and its variations to allow multiple lines of text in the field. If this flag is not set, the text field will be constrained to a single line. Corresponds to TYPE_TEXT_FLAG_MULTI_LINE.
textImeMultiLine0x00040001Can be combined with text and its variations to indicate that though the regular text view should not be multiple lines, the IME should provide multiple lines if it can. Corresponds toTYPE_TEXT_FLAG_IME_MULTI_LINE.
textNoSuggestions0x00080001Can be combined with text and its variations to indicate that the IME should not show any dictionary-based word suggestions. Corresponds to TYPE_TEXT_FLAG_NO_SUGGESTIONS.
textUri0x00000011Text that will be used as a URI. Corresponds to TYPE_CLASS_TEXT |TYPE_TEXT_VARIATION_URI.
textEmailAddress0x00000021Text that will be used as an e-mail address. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS.
textEmailSubject0x00000031Text that is being supplied as the subject of an e-mail. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_SUBJECT.
textShortMessage0x00000041Text that is the content of a short message. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_SHORT_MESSAGE.
textLongMessage0x00000051Text that is the content of a long message. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_LONG_MESSAGE.
textPersonName0x00000061Text that is the name of a person. Corresponds to TYPE_CLASS_TEXT |TYPE_TEXT_VARIATION_PERSON_NAME.
textPostalAddress0x00000071Text that is being supplied as a postal mailing address. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_POSTAL_ADDRESS.
textPassword0x00000081Text that is a password. Corresponds to TYPE_CLASS_TEXT |TYPE_TEXT_VARIATION_PASSWORD.
textVisiblePassword0x00000091Text that is a password that should be visible. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD.
textWebEditText0x000000a1Text that is being supplied as text in a web form. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_WEB_EDIT_TEXT.
textFilter0x000000b1Text that is filtering some other data. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_FILTER.
textPhonetic0x000000c1Text that is for phonetic pronunciation, such as a phonetic name field in a contact entry. Corresponds to TYPE_CLASS_TEXT |TYPE_TEXT_VARIATION_PHONETIC.
textWebEmailAddress0x000000d1Text that will be used as an e-mail address on a web form. Corresponds to TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS.
textWebPassword0x000000e1Text that will be used as a password on a web form. Corresponds toTYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_WEB_PASSWORD.
number0x00000002A numeric only field. Corresponds to TYPE_CLASS_NUMBER |TYPE_NUMBER_VARIATION_NORMAL.
numberSigned0x00001002Can be combined with number and its other options to allow a signed number. Corresponds to TYPE_CLASS_NUMBER |TYPE_NUMBER_FLAG_SIGNED.
numberDecimal0x00002002Can be combined with number and its other options to allow a decimal (fractional) number. Corresponds to TYPE_CLASS_NUMBER |TYPE_NUMBER_FLAG_DECIMAL.
numberPassword0x00000012A numeric password field. Corresponds to TYPE_CLASS_NUMBER |TYPE_NUMBER_VARIATION_PASSWORD.
phone0x00000003For entering a phone number. Corresponds to TYPE_CLASS_PHONE.
datetime0x00000004For entering a date and time. Corresponds to TYPE_CLASS_DATETIME |TYPE_DATETIME_VARIATION_NORMAL.
date0x00000014For entering a date. Corresponds to TYPE_CLASS_DATETIME |TYPE_DATETIME_VARIATION_DATE.
time0x00000024For entering a time. Corresponds to TYPE_CLASS_DATETIME |TYPE_DATETIME_VARIATION_TIME.

This corresponds to the global attribute resource symbol inputType.


2012년 11월 22일 목요일

게임 개발자를 위한 유튜브 세미나 동영상


지난 11월 15일에 있었던 게임 개발자를 위한 유튜브 세미나의 동영상이 업로드되었습니다. 많은 분들이 참석해 주셔서 즐거운 시간을 보냈구요. 여러모로 유익한 시간이었습니다. 관심 가지고 참석 지원해 주신 분들, 참석해 주신 분들 그리고 동영상을 시청하시는 분들 모두에게 감사드립니다.

세미나 자료: https://docs.google.com/file/d/0B4sGAlXaZCXNUzdGRW94S1BoelE/edit

http://googledevkr.blogspot.kr/2012/11/blog-post_12.html

Published - 유튜브를 활용한 게임 확산 전략 (Start Playing The Distribution Game on YouTube) v00.03.01.pdf .pdf

2012년 11월 7일 수요일

게임 개발자를 위한 유튜브 소개 시간을 마련했습니다~

게임 개발자를 위한 유튜브 소개 시간을 마련했습니다. 여러분의 게임에 유튜브를 결합할 수 있는 다양한 방법들과 성공 사례들을 공유합니다. 그동안 유튜브를 이용자 관점에서 동영상 시청 용도로만 생각하고 계신 분들이 많으실 텐데 유튜브에서 제공되는 다양한 API들이 어떤 기능을 가지고 있으며 어떻게 이용될 수 있는지를 직접 확인하실 수 있습니다.

일시: 2012년 11월 15일 오후 6시 30분 ~ 9시
장소: 구글코리아 사무실

- 제목: Start Playing the Distribution Game on YouTube (Jarek Wilkiewicz, Sang Kim)
- 내용: YouTube has over 800M unique visitors who watch 4 billion hours of video each month. One of the top categories on YouTube is gaming. By integrating your game with YouTube you can share rich and authentic game experiences that are more likely to convert viewers into gamers than any other medium. In this session, we will highlight fun and enlightening integration examples in PC, console and mobile areas. We will cover best practices from both the technical and business perspective. Last but not least, we will share our favorite gameplay videos with you!

관심있는 게임 개발자 여러분들의 많은 참여 부탁드립니다~!

참고
- 저녁 식사가 제공됩니다.
- 본 세션은 영어로 진행되며 별도의 통역은 제공되지 않습니다.
- 주차는 제공되지 않으니 대중교통을 이용해 주시기를 부탁드립니다.

참가 신청하기! - 참가 신청은 11월 13일 오전 10시까지 부탁드립니다. 선착순이 아니며 좌석이 한정되어 있어 참석 대상자로 선정되신 분께는 별도로 연락을 드리겠습니다.

2012 구글 핵페어 구글 2012. 11. 20. 03:39


2012년도 11월 17일 ~ 18일 양일간 강남 CNN the biz 강남 교육 연수센터에서 개최 되었습니다.

Make Faire Seoul과 Google I/O로부터 영감을 얻어서 이런 행사를 만들게 되었다고 하네요. 일반인 24개팀, 학생 16개 팀 총 40개 팀이 참여해서 안드로이드, 크롬, Go, Dart, HTML5, 구글TV, NaCl 등의 기술을 이용해 만든 다양한 성과물을 전시하고 공유하는 행사였습니다. 

전시에 참여한 팀들은 넥서스7과 Google TV 디바이스를 제공하고 우수 프로젝트 팀에는 2013년도 구글 I/O에 참석할 수 있는 혜택을 준다고합니다.


[안드로이드 단말기에서 이미지 프로세싱]

얼굴바라기

내용: 
사람 얼굴을 인식하고 얼굴이 이동하는 방향으로 관절 기능(모터2개)사용해서 스마트폰을 움직이고 자동을 사진을 촬영해줌자동으로 사진이 찍히는 ICS 버전에서 제공되는 Face Detected 기술을 사용해서 재미요소 제공. 

사용기술:
ICS 이상에서 지원하는 얼굴인식 API, ADK(Accessory Development Kit) 사용ICS 이상 지원되는 얼굴인식 기능 사용. 얼굴인식에서 제공하는 사각형을 바탕으로 왕관이라 리폰을 오버레이뷰에 표시하기 

문제점:
얼굴인식 기능은 LG전자 모델에는 탑재되지 않았음, 삼성것은 잘 동작했음 
갤럭시 S3와 아두이노 인터페이스간에 데이터 손신이 발생되었음


Face Shape Tracking Library

내용:
1. 얼굴 위치를 따라다니는 공.
2. 특징점을 연결하여 실시간 얼굴 윤곽선 그리기.
3. 입모양 추적 -> 음식이 나올때만 먹기 게임.

사용기술:
Android, OpenCV, Active Shape Model, JNI, NDK

문제점:
얼굴인식의 세밀함이 떨어져 입모양의 변화등의 처리는 부족함, 머리모양의 특징이 인식되지 않음

향후방향:
오픈소스 공유를 통해서 lib화
http://code.google.com/p/face-shape-tracking-library-for-android/


[WebRTC 기술을 이용한 이미지 프로세싱]

MultipleVideoChat

내용: 
추가적인 플러그인 없이 브라우저간 P2P통신으로 멀티화상채팅 기능을 제공함

사용기술:
크롬, HTML5, WebRTC, AppEngine, Javascript

기타:
WebRTC는 크롬브라우저에 탑재되었으며, 이후 다른 브라우저에도 적용될 예정임

참고:
http://webrtc-multivc.appspot.com


반딧불이의 숲

내용: 미디어아트 분야로 웹캡에 들어오는 영상에 반응하여 움직이는 위치에 해당하는 들풀 이미지가 흔들리는 영상과 소리를 출력해 줌

사용기술: 크롬HTML5, WebRTC, WebGL, Web Audio(미적용)

참고: http://wwww.unid.me/demo/firefly http://github.com/epicure/expr/tree/master/demo/fireflies


[가속도센서, 자이로스코프센서, 지자게 센서]

밴드로이드 내용: 스마트폰의 다양한 센서를 통해 합주 기능을 제공합니다. 가속도 센서는 리코더, 자이로스코프센서는 드럼, 나침반센서로 원거리의 친구들과 합주하고 내용을 유투브로 공유할 수 있음

사용기술: Android, HTML5, Google Maps, App Engine, Go, Youtube

문제점: 나치반센서는 값에 제대로 감지 되지 않았다. 여러종류의 단말기 모두 불안정 값이 도출되어 제대로 구현이 안되었다.


Swing The Music

내용: 흔들어서 음악 재생을 제어한다. 앞으로 뒤로, 위아래로 흔들면 랜덤재생

사용기술: Android Multimedia, 센서

참고사항: http://android.googlesource.com/platform/packages/apps/Music.git (AOSP 음악 플레이어)
http://code.google.com/p/gm-player/  (코드페이지)


[Arduino(ADK), NFC등]

ALRAME

내용:
단말기에 알람을 설정하면 단말기와 알람시계간에 NFC로 쉽게 연결해서 알람 시간을 동기화 한다. 또한 알람은 서버에도 저장되어서 알람이 어디에서 울리고 끌경우 동기화된 기기들이 함께 동작된다. 알람시계는 아두이노에 네트워크 모듈을 연동해서 서버와 연결되어 있고 Pusher로 이벤트를 받는다. 단말기는 GCM으로 받는다. 함께 전시한 메일 프린터기도  소형프린터에 네트워크모듈이 탑재된 아두이노가 메일 수신을 서버로부터 Pusher로 받아서 내용을 프린터로 출력해 주는 기능을 했다.

사용기술:
Android, Arduino, GCM, NFC

참고:
https://github.com/huewu/alarme
http://youtu.be/WR_2pHxrIE4


Project AndroFace 

내용:
젤리빈 사탕 제공 기기 내부에 아두이노가 탑재되어 있고, NFC태그가 부착되어 있고, 넥서스S단말기와 연결되어 있었다. 단말기가 기기의 NFC태그 부분을 터치하여 인식이 되면 단말기가 아두이노에게 명령을 내리고 아두이노에 연결된 모터는 젤리빈 사탕은 한줌 제공한다. 

사용기술:
Android, ADK, NFC

참고:
https://github.com/yunsuchoi/androface


A3CCTV

내용:
아두이노의 근접센서를 사용해서 움직임을 감지하고 연결된 단말기에서 촬영하면 사진은 AppEngine에 등록하고 등록시점에 GCM과 메일로 통지해 주며 웹을 통해서 사진을 확인할 수 있음

사용기술:
Android, Arduino, App Engine, Google TV

참고:
http://youtu.be/D_6XOyZob6w


SGR(술고래-음주측정어플리케이션)

내용:
PC와 아두이노가 연결되어 있고 아두이노는 냄새를 감지하는 센서가 있어서 PC상에 웹에서 냄새 감지 버튼를 눌러서 냄새를 감지하고 관련 정보를 수치화해서 표시해 준다. 수치는 음주 측정기의 수치와 비슷하게 출력된다고 한다.

사용기술:

참고:


Braille Printer(점자 프린터)

내용:
웹에서 문자을 입력받아서 점자로 변환하고 PC와 연결된 아두이노는 모터와 연결되어서 점자를 프라스틱롤에 인쇄를 한다.

사용기술:

참고:


내용:

사용기술:

참고:


CINOW

내용:
습도, 온도 센서가 장착된 아두이노와 이것과 연결된 스마트폰이 해당 기능을 감지하고 GPS의 위치 정보를 모아서 트위터에 특정 해쉬태크와 함께 등록하고 웹 페이지에서 관련 정보로를 모아서 보여주고 지도상에 표시해 준다.

사용기술:

참고:
http://goo.gl/AYp03
http://dev.naver.com/projects/cinow


Anroid Robot with SNS

내용:
전화, 문자, SNS 내용이 수신되면 로보트의 팔과 머리로 알림기능을 한다. OTG를 통해서 마우스가 연결도 가능하다. 

사용기술:
Anroid, Arduino

참고:
http://youtu.be/37UmIh-En_g



[TV 관련 기술]

WebDMB

내용:
DMB 시청을 브라우저에서도 시청할 수 있게 하는 플러그인 기술 소개. 웹표준으로 정착되도록 노력중, 브라우저에 DMB 시청이 가능하다면, 브로그, 포털 등 쉽게 적용이 가능하기에 DMB의 새로운 수익원 창출이 가능할 것으로 예측함. 

사용기술:
Android, HTML5, Plugins

단점:
DMB는 H/W 모듈이 탑재한 단말기에서만 시청이 가능함

참고:
WebRTC와 같은 수준의 웹 표준을 지향하고 있음


U+ TV G

내용:
구글 TV가 탑재된 디바이스를 LG U+ 제공함. 한달에 9,900원으로 서비스를 제공함. 현재는 리모콘에 센서가 적용되어 있지는 않지만 내년도에 적용 예정, 영상은 HD급으로 제공, 일반 UI는 1280해상도 제공. 브라우저, 구글마켓(TV전용앱 노출), 지난방송 다시보기(일주일 지난 프로 무료제공)

사용기술:
Android 3.2, 구글 TV

참고:
디바이스는 구글 TV API가 기본 제공되며, 별도로 U+와 협약을 통해서 U+ 제공 API 사용이 가능함. 방송 시청중 방송안내 검색이 가능한 기능 제공


테즈메니아(Tasmanian)

내용:
스마트리모폰, 인체의 움직임을 감지해서 TV를 콘트롤하거나, 터치패드 이용한 TV 제어

사용기술:
google TV, 자체제작한 HW 리모콘, javascript, HTML5

애로사항:
Wii의 리모콘 기술을 흡사한 TV 리모콘을 제작하고 TV리모콘이 TV마우스포인터를 움직이게 하는 기술을 모토로 하였으나, TV 마우스 포인터 움직이 매우 어려웠다고 함

참고:
http://www.funzin.co.kr

[MIM] 

IRCTalk

내용:
IRC 클라이언트를 모바일환경으로 구현하여 다중채팅이 가능하며, 채팅 기록이 남아있어서 접속이 끈겼다가 재 접속되어도 이전 내용 확인이 가능하면 IRC 사용자면 별도의 친구 관계와 관계없이 장소에 구애받지 않고 접속이 가능하다. 단말기 뿐만 아니라 웹에도 채팅이 가능하다. 

사용기술:
Go, Android, Crome Extension, Google Account API, HTML5, Javascript, CSS, Websocket

참고:
https://github.com/irctalk



[NaCI]

VW

내용:
구글의 Native Client(NaCl) 기술과 Opengl ES 2.0 기술을 활용해서 크롭 브라우저상에서 3D 모델 데이터를 브라우징하는 데모

사용기술:
NaCl, OpenGL ES

참고:


CboxConsole

내용:
조이스틱, 게임콘트롤 등을 USB로 연결해서 NaCl를 통해 브라우저를 제어 하는 기술, 

사용기술:
Chrome, NaCl, AppEngine, HTML5, JavaScript

참고:
https://github.com/CboxConsole
구글 그룹스에서 GDG Chrome 그룹 운영


[Procssing]

디지털 그림자 인형극

내용:
HTML5와 앱엔진으로 그림을 보관하고 노출시킨다. 프로세싱 기반으로 인형극을 만든다. 아두이노를 통해서 아날로그 레버를 통해 캐릭터를 움직이게 한다. 

사용기술:
GAE, HTML5, Arduino, Processing

참고:
https://github.com/akudoku/digital_shadow_puppetry


기타 더 있음 (추가 리포팅 예정)







Using the new Build System Android 2012. 11. 19. 18:01

http://tools.android.com/tech-docs/new-build-system 
We are working on a new build system to replace both the build system inside ADT and Ant.


Using the new Build System

Using the new Build System

The new build system is based on Gradle.
If you are not familiar with Gradle, it is recommended to read at least the first few chapters ofhttp://gradle.org/docs/current/userguide/userguide_single.html

The location of the SDK folder is still needed and is provided by one of the following methods:
  • local.properties file with a sdk.dir property, similar to the current build system. This is located in the project root directory. In multi-project setup, this is next to settings.gradle.
  • ANDROID_HOME environment variable
All other configuration goes in the standard build.gradle file.

Using the new Android plugin for Gradle

The android plugin for gradle is available through Maven:
  • groupId: com.android.tools.build
  • artifactId: gradle
  • version (current milestone): 0.1
Requirements:
Gradle 1.2.
The Android Platform-Tools component in version 15 rc7. To download it, you will need to enable the preview channel in the SDK Manager. Read more about it here.

To use it in your build.gradle file, put at the top:
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.1'
    }
}
apply plugin: 'android'

For library project, the plugin to apply is ‘android-library

In the future we will investigate how to simplify this step.

Basic Project Setup

All configuration related to the Android plugin is done inside the android namespace:
android {
    ...
}

The most important setting is the build target (previously found in project.properties):
android {
    target = ‘android-15’
}

Changing the default configuration is done using the defaultConfig object:
android {
    target = ‘android-15’
    defaultConfig {
        versionCode = 12
        versionName = “2.0”
    }
}

Default Config can be configured with the following properties:
  • packageName (String)
  • versionCode (int)
  • versionName (String)
  • minSdkVersion (int)
  • targetSdkVersion (int)
  • testPackageName (String)
  • testInstrumentationRunner (String)
  • signingStoreLocation (String)
  • signingStorePassword (String)
  • signingKeyAlias (String)
  • signingKeyPassword (String)
  • buildConfig (String...)
Note: it is best not to put signing passwords in the build script, and instead have your CI server does the signing itself, or use a local gradle.properties file.
However, you can use these signing properties if you share a single debug keystore across developers.

Build Types and Product Flavors

Creating new build types or editing the built-in debug and release is done with the buildTypes element. This configures the debug build type and adds another one called “staging”:
android {
    buildTypes {
        debug {
            packageNameSuffix = “.debug”
        }
        staging {
            packageNameSuffix = “.staging”
            debuggable = true
            debugSigned = true
        }
    }
}

Build Types can be configured with the following properties:
  • debuggable (bool; default:false; true for debug)
  • debugSigned (bool; default:false; true for debug)
  • debugJniBuild (bool; default:false; true for debug)
  • packageNameSuffix (String; default:null)
  • runProguard (bool; default:false) // unused right now.
  • zipAlign (bool; default:true; false for debug)
  • buildConfig (String...)
Creating product flavors is done with the productFlavors element:
android {
    defaultConfig {
        versionCode = 12
        minSdkVersion = 8
    }
    productFlavors {
        freeapp {
            packageName = “com.example.myapp.free”
            minSdkVersion = 10
        }
        paidapp {
            packageName = “com.example.myapp.paid”
            versionCode = 14
        }
    }
}

Flavors can be configured with the same properties as the default config. If both define a properties, then the flavor overrides the default config.

Flavor Groups

Using multi-flavor variants is done with the following two steps:

  • Defining the flavors groups. The order is important, they are defined higher priority first.
  • Assigning a group to each flavor.
android {
    flavorGroups “abi”, “version”

    productFlavors {
        freeapp {
            group = “version”
            ...
        }
        x86 {
            group = “abi”
            ...
        }
    }
}

Other Options

BuildConfig

BuildConfig is a class that is generated automatically at build time.
Similar to the old build system, the class is generated with a DEBUG boolean field. In this case it maps to the value ofBuildType.debuggable.

On top of this you can now insert new items in the class. This is done by providing full Java lines.
This is possible from the defaultConfig, any flavors, any build types. All lines are aggregated together in the same class for a given variant.

For instance: 
android {
    target = "android-15"

    defaultConfig {
        buildConfig "private final static boolean DEFAULT = true;", \
                "private final static String FOO = \"foo\";"
    }

    buildTypes {
        debug {
            packageNameSuffix = ".debug"
            buildConfig "private final static boolean STAGING = false;"
        }
        staging {
            packageNameSuffix = ".staging"
            buildConfig "private final static boolean STAGING = true;"
        }
        release {
            buildConfig "private final static boolean STAGING = false;"
        }
    }
}

Aapt Options

To provide options to aapt, the aaptOptions element is used. Right now two options are supported (more will come later):
  • noCompress (String list): list of extension to not compress
  • ignoreAssetsPattern: Assets to be ignored. Default pattern is: !.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~
android {
    target = "android-15"

    aaptOptions {
        ignoreAssetsPattern = “!.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~”
        noCompress "txt", “foo”
    }
}

Using Library Projects

As mentioned above, the plugin for library projects is android-library. It uses the same Maven artifact.

Libraries don’t have flavors, and only two build types. They can be configured this way:
android {
    target = “android-15”
    debug {
        ...
    }
    release {
        ...
    }
}

Using a library is done one of the following way:
Uploading to a maven repo is done the same way a regular Java library is uploaded. See more information here:http://www.gradle.org/docs/current/userguide/maven_plugin.html

Using a library through a repo is the same as a regular Java library, using the groupIdartifactId and version.

Standard Tasks

Java projects built with Gradle use 4 main tasks:
  • assemble -- assemble the software
  • check -- builds and run the checks and tests
  • build -- runs assemble and check
  • clean
The Android plugin use the same tasks but extends the first two to handle build variants.

For instance, a project with flavor1 and flavor2 and the two default build types will have the following 4 tasks:
  • assembleFlavor1Debug
  • assembleFlavor2Debug
  • assembleFlavor1Release
  • assembleFlavor2Release
On top of these, 4 other assemble tasks are available
  • assembleDebug -- builds all debug variants (for all flavors)
  • assembleRelease -- builds all release variants (for all flavors)
  • assembleFlavor1-- builds all flavor1 variants (for all build types)
  • assembleFlavor2-- builds all flavor2 variants (for all build types)
Adding new flavors and new build types will automatically create new assemble type tasks.

Additionally, assemble tasks for test apps are created:
  • assembleFlavor1Test -- builds the test app for the flavor1 app.
  • assembleFlavor2Test -- builds the test app for the flavor2 app.
  • assembleTest -- builds all test apps.
The default assemble tasks will call all (non test) assemble<flavors><buildtypes> tasks to build all variants of the application.

The check task is augmented similarly:
  • checkFlavor1Debug -- tests the flavor1 variant
  • checkFlavor2Debug -- tests the flavor2 variant
The default check tasks calls all check<flavor> tasks.

Checks are run by doing the following
  1. Install apps (if testing a library, only the test app)
  2. run tests
  3. Uninstall apps
Install / uninstall is done with the following tasks
  • install<flavors><type> for each variant
  • uninstall<flavor><type> for each variant
Additionally uninstallAll attempts to uninstall all variants.

Building an android application takes a lot of steps and each are available to be run on demand.
Here’s a full list of tasks used to build an application:
  • prepare<Variant>Dependencies
  • process<Variant>Manifest
  • generate<Variant>BuildConfig
  • crunch<Variant>Res
  • process<Variant>Res
  • compile<Variant>Aidl
  • compile<Variant>
  • dex<Variant>
  • package<Variant>

Customizing the tasks

Gradle provides an API to query for tasks by name or by classes.

The classes used by the Android tasks are the following:
  • Compile -- java compilation
  • CrunchResourcesTask
  • ProcessManifestTask
  • GenerateBuildConfigTask
  • ProcessResourcesTask
  • CompileAidlTask
  • DexTask
  • PackageApplicationTask
  • ZipAlignTask
In the future we intend to provide a custom API to access flavors, build types, and variants, as well as task inputs/output to do easier manipulation of the tasks.

Working with and Customizing SourceSets

Starting with 0.2, the build system uses its own SourceSet objects intead of the ones provided by the Java plugin.
You can use them to configure the location of all source elements as well as (in the case of the java source and resource folders) customize filters and exclusion.

The default config creates two sourcesets: "main" and "test". All flavors and build types automatically create their own sourceset, named after the flavor/build type name. Additionally, all flavors create a corresponding test flavor named "test<Flavorname>"

Default sourceset location is under src/<sourceset>
Sourceset have the following properties:
  • manifest, type AndroidSourceFile, default location src/<sourceset>/AndroidManifest.xml
  • res, type AndroidSourceDirectory, default location src/<sourceset>/res/
  • assets, type AndroidSourceDirectory, default location src/<sourceset>/assets/
  • aidl, type AndroidSourceDirectory, default location src/<sourceset>/aidl/
  • renderscript, type AndroidSourceDirectory, default location src/<sourceset>/renderscript/
  • jni, type AndroidSourceDirectory, default location src/<sourceset>/jni/
as well as the normal java project sourceset properties:

AndroidSourceFile and AndroidSourceDirectory have a single configurable property, respectively srcFile andsrcDir.

Example of reconfiguring the sourcesets to match an existing project structure:
android {
    sourceSets {
        main {
            manifest {
                srcFile 'AndroidManifest.xml'
            }
            java {
                srcDir 'src'
                exclude 'some/unwanted/package/**'
            }
            res {
                srcDir 'res'
            }
            assets {
                srcDir 'assets'
            }
            resources {
                srcDir 'src'
            }
        }
        test {
            java {
                srcDir 'tests/src'
            }
        }
    }
}

For more information about working with Sourceset, see: http://gradle.org/docs/current/userguide/java_plugin.html#sec:source_sets
Note that for Android projects, the sourceSets container must be modified inside the android container.

세로 프로그래스바와 씨크바 예제이다. 

[xml 구성시 주의 사항]

1. Thumb 이미지 보다 크게 layout_width 폭을 지정하면 프로그래스바 폭이 두껍게 된다.

2. 프로그래바 폭을 조절하려면 android:maxWidht에 값을 넣어 준다.


        <com.tokaracamara.android.verticalslidevar.VerticalSeekBar

            android:id="@+id/SeekBar02"

            android:layout_width="56px"

            android:layout_height="fill_parent"

            android:maxWidth="10px"

            android:progressDrawable="@drawable/progress_vertical"

            android:thumb="@drawable/seek_thumb_wide" />


[샘플 소스]

아래 프로젝트에 AbsVerticalSeekBar파일의 한 곳이 오류가 잇어서 수정했다. 

썸브 바운데리 설정시 LeftBounday가 -1로 되는 것을 방지했다. gap 부분

VerticalSlidebarExample.zip


[참고 사이트]

http://code.google.com/p/trimirror-task/source/checkout

http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip

12장 애니메이션

온라인주소: http://lingostar.co.kr/wp/archives/648


Animation , Dynamic UI

에니메이션은 UI적인 접근을 위한 것이다

에니메이션 오버뷰 / 잔상 효과,  

 - NSTimer / 초창기 사용
- NSAnimation / 10.4때 만들어졌다. 거창해 보이지만 그냥 NSTimer에 이지인, 이지아웃기능을 넣은 간단한 것이다.

  • CoreAnimation / 에니메이션 엔진을 만들었다.

Dynamic UI의 정수: 타임머신, 스페이시스, 아이툰즈의 커버플로우,
 - 반복적인 움직임.. 


View Animation을 몸풀기로 만들어 보자

 - 간단히 에니메이션을 얻어오는 것이다.
 - 비깅 컴인만 해 주면 에니메이션된다.

 - 만들자 MovingMoving

 1) UIView, Button을 넣는다.

 - 아웃렛, 액션 하나가 있어야 할 것이다

 

헤더파일

 

#import <UIKit/UIKit.h>

 


 

@interface MovingMovingAppDelegate : NSObject <UIApplicationDelegate> {

 

UIWindow *window;

 

UIView *movingView;

 

}

 


 

- (IBAction)move:(id)sender;

 

@property (nonatomic, retain) IBOutlet UIWindow *window;

 

@property (nonatomic, retain) IBOutlet UIView *movingView;

 


 

@end

 

 

임플리멘테이션파일

#import "MovingMovingAppDelegate.h"

 


 

@implementation MovingMovingAppDelegate

 


 

@synthesize window;

 


 


 

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

 


 

// Override point for customization after application launch

 

    [windowmakeKeyAndVisible];

 

}

 


 


 

- (void)dealloc {

 

    [window release];

 

    [super dealloc];

 

}

 


 

- (IBAction)move:(id)sender

 

{

 


 

movingView.center = CGPointMake(240, 400);

 

movingView.backgroundColor = [UIColoryellowColor];

 

movingView.transform = CGAffineTransformMakeRotation(90);

 

}

 


 

@end


 

이제 에니메이션 주자.

- (IBAction)move:(id)sender
{

 


 

[UIViewbeginAnimations:@"Moving"context:nil];

 

[UIViewsetAnimationDuration:2];

 

movingView.center = CGPointMake(240, 400);

 

movingView.backgroundColor = [UIColoryellowColor];

 

movingView.transform = CGAffineTransformMakeRotation(90);

 

 

 

[UIViewcommitAnimations];

 

}

 

 

블럭이 천천히 음직이려면

[UIViewsetAnimationCurve:UIViewAnimationCurveEaseInOut];

 

여기서 보면 에니메이션의 시작과 종료의 기준은 아래 것이다.

[UIViewbeginAnimations:@"Moving"context:nil]; // 시작

[UIViewcommitAnimations];  // 종료


현재까지는 코어에니메이션을 사용한 것이다. 코어 그래픽스는 어제 한 것이다. 

 

코코아터치는 코어 에니메션에 떠받혀져 있다.

따라서 UIKit은 코어에니메이션을 잠간 빌려서 사용할 수 있다.
에니메이션을 동작을 잠간 고민해 보자

 

상기 에니메이션 불럭을 바깥으로  컬러변경코드를 옮겨 보자.

[UIViewbeginAnimations:@"Moving"context:nil];

 

[UIViewsetAnimationDuration:2];

 

[UIViewsetAnimationCurve:UIViewAnimationCurveEaseInOut];

 

 

 

movingView.center = CGPointMake(240, 400);

 

movingView.transform = CGAffineTransformMakeRotation(90);

 

 

 

[UIViewcommitAnimations];

 

 

 

movingView.backgroundColor = [UIColoryellowColor];

 

그럼 움직이기전에 컬러값이 변경된후 움직이게 된다.

이렇게 되는 이유는 왜 그런지를 생각해 보라..

1초 딜레이를 주고 변하는 코드는 다음과 같다

[movingViewperformSelector:@selector(setBackgroundColor:) withObject:[UIColoryellowColor]afterDelay:1];


여기까지가 12-2까지 이다 

12-3 ~ 4까지 읽어 보라
12-5를 실습하자.

CoreAnimation Role을 만들어보자. (12.4.3 설명)

CABasicAnimation, CAKeyframeAnimation만 사용할 수 있고 나머지는 직접적으로 사용할 수는 없다.

CAAnimationGroup: 

패스를 갖는(반복)은 CAKeyframeAnimation으로 만들어야 한다.


아래 두개는 서로 약간다르다.

CALayer, CGLayer: 


CALayer : 코어에니메이션의 오브젝트 GPU가속이 되는 오브젝트로 하드웨어 가속이 가능하다. 

   이차원, 삼차원정의를 갖는 이차원 평명

  콘테츠로는 

   Quartz image, Quartz drawing, CoreText(Mac), OpenGL, Quarz Composer, QuickTime..(Mac)

Keyframe Animation Code

-  패스를 따라서 움직일 것이다.


새로운 프로젝터:

1.Helicopter를 만든다.

2.리소스를 넣어준다.  (Copy items into destination group's forlder를 체크해 준다)



스크린샷_2010-01-23_오후_3.07.47.png

Heli_1, 2, 3을 복사한다.

책 350페이지를 보자.

 

 

에니메이션 3가지 종류

1)UIView

 시작과 끝을 정의해서 한것.. MovingMoving

2)ImageAnimation 

    사람이 걷는 경우 걷는 이미지가 여러장이 있다. 이것은 코어에니메이션과는 전혀 상관이 없다. / 아주 많이 사용하는 방식

   Helicopter프로젝터 방식읻.

3)


4.인터페이스 빌더에서 미디어에서 이미지르 끌어다 놓는다

   버턴 두개.

5.프레임웤 추가 QuartzCore framework추가 / 임포트 하구
6. 아웃렛와 액션을 만든다. / 저장하고

 

#import <UIKit/UIKit.h>

#import <QuartzCore/QuartzCore.h>


@interface HelicopterAppDelegate : NSObject <UIApplicationDelegate> {

UIWindow *window;

UIImageView *helicopterImageView;

}


- (IBAction)toggleFly:(id)sender;

- (IBAction)moveThroughPath:(id)sender;


@property (nonatomic, retain) IBOutlet UIWindow *window;

@property (nonatomicretainIBOutlet UIImageView *helicopterImageView;

@end

7.인터페이스빌더에서 상호 연결스크린샷_2010-01-23_오후_3.17.59.png


8. 초기 정의와 액션을 코딩한다.

 

#import "HelicopterAppDelegate.h"

 


 

@implementation HelicopterAppDelegate

 


 

@synthesize window;

 

@synthesize helicopterImageView;

 


 

- (void)applicationDidFinishLaunching:(UIApplication *)application {

 


 

UIImage *heli1 = [UIImageimageNamed:@"Heli_1.png"];// 로컬의 이미지를 리소스를 읽어 오는 방법

 

UIImage *heli2 = [UIImage imageNamed:@"Heli_2.png"];

 

UIImage *heli3 = [UIImage imageNamed:@"Heli_3.png"];

 

NSArray *animationImageArray = [NSArray arrayWithObjects:heli1, heli2, heli3, nil];

 

helicopterImageView.animationImages = animationImageArray;

 

 

 

// Override point for customization after application launch

 

    [windowmakeKeyAndVisible];

 

}

 


 


 

- (void)dealloc {

 

    [window release];

 

    [super dealloc];

 

}

 


 

- (IBAction)toggleFly:(id)sender

 

{

 


 

if ([helicopterImageViewisAnimating]) {

 

[helicopterImageViewstopAnimating];

 

else{

 

[helicopterImageViewstartAnimating];

 

}

 

 

 

}

 

- (IBAction)moveThroughPath:(id)sender

 

{

 


 

}

 


 


 

@end

9. KeyframAnimation을 만들어보자

 

- (IBAction)moveThroughPath:(id)sender

 

{

 

// Create path

 

CGPoint currCenter = helicopterImageView.center;  // 시작포인터가된다.

 

// S자곡선을 3가지콘트롤포인터가생긴다.

 

CGMutablePathRef aniPath = CGPathCreateMutable();

 

CGAffineTransform xform = CGAffineTransformIdentity;

 

CGPoint dest1 = CGPointMake(160200);

 

CGPoint dest2 = CGPointMake(160400);

 

 

 

// 이후패스를넣어준다. 콘트롤두개인베젤코드

 


 

CGPathMoveToPoint(aniPath, &xform, currCenter.x, currCenter.y);

 

CGPathAddCurveToPoint(aniPath, &xform, 050050, dest1.x, dest1.y);

 

CGPathAddCurveToPoint(aniPath, &xform, 310350310350, dest2.x, dest2.y);

 

 

 

// Create Animation Object 에니메이션을 설계하는 것이다.

 

CAKeyframeAnimation *keyAni = [CAKeyframeAnimationanimation];

 

keyAni.duration = 4.0;

 

keyAni.path = aniPath;

 

 

 

// Apply Animation  CALayer 패스를 넘기겨 주는 것이다

 

// 뷰뒤에레이어가다숨어있다고보면이해가편해진다.

 

[helicopterImageView.layeraddAnimation:keyAni forKey:@"position"];//순간 GPU올라간다.

 

}

 

베젤 곡선을 코드 한줄로 변경해 보자.

//CGPathAddCurveToPoint(aniPath, &xform, 0, 50, 0, 50, dest1.x, dest1.y);

//CGPathAddCurveToPoint(aniPath, &xform, 310, 350, 310, 350, dest2.x, dest2.y);

CGPathAddCurveToPoint(aniPath, &xform, -20050500350, dest2.x, dest2.y);


결과는 다음과 같다.

스크린샷_2010-01-23_오후_3.42.40.png

 

에니메이션의 설계......음직임의 설계는 동일하며 내용만 달라진다... 애플도 이런 효고를 많이 사용한다.

추가로 하자.

버턴도 패스에 따라서 에니메이션 된다.

215페이지에 보면 UIView의 하부 것들은 모두 에니메이션 처리가 가능하다.

뷰에니메이션을 쌓주면 가능하다. 모든 프로퍼티가 다 에니메이션이 되는 것은 아니다. 

뷰의 프로퍼티가 되는 것은 에니메이션이된다.

 


모델과 프린젠테이션이 나누어져 있다.
에니메이션되는 것은 프리젠테이션이 되는 것이고 모델은 그대로 있다.

그래서 버턴이 움직일때 모델은 그대로 그 위치에 있어서 터치시 이벤트를 받고

움직이는 버턴을 클릭했을때는 반응이 없는 것이다

12.5.7
게임을 위한 확장

 중간에 장애물이 있을때에 대한 처리.. NSTimer를 사용해서 충돌 체크해 주는 것이다.
 360페이지 CGRectIntersectsRect이 중요한 함수 일 것이다


12.6.0 

코어에니메이션에 대해서 조금더 볼 것이다.

코아슬라이드라는 맥용 어플리케이션이 있다.

큰이미지는 UIView로는 할 수 없구. 타일드해야 해야 하는데 CALayer의 타일링 레이어를 사용해야 하다.

      큰PDF 파일을 헨들링

 

불꽃예제.. 2개의 큐뷰가 돌면서 전체를 큐뷰로해서 다시 돌리는 것 등이 가능하다.
레이어를 여러개 두어서.. 움직이게 된다. 

 

레이어로 모든 뷰를 바꿀수 있다.
단지 에니메이션되는 것이 아니라 GPU를 사용해서 콤포지트하기 위해서 가장 좋다.

모든 시작적인 미디어들을 레이어를 사용하는 것이 확장성과 빠르게 동작한다.

레이어를 서브클래서해서 사용할 수 있는 것은 더욱 많이 있다.
예제와 함께 어드벤스드하게 강의을 준비할 것이다. 

 

코어 에니메이션 책이 있다. 그런데 좀 부실하다. 애플의 가이드를 보고 하는 것이 좋다.


12.6 예제는 심화.. 뷰 트렌지션이다. 17.게임킷은 심화에서 하자.


Save - 아카이빙.. 

큰개념만 설명하고 18장으로 넘어가자..

380
과제 1.  <<  시도해 봐라..  헬리곱터가 심플스케치에서 손가락으로 움직인 경로로 헬리곱터가 움직이면 제미 있을 것이다.
과제2

쓸만한 위젯 lib Android 2012. 11. 16. 09:44



http://d.hatena.ne.jp/thorikawa/20101130/p1

Android 응용 프로그램에서 사용할 수있는 편리한 UI 라이브러리Add StarrgfxshepherdMastershepherdMastergabuchancanotnanatsumaKazzzdeg84jmab

Android 애플 리케이션 말하면 UI 생명! 라는 것으로 괴짜 분들이 만들어지는 편리한 UI 라이브러리를 찾아낸 한 스크린 샷과 함께 정리해 있습니다 .

여러분 모두 소스와 일부 샘플 응용 프로그램을 게시되어 있으므로 당장이라도 시도 할 수 있습니다.

(작가 분들, 싣기로 문제가있는 것 같다면 수고 스럽겠지만 연락해주십시오)

Quick Action

  • 공식 Twitter 어플 바람에 터치 한 부분에 풍선을 볼 수
  • 레이아웃도 지정 가능

YAM의 잡기장 : Android Quick Action의 Android 라이브러리 프로​​젝트를 만들어 보았다

f : id : thorikawa : 20101130005022p : image

Drag and Drop ListView

  • 드래그 앤 드롭으로 정렬 가능한 목록 보기
  • 비슷한 같은 것은 여러가지 있지만 이것이 가장 사용하기 쉬웠다!

사용자가 정렬 가능한 ListView를 조금 리치에 해 보았다 - 내일의 열쇠

f : id : thorikawa : 20101130005750p : image

Calendar

  • 뷰에서 공휴일 을 판별 표시 가능한 달력 보기
  • 상하 좌우 톡에서 월을 전환 할 수도 있으므로, 제스처 조작을 실현하고 싶은 사람은 그 부분 만이라도 참고가 될지도

CalendarView 공개했습니다 - Kazzz의 일기

f : id : Kazzz : 20101112133610p : image

3D ListView

  • 3D 로 회전하면서 스크롤 하는 목록 보기
  • 개인적으로 좋아 합니다만, 사용 장소가 떠오르지 않는다 w

Android Tutorial : Making your own 3D list - Part 3 (final part) | Developer World

f : id : thorikawa : 20101130005020p : image

CoverFlow

Interfuser : Android Coverflow Widget V2

f : id : thorikawa : 20101130005019p : image

ChartLibrary

afreechart - Project Hosting on Google Code

f : id : thorikawa : 20101130005446p : image : left

f : id : thorikawa : 20101130005447p : image : left

f : id : thorikawa : 20101130005540p : image

Zoomable ImageView

  • 길게 누르면 터치로 확대 · 축소 할 수있게된다 ImageView
  • 이미지 가 화면보다 클 것으로 표시 위치를 이동할 수있게된다
  • 이동시 후치까지 가면 바운드 애니메이션 된

Android one finger zoom tutorial - Part 4 | Developer World

Drag and Drop ImageView

  • 이미지 를 드래그 앤 드롭하여 버튼 을 두드리는
  • 아래의 스크린 샷이라고 분 에서 아니지만, 이미지 를 드롭 할 때 회전하는 것입니다. 그 애니메이션이 멋진

Android에서 드래그 앤 드롭 - hidecheck의 일기

f : id : thorikawa : 20101130010017p : image

NumberPicker

  • 증가 · 감소의 간격을 조정 가능한 수치 피커

사용자 NumberPicker 만들기 - 냐ン다후루 일기

f : id : thorikawa : 20101130084357p : image

Color Picker

  • 색상 선택기
  • 이쪽은 구형

Android에서 색상 선택기를 만들자 - 내일의 열쇠

f : id : thorikawa : 20101130005917p : image


Color Picker 11 / 30 추가)

YAM의 잡기장 : Android ColorPickerDialog을 만든

f : id : thorikawa : 20101130233733p : image

Vertical Slider 11 / 30 추가)

Vertical Seekbar - Android Developers | Google 그룹

f : id : thorikawa : 20101130233734p : image

그 밖에도

이런 편리한있어! 라고하는 것이 있으면 가르쳐주세요


프로그래머로 사는 법 2012. 11. 15. 16:14

http://blog.hanb.co.kr/375

[프로그래머로 사는 법 기획연재 08 : 대한민국에서 나이 많은 개발자가 살아남는 법]

사용자 삽입 이미지


* 본 내용은 도서의 내용을 일부 발췌하여 작성한 것입니다. 도서에는 더 많은 이야기를 담고 있답니다 :)
변종원(43세)
CodeIgniter 한국사용자포럼 운영진으로 활동했으며, 웹사이트 통합 관리 시스템 webmaker3를 개발했다. 2011 PHPFest에서 CodeIgniter 관련 발표를 했으며, 그 외 다수의 세미나에서 발표했다. 현재 ㈜프리비 개발팀 부장으로 재직 중이다.


곰곰이 생각해보니 연차가 올라감에 따라 급여도 올려야 하고 그러다 보면 순수하게 개발자로서 받을 수 있는 급여수준을 넘어가는 순간이 있는데 계속 개발만 하면 다행이지만 회사 입장에서 나이 어린 개발팀장이 자기보다 수준도 높고 나이 많은 차장급 개발자를 관리하는 게 쉽지가 않습니다. 주변의 개발자를 보면 빠르면 30대 초반 또는 중반에 개발팀장을 하고 그 이후에 CTO급이 되지 못하면 기술 영업으로 가거나 전직을 해야 했습니다.

한때 우스갯 소리로 사수가 없는 초급 개발자에게 개발하다가 막히면 회사 근처의 통닭집 사장님에게 물어보면 금방 해결된다는 말을 했습니다. 많은 개발자가 외식 프랜차이즈 쪽으로 전업했던 때가 있었습니다. IT 회사 근처의 통닭집 중에 그런 분이 계셨고 그분들께 물어보면 다양한 경험을 하셨던 분이었기에 쉽게 답변을 얻을 수있었다고 합니다. 안타까운 현실이지만 저도 전업을 심각하게 고민을 했던 때가 있었습니다.

5년 차 정도까지는 급여에 만족하면서 지냈는데 경력이 7년이 넘어가면서 급여는 기대만큼 오르지 않고 제2의 IMF라는 시기와 맞물리고 급여가 밀리는 등 39살이던 2008년 즈음에 전업을 심각하게 고민해야 했습니다. 그러던 중에 자영업을 하다가 부동산 개발회사를 거쳐 모 보험사 컨설턴트로 일하고 있는 대학교 친구를 우연히 만나게 됐고 외제차를 타고 다니는 친구와 제 처지를 비교할 수밖에 없었습니다. 그 친구와 저는 사람 만나는 것을 좋아하는 성향이 비슷했기에 제게 보험 쪽 입사를 권유했고, 모 보험사 지점에서는 저의 대학 시절 활동(과 홍보부장, 농구동아리 회장)과 PC 통신 시절의 하이텔 지역모임 대표시삽 활동 등을 인정하여 6개월에 걸쳐 부지점장과 수차례에 걸친 미팅과 교육, 2번의 시험을 거쳤고, 최종적으로 지점장 인터뷰까지 끝내고 출근할 날만 정하면 되는 상태였는데 마지막으로 생각을 해봤습니다. “내가 개발을 그만두고 다른 일을 하면서 정말 후회하지 않을 수 있을까?” (제 신념 중의 하나가 후회 없는 삶입니다) 그리고 여태까지 쌓아왔던 경험(인사, 총무, 경리, 물류, 교육, 배송, 제휴, 기획, 사이트 운영, 쇼핑몰, 솔루션 개발)과 SVN, 이슈트래커, 스크럼 등 을 회사에 정착시켰던 경험과 노하우를 이대로 사장하기엔 너무나 아까웠습니다.

전직을 하게 되면 그동안 쌓아왔던 다양한 경험과 노하우를 사장시킬 수 있기에 “앞으로 나는 개발자로 살아야겠다”고 생각을 굳게 다짐을 했고 현재 회사에 입사할 때 “나는 계속 개발을 하고 싶다”고 이야기했습니다(회사는 다 어쩔 수 없나 봅니다. 요즘은 살짝 관리도 넘나듭니다. PM도…).

물론 주변에 성공적으로 전업을 한 분도 계십니다. 저보다 3살 많은 형님인데 비슷한 시기에 웹 개발에 입문하여 그분은 보안 솔루션 기술 영업으로 전직했다가 지금은 취미 생활을 직업으로 삼아 일산에서 나름 알려진 목공방을 운영하고 계십니다. 또 한분은 저와 같은 시기에 저는 개발자로, 그분은 관리자로 시작하여 5년 정도 같이 근무했습니다. 그 후에는 자기 사업을 하겠다고 독립하셨고 이러저러한 과정을 거쳐 지금은 그분도 취미 생활이었던 여행을 업으로 삼고 계십니다. 제 경우에는 개발 자체가 저에게는 즐거움이었기 때문에 계속 개발을 할 수 있었던 것 같습니다. 개발이 주는 즐거움이 스트레스를 덜 받게 해주었던 것 같습니다.

2008년 CodeIgniter를 만나게 되면서 제 개발자 인생에 큰 전환점이 됩니다. 날코딩에 지쳐 있을 때였고 SNS를 개발하는 회사에 입사했는데 처음 시작하는 회사라 프레임워크 도입을 강력하게 주장하여 영문 매뉴얼과 외국 포럼의 Q&A를 보면  개발을 시작했습니다. 그러다 최용운이라는 친구가 매뉴얼을 한글로 번역을 하여 PHPSCHOOL에 공개를 했고 자주 의견을 나누던 사람들 몇몇이 모여 술 한 잔을 하기로 한 날 CodeIgniter 한국사용자포럼이 발족됩니다. 돈을 모아 도메인을 구입하고 CodeIgniter로 사이트를 만들고 소스도 공개하고 운영을 시작한 것이 2009년입니다.

초기에는 친목 수준이었는데 한글 매뉴얼과 질문답변 그리고 PHP에서도 프레임워크를 이용하고자 하는 열망이 맞물려 국내 PHP 프레임워크 모임 중에서는 제일 활발하게 활동을 하고 있습니다.

공통 관심사를 가진 사람들이 모여 포럼을 운영하고 소스를 공개하고 노하우를 나누다 보니 저에게 어느새 금전적 보상이 돌아오기 시작했습니다. CodeIgniter 개발 의뢰라던가 교육, 이직 시 유리함, 더 나아가서는 컨설팅까지 단순히 회사 내부의 개발자로서만이 아니라 외부에서도 인정을 받을 수 있었습니다.

포럼에서 한 달에 한 번 정모를 진행하는데 1년에 한 번 정도를 빼고 항상 정모를 진행합니다. 엠티도 가고 술자리도 하고 세미나도 하고 하는데 술자리에서 포럼 후배들에게 하는 이야기가 있습니다. “힘들게 이 자리까지 왔는데 더 가겠다.”라고요. 주변에 누군가 나이가 많은데도 현업에서 개발을 하고 높은 연봉과 부수입을 가진 선배 개발자가 있다면 “나도 저렇게 할 수 있겠다. 저런 길이 있을 수 있겠구나.”라고 생각하고 그런 길을 갈 수 있을 거로 생각합니다.

가끔 면접을 보다 보면 이력서에 “백발이 될 때까지 개발을 하고 싶다.”라고 쓰여 있는 것을 보게 됩니다. 저도 그런 생각으로 현재의 길을 가고 있습니다. 그러기 위해서 개발자에게 신기술 습득과 트렌드에 대한 이해, 지속적인 공부는 필수입니다. 자기 자신의 계발을 위해 투자하지 않는 개발자는 진정한 개발자가 아닙니다. 회사에서 시켜서, 남들이 하니까 따라 해서는 오래 살아남을 수가 없습니다.

저는 5년 차쯤에 항상 하던 일과가 하나 있었습니다. PHPSCHOOL이나 기타 사이트에 새로 공개된 프로그램을 설치해보고 소스를 열어보고 공부하는 것입니다. 거기서 얻는 것은 새로운 알고리즘과 새로운 경험입니다. 문제를 다른 시각에서 바라보고 개발한 소스를 보게 되면 제가 만든 소스와 비교를 해봅니다. 똑같은 문제를 어떤 시각에서 보느냐에 따라 다른 해결 방법과 소스가 나옵니다. 맞고 틀리고의 문제가 아닙니다. 다른 사람의 개발 방식이 효율 면에서 떨어질 수 있지만, 나중에 다른 상황에서는 그런 방식을 써야 할 수도 있습니다.

너무 잡다하게 많은 것을 알고 있을 필요는 없지만 힘들었던 시절에 습득했던 다양한 경험과 다른 사람의 소스를 보고 분석하는 일을 습관처럼 반복한 결과 지금은 문제 해결과 변수 제거에 많은 도움을 주고 있습니다.

포럼에서 질문, 답변을 하다 보면 내가 접하지 못했던 상황과 내가 모르는 질문이 올라옵니다. 내가 접하지 못했던 상황을 만났을 때 제 PC에서 재현을 해봅니다. 어떤 때는 PHP 버그라던가 CodeIgniter 버그 같은 것도 발견하게 됩니다. 그러면서 그러한 상황에대한 간접 경험을 할 수 있고 모르는 질문은 구글이나 다른 검색 사이트를 통해 찾아보거나 올라온 소스를 실행해보거나 아니면 프레임워크 코어 소스를 열어서 찾아봅니다. 그러면서 또 하나의 지식을 습득합니다.

웹메이커3라는 솔루션을 만들 때는 CodeIgniter 외국포럼의 wiki에 올라온 라이브러리나 소스를 모두 설치해서 실행해보고 소스를 본 적도 있습니다. 솔루션에 사용할기술을 선별하고 당장 사용하지 않더라도 나중을 위해 어느 분야에 사용하면 좋을지 기록하고 보관했습니다. CodeIgniter의 라이브러리는 클래스 형태라서 누군가가 개발한 대부분의 PHP 클래스를 그대로 사용할 수 있습니다. CodeIgniter 입문 초기에는 시간이 날 때마다 PHPCLASSES.ORG라는 PHP 클래스 소개 사이트에서 많은 시간을 보내기도 했습니다.

이런 일련의 활동이 내 지식을 살찌게 하고 내 가치를 높이고 PHP만 다룰 수 있는 43세인 제가 개발자로 살 수 있는 비법(?)입니다.

언젠가부터 꿈인 연구소에서의 개발자도 언젠가는 이루고자 합니다. 현재는 회사의 개발 규약을 정하고 소스와 개발에 적용하게 하고 Redmine이라는 이슈 트래커를 이용하여 업무를 히스토리화 하고 SVN을 통해 협업 개발을 할 수 있는 환경을 구축하였고 스크럼 개발방법론에서 일부 차용하여 회의를 진행하고 있습니다. 개발에 집중할 수 있도록 시스템을 구축하는 것도 경험 많은 개발자의 롤이라는 생각이 들고 앞으로는 정말 개발에만 매진할 수 있는 그런 환경을 만들고 싶습니다.

후배 개발자에게 당부하고 싶은 것은 지속적인 자기계발을 하라는 것입니다. 구글플러스에 개발자의 비애 비슷한 내용으로 신기술이 지속해서 나오기 때문에 계속 공부해야 한다고 썼더니 의사도 마찬가지라고 어떤 의사분이 써주셨습니다. 새로운 수술방법이 나오고 기계가 나오면 방법을 습득해야 먹고 살 수 있다고… 개발자도 마찬가지입니다. 바뀌는 트렌드에 대응하지 못하는 개발자는 도태될 수밖에 없습니다. 개발자는 타성에 젖어 있으면 안 됩니다. 끊임없이 노력해야 합니다. 얼리어답터가 되어야개발자로서 오래 살아남을 수 있습니다.

간혹 포럼의 팁 게시판을 보면 PHP 함수 하나면 처리할 수 있는 것을 함수를 만들어서 올리는 사람이 있습니다. 공부하는 목적에는 맞으나 프로젝트 시간에 쫓기는 상황에서 알고리즘을 공부하고 있는 우를 범하지 말았으면 합니다. 어떤 것이 우선순위가높은지 잘 판단해야 합니다.

같이 일했던 개발자 중에 클래스, 인터페이스를 구조적으로 잘 만드는 개발자가 있었습니다. 빡빡한 프로젝트 일정 속에서 어느 날부터인가 일 진척도가 떨어지길래 봤더니 API에 1:1로 대응하는 클래스를 만들고 있었습니다. 외국에서 개발된 API라 사용법이 불편하기는 했는데 굳이 전부를 1:1로 만들지 않아도 되는데 숲을 보지 못하고 시간을 허비하고 있었습니다. 프로젝트 초기 스터디가 가능한 시간이 있을 때나 유지보수로 넘어가서 하면 좋을 일이었는데 프로젝트 중간에 사용법이 불편하다고 자기 입맛에 맞게 API에 1:1로 대응되게 100여 개의 함수를 만들고 있었던 것은 일의 순서, 무엇이 중요한지 파악하지 못해서 그런 것입니다. 나중에 범용 함수 하나로 통일했습니다. API라는 것이 함수명, request, response로 구성된 것이라 범용적으로 처리가 가능했습니다.

또 하나의 케이스는 변화에 익숙하지 않은 개발자입니다. 닷넷 개발사 개발팀장으로 근무할 때였는데 현재도 그렇지만 닷넷 개발자 구하기가 쉽지 않습니다. 지원한 이력서를 보던 중에 53세의 닷넷 개발자가 있었고 화려한 경력과 기술 등이 마음에 들어 면접을 보게 됐고 나이가 많음에도 하고자 하는 열정이 보여서 구인을 했습니다. 그런데 웹보다는 CS 프로그램 위주로 개발하시던 분이라 웹의 생태에 대해 이해도가 떨어지고 변화를 빨리 받아들이지 못하는 성향이어서 4개월이 지나서야 제대로 커뮤니케이션이 될 정도였습니다. 자신감은 충만했지만, 변화를 두려워(?)하여 회사에 도움이 되고자 했던 구인이 오히려 다른 개발자의 리소스를 할당하게 만드는 상황이 되었습니다. 그리고 간혹 직위는 대리인데 PM만큼 넓은 시야를 가진 사람이 있습니다. 나중에는 좋습니다. 그런데 이런 유형은 개발할 때 개발자가 신경 쓰지 않아도 될 부분을 신경을 써서 개발에 집중을 못 하는 경우가 있습니다. 큰 시야는 가지고 있지만 제대로 볼 수가 없으므로 마음만 다급하고 복잡합니다. 반대로 아주 좁은 시선을 가지고 있는 개발자가 있습니다. 소위 땅파기를 잘하는 개발자입니다. 숲을 봐야 하는데 나무만 보는 격입니다. 개발과 관련이 있지만, 특정 부분에 집착하거나 해결하지 못할 경우 혼자서 끝까지 해결하려고 하는 경우인데 이런 때에도 시간을 허비하게 됩니다. 사원, 대리, 과장, 차장, 부장 직위가 올라갈수록 사물을 보는 시야가 넓어지고 단락을 구분할 수 있게 되며 문제점을 빨리 파악을 할 수 있습니다. 선택을 빨리할 수 있고 우선순위를 빨리 결정할 수 있습니다. 

개발자로 오래 살아남으려면 사회 풍토도 바뀌어야 하지만 개발자 본인의 부단한 노력이 필요하고 약간의 운(시류)도 필요합니다. 6년을 넘게 재직했던 회사에서 이직해야 했을 때 “내가 갈 곳이 있을까?”라는 생각을 했습니다. 걱정도 많이 했는데 필요로하는 곳은 있었고 요즘은 개발을 빨리하느냐 잘하느냐 이런 것보다는 내가 가지고 있는 경험을 요구하는 것이 아닌가 생각이 됩니다. 신생 회사는 조직 세팅이라던가 개발 시스템 구축이라던가 한 명의 시니어가 멘토 역할, 길잡이 역할을 수행해주기를 바랍니다.

현재 재직 중인 회사에서 제가 나이가 제일 많습니다. 직책은 없습니다. 명함의 직위는 부장이고 이전 회사가 연구소 구조라서 수석 연구원이었기에 회사 직원들은 그냥변 수석님이라고 부릅니다. 직책이 없지만 웹, 모바일 모두 관여하고 있고 개발 시스템 구축, 스크럼 회의 등을 진행하고 있기에 제가 미치는 영향력은 적지 않습니다. 회사에서 앱 게임 출시를 목전에 두고 있는데 그 앱 게임과 통신을 위한 서버 전문 프레임워크를 구상하고 개발하여 실무에 사용하고 있고(앱 뿐만 아니라 하이브리드 앱, 모바일 웹, 웹에도 대응할 수 있도록 개발되어 있습니다. CodeIgniter기반) 매출이나 수익에 크게 신경 쓰지 않고 개발 쪽에만 전념하고 있습니다.

조직의 기대도 만족 시켜야 하고 제 꿈도 펼치기 위해서는 부단한 노력이 필요합니다. PHP 솔루션으로 신규 사업 제안도 하고 여러 가지 역할을 하고 있지만 제 본분은 개발자이고 제가 꿈꾸는 백발이 성성한 개발자가 되기 위해서 열심히 노력하고 있습니다. 언어의 종류와 관계없이 개발자의 길을 가고자 한다면 끊임없는 자기계발과 업무에 대한 공부가 필요하다는 것을 다시 한번 강조하고 싶습니다. 열정만 있는 개발자가 되지 말고 열정과 실력을 겸비한 개발자가 되세요.

대한민국의 모든 개발자 분들 힘내세요!
 

<한빛미디어 페이스북 놀러가기>