2016년 7월 13일 수요일

Gear S 기기에 Tizen App 설치 오류 해결 방법



Gear S (SM-R750) 에 Tizen app을 설치를 위해서는

- Tizen IDE에 2.3 wearable package로 빌드? 및 설치 해야 함.
- Gear S에는 web app 설치 만 가능 하다.
- config.xml에서 Required version을 2.3에서 2.2로 변경 해야 함



 : 프로젝트 내 config.xml 파일 열기 > Tizen tab 선택 > Required version 을 2.2로 수정

Tizen 디바이스의 platform 버전에 맞는 app을 설치해야 하며
Gear S2의 경우는 Tizen 2.3.1이고 Gear S의 경우는 Tizen 2.3인 것 같은데(2.2인가?),
암튼 해당 기기에 맞는 버전으로 빌드 후 설치 가능하다.


그리고 Tizen IDE에서 필요한 Tizen package가 없다면
Tizen SDK가 설치 된 폴더 내 update-manager 폴더내
( C:\tizen-sdk\update-manager,  ~/tizen-sdk/update-manager)
update-manager를 실행하여 원하는 package를 추가 설치 해야 함.


2016년 7월 3일 일요일

애자일 마스터

애자일 마스터
조너선 라스무슨 저/최보나 역 | 인사이트(insight)

http://www.yes24.com/24/goods/6289137?scode=032




우선 책의 구성이 재미있다.
Head first 시리즈의 mini 버전 같아 너무 과하지도 않고 너무 딱딱하지도 않게 설명하고 있다.

책은 애자일 개발 방법론에 대해서도 다루지만 전반적인 내용은 애자일 방법론에 기반을 둔 프로젝트 진행에 대해서이며 각각의 주제들을 깊게 다루기보다 실제적인 예시와 상황으로 실제적인 부분들을 설명하고 개념 및 방법들을 설명하고 있다.

또한, 애자일 프로젝트 진행 시 수행되어야 할 프로젝트/팀 구성, 프로젝트 계획, 프로젝트 진행, 회고 등을 순서대로 설명해 주고 있어 애자일 프로젝트 진행에 대한 전체적인 이해를 도와주고 있다.
그래서 애자일 개발 방법론에 대해 기본 개념은 있고 프로젝트에 애자일을 적용하여 진행 시 참고할 만한 책으로 보인다.
이 책과 함께 추정, 회고, Kanban등의 주제에 대해서는 별도의 책을 참고할 필요성은 있어 보인다.

아래는 책을 보면서 동의하거나 도움이 되었던 부분들을 일부 발췌하였다.
책을 사서 보면 더 자세하고 다양한 다른 주제들이 있으니 꼭 책을 읽어 보시길~


[모두 한 버스를 타기 위한 인셉션 덱]
인셉션 덱은 로빈 기반스(Robin Gibbons)이 만든 것으로 다음의 것들로 구성되어 있다.
참고 : https://agilewarrior.wordpress.com/2010/11/06/the-agile-inception-deck/

- 우리가 왜 여기에 모였을까?
- 엘리베이터 피치
- 제품의 광고를 직접 디자인 해보기
- NOT 리스트
- 프로젝트와 관련된 다양한 사람들과 알고 지내기
- 해결책 보여주기
- 야근거리
- 규모 정하기
- 우선순위 정하기
- 미리 알아야 할 비용

책에서 말하다시피 인셉션 덱의 시작 아이디어인 "프로젝트와 관련이 있는 사람들을 보아, 모든 사람이 프로젝트에 기대하는 바가 같도록 서로 적절한 질문을 통해 생각을 공유한다면 프로젝트가 성공할 확률이 높을 것이다.' 처럼 프로젝트 팀의 방향과 구성원들의 생각을 조율하기 위해 인셉션 덱은 괜찮은 방법으로 보인다.

[전설의 사총사 : 시간, 비용, 품질, 범위]
- 시간, 비용, 품질을 정해 놓고 범위만은 프로젝트에 따라 변경할 수 있다.
- 트레이드오프 슬라이드에서 그 외 모두 우선순위를 1로 정할 수 없고, 두 항목의 우선순위가 같을 수 없다는 것도 꼭 생각해두고 있어야 한다.


[사용자 스토리의 요건 INVEST]
좋은 사용자 스토리의 요건은 Independent(독립적인), Negotiable(협상 가능한), Valuable(가치 있는), Estimatable(추정 가능한), Small(작은), Testable(테스트 가능한) 이다.


