BackLog란 무엇인가 ? 



스크럼 백로그는 프로젝트 네비게이터다. 

네비게이터는 우리가 길을 떠날때, 우리가 가야할 방향, 예상 소요시간등을 제시한다.

스크럼 백로그는 해야할 일 목록, 소요 시간등을 포함한
프로젝트를 완료에 필요한 모든것들을 우리에게 보여준다.

BackLog에는 무엇을 어떻게 써야 하는가 ?

1. 형식

아이디는  Log Item에 대한 유일한 ID이며, 경우에 따라서, Issue Tracker ID와 동일 시 될 수 있다. 
BackLog의 형식은 프로젝트 의 특성, 개발팀의 성향 등에 따라, 가감하여 사용된다.

그러나, "우선순위" 와 "추정시간"을 빼버리는 일은 해서는 권장하지 않는다.
우선순위가 없다면, Scrum을 할 이유도, 할수도 없다. 

그렇다고 위의 예시 대로 따를 필요 없다.
말 그대로 Agile하게, 프로젝트별로(혹은 개발팀성향에 맞게) Customizing해서 사용하면 된다. 

2. 내용

BackLog에는 프로젝트에 수행에 필요 한 모든 내용이 기록되어야 한다. 

개발 기술, 제품의 기능만이 아니라, 개발에 필요한 모든 것들을 기록해야 한다. 
특히 개발에 걸림돌이 되는 것들은 높은 우선순위로 기록하여, 먼저 제거 하도록 해야한다.

BackLog는 누가 쓰고 관리하는가?

BackLog는 오직 Scrum Master만 이 쓰기 권한을 가진다.

Scrum Master는 고객, 외부팀, 개발팀 등의 의견을 고려하여, Project Back Log 를 작성한다.
Scrum Master만이 BackLog를 작성함으로, 얻는 이득은
커뮤니케이션 창구의 단일화다.

Scrum에서는 개발자들은 더이상 기획자들에게서 Interrupt를 받을 필요가 없다. 

BackLog는 언제 쓰는가?

최초에 BackLog는 프로젝트 시작전 , 스프린트 시작전에 작성된다.
그러나 BackLog는 항상 갱신되어야 한다. 

Sprint에 대한 BackLog를 수정하는 일은 최대한 기피하여하 하지만 
프로젝트 BackLog 는 시시때때로 갱신되어야 한다. 

Sprint에대한 Back Log은 최대한 변경을 자제해야만한다.
만약, 전반적인 수술이 필요성이 느껴진다면, Sprint를 취소하는 것을 고려해야 한다.


1. MapView 보여주기

Interface Builder 상에서, MapView를 집어 놓고, Run!! 하면 다음과 같은 에러가 난다. 


그 이유인 즉슨, MapView는 MapKit이라는 Framework에 소속되어 있고, 기본적으로 
MapKit Framework은 링크 되어 있기 때문이다. 


Add Existing Framework을 선택하여, Mapkit 을 추가 해주면. 짜잔하고 잘 나온다. 


2. Annotation Pin 노출하기

- (void)addAnnotation:(id <MKAnnotation>)annotation;


MKMapView에 addAnnotation: Method를 통해 MapView에 Annotation Pin이 표기될 Data를 추가 할 수 있다.

일단 기본적으로 제공하는 MKPlaceMark Object를 생성해서, addAnnotation 해주면, 아래와 같이 Pin이 노출된다.


3. Annotation Draggable 하도록 하기.

// If YES and the underlying id<MKAnnotation> responds to setCoordinate:, 

// the user will be able to drag this annotation view around the map.

@property (nonatomic, getter=isDraggable) BOOL draggable __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);


MKAnnotationView 의 Header를 살펴보면, draggable 이라는 변수가 있다.
여기서, 주의 할점은 addAnnotation으로 추가한 MKAnnotation을 Adopting하고 있는 Object가
setCoordinate: Message에 응답가능해야 한다는것이다.

우리는 Annotation Object를 MKPlaceMark를 이용했는데, 애석하게도 MKPlaceMark Class는 setCoordinate: Message 에 응답하지 않는다.

@interface DraggableAnnotation : MKPlacemark {


}

@property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;


@end


MKPlacemark를 상속받는 DraggableAnnotation을 정의한다. 
coordinate라는 변수는 MKPlacemark에 이미 존재 함으로 property 만 Override해준다.
그리고 ViewController에서 MKPlacemark를 사용했던 부분을 DraggableAnnotation을 사용하도록 수정한다. 

MKAnnotationView의 draggable값은 기본으로 YES이지만, MKMapView에서 내부적으로 생성하는 MKAnnotationView는 Draggable=NO이다.

