아이디는 Log Item에 대한 유일한 ID이며, 경우에 따라서, Issue Tracker ID와 동일 시 될 수 있다.
Development
- [Scrum] Back Log 에 관하여. 2010.12.29
- [iOS] MapView Drag가능한 Annotation 추가하기. 2010.12.29
- Daily Build, "정말" 필요한 걸까? 2010.12.27
- [iOS] 현재의 locale및 language 알아 오기. 2010.12.23
- SRP - Single Responsibility Principal 2010.12.22
- [Android] App Widget 만들기 2010.12.22
- [Android] Android 2.0 용 아이콘 Design - 일반 2010.12.21
- [Android] R Class, Package 변경하기. 2010.12.20
- [Andorid] proguard.cfg 파일이 없다면서, Project 생성이 안되는 문제... 2010.12.20 1
- [iOS] EditMode 일때, TableView가 터치 안되는 문제 2010.12.17
[Scrum] Back Log 에 관하여.
아이디는 Log Item에 대한 유일한 ID이며, 경우에 따라서, Issue Tracker ID와 동일 시 될 수 있다.
[iOS] MapView Drag가능한 Annotation 추가하기.
- (void)addAnnotation:(id <MKAnnotation>)annotation;
// 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);
@interface DraggableAnnotation : MKPlacemark {
}
@property (nonatomic, readwrite, assign) CLLocationCoordinate2D coordinate;
@end
- (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;
}
Daily Build, "정말" 필요한 걸까?
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 자동화는 사실 큰 의미가 없습니다.
당신의 프로젝트가 혼자서 하는게 아니라면,
"나는 무조건 빌드자동화를 도입해야 한다" 고 생각합니다.
[iOS] 현재의 locale및 language 알아 오기.
#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
Language | ISO 639-1 | ISO 639-2 |
---|---|---|
English |
|
|
French |
|
|
German |
|
|
Japanese |
|
|
Hawaiian | no designator |
|
SRP - Single Responsibility Principal
SRP
S/W 공학에서 특정 Module을 Design할때, 특정 모듈이 단 하나의 책임만을 가져야 한다는 원칙을 의미한다.
SRP에서 말하는 책임은 "변화의 주체"이다.
Module을 변화시킬수 있는 주체는 단 하나여야만 하는것이다.
이 원칙을 지키게 되면, Module의 분리가 일어남으로 거시적인 관점에서의 S/W Artchitecture의 복잡도가 상승하는 것처럼
보일 수도 있다.
그러나, 특정 모듈의 Task가 단순해짐으로써, 개발효율 , 그리고 유지보수성이 증대하게 된다.
거기다가 사실은 S/W Architecture의 복잡도 역시 줄어 들게 된다.
내가 추구하는 간결함과 미니멀리즘에 잘 부합하는 내가 명심하는 원칙중 하나이다.
[Android] App Widget 만들기
App Widget 이란 Home Screen에 노출되는 miniature Application입니다.
보통 시계 어플등이 Widget 형태로 존재 하게 됩니다.
App Widget을 구현에 필요 한것들
A. 꼭 필요 한것들
- XML 에 정의 되어야함.
- AppWidget이 Update/Enabled/Disabled/Delete되었을때, BroadCast를 받는 Receiver역할을 한다.
Layout을 통해 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을 띄울 수 있는 기본적인 개념은 알게 되었다.
[Android] Android 2.0 용 아이콘 Design - 일반
"화면해상도별 아이콘 제작하기"
Table 1. 해상도별 아이콘 사이즈 요약정리
Icon Type | Standard Asset Sizes (in Pixels), forGeneralized Screen Densities | ||
---|---|---|---|
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, Package 변경하기.
[Andorid] proguard.cfg 파일이 없다면서, Project 생성이 안되는 문제...
[iOS] EditMode 일때, TableView가 터치 안되는 문제
즉, didSelectRowAtIndexPath: Delegate Method가 호출이 안되는것이죠.