[데일리 미팅에서 질문]
일반적으로 데일리 미팅에서 아래와 같이 발언을 하는데, 책에서 제시한 질문들이 흥미로웠다.

- 어제 무엇을 했는가?
- 오늘은 무엇을 할 것인가?
- 내 잡업 속도를 늦추거나 방해하는 요소가 있는가?

=>
- 세상을 바꾸기 위해 어제 무엇을 했는가?
- 오늘 그 작업을 어떻게 끝낼 것인가?
- 불행히도 지금 내 앞을 가로막고 있는 이 장애물을 어떻게 없앨 것인가?


시각적인 작업환경 조성하기
특히나 프로젝트 진행 시 임원들이나 관리직들 대상으로 설명하거나 보여줄 것들이 필요하기 마련이다. 이때 프로젝트의 상황을 보여주거나 상황을 설명하기 위해 요긴하게 사용 될 수 있는 것들은 스토리보드, 릴리즈 상황판, 속도와 번다운 차트, 인셉션 덱이다.

2016년 6월 27일 월요일

[Link] GDB 사용

나중에 정리하려고 GDB 사용 관련 링크 저장

GDB를 이용한 디버깅

Debugging Under Unix: gdb Tutorial


실행 중인 process에 attach
$ gdb - `pidof PROCESS이름`


gdb 를 통한 디버깅 따라하기

GDB 사용법




2016년 6월 14일 화요일

The Node Beginner Book 대충 정리

The Node Beginner Book 대충 정리

보면서 눈에 띄는 것 만 대충 정리함.

http://www.nodebeginner.org/index-kr.html


Node.js

- server side JavaScript
 : Server side JavaScript 실행환경과 라이브러리로 이루어져 있음.

- Event driven callbacks
 : event에 대한 callback을 등록하여 처리 하도록 함.
   각 event 상황에 대해서 처리하도록 callback을 등록하여 단순해 지지만
   callback 내에서 과도한 operation을 처리할 경우 성능 문제 발생 가능

http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb


[Documentation에서 설명하는 기본 use scenario]

- 웹페이지 제공 => HTTP 서버가 필요.
- 서버는 어떤 URL 요청(request)에 응답 => 요청과 요청을 처리할 핸들러들을 위한 라우터(router) 필요.
- 서버로 도착한 요청 처리 => 요청 핸들러(request handlers)가 필요.
- 라우터에서의 POST 데이터 처리, request handler 들에게 넘기기 위한 request 가공 => 요청 데이터 핸들링(request data handling)이 필요.
- URL 요청 시 내용 표시 => request handler 들이 사용자 브라우저로 콘텐트를 보내기 위해 사용할 수 있는 뷰 로직(view logic)이 필요.
- 이미지들을 업로드 => 업로드 핸들링(upload handling)이 필요.


[Hello world example]

server.js


var http = require("http");
function start() {
  function onRequest(request, response) {
    console.log("Request received.");
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }

  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}

exports.start = start;
http server를 사용해서 hello world를 만들 것이므로
require로 http 모듈을 사용할 수 있도록 함.

http server 모듈의 request event를수신했을 때 response로
text/plain content type으로 "hello world"를 전송함.
http://nodejs.org/api/http.html#http_class_http_server

exports는 함수를 외부에서 사용할 수 있도록 할 때 사용.



index.js


var server = require("./server");

server.start();
다른 js파일을 내장 모듈 불러오듯 require를 사용해서 불러오고 export된 함수를 사용.


[request 정보 확인 for route]


                               url.parse(string).query
                                           |
           url.parse(string).pathname      |
                       |                   |
                       |                   |
                     ------ -------------------
http://localhost:8888/start?foo=bar&hello=world
                                ---       -----
                                 |          |
                                 |          |
              querystring(string)["foo"]    |
                                            |
                         querystring(string)["hello"]
request의 method, path, query 들을 확인하여 적절한 handler에서 처리하기 위해 필요한 함수들 



request handler들을 path에 따라 등록하고 route하는 예제


var http = require("http");
var url = require("url");
function start(route, handle) {
  function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");

    route(handle, pathname);

    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }

  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}

exports.start = start;
기본 hello world server에서 변경된 점은
url의 pathname을 확인하여 route하는 루틴이 포함된 점이다.
간단한 예제라 route의 결과를 가지고 response를 보내는 것이 구현되어 있지는 않음.



function route(handle, pathname) {
  console.log("About to route a request for " + pathname);
  if (typeof handle[pathname] === 'function') {
    handle[pathname]();
  } else {
    console.log("No request handler found for " + pathname);
  }
}