MKMapViewDelegate의 Method를 하나 구현한다.

- (MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id <MKAnnotation>)annotation {

NSString *reuseIdentifier = @"abcdefg";

MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[aMapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];

if(annotationView == nil) {

annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

annotationView.draggable = YES;

annotationView.canShowCallout = YES;

}

[annotationView setAnnotation:annotation];

return annotationView;

}

 

기본적인 Pin을 보여주는 MKPinAnnotationView Object를 하나 만들고, 
draggable 을 YES로 세팅해주면, 이제 원하는대로 Pin이 Dragging된다. 

MKMapView의 구조가 UIKit이랑은 조금 달르지만, 언제나 그렇듯이 알고 나면 별것 없다. 



Daily Build라는 개념을 처음 알게 된건, 아마도,
2007년 언젠가, "조엘 온 소프트웨어"라는 책을 읽으면서 였을 껍니다.

1년차 개발자로써, "조엘 테스트" 항목에 있으니까, 그저 좋은 건가 보다 하면서,
다니고 있던 회사에 도입을 극구 주장했었습니다.

지금 생각해 보면 참 우스은 일이죠. 뭐가 어떻게 좋은건지도 제대로 이해하지 못하면서,
좋은가 보다 하면서 도입하자고 했으니 말입니다.

최근에, 이 Daily Build 라는 녀석에 대해서 다시 한번 생각해봤습니다.

" 이거 정말 필요한거야 ? " 라는 생각말입니다.

결론부터 말씀드리면,

"평생 혼자서만 개발할꺼라면 필요 없다."
그러나, 그런일은 거의 없겠죠? ^^

"소프트웨어 개발" 에 "협업"이라는 키워드가 추가되면, "Daily Build"가 힘을 발휘합니다.

우리가 협업을 하고 있다고 가정해봅시다.
거기다가, 우리의 프로젝트는 "국제적인" 프로젝트라서,
내가 퇴근하고나서야, 일을 시작하는 나라에 사는 사람과 협업을 하고 있습니다.

나는 퇴근하기전에 작업물을 Commit하고 갔는데,
재수가 없게도, Build가 깨져버렸습니다. 물론 Daily Build를 하고 있지 않으니, 나는 알턱이 없죠.

저 멀리 아주 먼 나라에서 같이 일하는 개발자는 기쁜 마음으로 출근했지만,
이런 우라질, 소스 컴파일 이 안됩니다.ㅜㅜ

그 사람은 자기가 잘 알지도 못하는 코드를 분석해가며, (거기다가 욕을 해가면서 ... )
수정하고 나서야, 자기 일을 시작하게 됩니다.

다음 날 출근한 저는 내 코드를 잘 알지도 모하는 녀석이, 기괴한 방법으로 수정했음을 발견합니다.
아.. 나는 Refactoring을 해야 겠군요 ;ㅂ;

만약, 여기에 Daily Build를 하고 있었다면 어땠을까요?

나는 퇴근하기전 Daily Build가 깨진것을 확인하고,
수정을 해놓고 나서야 퇴근합니다.

그럼 외쿡인 개발자가, 잘 알지도 모르는 소스를 분석할일도, 수정할일도 없었을테고,
내 소스를 그 사람이 자기 멋대로 수정할 일도 없었겠죠.

바로 이것입니다.

Daily Build는 빌드가 깨지는 일을 방지합니다.
CI Server를 통해 자동화 된 테스트 까지 "정상적"으로 수행시키도록 프로젝트를 꾸려가면,
S/W 가 Compilable 한 상태 뿐 아니라, "Runnable"한 상태를 유지하도록 도와줍니다.

사실 Daily Build라는 말을 사용했지만,
Commit Build, Integration Build 등등 다른 말로 표현되고 있는 "Build 자동화"에 대한 이야기입니다.

약간의 극단적인 예를 들긴했지만, 같은 사무실에 동시간대에 일하는 사람들도,
이런 자동 빌드가 없는 경우 , 빈도는 조금 적을 수 있겠지만, 여전히 같은 문제가 발생합니다.

"나는 Build 자동화를 무조건 도입해야 한다 !" 라고 생각하지 않습니다.

모바일 앱 개발 같은 경우, 혼자서 작업하는 경우도 분명히 많습니다.
그런 경우 Build 자동화는 사실 큰 의미가 없습니다.

당신의 프로젝트가 혼자서 하는게 아니라면,
"나는 무조건 빌드자동화를 도입해야 한다" 고 생각합니다.





#if 1 // DEBUG

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

NSArray *languages = [defaults objectForKey:@"AppleLanguages"];

NSString *currentLanguage = [languages objectAtIndex:0];

