'분류 전체보기'에 해당되는 글 366건
- 2010.04.28 Custom View 만들기 3
- 2010.04.26 터치모드 정리 1
- 2010.04.26 articles of Layout Tricks 1
- 2010.04.24 MoSync ?? 2
- 2010.04.23 The Joel Test: 나은 코딩을 위한 12단계 1
- 2010.04.22 Sample Sync Adapter 테스트 방법 2
- 2010.04.22 Google Begins Testing Android OS 2.2(Froyo) 1
- 2010.04.21 Technical Arcticles 4. Tracking Memory Allocations 1
- 2010.04.19 볼륨키로 볼륨조정시 mixer결정 방식. 2
- 2010.04.19 스마트폰 개발자들이 뛰어놀게 될 레드오션~! 1
터치 모드
안드로이드용 사용자 인터페이스를 디자인하고 개발하는 것은 일반적인 데스크탑 환경에서 하는 것과는 상당한 차이가 있습니다. 안드로이드는 모바일 장치에서 어플리케이션을 실행하고, 어플리케이션 디자이너와 개발자들은 명확하지 않은 다수의 제약사항을 다뤄야 하기 때문입니다. 우리는 여러분이 더 나은 어플리케이션을 디자인하고 개발하는 것을 돕기위해 안드로이드 사용자 인터페이스에 관한 새로운 시리즈의 게시물을 작성하고자 합니다. 이 시리즈에서 우리는 여러분에게 디자인 가이드, 툴, 개발팁을 제공하고 안드로이드 UI 툴킷의 핵심적인 원리들을 설명할 것입니다. 목표는 간단합니다: 우리는 여러분이 훌륭한 사용자 경험(인터페이스)을 디자인하고 개발하는 것을 돕고 싶습니다. 이 시리즈를 시작하면서, UI 툴킷의 가장 중요한 원리 중 하나인 터치 모드에 대해 소개하고자 합니다. 터치 모드는 폰과 사용자의 접촉에 따른 뷰 계층의 상태입니다. 터치 모드는 마지막 사용자 접촉이 터치 스크린에 실행됐는지 간단히 표시하기 때문에, 그 자체만으로도 아주 이해하기 쉬운 것입니다. 예를 들어, 여러분이 G1 폰을 사용하고 있다면, 틀랙볼로 위젯을 선택하는 것이 여러분을 터치 모드에서 빠져나오게 할 것입니다; 하지만, 여러분이 스크린의 버튼을 손가락으로 접촉하면, 여러분은 터치 모드로 들어오게 됩니다. 사용자가 터치 모드가 아닐 때, 우리가 틀랙볼 모드, 네비게이션 모드 혹은 키보드 네비게이션이라고 말할 때 이 용어들에 놀라지 마시기 바랍니다. 마지막으로, 터치 모드와 직접 관련된 단 하나의 API만이 존재합니다.View.isInTouchMode(). 쉽죠? 이상하리만큼, 터치 모드는 거짓말처럼 간단하지만 터치 모드에 들어감으로 인해 생기는 결과는 여러분이 생각하는 것보다 훨씬 큽니다. 몇 가지 이유에 대해 알아봅시다.
터치 모드, 선택, 그리고 Focus
모 바일 장치용 UI 툴킷을 디자인하는 것은 모바일 장치가 제공하는 다양한 상호작용 메카니즘으로 인해 매우 어렵습니다. 일부 장치들은 12개의 키만 제공하고, 어떤 장치는 터치 스크린이 있고, 어떤 장치는 스타일러스가 필요하고, 어떤 장치는 터치 스크린과 키보드 둘 다 가지고 있습니다. 이런 상황에서, 최초의 상용 장치 G1이 터치 스크린, 트랙볼, 키보드를 사용하는 다중 입력폼을 제공한다는 사실은 안드로이드 개발 커뮤니티에 긍정적인 영향을 줍니다. 사용자가 세 가지의 다른 메카니즘을 통해 어플리케이션과 소통할 수 있기 때문에, 우리는 가능한 모든 상황을 심각하게 고려해야만 합니다. 우리는 한 가지 문제 때문에 터치 모드를 만들게 되었습니다.텍스트 아이템 리스트를 보여주는 간단한 어플리케이션(예) ApiDemos )을 생각해 보세요. 사용자는 틀랙볼을 사용해서 자유롭게 리스트를 볼 수 있고, 또한 스크롤 하거나 손가락을 이용해 화면을 이동할 수도 있습니다. 이 시나리오에서 선택이 문제가 됩니다. 만약, 제가 리스트에 있는 최상단의 아이템을 선택하고 아래로 쓸어내리면, 선택의 관점에서는 어떤 일이 일어나야 할까요? 아이템이 그대로 선택되어져 있고 화면만 스크롤 되어야 할까요? 이 상황에서, 제가 트랙볼을 이용해 선택위치를 옮기기로 결정한다면 무슨 일이 일어날까요? 혹은 더 심하게, 만약 제가 화면에 더 이상 보이지 않는 현재 선택된 아이템을 실행하기 위해 트랙볼을 누른다면? 신중하게 생각한 후, 우리는 선택을 해젷기로 결정했습니다.
터 치 모드에서는 Focus도 선택도 없습니다. 사용자가 터치 모드에 들어서자마자, 그리드 안의 리스트에 있는 선택 아이템은 선택해제 됩니다. 마찬가지로, 사용자가 터치 모드에 들어서면, 선택된 위젯도 선택해제 됩니다. 아래 이미지는 사용자가 틀랙볼로 아이템을 선택한 후 리스트를 터치하면 어떻게 되는지 보여줍니다.
프레임 워크는 사용자가 좀 더 자연스러움을 느끼게 하기 위해, 터치 모드를 벗어나면 기존의 선택/Focus 상태를 복원할 수 있습니다. 예를 들어, 위의 예제와 같이, 사용자가 트랙볼을 다시 사용해야 한다면, 이전에 선택된 아이템이 다시 선택되어 집니다. 이것이 왜 일부 개발자들이 언제 커스텀 뷰를 생성하고 트랙볼을 한번 움직인 다음부터 키 이벤트를 받기 시작하는 것을 혼동하는 이유입니다: 어플리케이션은 터치 모드에 있고, 터치 모드를 나가 Focus를 복원 하기 위해 트랙볼을 사용해야 합니다.
터치 모드, 선택, Focus의 관계는 여러분이 여러분의 어플리케이션을 빠져나가기 위해 선택과(혹은) Focus에 의존해서는 안된다는 뜻입니다. 새내기 안드로이드 개발자들이 가지는 일반적인 문제는 ListView.getSelectedItemPosition()에 의존하는 것입니다. 터치 모드에서 이 메서드는 INVALID_POSITION을 리턴할 것입니다. 여러분은 click listeners 혹은 choice mode를 사용해야 합니다.
터치 모드에서 focusable
이 제 여러분은 터치 모드에서 Focus가 존재하지 않는다는 것을 압니다. 하지만 저는 이것이 100% 사실은 아니라는 것을 설명해야 합니다. Focus는 터치 모드에 존재할 수 있지만, 아주 특별한 방법으로만 가능합니다. 우리는 이것을 터치 모드의 focusable이라고 부릅니다. 이 특별한 모드는 EditText와 같은 텍스트 입력을 받는 위젯이나 ListView에 서 필터링이 활성화 되었을 때를 위해 만들어졌습니다. 이것이 왜 사용자가 트랙볼이나 손가락으로 먼저 선택하지 않고도 텍스트 필드에 텍스트를 입력할 수 있는 이유입니다. 사용자가 스크린을 터치할 때, 어플리케이션이 이미 터치 모드가 아니면, 터치 모드로 들어갑니다. 터치 모드로 들어가는 과정에서 생기는 일은 사용자가 무엇을 터치했는지와 현재 Focus의 상태에 따라 다릅니다. 사용자가 터치 모드의 focusable 상태인 위젯을 터치하면, 위젯이 Focus가 됩니다. 그 외에 터치 모드의 focusable 상태가 아닌 한, 현재 Focus된 어떤 위젯도 Focus되지 않습니다. 예를 들어, 아래의 이미지에서, 사용자가 스크린을 터치하면, 입력 텍스트 필드가 Focus가 됩니다.터 치 모드의 focusable은 여러분이 코드나 XML에서 스스로 설정할 수 있는 속성입니다. 그러나, 이 속성이 안드로이드의 일관된 일반적인 습성을 훼손하기 때문에, 최소한으로 그리고 아주 특별한 상황에서만 사용되어야 합니다. 터치 모드의 focusable 속성을 잘 사용할 수 있는 게임은 좋은 어플리케이션 예제입니다. 구글 맵에서처럼, 풀스크린에서 사용되는 MapView는 터치 모드의 focusable을 올바로 사용할 수 있는 또 다른 좋은 예제입니다.
아래는 터치 모드의 focusable 위젯을 사용하는 다른 예입니다. 사용자가 AutoCompleteTextView의 제안을 손가락으로 선택하면, Focus가 텍스트 입력 필드에 남아있습니다:
새내기 안드로이드 개발자들은 종종 터치 모드의 focusable이 선택/Focus가 사라지는 문제를 "고치는" 해결책이라고 생각합니다. 우리는 여러분이 이것을 사용하기 전에 매우 신중히 생각해 보기를 권유드립니다. 만약 잘못 사용되면, 이것은 여러분의 어플리케이션이 시스템의 나머지 다른 것들과 다르게 행동하게 만들며, 사용자의 습관을 무시하게 됩니다. 안드로이드 프레임워크는 "터치 모드의 focusable"을 사용하지 않고 사용자와의 상호작용을 다룰 수 있는 모든 도구를 포함하고 있습니다. 예를 들어, 선택상태를 유지하는 ListView를 만드는 대신, 간단히 적당한 choice mode를 사용합니다. 만약 여러분이 프레임워크가 여러분의 필요를 충족시키지 못한다고 느낀다면, 우리에게 알려주시거나 패치를 제공해 주시기 바랍니다.
터치 모드 컨닝 페이퍼
해야할 것:
- 핵심 어플리케이션과 일관성을 유지하라
- 지속적인 선택상태가 필요하면, 적절한 기능을 사용하라 (라디오 버튼, 체크 박스, ListView의 선택 모드 등)
- 게임을 개발한다면, 터치 모드의 focusable을 사용하라
하 지 말아야 할 것:
터치 모드에서 Focus나 선택을 유지하려고 하지 말라<com.android.launcher.Workspace
android:id="@+id/workspace"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
launcher:defaultScreen="1">
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
<include android:id="@+id/cell3" layout="@layout/workspace_screen" />
</com.android.launcher.Workspace>
<include android:layout_width="fill_parent" layout="@layout/image_holder" />
<include android:layout_width="256dip" layout="@layout/image_holder" />
Layout Tricks: Creating Efficient Layouts
안드로이드 UI 툴킷은 몇 가지 Layout 매니저(LinearLayout / RelativeLayout 등의 ViewGroup)를 제공한다. Layout 매니저들은 쉽게 사용할 수 있으며, 많은 경우 기본적인 기능만을 이용해서 원하는 사용자 인터페이스를 구현할 수 있다.
하지만 불행하게도, 기본적인 구성요소만을 사용하는 것이 사용자 인터페이스를 작성하는데 가장 효율적인 방법은 아니다. 예를 들어, 개발자가 LinearLayout 을 남용해서 사용할 경우, 전체 UI를 구성하는 View의 계층구조가 복잡해지고, 사용되는 View 의 숫자가 크게 증가될 수 있다. 화면을 구성하는데 사용된 모든 View 와 Layout 매니저들을 처리하는데는 비용이 든다. 특히 LinearLayout 의 weight 파라매터를 사용하는 경우, Layout 화면을 구성하기 위해, 두 번의 Measure Pass 를 거쳐야 하기 때문에 더욱 많은 비용이 소모된다.
여기 매우 단순하고 일반적인 예가 하나 있다. 아래의 그림과 같이 하나의 리스트 아이템을 표현하기 위한 Layout 을 생각해 보자. 왼쪽에는 아이콘 이미지가 있고, 상단에는 타이틀 텍스트가 그 아래는 부가적인 설명이 포함된 Layout 이다.
HierarchyViewer 로 캡처한 Layout 와이어 프레임을 살펴보면, 하나의 ImageView 와 두 개의 TextView 가 어떻게 구성되어 있는지 보다 명확하게 확인 할 수 있다.
LinearLayout 을 이용하 이러한 화면을 구성하는 것은 어렵지 않다. 전체 Layout 은 Horizontal LinearLayout (orientation 속성값이 Horizontal ) 이며, 하나의 ImageView 와 Vertical LinearLayout 을 포함하고 있다. 또한 Vertical LinearLayout 은 두 개의 TextView 를 포함한다. 소스 코드는 다음과 같다.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginRight="6dip"
android:src="@drawable/icon" />
<LinearLayout
android:orientation="vertical"
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="fill_parent">
<TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center_vertical"
android:text="My Application" />
<TextView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application" />
</LinearLayout>
</LinearLayout>
이 Layout 은 정상적으로 작동하지만, 낭비 요소를 담고 있다. 개발자는 하나의 RelativeLayout 이용해서 동일한 형태의 UI를 구성할 수도 있다. 그럼으로 화면을 구성하는데 사용되는 View 의 수를 하나 줄일 수 있고, 추가 적으로 View 의 계층 구조도 좀 더 단순화 될 수 있다. 또한 RelativeLayout 을 이용해서 구현하는 것은 어렵지도 않다.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip">
<ImageView
android:id="@+id/icon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="6dip"
android:src="@drawable/icon" />
<TextView
android:id="@+id/secondLine"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_toRightOf="@id/icon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Simple application" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/icon"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="@id/secondLine"
android:layout_alignWithParentIfMissing="true"
android:gravity="center_vertical"
android:text="My Application" />
</RelativeLayout>
새로운 구현 방식은 이전에 LinearLayout을 이용한 구현한 것과 거의 동일하게 작동하지만, 한가지 주의해야할 점이 있다. 위의 Layout 중에, 만일 특정 리스트 아이템에 대해서, 부가적인 설명을 나타내는 TextView 가 사용될 필요가 없는 경우 이전 LinearLayout 을 이용해서 구성한 경우, 해당 TextView 의 Visibility 속성을 Gone 으로 설정하면 손쉽게 부가 설명 항목을 제외 시킬 수 있다. 하지만 그러한 방식은, RelativeLayout 을 사용하는 경우 정상적으로 작동하지 않을 수도 있다.
RelativeLayout 에서 View 들은 특정 부모 View (RelativeLayout 자체나 아니면 해당 Layout이 참조하고 있는 View) 를 기반으로 정렬되어 진다. 예를 들어, 위 예제의 경우, 부가적인 설명을 표시하는 TextView 는 RelativeLayout 의 바닦면에 정렬되며, 타이틀을 표시하는 TextView 는 그 View 위에 위치하도록 선언되어 있다. 이 때, 부가적인 설명을 표시하는 TextView 가 Gone 이 될 경우, RelativeLayout 은 타이틀을 표시하는 View 를 어디에 위치시켜야 할지 알 수 없게 된다. 이러한 문제를 해결하기 위해, 개발자는 layout_alignWithParentIfMissing 파라매터를 사용할 수 있다.
이 Boolean 인자는 만일 특정한 View 가 기준으로 삼아야되는 부모 View 가 없을 경우, 해당 View 를 포함하고 있는 RelativeLayout 자체를 기준으로 삼으라고 알려준다. 예제의 경우, aliginWithParentIfMissing 를 설정함으로서, 만일 타이틀을 표시하는 TextView 가 기준으로 삼고 있는 TextView 가 없을 경우 (Gone 에 의해...), 해당 View 대신 RelativeLayout 을 기준으로 삼게 되고, 그 결과 TextView 는 아래와 같이 RelativeLayout 의 바닦면 바로 위에 위치하게 된다.
이로서 RelativeLayout 을 이용해 구성한 두 번째 UI도 완벽하게 작동한다. 무엇보다도, 계층구조는 더 단순해 졌고, LinearLayout 의 weight 파라메터를 사용하지 않았기 때문에 더 효율적이다. 두 가지 구현 방식의 차이점은 HierarchyViewer 를 이용해 살펴 보면 확실하게 들어난다.
다시한번 말하지만, 이러한 차이는 ListView 를 구성하는 개발 아이템 아이템 마다, 동일한 형식의 Layout 을 사용하게 되면 훨씬 더 중요해 질 수 있다. 개발자들이 이번 글에서 예로든 간단한 예제를 통해, 여러가지 레이아웃에 대해 잘 아는 것이, UI 를 최적화하는데 최선의 길임을 알 수 있기를 희망한다.
Layout Tricks: Using ViewStubs
안드로이드에서 Activity 간에 UI 구성 요소를 공유하고 재사용하는 것은 매우 쉽다. <include/> 태그에게 감사하자. 때로는 복잡한 UI를 만들어내는 것이 너무 쉬운 나머지, 매우 드물게 사용되는 View 들도 전부 포함하는, 굉장히 많은 View 로 구성된 UI를 만들어 낼 수도 있다. 이런 경우를 대비해, 매우 고맙게도, 안드로이드에서는 ViewStub 위젯을 제공해 준다. ViewStub 을 사용하면, 개발자는 <include/> 태그가 제공하는 이점을 취하면서도, 잘 사용되지 않는 View 는 생성하지 않고 Layout 을 구성할 수 있다.
ViewStub 은 매우 가벼운 더미 View 이다. 이 View 는 어떤 영역을 차지하지도 않으며, 무엇을 그리지도 않고, UI 를 구성하는 Layout 에 참여하지도 않는다. 즉, ViewStub 을 생성하고, View 계층구조내에서 유지하는데 매우 적은 비용만이 필요하다. ViewStub 은 Lazy Include 하다고 표현할 수 있는데, ViewStub 에 의해 참조되고 있는 View 는 오직 개발자가 명시적으로 지시하는 경우에 한해서, 생성(inflate)되고 View 계층 구조에 추가되기 때문에 그렇다. (즉, Layout Inflate 시점에 바로 생성되지 않고 그 이 후에 생성된다...)
다음 그림은 Shelves 어플리케이션의 스크린 샷이다. 이 Activity 는 책 선 반위에 놓인, 사용자들이 열람가능한 책 목록을 보여준다.
동일한 Activtriy 가 사용자가 새로운 책을 추가할 때도 사용된다. 그런데, 책을 추가하는 작업이 이루어지는 동안에, Shelves 는 추가적인 사용자 인터페이스를 보여준다. 아래의 스크린샷에서 볼 수 있듯이, 책을 추가하는 동안 화면 하단에, 프로그래스바와 취소 버튼이 나타난다.
책을 추가하는 작업은, 적어도 책 목록을 살펴보는 작업에 비해 일반적인 작업이 아니기 때문에, 해당 정보를 표시하는 패널은 ViewStub 을 이용하여 구현되어 있다.
사용자가 책을 추가하는 작업을 시작하는 시점에 ViewStub 이 실재로 형상화 되며, 해당 ViewStub 이 참조하고 있는 Layout 파일이 ViewStub 을 대체하게된다.
ViewStub 을 사용하기 위해서, 개발자는 ViewStub 을 실재로 형상화 하기 위해 필요한 android:id 속성 값과 해당 ViewStub 이 어떤 Layout 파일에 정의된 View 와 교체될지를 나타내는 android:layout 속성 값을 지정해 주면된다. 추가로, ViewStub 에서는 또 한 가지 속성값이 사용된다. android:inflatedId 는 참조되는 Layout 파일의 루트 View 의 android:id 속성 값을 Override 할 수 있게 해 준다. 또한, ViewStub 에 정의한 Layout 파래매터들은, ViewStub 이 참조한 Layout 의 루트 View 에 적용된다. 실재 사용예는 아래와 같다.
<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
개발자가 ViewStub 을 형상화 하고자 할 때면, 단순히 해당 ViewStub 의 inflate()메서드를 호출 하거나, Visibility 속성을 VISIBLE 이나 INVISIBILE 로 변경하면 된다. 단, inflate() 메서드를 를 호출할 경우, 형상화된 Layout 파일의 루트 View 를 반환값으로 전달 받을 수 있는 장점이 있다.
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
ViewStub 이 형상화된 이 후에는, View 계층 구조에서 완전히 제거된다는 것을 기억하는 것은 매우 중요하다. 즉, ViewStub 에 대한 참조를 Class 멤버 변수로 두는 식으로 오래 동안 유지할 필요가 없다.
ViewStub 은 쉬운 프로그래밍과 효율적인 프로그래밍 사이에서 환상적인 조화를 이루고 있다. 어플리케이션 실행 중에, 특정한 View 를 코드상에서 생성한 후, View 계층 구조에 추가하도록 구현하기 보다 ViewStub 을 사용하는 것이 훨씬 쉽고 효율적일 수 있다. 현재 ViewStub 이 갖고 있는, 딱 한가지 단점은 <merge/> 태그를 지원하지 않는다는 것이다.
Layout Tricks: Merging Layouts
한 번 작성한 Layout 코드를 공유하고 재사용하기 위해 <include/> 태그를 사용하는 방법에 대하여 이야기 했었다. 이번 글에서는 <include/> 태그를 사용할 때 생기는 문제점을 보완해 줄 수 있는 <merge/> 태그에 관해 이야기해 본다.
안드로이드에서 UI Layout 을 구성 할 때, View 계층 구조의 단계를 줄여 최적화 하기 위해 <merge /> 태그가 만들어졌다. 예제를 통해 살펴보면, 이 태그를 사용하는 목적에 대해 쉽게 이해할 수 있다. 다음의 예는, 어떤 이미지를 표시하고, 그 이미지 위해 해당 이미지의 제목을 표시해 주는 XML Layout 이다. 구조는 매우 단순하다. FrameLayout 을 이용해서, ImageView 위에 TextView 를 표시하였다.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/golden_gate" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Golden Gate" />
</FrameLayout>
이 Layout 은 원하는 대로 잘 작동하며, 특별히 잘못된 점은 찾을 수 없다.
하지만 만일 이 레이아웃을 HierarchyViewer 를 통해 살펴보면 흥미로운 점이 들어난다. 개발자가 View 계층 구조를 잘 살펴보면, 우리가 XML 파일에 정의한 FrameLayout 이 딱 하나의 FrameLayout 만을 자식 View 로 가지고 있는 것을 확인 할 수 있다. (파란색으로 강조되어 있다.)
이 때 FrameLayout 은 fill_parent 속성 값을 사용하고 있기 때문에, 그 부모와 동일한 영역을 차지한다. 또한, 특별한 배경을 지정하지도 않았으며, 추가적인 Padding 속성이나 Gravity 속성을 지정하지 않았기 때문에, 사실 화면을 구성 하는데 역할을 수행하지 않는다. 즉, 이 경우 추가적으로 사용된 FrameLayout 은 어떠한 이유도 없이 그저 UI 를 보다 복잡하게 만들 뿐이다. 하지만 우리가 어떻게 이 FrameLayout 을 제거할 수 있을까? 어찌되었든, Layout 을 지정하는 XML 다큐먼트는 Root 태그를 가져야 하면, XML 상에 정의된 태그 는 실제View 로 구현된다.
바로 이 경우에 <merge/> 태그가 쓸모있다. LayoutInflater 가 View 를 형상화 하는 과정 중에, <merge/> 태그를 만나게 되면, 해당 <merge/> 태그는 건너 뛰고, 그 자식 View 들을 <merge/> 태그의 부모 View 에 추가한다. 설명이 조금 헷갈릴 수도 있겠다. 이해를 돕기 위해, 이전 예제에서 사용된 FrameLayout 대신 <merge/> 를 사용한 후 살펴 보자.
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/golden_gate" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom"
android:padding="12dip"
android:background="#AA000000"
android:textColor="#ffffffff"
android:text="Golden Gate" />
</merge>
이 새로운 버전의 Layout 에서 TextView 와 ImageView 는 최상위 FrameLayout 에 바로 추가된다. 그 결과, 화면상으로 동일하게 보이지만, 실재 View 계층구조는 좀 더 단순해 진다.
명백하게도 위의 예제에서 <merge /> 태그를 사용 할 수 있는 것은, Activity 에 사용된 Content View 가 FrameLayout 이기 때문이다. (FrameLayout 이 두 번 반복되기 때문에 하나를 줄일 수 있음) 만일 FrameLayout 대신 LinearLayout 이 Root 태그로 사용되었다면, <merge/> 태그를 사용할 수 없다.
하지만 <merge /> 태그는 다른 경우에도 유용하게 사용될 수 있다. 예를 들어, <merge /> 태그는 <include /> 를 통해 View 를 추가하고자 할 때, 완벽하게 작동한다. 또한, XML 상에서 몇개의 View 를 조합하여, 커스텀한 View 를 구성하고자 하는 경우에도 <merge /> 태그는 유용하게 사용된다. Button 내부의 내용을 원하는 대로 수정할 수 있는, 두 개의 Button 을 보여주는 OKCancelBar 라는 CustomView 를 만들 때, <merge /> 를 어떻게 사용할 수 있는지 한 번 살펴보자. (원한 다면, 이 예제의 완벽한 소스를 다운로드 받을 수도 있다.) 아래의 예제는, 어떤 이미지 위에 우리가 새롭게 정의한 CustomView 를 표시한다.
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="center"
android:src="@drawable/golden_gate" />
<com.example.android.merge.OkCancelBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingTop="8dip"
android:gravity="center_horizontal"
android:background="#AA000000"
okCancelBar:okLabel="Save"
okCancelBar:cancelLabel="Don't save" />
</merge>
새로운 Layout 은 다음과 같은 결과를 만들어 낸다.
새로운 CustomView 인 OKCancelBar 의 소스 코드는 매우 단순하다. 왜냐하면 두 개의 버튼을 생성하기 위한 코드는 외부 XML 파일에 별도로 지정되어 있기 때문이다. 다음 코드에서 확인 할 수 있듯이, R.layout.okcancelbar 에 지정된 Layout 이 LayoutInflate 를 통해 형상화 된 후, OKCancelBar 의 자식 View로 추가된다.
public class OkCancelBar extends LinearLayout {
public OkCancelBar(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
setGravity(Gravity.CENTER);
setWeightSum(1.0f);
LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
String text = array.getString(R.styleable.OkCancelBar_okLabel);
if (text == null) text = "Ok";
((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
text = array.getString(R.styleable.OkCancelBar_cancelLabel);
if (text == null) text = "Cancel";
((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
array.recycle();
}
}
두 개의 버튼은 다음의 XML Layout에 정의되어 있다. 추가적인 Layout 없이, 부모 View 인 OKCancelBar 에 두 개의 버튼을 직접 추가하기 위해서 <merge /> 태그를 사용했다. 또한, 개별 버튼은 유지하고 관리하기 쉽게 하기 위해, 외부 XML 파일에 별도로 구현된 후, <include/> 태그를 이용해 두 번 포함되었고, 단순히 id 값만을 Override 하였다.
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<include
layout="@layout/okcancelbar_button"
android:id="@+id/okcancelbar_ok" />
<include
layout="@layout/okcancelbar_button"
android:id="@+id/okcancelbar_cancel" />
</merge>
결과적으로 우리는, 효율적인 View 계층 구조를 갖으면서도, 유연하고 유지보수 하기 쉬운 Custom View 를 작성 하였다.
살펴본 봐와 같이, <merge/> 태그는 코드를 작성할 때, 굉장히 유용하며 깜짝 놀랄만한 일들을 해 준다. 하지만, 몇 가지 한계점도 갖고 있다.
- <merge/> 는 Root 태그로만 사용될 수 있다.
- <merge/> 로 시작되는 Layout 을 형상화 할 때, 개발자는 반드시, ViewGroup 을 지정해 주어야 하고, attachToRoot 값을 true 로 설정 해 주어야 한다. (보다 자세한 설명은 inflate() 메서드에 관한 다음 내용을 살펴 보라.)
MoSync - Mobile Development Made Easy
MoSync는 동일하게 실행되고 표준에 기반한 모바일애플리케이션 개발 SDK이다. MoSync로 당신은 복잡한 애플리케이션을 쉽게 개발할 수 있고 몇 번의 클릭만으로 많은 다른 모바일플랫폼과
수백개의 다른 모바일디바이스에 맞는 애플리케이션을 빌드할수 있다.
오늘날의 모바일디바이스 마켓은 이전보다 더 많이 세분화되어 있다. 매년
새로운 플랫폼이 선보여지며, 매달 수많은 디바이스가 쏟아져 나오고 있다. 당신이 어플리케이션을 작성하는 것은 아주 쉬운 파트로 보여지기도 한다. 하지만
두통의 원인은 서로다른 플랫폼과 디바이스에 맞추는것과 변화하는 마켓에 뒤쳐지지 않게 하는 것이다.
One Solution For All Platforms |
우리는 모바일애플리케이션개발은 포팅문제에 대한 걱정을 제외하고도 충분히 어렵다고 생각한다. 그것이
우리가 MoSync를 만든 이유이기도 하다. 세분화된 모바일마켓을
위한 진정한 오픈소스솔루션을 지향하는 MoSync MoSync은 전체 개발Kit은
단순한 어플에서부터 아주 인텔리전트한 어플까지 개발할 수 있게 해준다. |
||
Develop for multiple mobile platforms simultaneously | |||
Build and package for hundreds of mobile devices | |||
Gain huge savings in porting and testing costs | |||
Faster time-to-market and a quicker return on investment | |||
And it's open-source! |
Fully-Featured SDK
- Eclipse-based IDE for C/C++ application development
- Runtime emulation and debugging
- Comprehensive mobile device database, with regular updates
- Application transfer by bluetooth/USB
- Mobile development tools and utilities
- Extensive documentation
- Active, dedicated worldwide development community
Comprehensive Libraries
- Selected standard C libraries
- Graphics, audio, multimedia
- TCP/HTTP/Bluetooth/SMS
- Collection classes
- XML parsing
- UI library and font framework
- Map rendering library
Extensive Mobile Platform Support
- Android Cupcake 1.5
- Java ME MIDP 2 (J2ME)
- Moblin 2.x
- Pocket PC 2003
- Smartphone 2003
- Symbian S60 2nd, 3rd, and 5th ed
- Windows Mobile 5.0-6.5
- Read more: Feature/Platform Support
Highly Active Development Community
MoSync는 모바일애플리케이션의 개발을 더 빠르고 더 쉽고 더 저렴하게 만드는데 참여하는 헌신적이고 열정넘치는 개발자들의 팀에 의해 개발되었다. – www.mosync.com을 확인해 보라
얼마나 자주 우리가 커밋하는지…
And It's Open Source!
MoSync는 GPL라이선스에 따른다. 이는 개인적으로 사용하는
것은 완전 무료이며 소스코드를 오픈하는 조건으로 상업적목적으로 사용도 가능하다. MoSync기반의 애플리케이션을
개발하고자 하는 개인, 비즈니스, 그리고 단체가 그들의 소스코드를
배포하지 않고자 한다면 우리는 상업적인 라이선스동의서의 범위를 제안한다.
번역 : B.K. Chung 정봉겸
감수 : Jang Han Goo 구장한
2000년 8월 9일
SEMA에 대해서 들어보신 적이 있습니까? 소프트웨어 팀이 얼마나 잘하는지를 재는 나름대로 복잡한 시스템입니다. 앗, 아니! 그 링크를 누르지 마세요. SEMA를 "이해"만 하는데 아마 6년정도가 걸릴것입니다. 그래서 소프트웨어 팀이 얼마나 좋은지 등급을 매길 수 있는 - 좀 무책임하고 되는대로의 - 자체적인 버젼의 테스트를 만들었습니다. 이 테스트의 장점은 3분정도밖에 걸리지 않는다는 것입니다. 절약되는 시간으로 의대에 가서 공부할 수도 있을 것입니다.
The Joel Test
|
Joel Test이 특별한 점은 각 직문에 예/아니오 로 바로 대답할 수 있다는 것이다. lines-of-code-per-day(하루동안 산출되는 코드의 줄수)나 average-bugs-per-inflection-point(산출 시점의 평균 버그수) 같은 것은 알 필요가 없습니다. "예"에 해당 하는 질문에 1점씬 가산됩니다. 하지만 이 테스트는 핵 원자로에 사용하는 소프트웨어가 안전한지를 검사하는등 에는 사용하지 말아주십시오.
12점은 완벽, 11은 충분한 점수이지만 10점이나 그 이하는 심각한 문제가 있다는 신호입니다. 사실은 대개의 소프트웨어 회사 들이 2~3점을 받고 있고, 심각한 도움을 필요로 하고 있습니다. Microsoft같은 회사는 12점 만점을 받고 있습니다.
당연한 이야기지만 이것들만으로 성공과 실패를 가를 수는 없습니다. 특히, 아무도 필요없는 제품을 굉장히 훌륭한 소프트웨어 팀이 만들고 있다면, 역시나 아무도 원하지 않을 것입니다. 반대로 이런 방식을 따르지 않는 명인들이 세상을 바꾸는 소프트웨어 를 만드는 경우로 생각할 수 있겠습니다. 그러나, 이 12가지 이외의 요소를 모두 동등하게 놓고 본다면, 이들만 제대로 한다면 지속적으로 좋은 결과를 내는 잘 훈련된 팀이 될 것입니다.
1. Source Control(소스 컨트롤)을 사용하십니까?
상용 소스 컨트롤 패키지들도 사용해보았고, 무료로 사용할 수 있는 CVS도 사용해보았습니다. CVS는 무료이기는 하지만 충분합니다. 그렇지만 소스 컨트롤이 없다면 프로그래머들을 조율하는 일이 상당히 피곤할 것입니다. 프로그래머들은 다른 사람들이 어떤 것을 했는지 알 수 있는 방법이 없습니다. 이를 사용하면 실수를 쉽게 롤백할 수 있습니다. 소스 컨트롤의 다른 장점은 소스코드 자체가 모든 프로그래머의 하드디스크에 체크아웃(check out)되어 있다는 것입니다. 소스 컨트롤을 사용하는 프로젝트에서 코드를 날렸다는 이야기를 들어본 적이 없습니다.
2. 한번에 빌드를 만들어낼 수 있습니까?
"최신의 소스로부터 몇단계를 거쳐서 완제품(shipping build)을 만들 수 있습니까?"라는 의미의 질문입니다. 잘 되어있는 팀인 경우라면 하나의 스크립트로 checkout부터 시작하여 각 소스를 리빌드(rebuild)하고 각 버젼, 언어, #ifdef같은 조건별로 실행파일을 만들어내어 마지막 CDROM 레이아웃, 다운로드할 수 있는 웹사이트를 만들어 내는 정도까지 되어 있을 수 있겠습니다.
만일 이 과정이 하나의 단계 이상을 거친다면, 여기서부터 에러가 발생할 확률이 생깁니다. 정해진 기일이 가까워질수록 "마지막" 버그를 수정하고 실행파일을 만드는 등을 위해 빠른 사이클을 필요로 할 것입니다. 코드를 컴파일하고 설치파일을 구성하는데에 20단계가 필요하다면 급박한 시간때문에 사소한 실수를 저지르게 될 것입니다.
필자가 마지막으로 근무했던 회사에서는 이런 이유로 WISE를 InstallShield(역자주 : 두 제품 모두 설치본을 만들기위한 도구 입니다.)로 교체하였습니다. 설치 과정을 스크립트를 통해서 NT 스케줄러로 밤새에 자동으로 실행하도록 하고자 하였는데, WISE는 스케줄러로 실행할 수 없던 이유입니다. (WISE의 친절한 분들이 최신 버젼에는 이것이 가능하다고 알려왔습니다.)
3. daily build(일별 빌드)를 만드십니까?
소스 컨트롤을 사용하다 보면 누군가가 빌드를 실패하게 만드는 코드를 체크인 할 수 있습니다. 예를 들면, 새로운 소스파일을 추가해서 그 사람의 컴퓨터에서는 잘 컴파일되지만, 이를 코드 레파지토리(repository)에는 추가를 하지 않았을 수 있습니다. 이 사람은 이를 잊고 만족한 상태에서 컴퓨터를 잠그고 집에 돌아갑니다. 그렇지만 이로 인해 다른사람들은 작업을 할 수 없게 되고 결국 찝찝하지만 결과없이 집으로 돌아갈 수 밖에 없습니다.
모르는 사이에 빌드를 실패하는 이런 컴파일 오류가 나지 않도록 daily build를 만들게 됩니다. 큰 팀에서는 이런 경우를 위해서 daily build를 매일 오후 - 점심시간등 - 에 합니다. 사람들은 점심시간 이전에 될 수 있는 한 많이 체크인을 합니다. 점심을 먹으로 갔다가 다시 돌아오면 빌드는 이루어져 있습니다. 빌드가 실패하면, 사람들은 빌드가 성공한 이전 소스로 작업을 하면 됩니다.
엑셀팀에서는 누군가 빌드를 깨면 벌칙으로 다른 사람이 다시 깰때까지 빌드를 관리하도록 벌칙을 주었습니다. 이는 빌드를 깨면 받는 벌칙으로써 뿐만 아니라 모든 이들이 돌아가면서 빌드를 관리할 수 있게하여, 어떻게 돌아가는 지를 익히게 하는 방법으로써도 좋았습니다.
daily build에 관해 더 자세히 아시려면 저의 기사 daily builds are your friend를 읽으십시오.
4. 버그 데이타베이스를 가지고 있습니까?
뭐라고 반박하셔도 확신합니다. 코드를 짜고 있다면 설령 혼자 짜더라도 정리된 버그 명세 데이타베이스를 가지고 있지 않다면 낮은 질의 코드로 제품을 출시할 것입니다. 많은 프로그래머들이 머리로 버그들을 모두 기억할 것이라고 생각합니다. 말도 안되는 이야기입니다. 제 경우에는 한번에 2~3개의 버그밖에 기억을 못하고, 다음날이 되거나 출시를 위해 급해지면 전부 잊어버리게 됩니다. 버그를 제대로 트래킹해야합니다.
버그 데이타베이스는 복잡할 수도 있고, 간단할 수도 있습니다. 최소한으로 갖추어야할 요소는 다음과 같습니다:
- 버그를 완벽하게 재현할 수 있는 과정
- 버그가 없었다면 이루어졌어야할 결과(동작)
- 버그로 인하여 생긴 결과(동작)
- 누가 이 버그에 할당되어 있는지
- 고쳐진 버그인지 아닌지
버그 트래킹에 관해 더 읽으려면, Painless Bug Tracking을 읽으세요.
5. 새로운 코드를 작성하기 전에 버그들을 잡습니까?
마이크로소프트 Windows용 Word의 첫 버젼은 죽음의 프로젝트였습니다. 끝이 없었습니다. 계속해서 스케줄을 펑크냈습니다. 팀 전체는 말도 안되는 시간동안 일했고, 계속해서 연기되고 또 연기되었습니다. 그 스트레스는 엄청났습니다. 빌어먹을 제품이 몇년 후에 출시되었을때, 마이크로소프트는 팀 전원을 Cancun으로 휴가보내고, 이 원인을 분석하기 시작했습니다.
그들이 깨닫게 된 것은 프로젝트 매니저들이 스케줄을 너무 강요하였기 때문에 프로그래머들은 코딩을 빨리 할 수 밖에 없었습니다. 게다가 버그를 고치는 단계는 스케줄에 아예 존재하지 않았습니다. 결과적으로 질이 아주 나쁜 코드를 만들게 되었습니다. 버그 갯수를 줄이려는 노력은 전혀 하지 않았습니다. 한 프로그래머는 텍스트의 높이를 계산하는 루틴 대신에 "return 12;"로 대체하여 버그 리포트로부터 이 값이 어떤 영향을 주었는지를 알고자 했습니다. 스케줄은 단지 버그일 수 밖에 없는 기능들을 모아 놓은 체크리스트였습니다. 나중에 이 상황을 "무한 결함 방식(infinite defects methodology)"이라고 이름지었습니다.
문제를 해결하기 위해서 마이크로소프트는 반대의 "무결함 방식(zero defects methodology)"라는 방식을 체택했습니다. 많은 프로그래머들은 경영진들의 명령에 의해서 버그 갯수를 줄일 수 있다고 생각했음직한 이 방식의 이름 탓에 이를 비웃었습니다. 하지만 실제로는 "무결함(zero defects)"이라는 이름은 주어진 시간에 가장 우선순위가 높은 것은 코딩하기전에 버그를 잡는 것이란 사실을 지칭하는 말이었습니다. 이유는 다음과 같습니다.
일반적으로 버그를 고치지 않고 방치하는 시간이 길어지면 길어질수록 고치는데 더 많은 시간과 금전이 요구된다는 것입니다.
예를 들면, 오타나 문법오류등은 컴파일러가 쉽게 잡아서 고치는데도 별로 문제가 되지 않습니다.
만일 버그가 처음 실행시에 발생하여 보이게 되면, 모든 코드가 머릿속게 생생하게 존재하기에 바로 고칠 수 있을 것입니다.
며칠전에 작성한 코드에서 버그를 찾게 되면 이를 고치기 위해 조금 시간이 더 걸릴 것입니다. 아마도 코드를 다시 보게 되면 대부분의 내용이 기억나고 적정한 시간내에 버그를 고칠 수 있을 것입니다.
하지만 몇달전에 작성한 코드에서 버그가 발견된다면 이미 그 코드에 관해서 많은 것이 이미 생각나지 않을 것이고, 고치기도 상대적으로 힘들 것입니다. 그때쯤 되면 다른 사람의 코드를 수정하고 있는 와중일지도 모르고, 그사람은 Aruba로 휴가를 떠나있을지도 모릅니다. 이렇게 된다면 버그를 고치는 것은 기술을 익히는 것같이 되어버릴 것입니다. 천천히 꼼꼼하게 그리고 주의 깊게 코드를 살펴봐야 하고, 물론 문제를 해결하는데에 얼마나 걸릴지 정확하게 판단하기 힘든 상황이 될 것입니다.
게다가 이미 출하된 코드에서 버그를 발견한다면, 이를 고치는데에 큰 대가를 치뤄야할지도 모를 것입니다.
이렇게 시간이 적게 들기 때문이라는 이유가 하나의 이유가 됩니다. 또다른 이유는 버그를 수정하는데 걸리는 시간을 예상하는 것보다는 새로운 코드를 작성하는데 걸리는 시간을 예상하기가 훨씬 쉽기 때문입니다. 예를 들면, 내가 당신에게 리스트를 소트하는 코드를 만드는데 얼마나 걸리냐고 물어본다면, 꽤 정확한 대답을 할 수 있을 것입니다. 그렇지만, 질문을 바꿔서 당신의 코드가 Internet Explorer 5.5만 설치되어있으면 동작하지 않는 버그를 고치는데 걸리는 시간을 묻는다면, 문제가 무엇인지도 모르는 상황이기 때문에 얼마나 걸릴지 추측하지도 못할 것입니다. 3일이 걸릴 수도 있을 것이고, 운좋으면 2분이 걸릴 수도 있을 것입니다.
이것이 의미하는 바는 고쳐야할 버그가 많이 존재하는 상태의 스케줄이라면 그 스케줄은 정확할 수가 없다는 것입니다. 그렇지만 이미 알고있는 버그들은 모두 고친 상태라면 그 스케줄은 상대적으로 상당히 정확하게 지킬 수 있는 스케줄일 것입니다.
버그 갯수를 0에 가깝게 하는 또하나의 좋은 점은 경쟁에서 훨씬 빠르게 대응할 수 있다는 것입니다. 어떤 프로그래머들은 이를 두고 제품을 바로 출하할 수 있는 항상 유지하는 것이라고 이야기합니다. 경쟁자가 고객들을 가로채갈만한 굉장히 좋은 기능을 새로 만들었다면 축척된 많은 버그를 수정할 필요없이 바로 이 기능을 추가할 수 있을 것입니다.
6. up-to-date(최신) 스케줄을 가지고 있습니까?
비즈니스에 당신의 코드가 조금이라도 중요한 부분이라면, 코드가 언제쯤 완성될 수 있는지를 아는 것 또한 중요하다는 것은 당연할 것입니다. 프로그래머들은 엉터리 스케줄을 만드는데 악명이 높습니다. "언젠가는 될꺼야!"하고 외칩니다.
불행하게도 그런 식으로는 해결할 수 있는것은 없습니다. 비즈니스에는 코드를 출하하기 전에 데모, 전시회, 광고등등 미리 많은 것들을 판단하여 결정해야합니다. 이를 할 수 있는 단 한가지 방법은 스케줄을 가지고 이를 계속해서 현실적으로 최신내용으로 유지하는 것입니다.
스케줄을 가져야하는 또다른 중요한 이유는 이를 통해서 어떤 기능이 필요한지를 결정하게끔 만들어준다는 것입니다. 때문에 어떤 기능이 덜 중요한지 결정해야하고 featuris가 되기 전에 이들을 포기하도록 합니다.
스케줄을 관리하는 것이 어려울 필요는 없습니다. 제 글 Painless Software Schedules에 좋은 스케줄을 만드는 간단한 방법을 설명하였습니다.
7. spec(설계서)를 가지고 있습니까?
스펙을 만드는 것은 이빨을 쑤시는것과 같습니다: 모든 사람들이 좋다고 인정하지만, 아무도 하지 않습니다.
왜 그런 현상이 일어나는지는 정확히 모르겠습니다만, 아마도 프로그래머들이 문서를 만드는 것을 굉장히 싫어하는데에 기인하는 것 같습니다. 그 결과로, 프로그래머밖에 없는 집단에서 한가지 문제를 해결하고자 하면, 이들은 문서를 만들기 보다는 코드로 자신들의 의견을 표명하려 합니다. 스펙을 먼저 만들기보다는 차라리 코드를 짜서 보여주는 것을 택한다는 것입니다.
설계 단계에서 문제를 발견하면 몇줄을 고쳐서 이를 수정할 수 있습니다. 그렇지만 코드가 짜여진 상황이라면 이 문제를 수정하는 댓가는 감정적으로나(코드를 그냥 버리는 것을 좋아하는 사람은 없습니다) 시간적으로나 훨씬 높게 되고 더 힘든 작업이 되어버립니다. 스펙을 통해서 만들어지지 않은 소프트웨어는 대개 설계가 잘못되어 스케줄을 엉망으로 만들어놓습니다. Netscape에서도 이런 문제로 인해 브라우저의 초기 네개의 버젼이 너무 엉망이 되어 결국 관리자들이 멍청하게도 코드를 전부 버리고 다시 짜도록한 결정을 내려버리게 되는 상황이 벌어졌습니다. 거기다 한술 더 떠서 Mozilla에서 이런 실수를 다시 반복하여 겨우 Alpha 단계에 가는데 몇년이라는 시간이 걸리게 되었습니다.
필자의 지론은 이 문제는 프로그래머들이 문서를 작성하는데 거부감이 없도록 작문 강의를 듣도록 보내는 것으로 해결할 수 있다는 것입니다. 다른 해결책이라면 스펙같은 문서 작성에 능숙한 관리자를 두는 것입니다. 두 경우 모두 "스펙없는 코드는 금물"이라는 간단한 규칙을 따라야 할 것입니다.
저의 4부짜리 글에 스펙 작성하는 요령에 대해 이야기했습니다.
8. 프로그래머들이 조용한 작업환경을 가지고 있습니까?
지식 근로자에게 공간, 조용함, 프라이버시를 줌으로해서 많은 생산성 향상을 얻는다는 것은 이미 증명된 사실입니다. 소프트웨어 관리의 고전인 Peopleware에서는 이 생산성 향상에 대해 자세히 기술합니다.
문제는 여기에 있습니다. 지식 근로자는 "in the zone"상태라고도 하는 "flow"상태에 들어섬으로써 가장 최상의 상태가 되어 일에 완벽히 집중하고 외부에 개의치 않게 됩니다. 완벽한 집중으로 시간 가는 것을 잊고 좋은 결과를 내게 됩니다. 이때에 바로 대부분의 생산적인 일들을 처리하게 됩니다. 작가, 프로그래머, 과학자 그리고 심지어 농구선수들까지도 "in the zone"상태가 있음을 이야기할 것입니다.
문제는 "zone"으로 들어가는 것이 쉽지 않다는 것입니다. 측정해보면, 최상의 생산성으로 일을 하기 위해서는 평균 15분이 걸립니다. 하지만 어떤 경우에는 피곤하고 이미 많은 일을 한 상태에서 "zone"상태에 들어가지 못하고 다른 일을 하거나 웹서핑이나 테트리스로 시간을 허비하게 될 수도 있습니다.
또다른 문제는 "zone"상태에서 빠져나가는 것이 매우 쉽다는 것입니다. 잡음, 전화소리, 점심식사, 잠시 스타벅스에 5분간 갔다오는 것 그리고 특히 동료에 의한 방해등에 의해 바로 "zone"에서 빠져나가게 됩니다. 동료가 1분이라는 짧은 시간 동안이라도 질문을 하여 "zone"상태에서 빠져나간다면 다시 되돌아가기 위해서 30분이 넘는 시간이 걸려 전체 효율에 치명적인 영향을 미칠 수 있습니다. 카페인 가득한 닷컴 회사들이 좋아하는 합숙소같은 곳에 옆의 마케팅 부서에서 계속해서 오는 전화에 대고 소리지르는 그런 시끄러운 환경이라면 계속된 방해로 지식 근로자들의 생산성은 추락하여 "zone"상태에 절대 이르지 못할 수도 있습니다.
프로그래머들에게 있어서 특히 어렵습니다. 생산성은 단기적인 기억력으로 한번에 얼마나 많은 작은 세부사항들을 다루느냐에 달려있습니다. 어떠한 방해도 이런 세부사항들을 잊어버리게 할 수 있습니다. 일을 다시 재개하면 그것들을 다시 기억하지 못하여 (사용하던 지역변수나 검색 알고리즘을 만들던 중에 어디에서 멈줬었는지등) 다시 찾아보게 되고, 이로 인해 다시 속도가 붙을때까지 느려지게 됩니다.
직관적으로 계산해보면 다음과 같습니다. 만일 프로그래머가 단 1분이라도 방해를 받아서(명백한 근거에 의해) 15분의 생산성을 날려버린다고 합시다. 철수와 영희 두 프로그래머가 낮은 칸막이로 주욱 늘어선(a standard Dilbert veal-fattening farm) 열린 사각 파티션 옆자리에 앉아 있다고 합시다. 영희가 strcpy함수의 유니코드 버젼 이름을 잊었습니다. 30초면 찾아볼 수 있겠지만, 철수한테 물어보면 15초가 걸립니다. 그래서 바로 옆에 앉아 있는 철수에게 묻습니다. 철수는 산만해지고 - 영희의 15초를 아끼기 위해 - 15분을 낭비하게 됩니다.
이번에는 벽과 문으로 나뉘어진 별도의 사무실로 가정을 합시다. 여전히 영희는 함수를 기억하지 못합니다. 다시 찾아보는 것으로 30초를 보낼 수 있을 것이고 옆 방에 있는 철수에게 물어보기 위해서 (일반적인 프로그래머의 평균 물리적인 건강상태를 봐서는 쉽지 않은) 일어나서 걷는 것을 포함한 45초를 보낼 수 있을 것입니다. 결국 찾아보는 것을 선택하여 30초를 보내게 되지만 철수의 15분을 벌어주게 됩니다. 대단하죠!
9. 돈이 허락하는 한도내의 최고의 툴들을 사용하고 있습니까?
컴파일 되는 언어로 코드를 작성하는 것은 여전히 아무 PC에서 할 수 없는 것 중의 하나입니다. 컴파일을 하는데 몇초 이상 걸린다면 최상의 기종을 사용함으로써 시간을 절약할 수 있을 것입니다. 15초 이상 걸린다면 지루해서 그 시간동안The Onion을 읽게 될 것이고 너무 재미있는 관계로 거기에 빠져 수시간의 생산성을 날려버릴 것입니다.
모니터 하나로 GUI코드를 디버깅한 것은 불가능하지는 않지만 고통스러운 작업입니다. GUI코드를 작성하고 있다면, 2대의 모니터로 훨씬 쉬운 작업을 할 수 있을 것입니다.
대개의 프로그래머들은 아이콘이나 툴바를 위해 비트맵을 수정해야하고 대부분의 프로그래머 역시 좋은 비트맵 에디터를 가지고 있지 않습니다. 마이크로소프트에서 기본적으로 제공하는 Paint 프로그램으로 비트맵을 수정하는 것은 웃긴 일이지만 대부분 이렇게 하고 있습니다.
필자의 가장 최근 직장에서 시스템 관리자가 계속해서 자동적으로 스팸을 보냈습니다. 이유인 즉슨 220MB이상의 하드드라이브를 사용하고 있다는 것이었습니다. 필자는 요즘 HD가격을 본다면 이 공간의 환산된 가격은 내가 이용하는 화장실 휴지보다 싸다는 것을 지적했습니다. 디렉토리를 정리하기 위해 10분을 허비하는 정도로도 큰 생산성 저하일 것입니다.
"최고의 개발팀은 절대 그들의 프로그래머들을 고문하지 않습니다!" 후진 제품으로 인한 작은 불편함이 쌓여서 프로그래머들이 불만에 찰 수도 있습니다. 그리고 그로 인한 불만에 찬 프로그래머는 비생산적인 프로그래머이기 쉬울 것입니다.
이런 것들을 모두 종합하면 프로그래머들은 최고/최신의 것들로 쉽게 매수된다는 뜻이 됩니다. 이는 높은 연봉을 주는 것보다는 훨씬 싼 방법일 것입니다!
10. 테스터들을 고용하고 있습니까?
팀이 최소한 2~3명의 프로그래머에게 테스팅만 전담하는 테스터가 할당되어 있지 않다면, 버그가 많은 제품을 출하하고 있거나 시간당 $100짜리 프로그래머에게 시간당 $30의 일을 시키는 낭비를 하고 있는 것입니다. 테스터를 고용하는 것이 낭비로 생각하는 것은 정말 잘못된 계산을 하고 있는 것이며, 많은 사람들이 이를 깨닫지 못하고 있는데에 놀랍니다.
이에 관해 더 자세히 알고자 한다면 Top Five (Wrong) Reasons You Don't Have Testers를 읽으십시오.
11. 신입사원들은 면접때 코드를 직접 짜는 실기시험을 봅니까?
마법사를 고용하는데 그의 마법을 보지 않고 고용하시겠습니까? 당연히 그렇지 않겠죠.
결혼식에 요리사를 고용하는데 요리사가 만든 요리의 맛도 모르고 고용하시겠습니까? 그렇지 않을것입니다.(역자주: 실제로 결혼식장 요리사의 맛을 보는 비유는 우리나라에 맞지 않을 것 같네요. 이 문구의 뜻만 이해하세요)
하지만 현실에서는 매일 인상적인 이력서나 면접에서 맘에 든 이유로 고용하는 일들이 일어납니다. 혹은 ("CreateDialog()와 DialogBox()의 차이점은 무엇입니까")등의 문서만 보면 알 수 있는 사소한 질문으로 채용하기도 합니다. 프로그래머를 채용하는데 있어서 중요한 것은 그런 사소한 것들을 얼마나 많이 외웠느냐가 아니고 코드를 잘 작성할 수 있느냐입니다. 혹은 "아하!"류의 질문으로 채용하기도 합니다. "아하!"류의 질문이란 답을 알면 간단하지만 모르는 경우에는 절대 맞출 수 없는 질문을 이야기합니다.
제발 이런 방식을 그만 두십시오. 면접때 무얼해도 상관없지만 반드시 코드를 작성하도록 해야합니다.(더 많은 것을 알고 싶다면 Guerrilla Guide to Interviewing를 읽으십시오)
12. hallway usability testing(무작위 사용성 테스팅)을 하십니까?
무작위 사용성 테스트(hallway usability test)는 복도를 지나가는 다음 사람을 붙잡고 방금 짠 코드를 사용하게 하는 방식입니다. 5명에게 이 테스트를 한다면 95%의 사용성 문제에 대해 배울 수 있을 것입니다.
좋은 사용자 인터페이스 설계는 생각처럼 어려운 것이 아니고 사용자들이 당신의 제품을 구입하고 사용하게 하는데 있어서 절대적으로 중요합니다. 짧은 프로그래머 입문서로 UI 설계에 관해 필자가 쓴 무료 온라인 책을 읽어보실 수 있습니다.
하지만 사용자 인터페이스에서 제일 중요한 것은 많은 사람들에게 당신의 프로그램을 보여주면(5~6명이면 충분합니다) 제일 큰 문제점을 빠른 시간에 발견할 수 있다는 것입니다. Jakob Nielsen의 글에서 그 이유에 대한 설명을 찾을 수 있습니다. UI 설계 경험이 별로 없다고 하더라도 - 비용이 전혀 들지 않는 - 무작위 사용성 테스트를 한다면 당신의 UI는 훨씬 좋아질 것입니다.
Joel Test를 사용하는 4가지 방식
- 자신이 속한 소프트웨어 팀의 점수를 매기고 그것에 대해 언급할 수 있도록 결과에 대한 이유를 필자에게 알려주십시오.
- 프로그래머 팀의 관리자라면, 당신의 팀이 최대한 잘 운영될 수 있는지 확인할 수 있는 지표로 사용하십시오. 12점을 받기 시작하면 프로그래머들을 간섭없이 그냥 두고 비즈니스쪽 사람들이 그들을 간섭하지 못하게 하는데에 모든 시간을 할 수 있습니다.
- 프로그래머 일을 맡을지를 결정해야하는 상황이라면 그 팀의 친한 사람에게 이 테스트 결과가 어떤지를 물어보십시오. 결과 점수가 너무 낮다면 이를 고칠 수 있는 권한을 받을 것인지를 확인하십시오. 그렇지 않으면 불만과 스트레스에 빠질 것입니다.
- 프로그래밍 팀을 평가하여야 하는 투자자이거나 당신의 회사가 다른 소프트웨어 회사와 합병을 한다면 이 평가가 급한대로 괜찮은 지표가 될 것입니다.
이 기사는 영어로 The Joel Test: 12 Steps to Better Code 라는 이름의 기사가 원본입니다
I have uploaded the zipped source files for this sample at:
http://code.google.com/p/apps-for-android/downloads/list
Sorry about the server related python source files not being visible
on developer.android.com. We will fix it soon.
This sample source will be available with the next sdk package, we are
working on making zipped samples downloadable from
developer.android.com itself in future.
Regarding password issue, please use account user1/test on
samplesyncadapter server.
I would recommend that to add new accounts, download the server code,
modify it as you want and host it on a separate app engine instance.
If you look at dashboard.py and app.yaml in server code it should be
pretty clear how to do this..giving a short overview below:
1) Add a new Sample SyncAdapter account @:
http://samplesyncadapter.appspot.com/add_user
For example I have added user1:
http://samplesyncadapter.appspot.com/edit_user?user=1
2) Enter username/password @
http://samplesyncadapter.appspot.com/add_credentials
The password for user1 is test.
3) Modify the android code to use your server instance.
Sorry for the confusion so far, please let me know if you have more
questions.
Thanks,
Megha
On Feb 18, 10:28 am, HCH <hayeshau...@gmail.com> wrote:
위와 같이 수행하여 계정을 추가한 후 추가한 계정의 Friends를 등록하면 Sync시 추가한 Friends가 Contacts에 동기되어 표시되는것을 확인할 수 있다. 이 때 Friends를 추가할 때 다른 계정의 Handle명을 입력해야 함을 주의해야 한다.
Google Begins Testing Android OS 2.2
Google has been spotted actively testing the next version of the Android OS, version 2.2. The upcoming OS, codenamed Froyo (frozen yogurt), has been showing up in web logs on various sites.
Google has not yet publicly announced a 2.2 release, nor has it detailed the future enhancements the update will deliver, however the release is anticipated to deliver major performance enhancements and at least some of the following:
- JIT compiler
- Free additional RAM
- OpenGL ES 2.0 enhancements
- Flash 10.1 support
- Activation of Color Trackball
- Enable FM radio
The Android OS 2.2 update is also expected to provide some of the support required for Flash 10.1. However, the full release of 10.1 on the 2.2 OS could also be a possibility.
Since Google has not supplied any information regarding the 2.2 update, rumors have pegged a tentative release date for May 19, 2010. That day is when Google begins its I/O conference, which in the past has announced major Android news.
소문만 무성하던 프로요가 테스트에 들어갔군요. 대채 언제 나올지는 모르지만 5월 19일에 있은 IO conference때 어떤식으로든 언급이 있지 않을까 싶습니다. FM radio가 프레임웤단에서 지원이 되고 Flash 10.1이 지원되는것이 인상적이네요. 성능이 최대 30퍼센트정도 개선되었다고 하더니 JIT compiler가 들어갔네요.
효율적인 모바일앱의 작성은 항상 쉽지 않다. 특히, 안드로이드처럼 Dalvik의 garbage collector에 의해 자동으로 메모리가 관리되는 경우 충분히 주의하지 않으면 성능이슈가 발생할 수밖에 없다.
성능에 민감한 코드들(layout생성, view시스템의 그리기, 게임의 로직부분)은 필연적으로 비용을 초래한다. 너무 많은 메모리 할당후에는 당신의 앱은 메모리를 해재하도록 잠시 멈출수 있다. 대부분의 경우 사용자가 느끼지 못할정도로 gc는 이루어지는 반면에 리스트를 scroll하거나 게임에서 적을 물리치거나 하는 경우 심각한 성능과 응답성의 저하를 느낄수 있다. 100~200ms정도 gc시간이 걸리는 것은 일반적인 상황은 아니다. 부드러운 애니매이션의 경우 각 프레임이 16~33ms정도의 속도가 필요하다. 초당 10프레임정도로만 떨어져도 사용자는 문제를 느끼게 된다.
대개의 경우 gc는 tons of small, short-lived object, 일부 garbage collector때문에 발생한다. 그리고 그런 object의 collection을 최적화할 수 있으며 그렇게 해서 애플리케이션의 좀더 덜 방해받게 할 수 있다. 안드로이드의 garbage collector는 불행히도 이러한 성능최적화등을 할 수 없다.
DDMS가 실행되면 해당 애플리케이션 프로세스를 선택하고 Allocation Tracker탭을 클릭하라. 새로운 뷰에서 Start Tracking을 클릭하면 분석하고자 하는 애플리케이션을 선택한다. 준비가 되었다면 Get Allocations를 선택하가. 할당된 object들이 첫번째 테이블에 리스트될것이다. 보여지는 한 line을 선택하면 두번째 테이블에 애플리케이션에 할당된 stack이 보여진다. 어떤 타입의 object들이 할당되었는지는 물론이고 포함된 스래드, 클래스, 파일의 라인까지 표시된다. 아래 스크린샷은 Shelves앱의 listView를 스크롤하는 동안의 할당상태를 보여준다.
성능에 영향을 주는 부분을 모두 제거할 필요가 없다고 하더라도 코드에서 중요한 이슈를 확인하는데 도움이 될것이다. 예를 들면 내가 보아온 많은 애플리케이션에서 draw시마다 매번 Paint 객체를 새로 생성한다. 이 Paint객체를 하나의 인스탄스로 관리하는 것 만으로 성능이슈를 간단히 개선할 수 있다. 나는 Android source code를 살펴볼것을 강력하게 권고한다. 이유는 성능을 끌어올리기 위해 어떤 기술을 사용하였는지 볼수 있기 때문이다. 그리고 객체의 재사용에 대한 안드로이드가 제공하는 API들을 발견하게 될것이다.