exports.route = route;
hanlder들 중에서 pathname의 key를 가진 function object를 찾아서 실행함.



var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;

server.start(router.route, handle);
url path에 따른 handler들을 매핑한 뒤
server로 router와 handle을 넘겨서 시작함.


[TODOs]

- understanding node.js : http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb

- dependency injection pattern : http://martinfowler.com/articles/injection.html

- function programming 관련 : http://steve-yegge.blogspot.kr/2006/03/execution-in-kingdom-of-nouns.html





2016년 5월 11일 수요일

Tizen Gear S2에서 지역에 따른 date 출력 방법

Tizen Gear S2에서 locale에 따른 date를 출력하기 위해 찾아봄

i18n (Internationalization)
: https://ko.wikipedia.org/wiki/%EA%B5%AD%EC%A0%9C%ED%99%94%EC%99%80_%EC%A7%80%EC%97%AD%ED%99%94

Tizen i18n Tutorial & Guide
: https://developer.tizen.org/ko/development/api-tutorials/native-application/base/i18n#dates
 : https://developer.tizen.org/ko/development/guides/native-application/base/i18n?langredirect=1

Get System Settings for Current Locale, Time Zone
 : https://developer.tizen.org/ko/development/tutorials/native-application/system/system-settings
 : https://developer.tizen.org/ko/development/guides/native-application/system/system-settings?langredirect=1

Date, Time Display Guide by Time Zones
 : https://developer.tizen.org/ko/development/api-tutorials/web-application/tizen-features/system/time



<샘플코드>

#include <utils_i18n.h>
#include <system_settings.h>

bool print_loca_date()
{
i18n_udatepg_h pattern_generator = NULL;
char *locale;

if (SYSTEM_SETTINGS_ERROR_NONE != system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &locale))
return false;
dlog_print(DLOG_INFO, LOG_TAG, "Current Locale Country : %s\n", locale);

i18n_udatepg_create(locale, &pattern_generator);
if (!pattern_generator)
return false;

i18n_uchar bestPattern[64] = {0,};
char bestPatternString[64] = {0,};
int bestPatternLength, len;
const char *custom_format = "EEE, MMM d, yyyy 'at' HH:mm:ss zzz";
i18n_uchar uch_custom_format[64];

i18n_ustring_copy_ua(uch_custom_format, custom_format);
len = i18n_ustring_get_length(uch_custom_format);
i18n_udatepg_get_best_pattern(pattern_generator, uch_custom_format, len, bestPattern, 64, &bestPatternLength);
i18n_ustring_copy_au_n(bestPatternString, bestPattern, 64);
dlog_print(DLOG_INFO, LOG_TAG, "BestPattern(char[]) : %s \n", bestPatternString);
i18n_udatepg_destroy(pattern_generator);

i18n_udate_format_h formatter_Current = NULL;
i18n_uchar formatted[64] = {0,};
char result[64] = {0,};
int formattedLength;
i18n_udate date;
char *timezone_Current;
i18n_uchar utf16_timezone_Current[64] = {0,};

if (SYSTEM_SETTINGS_ERROR_NONE != system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_TIMEZONE, &timezone_Current))
return false;

i18n_ustring_copy_ua_n(utf16_timezone_Current, timezone_Current, strlen(timezone_Current));
if (I18N_ERROR_NONE != i18n_udate_create(I18N_UDATE_PATTERN , I18N_UDATE_PATTERN , locale,
utf16_timezone_Current, -1, bestPattern, -1, &formatter_Current))
return false;

if (utf16_timezone_Current)
{
i18n_ucalendar_get_now(&date);
i18n_udate_format_date(formatter_Current, date, formatted, 64, NULL, &formattedLength);
i18n_ustring_copy_au_n(result, formatted, 64);
dlog_print(DLOG_INFO, LOG_TAG, "Current Date : %s\n",result);
}
i18n_udate_destroy(formatter_Current);
return true;
}

<결과>

Current Locale Country : en_US
BestPattern(char[]) : EEE, MMM d, yyyy, h:mm:ss a zzz
Current Date : Thu, May 12, 2016, 11:22:56 AM GMT+9

Current Locale Country : de_DE
BestPattern(char[]) : EEE, d. MMM yyyy HH:mm:ss zzz
Current Date : Do., 12. Mai 2016 11:23:33 GMT+9