NSLog(@"Current Locale: %@", [[NSLocale currentLocale] localeIdentifier]);

NSLog(@"Current language: %@", currentLanguage);

NSLog(@"Welcome Text: %@", NSLocalizedString(@"WelcomeKey", @""));

#endif


2010-12-23 06:48:34.061 Sample[327:207] Current Locale: en_US

2010-12-23 06:48:34.062 Sample[327:207] Current language: en

2010-12-23 06:48:34.063 Sample[327:207] Welcome Text: WelcomeKey


current language 의 경우 ISO639 에 따라 표기 된다.

Language

ISO 639-1

ISO 639-2

English

en

eng

French

fr

fre

German

de

ger

Japanese

ja

jpn

Hawaiian

no designator

haw

SRP


S/W 공학에서 특정 Module을 Design할때, 특정 모듈이 단 하나의 책임만을 가져야 한다는 원칙을 의미한다. 


SRP에서 말하는 책임은 "변화의 주체"이다. 


Module을 변화시킬수 있는 주체는 단 하나여야만 하는것이다.


이 원칙을 지키게 되면, Module의 분리가 일어남으로 거시적인 관점에서의 S/W Artchitecture의 복잡도가 상승하는 것처럼

보일 수도 있다. 


그러나, 특정 모듈의 Task가 단순해짐으로써, 개발효율 , 그리고 유지보수성이 증대하게 된다. 

거기다가 사실은 S/W Architecture의 복잡도 역시 줄어 들게 된다


내가 추구하는 간결함과 미니멀리즘에 잘 부합하는 내가 명심하는 원칙중 하나이다. 



App Widget 이란 Home Screen에 노출되는 miniature Application입니다.
보통 시계 어플등이 Widget 형태로 존재 하게 됩니다.

App Widget을 구현에 필요 한것들

A. 꼭 필요 한것들
1. AppWidgetProviderInfo object
- App Widget을 위한 MetaData, update frequecy 나 layout에 대한 정의.
- XML 에 정의 되어야함.
2. AppWidgetProvider
- Programming Interface
- AppWidget이 Update/Enabled/Disabled/Delete되었을때, BroadCast를 받는 Receiver역할을 한다.
3. View Layout
- AppWidget Design , Android Layout XML 로 정의한다.
B. 추가로 할 수 있는것
App Widget Configuration Activity
- AppWidget이 생성될때, User가 설정하게 할수 있는 Optional Feature

요약
Android Manifest에 AppWiget을 정의하고, AppWidgetProvider를 구현함으로써 Programming 하고,
Layout을 통해 App Widget을 디자인한다.

Manifest에 App Widget 선언하기.

앞서 언급한대로, AppWidget에는 AppWidgetProvider라는 BroadCast Receiver가 필요 합니다.

<receiver android:name="ExampleAppWidgetProvider" >
   
<intent-filter>
       
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
   
</intent-filter>
   
<meta-data android:name="android.appwidget.provider"
               
android:resource="@xml/example_appwidget_info" />
</receiver>

  • AppWidget Broadcast Reciver 등록
  • MetaData Resource 설정 

AppWidgetProviderInfo MetaData


res/xml/ folder에 <appwidget-provider /> 태그를 작성한 yourappwidget-info.xml을 추가합니다.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
   
android:minWidth="294dp"
   
android:minHeight="72dp"
   
android:updatePeriodMillis="86400000"
   
android:initialLayout="@layout/example_appwidget"
   
android:configure="com.example.android.ExampleAppWidgetConfigure" >
</appwidget-provider>

  • minWidth/minHeight 설정
    • 사실상 width값대로 표기되는게 아니라, 현재의 Cell Size에 따라 자동 계산된다.
    • Cell Size는 Device별로 다르고, 같은 Device일때도, Vertical이냐 Horizontal에 따라서 또 다르다.
    • ( Number of Cells ) * 74 -2 의 계산식으로 계산하여 설정하도록 한다.
  • updatePeriodMillis 설정
  • layout 명시
    • AppWidget Layout XML
  • configure(optional)
    • 유저가 AppWidget 설정시 사용될 Activity

AppWidget Layout

AppWidget의 Layout은 기본적으로 Activity용 Layout과 다를 바가 없다.
다만, AppWidget은 RemoteView를 기반으로 하고 있기 때문에, 사용할 수 있는 종류에 제약이 있다.

사용가능한 Layout Classes

사용가능한 Widget Classes

AppWidgetProviderClass 구현하기

아래 소스는 appWidget을 Click했을 때, 특정 Activity를 띄우는 AppWidget의 예이다.

public class ExampleAppWidgetProvider extends AppWidgetProvider {

   
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
       
final int N = appWidgetIds.length;

       
// Perform this loop procedure for each App Widget that belongs to this provider
       
for (int i=0; i<N; i++) {
           
int appWidgetId = appWidgetIds[i];

           
// Create an Intent to launch ExampleActivity
           
Intent intent = new Intent(context, ExampleActivity.class);
           
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

           
// Get the layout for the App Widget and attach an on-click listener to the button
           
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
            views
.setOnClickPendingIntent(R.id.button, pendingIntent);

           
// Tell the AppWidgetManager to perform an update on the current App Widget
            appWidgetManager
.updateAppWidget(appWidgetId, views);
       
}
   
}
}

AppWidget의 기본적인 목적은 주기적으로 화면을 구성해주서 보여주는것이다.
그럼으로 특별히 Enable/Disable를 처리할 이유가 없다면, 내가 해야 할일은 onUpdate() Method를 구현하는것 뿐이다.

이제 AppWidget을 띄울 수 있는 기본적인 개념은 알게 되었다.
 

"화면해상도별 아이콘 제작하기"

안드로이드 Device는 제각각이기때문에, 해상도별로 Icon을 각각 제작하길 권장합니다. 
보통은 "low/medidum/high" 이 3가지 Type의 아이콘을 만들어야 합니다. 

Resourcedirectory qualifiers for screen size and density. 에서 알수 있듯이 다른 Type도 존재 하기 때문에, 필요 하다면 그에 대한 고려도 필요 합니다.

안드로이드 Device의 기준 해상도는 mdpi(medium) 입니다. 
그래서 안드로이드용 Icon 을 제작할때는 아래의 절차에 따라 제작하는것이 좋습니다.

1. 먼저 BaseLine 해상도(mdpi)로 먼저 아이콘을 재작합니다.
2. AVD나 HVGA( e.g T-Mobile G1) 의 Device 에 올려서 테스트 하고. 조정합니다.
4. mdpi 용 icon 제작이 끝나면 hdpi 와 ldpi용 아이콘을 제작합니다.
  • hdpi 용 아이콘은 mdpi 용 icon을 150%정도로 upscale합니다.
  • ldpi용 아이콘은 mdpi용 icon을 75%정도로 downscale합니다.
  • 5. 해상도 별로 AVD혹은 Device에 올려서 테스트 합니다.

    Table 1. 해상도별 아이콘 사이즈 요약정리

    Icon Type Standard Asset Sizes (in Pixels), forGeneralized Screen Densities
    Low density screen (ldpi) Medium density screen (mdpi) High density screen (hdpi)
    Launcher 36 x 36 px 48 x 48 px 72 x 72 px
    Menu 36 x 36 px 48 x 48 px 72 x 72 px
    Status Bar 24 x 24 px 32 x 32 px 48 x 48 px
    Tab 24 x 24 px 32 x 32 px 48 x 48 px
    Dialog 24 x 24 px 32 x 32 px 48 x 48 px
    List View 24 x 24 px 32 x 32 px 48 x 48 px
     
    Android R Class는 AndroidManifest를 기준으로 자동 생성되는 Class 파일이다.

    고로, AndroidManifest에서 Package를 변경할 수 있다.

    <manifest></manifest> 를 보면,

    packge라는 attribute 가 있고, 그 값을 수정해주고, 저장하면 자동으로 변경된다. 

    단, R Class를 사용하는 소스의 import는 알아서 정리해줘야 한다. 




    오늘 오래간만에, Android New Project를 만들려고하는데,

    proguard.cfg 가 없다는 에러가 발생 ;ㅂ;

    이건 도 뭐야 하면서 짜증내는데,, stackoverflow.com 을 보니까, Android SDK Tool을 Upgrade해보라고 했다. 


    update 하니까 잘된다 ㅎㅎ



    EditMode 일때는 TableView의 TableViewCell이 Touch가 안됩니다. 


    즉, didSelectRowAtIndexPath: Delegate Method가 호출이 안되는것이죠. 


    그런데, EditMode일때도, Touch 즉 TableView Selection이 동작했으면 하는 상황이 있다면??

    이건 생각보다 쉽습니다.


    UITableView Header 파일을 보면

    allowsSelection 과 allowsSelectionDuringEditing이라는 옵션이 있습니다.

    allowsSelection 은 기본인 Selection에 대한 옵션이고,
    allowsSelection의 경우 Edit Mode에 대한 Selection입니다. 

    근데, 이 녀석이 Default=NO 인 까닥에, Edit Mode에서 didSelectRowAtIndexPath: Delegate Method가 호출 되지 않은것이죠.

    그냥
    [tableview setAllowsSelectionDuringEdit:YES]를 한번 호출 해주면됩니다.


    + Recent posts