Current Locale Country : ko_KR
BestPattern(char[]) : yyyy년 MMM d일 (EEE) a h시 m분 s초 zzz
Current Date : 2016년 5월 12일 (목) 오전 11시 24분 13초 GMT+9

Current Locale Country : zh_CN
BestPattern(char[]) : yyyy年M月d日EEE zzzah:mm:ss
Current Date : 2016年5月12日星期四 GMT+9AM11:24:48

Current Locale Country : ja_JP
BestPattern(char[]) : yyyy年M月d日(EEE) H:mm:ss zzz
Current Date : 2016年5月12日(木) 11:25:13 GMT+9

Current Locale Country : hi_IN
BestPattern(char[]) : EEE, d MMM yyyy h:mm:ss a zzz
Current Date : गुरु, 12 मई 2016 11:26:29 AM GMT+9

2016년 5월 6일 금요일

Tizen Native app 개발 시 crash information에서 crash point file, line number 확인 방법

Tizen Native App의 crash 발생 시
crash information을 통해 crash가 발생된 file과 위치(line number)를 확인하는 방법을 정리함.

Native app 개발 하다 보면 Crash를 자주 보게 되는데
그냥 log만 사용해서 확인하자니 빌드 및 실행, 로그 추가로 좀 비효율적임.

다른 디버깅 방법으로 crash 발생 시 생성되는 crash information 중  callstack과
linux에서 개발을 하여 shell을 사용할 수 있다면
간단하게 crash가 발생한 위치를 addr2line을 사용하여 파악할 수 있다.



[Crash information 획득]


Tizen SDK를 사용하고 단말(Gear S2)가 연결이 되어 있는 상태라면
Crash 발생 시 자동으로 SDK에서 call stack view(Window > Show View > Call Stack)를 통해서 보여주게 된다.

Call Stack View를 통해 Crash information, Call stack, Crash 발생 당시 Log를 확인 가능하며
아래 사진은 Sample app을 사용하여 crash를 발생 시킨 것이라 다소 call stack depth가 얕다.

그리고 call stack 내에 app의 binary(ex basicuiw)의 실행 내역이 포함되어 있어야 해당 실행 주소를 사용하여 위치를 확인할 수 있다.




Callstack Information (PID:32525)
Call Stack Count: 1
 0: create_base_gui + 0x1c9 (0x4155e13a) [/opt/usr/apps/org.example.basicuiw/bin/basicuiw] + 0x113a
End of Call Stack


Call Stack에서 basicuiw 앱의 create_base_gui 함수에서 발생되었고 주소는 0x113a임을 알 수 있다.
이를 addr2line을 사용하여 확인하려면 다음과 같이 실행한다.
* 다만 여기서 사용하는 앱 바이너리(basicuiw) crash가 발생된 bianry와 같아야 한다.
   만약 crash 발생 이후 다시 컴파일을 했다면 위치를 확인하기가 어렵다.

hhh@:~/workspace_tizen/BasicUIw/Debug$ pwd
/home/hhh/workspace_tizen/BasicUIw/Debug
hhh@:~/workspace_tizen/BasicUIw/Debug$ addr2line -C -f -e basicuiw 0x113a
create_base_gui
/home/hhh/workspace_tizen/BasicUIw/Debug/../src/basicuiw.c:71

Crash는 basicuiw.c의 71번 line에서 발생한 것을 확인하였고
해당 위치를 확인하면 다음과 같이 crash가 발생하도록 작성한 코드가 맞음을 알 수 있음.




참고로 crash information들은 다음의 위치들에 저장이 된다.
SDK가 설치된 host pc의 app project 내 crash-info 폴더(연결 중 crash가 발생했다면)나
단말내 /opt/usr/share/crash/report 에서 확인할 수 있다.



2016년 4월 25일 월요일

Visual Studio emulator for Android 사용 시 adb reverse 안되는 현상

Windows에서 Visual Studio emulator for Android를 사용하던 중
adb reverse 가 안되는 현상이 있어서 찾아보니
원인은 emulator의 Android 버전이었음.

adb reverse가 Android 5.0(API21) 이상에서 부터 사용되는 기능이므로
emulator Android 버전이 그 미만이면 사용 불가능함.

[증상]
D:\>adb reverse tcp:8081 tcp:8081
error: closed

[참고]
http://facebook.github.io/react-native/docs/running-on-device-android.html#using-adb-reverse

* Emulator에서 Reload JS를 하기 위해서 Developer menu를 여는 방법은 다음과 같다.
 : adb shell input keyevent 82