반응형





좋은 언어와 좋은 프래임워크란 ?

언어와 framework의 발전사가 이렇다고 하고, 그러면 제목에서 적은 좋은 언어와 좋은 프래임워크란 무엇일까요?


가장 기본적인 기준이 되는 것이 2가지 일것 입니다.

첫번째로 프래임워크에서 제공하는 사용성과 정책이 프로그래밍 언어에서 제공하는 것과 일관되어야 합니다.

두번째는 일반적일 것 같은 동작은 그렇게 동작하도록 해야 합니다.


위에서 예기한 것들을 좀 살펴봅시다.

우선 첫 번째 "프래임워크와 언어의 일관성"에 대한  예를 들면, 

프로그래밍 언어에서  var A =  a; 라는 코드가 A에 a를 copy하는 것이라고 정의하고 있다면,  이 언어로 작성된 프래임워크의 MyObject obj = OldObj; 의 코드 역시 obj 에 OldObj의 내용들을 copy하는 것이어야 합니다. 그런데 만약 여기서, obj에 copy 하는 것이 아니라 OldObj의 내용을 가리키도록 동작하도록 작성되었다고 한다면,

obj의 내용을 변경했을때 왜 OldObj의 내용이 바뀌는지등에 대한 의문을 만들게 됩니다.

또는 실제 obj가 쓰일때 copy를 한다거나, obj.sync() 를 불렀을때 실제 복사가 일어난다거나 한다면, 사용자 입장에서 '=' 가 불렸을때 copy가 될 것을 기대하고 퍼포먼스를 높이기 위해 튜닝을 했는데, 실제로는 다른 timing에서 data가 copy 되기 때문에 제대로 된 튜닝을 못하게 되는 상황이 발생합니다.

이는 사용자에게  framework에서 제공하는 "=" 동작에 대해 혼란을 주는 결과가 됩니다.

이는 실수를 유발하거나 직관성을 떨어뜨리게 됩니다.


두번째 "일반적일것 같은 동작" 대한 예를 들어보자면,

ImageViewer class 가 있고, ImageViewer에는 Draw()라는 함수가 있습니다. 이 Draw() 라는 함수는 ImageViewer의 image를 화면에 그려주는 기능을 하는 함수입니다.

Draw()기능을 좀더 세밀하게 정의 해보자면, 

1. Draw()는 ImageViewer가 들고있는 display용 context에 image를 drawing하는 함수라고 합시다.

2. Draw()가 불렸을때 화면에 보이지는 않고 framework의 rendering 시점에 이 display context의 내용이 화면에 출력되는 방식입니다.

그런데 이 class 개발자가 Draw()가 불렸을때 image를 직접 display context에 drawing하는 것보다, rendering 시점에 display context에 drawing 하도록 하는것이 성능상 이득이라고 판단하여, Draw()함수가 나중에 drawing이 필요하다는 flag만 설정하고 나오는 것으로 정의했습니다.

Draw() 함수에 대한 정의가 좋은 방향으로 결정 된것 일까요? 옳다 그르다의 표현은 좋지 못하고, API의 직관성을 흐리는 방향으로 간것 같다는 표현이 맞죠.


만약 위와 같은 경우에 사용자는 ImagViewer의 Draw()호출한 다음에 Display context에서 draw된 image를 꺼내와서, 그위에 text를 더 그리려는 작업을 하려 했다면, 전혀 엉뚱한 결과를 얻게 될것입니다.

여기에서 과연 Draw()라는 함수이름에서 보여주는 직관적인 동작은 무엇인가요? 바로 drawing입니다.

즉, 만약 ImageViewer의 성능을 높이기 위해서 flag 설정을 하여 Lazy update을 구현 할 생각이었다면, 다른 이름을 사용하는게 옳습니다.

많은 방법이 있죠. requestDraw나, Invalidate(windows에서 많이 사용하는 용어죠), SetRenderingTimeDrawEnabled() 등 API이름에서 해당 목적이 명확하게 나오도록 하는 것이 더 낳았을것 입니다.


framework은 직관성을 유지 하면서, 일반적인으로 예상할 수 있는 동작을 기본 동작으로 하고, 다양한 옵션을 제공하는 방향으로 되어야 한다고 생각합니다.


다음과 같은 항목들이 대표적인 사항들일 것입니다.

- Sync call와 Async call의 구분 

- lazy update와 immediate update 

- resource 소유권에 대한 규칙 


이와 같은 부분들이 아마도 platform에서 일관되게 동작하도록 정의하고 정리하기 어려운 부분일 것입니다.


특히 Resource 라고 표현한 객체의 lifecycle 관리 즉, 객체를 생성한 주체와 삭제하는 주체에 대한 것은 아주 자주 접하는 케이스이기 때문에, 명확히 하고 일반적으로 방법(개발자들이 흔히 예상할 수 있는 )으로 제공하는 것이 맞습니다.



아주 특별하고 획기적인 기능이라 하더라도, 그게 일반적인 상식이나 생각에서 벗어난다면, 좋지 못하겠죠.


몇가지 예를 들어보겠습니다.


DDD::CreateObj()

{

   ABC* obj = new ABC;

   Dock.Set(obj);

}


라는 아주 간단한 code가 있다고 합시다. 이 경우 obj는 누가 관리하는 것이 맞을까요?

1. DDD class에서 해야한다.

2. Dock에서 하는 것이 맞다.

3. 가비지 collector에 맡긴다.



또 다른 예를 들어보자면, array와 list가 있다고 합시다.

C++로  SoCool이라는 프래임워크 를 개발하고 있는 탐 이라는 사람이 있다고 합시다.

탐은 Array 와 List 를 만들때, "왜 다른 언어들은 index를 0 부터 시작하지? 그래서 개수가 10개 이면 0~9까지 카운트 되게 했지? 이건 일반인들은 상상도 할 수 없는 일이야" 라고 생각했습니다.


이 생각을 바탕으로 하나씩 짚어봅시다.


Array의 index는 프로그래밍 세계에서는  일반적으로 0부터 시작하는 반 열린 집합 형태로 표기 됩니다.

즉 개수가 10개인 array는 0<= index<10 으로 표현하는 것이 일반적인 표현 방식이죠. 이유는 memory와 관련 있는데, array 의 변수명은 그 변수가  잡고있는 memory의 시작 위치를 표시합니다. 따라서 Array[0]의 표시는 address + 0의 위치 시작 위치로 표시되는 것이죠.

이를 실생활에서 처럼 첫번째 item이니까 Array[1] 로 표현 한다면, address + 1 -1 과 보정을 하거나 아니면, 메모리상 address +1  위치 부터 data를 사용하도록 해야 합니다. 

이 두가지 모두 Computer 구조랑 잘 맞지 않는 표현 방법이 되죠.

(생각하기 나름이긴 하지만 시스템 이나 메모리구조 등을 이해하고 있는 많은 프로그래머들의 일반적인 생각은 이렇다는 것입니다.)


이러한 이유에 의해서 인지는 모르지만, 결과적으로 보면, 아래와 같은 의미가 되었습니다.

개념 상 뭐 어떻게 생각하느냐에 따라 다를 수 있습니다. 하지만 수학의 집합 형태로 생각 해봅시다.

우선 수학에서 어떤 집합을 표현 할때 열린 집합, 닫힌 집합, 반 열린 집합 등의 명칭으로 분류를 하기도 합니다.

무슨 의미냐 하면, 1 부터 9까지의 숫자들의 모음(1과 9을 포함하는)을 위에서 예기한 집합으로 표현하자면 다음과 같습니다.

1. [열린집합] 0<집합<10   즉, 경계인 0을 포함하지 않고, 10을 포함하지 않는 집합.

2. [닫힌집합] 1<=집합<=9  즉, 경계인 1을 포함하고 , 9는 포함하는 집합.

3. [반 열린 집합] 1<=집합<10  즉, 경계인 1을 포함하고 , 10을 포함하지 않는 집합.

4. [반 열린 집합] 0<집합<=9   즉, 경계인 0을 포함하지 않고 , 9는 포함하는 집합.


Computer programming 에서는 memory addressing 방식 때문에 자연스럽게 3번 형태를 띄게 되었습니다.

Computer에서는 시작을 1부터가 아닌 0부터 시작하고 있기 때문에, 10개 라는 의미가 0~9까지를 의미하는 것이 되었기 때문이죠.


탐은 array에 대해서는 이해를 했고, 리스트는 고치고 싶었습니다. "그래 . array는 메모리 상에 존재하는 특정 블럭을 표현 한것이니가 그렇다 치고, 그럼 list는 논리적으로 head 와 tail을 따로 구성할 수 있고, 가변적인 데이타 구조이니까, 앞으로 우리는 list에서는 index가 1부터 시작하도록 할거야."

라고 생각하고 list의 index를 1부터 시작하는 것으로 제공하기로 하였습니다.


만약 list 의 index를 1부터 시작하겠다고 하는 것은, "2번 닫힌 집합으로 표현 해라." 라는 의미가 되는 것입니다. 즉, 10개가 있다는 의미가 1~10까지 닫힌 집합으로 표현해야 한다가 되는것이고,  code로는   1<= index <=10 이라는 의미가 되는 것이죠.

array에서는 0<=index<10 이고, list에서는 1<=index<=10 이라고 표현 하면, 결국 data의 집합을 표현 하는 자료 구조인데 한 언어나 프래임워크 내에서 서로 다른 규격을 제시 하는 것이 됩니다. 


이런 비슷한 기능을 제공하는 class들이 각각 다른 기준의 동작을 유도하는 것은, 어플리케이션 개발에 수많은 혼선을 줄 가능성이 있습니다.

단순히 list와 array의 차이가 아니라, 어떤 API들도 직관적으로 접근 할 수가 없고, 숨은 의도들을 파악해야 하는 상황이 발생하죠. 

위의 경우, 어플리케이션 개발자는  "아 array는 memory 블럭을 잡는 것이니까 index는 0 부터 사용해야 하고, list는 동적이기 때문에 메모리 블럭과 관련이 없어 그러니까 프로그래머가 아닌 일반적인 사람 입장에서 생각해서  index가  1부터 인거야, 이건 꼭 외워야 해. 나중에 index array와 list간의 index변환도 고려 해야 하니까. 이런게 또 뭐가 있을까? Stack ? Stack은 어떻게 동작하지?" 라는 생각을 하게 할겁니다.



전반적인 S/W 도메인 별로 보면 여러 주제들 예를 들면 Synchronous와 Asynchronous, mutable, thread, lock, ipc, data binding, runtime, reflection 등등, 이러한 요소들을 프레임워크와 언어에 대해서 일관성, 과 일반적이고 상식적인 기본 동작과 컨셉을 가져가야 할 것인지를 잘 정리하고 제공되어야 좋은 플랫폼 또는 프래임워크 라고 할 수 있을 것입니다.


이런 이유에서 규모가 큰 S/W 회사들은 , 프래임워크 구축하려 할때, 기존의 언어로 새로운 패러다임을 반영하기 힘들거나 , 프래임워크에서 제공하려는 기능이 기존의 언어로 표현이 힘들 경우, 새로운 언어들을 만들기도 하는 것입니다. (C#, Java가 대표적이랄까요?)



'개발 Note > UI Framework 개발하기' 카테고리의 다른 글

Core Image Concepts  (0) 2011.09.20
stdafx.h 를 없애보자!  (0) 2011.08.18
CoreAnimation in iOS  (0) 2011.07.13
key - value 관리  (0) 2011.06.08
[애자일] 릴리즈 계획 과정에서 가장 중요한 것들  (0) 2010.10.29
반응형

 

Core Image Concepts


 


 

1. crop image 
2. color 수정 - white color 정정 같은 것들 수행.
3. color effect 적용  - sepia tone ,gray scale등등
4. 이미지에 Blur 나 샤픈(sharpen) 적용 
5. 이미지 합성
6. 이미지에 기하학적인 변형이나 휨 적용
7. color , 채크보더 패턴, 가우스 변환, 기타 패턴 이미지 생성.
8. 이미지나 비디오에 변환 효과 추가.
9. 비디오에 실시간 컬러 조정 제공.

Graphic system에 대한 컨셉적인 이해와 구축의 방향을 잡기에 좋은 그림이 아래의 그림입니다.
Graphics 나 Image , Video등 display와 관련 된 모든 부분은 결국 OpenGL을 이용하도록 설계되어있고, 전반적인 processing의 로드를 GPU와 분담되게 됩니다.

Figure 1-1
 gives a general idea of where Core Image fits with other graphics technologies in Mac OS X. Core Image is integrated with these technologies, allowing you to use them together to achieve a wide range of results. For example, you can use Core Image to process images created in Quartz 2D (Core Graphics) and textures created in OpenGL. You can also apply Core Image filters to video played using Core Video.

Figure 1-1  Core Image in relation to other graphics technologies


Core Image and the GPU


OpenGL은 고성능 2D and 3D 그래픽을 위한 업계 표준으로 GPU 를 사용하기 위한 인터페이스 또는 게이트웨이 같은 모듈입니다.
GPU를 이용하여 image processing을 하려면 OpenGL Shading Language를 알아야만 합니다.  
          <결국 모든 primitive 가 OpenGL 을 사용하게 되면 image processing 역시 GPU의 로드로 넘길 수 있다는 의미로 해석되는 군요.>


현재 대부분의 시스템들은 2D primitive drawing은 CPU를 통한 buffer에 processing 하는 방식과 GPU를 사용하는 방식등 , 혼재되어있는 시스템들이 많다.
이렇게 단일 Graphic module을 사용하지 않아 ,Buffer에 그린 image를 GPU가속을 받기 위해 OpenGL texture로 변환한다거나, 또는 double buffering을 위해 따로 메모리를 잡고 하는 , 중복적인 기능들이 필요하게 되고, GPU 의 도움을 받지 않고 image filtering을 한다거나 변환을 행하는 경우는  CPU에 더더욱 큰 부하를 주게 됩니다.

그런 의미에서 iOS의 그래픽 시스템은 보고 배울만한 교과서 같은 시스템 처럼 느껴집니다.

 Graphics module 과 정책에 대해서는 Quartz를 좀 살펴 봐야 하는데, 이는 따로 정리할 필요하 있을것 같습니다.

 

Filter Clients and Filter Creators


Core Image 는 필터 사용자와 필터 제작자 이렇게 두가지 형태의 개발자를 위해 설계되었습니다.( 모두를 위해서라고 표현해야 하나?)

filter category 는 이펙트 타입 즉, blur, distortion, generator 등등 과 정지 이미지, 비디오 사각형이 아닌 픽셀 을 위한 것들이 명시됩니다.




아래의 대표적인 필터의 컴포넌트를 자세히 들여다 본것입니다.

outputImage 메소드는  이미지를 만들어는 것이 가능하도록 계산 결과들을 모으고 저장한다. 그러나 실제로 Core Image를 이미지 프로세싱 하지 않는다.
Core Image는 lazy evaluation을 사용하기 때문입니다.
                         < 어떤 작업을 되도록 늦추고 늦춰서 꼭 필요해지는 최종 순간에 처리하는 것을 의미합니다..>

다른게 표현하면, processing된 pixel을 최종 타겟에 실제로 칠해야 하는 시점이 오기 전까지는 Core Image가 image processing하는 일은 없다고 할수 있겠군요.

outputImage 메소드는 Core Image가 필요로 하는 계산 값들을 모으거나 , CIImage에 계산 값들을 저장하는 것 밖에 없다. 실제 이미지는 가 만들어지는 것은  명시적으로 image drawing 메소드가 불렸을  때 뿐이다.  (drawImage:atPoint:fromRect 나 drawImage:inRect:fromRect 같은 메소드)

Figure 1-2  The components of a typical filter
The components of a typical filter

Core Image stores the calculations until your application issues a command to draw the image. At that time, Core Image calculates the results. Lazy evaluation is one of the practices that makes Core Image fast and efficient. At rendering time, Core Image can see if more than one filter needs to be applied to an image. If so, it can concatenate multiple “recipes” into one operation, which means each pixel is processed once rather than many times. Figure 1-3 illustrates how lazy evaluation can make image processing more efficient for multiple operations. The final image is a scaled-down version of the original. For the case of a large image, applying color adjustment before scaling down the image requires more processing power than scaling down the image and then applying color adjustment. Because Core Image waits until the last possible moment to apply filters, it can perform these operations in reverse order, which is more efficient.

Figure 1-3  A work flow that can benefit from lazy evaluation

For the filter creator, the most exciting component of a filter is the kernel, which is at the heart of every filter. The kernel specifies the calculations that are performed on each source image pixel. Kernel calculations can be very simple or complex. A very simple kernel for a “do nothing” filter could simply return the source pixel:

destination pixel = source pixel

Filter creators use a variant of OpenGL Shading Language (glslang) to specify per-pixel calculations. (See Core Image Kernel Language Reference.) The kernel is opaque to a filter client. A filter can actually use several kernel routines, passing the output of one to the input of another. For instructions on how to write a custom filter, see “Creating a Custom Filter.”

Filter creators can make their custom filters available to any application by packaging them as a plug-in, or image unit, using the architecture specified by the NSBundle class. An image unit can contain more than one filter, as shown in Figure 1-4. For example, you could write a set of filters that perform different kinds of edge detection and package them as a single image unit. Filter clients can use the Core Image API to load the image unit and to obtain a list of the filters contained in that image unit. See “Loading Image Units” for basic information. See Image Unit Tutorial for in-depth examples and detailed information on writing filters and packaging them as standalone image units.

Figure 1-4  An image unit contains packaging information along with one or more filter definitions

The Processing Path

Figure 1-5 shows the pixel processing path for a filter that operates on two sources images. Source images are always specified as CIImage objects. Core Image provides a variety of ways to get image data. You can supply a URL to an image, read raw image data (using the NSData class), or convert a Quartz 2D image (CGContextRef), an OpenGL texture, or a Core Video image buffer (CVImageBufferRef) to a CIImage object.

Note that the actual number of input images, and whether or not the filter requires an input image, depends on the filter. Filters are very flexible—a filter can:

  • Work without an input image. Some filters generate an image based on input parameters that aren’t images. (For example, see the CICheckerboardGenerator and CIConstantColorGeneratorfilters in Core Image Filter Reference.)

  • Require one image. (For example, see the CIColorPosterize and CICMYKHalftone filters in Core Image Filter Reference.)

  • Require two or more images. Filters that composite images or use the values in one image to control how the pixels in another image are processed typically require two or more images. One input image can act as a shading image, an image mask, a background image, or provide a source of lookup values that control some aspect of how the other image is processed. (For example, see theCIShadedMaterial filter in Core Image Filter Reference.)

When you process an image, it is your responsibility to create a CIImage object that contains the appropriate input data.

Figure 1-5  The pixel processing path

Pixels from each source image are fetched by a CISampler object, or simply a sampler. As its name suggests, a sampler retrieves samples of an image and provides them to a kernel. A filter creator provides a sampler for each source image. Filter clients don’t need to know anything about samplers.

A sampler defines:

  • A coordinate transform, which can be the identity transform if no transformation is needed.

  • An interpolation mode, which can be nearest neighbor sampling or bilinear interpolation (which is the default).

  • A wrapping mode that specifies how to produce pixels when the sampled area is outside of the source image—either to use transparent black or clamp to the extent.

The filter creator defines the per-pixel image processing calculations in the kernel, but Core Image handles the actual implementation of those calculations. Core Image determines whether the calculations are performed using the GPU or the CPU. Core Image implements hardware rasterization through OpenGL. It implements software rasterization through an emulation environment specifically tuned for evaluating fragment programs with nonprojective texture lookups over large quadrilaterals (quads).

Although the pixel processing path is from source image to destination, the calculation path that Core Image uses begins at the destination and works its way back to the source pixels, as shown in Figure 1-6. This backward calculation might seem unwieldy, but it actually minimizes the number of pixels used in any calculation. The alternative, which Core Image does not use, is the brute force method of processing all source pixels, then later deciding what’s needed for the destination. Let’s take a closer look at Figure 1-6.

Figure 1-6  The Core Image calculation path

Assume that the filter in Figure 1-6 performs some kind of compositing operation, such as source-over compositing. The filter client wants to overlap the two images, so that only a small portion of each image is composited to achieve the result shown at the left side of the figure. By looking ahead to what the destination ought to be, Core Image can determine which data from the source images affect the final image and then restrict calculations only to those source pixels. As a result, the samplers fetch samples only from shaded areas in the source images shown in Figure 1-6.

Note the box in the figure that’s labeled domain of definition. The domain of definition is simply a way to further restrict calculations. It is an area outside of which all pixels are transparent (that is, the alpha component is equal to 0). In this example, the domain of definition coincides exactly with the destination image. Core Image lets you supply a CIFilterShape object to define this area. TheCIFilterShape class provides a number of methods that can define rectangular shapes, transform shapes, and perform inset, union, and intersection operations on shapes. For example, if you define a filter shape using a rectangle that is smaller than the shaded area shown in Figure 1-6, then Core Image uses that information to further restrict the source pixels used in the calculation.

Core Image promotes efficient processing in other ways. It performs intelligent caching and compiler optimizations that make it well suited for such tasks as real-time video control. It caches intermediate results for any data set that is evaluated repeatedly. Core Image evicts data in least-recently-used order whenever adding a new image would cause the cache to grow too large, which means objects that are reused frequently remain in the cache, while those used once in a while might be moved in and out of the cache as needed. Your application benefits from Core Image caching without needing to know the details of how caching is implemented. However, you get the best performance by reusing objects (images, contexts, and so forth) whenever you can.

Core Image also gets great performance by using traditional compilation techniques at the kernel and pass levels. The method Core Image uses to allocate registers minimizes the number of temporary registers (per kernel) and temporary pixel buffers (per filter graph). The compiler performs CSE and peephole optimization and automatically distinguishes between reading data-dependent textures, which are based on previous calculations, and those that are not data-dependent. Again, you don’t need to concern yourself with the details of the compilation techniques. The important point is that Core Image is hardware savvy; it uses the power of the GPU whenever it can, and it does so in smart ways.

Coordinate Spaces

Core Image performs operations in a device-independent working space, similar in concept to what’s shown in Figure 1-7. The Core Image working space is, in theory, infinite in extent. A point in working space is represented by a coordinate pair (xy), where x represents the location along the horizontal axis and y represents the location along the vertical axis. Coordinates are floating-point values. By default, the origin is point (0,0).

When Core Image reads images, it translates the pixel locations into device-independent working space coordinates. When it is time to display a processed image, Core Image translates the working space coordinates to the appropriate coordinates for the destination, such as a display.

Figure 1-7  Core Image performs image operations in a device-independent working space

When you write your own filters, you need to be familiar with two coordinate spaces—the destination coordinate space and the sampler space. The destination coordinate space represents the image you are rendering to. The sampler space represents what you are texturing from (another image, a lookup table, and so on). You obtain the current location in destination space using the destCoord function whereas the samplerCoord function provides the current location in sample space. (See Core Image Kernel Language Reference.)

Keep in mind that if your source data is tiled, the sampler coordinates have an offset (dx/dy). If your sample coordinates have an offset, it may be necessary for you to convert the destination location to the sampler location using the function samplerTransform.

The Region of Interest

Although not explicitly labeled in Figure 1-6, the shaded area in each of the source images is the region of interest for samplers depicted in the figure. The region of interest, or ROI, defines the area in the source from which a sampler takes pixel information to provide to the kernel for processing. If you are a filter client, you don’t need to concern yourself with the ROI. But if you are a filter creator, you’ll want to understand the relationship between the region of interest and the domain of definition.

Recall that the domain of definition describes the bounding shape of a filter. In theory, this shape can be without bounds. Consider, for example, a filter that creates a repeating pattern that could extend to infinity.

The ROI and the domain of definition can relate to each other in the following ways:

  • They coincide exactly—there is a 1:1 mapping between source and destination. For example, a hue filter processes a pixel from the working space coordinate (r,s) in the ROI to produce a pixel at the working space coordinate (r,s) in the domain of definition.

  • They are dependent on each other, but modulated in some way. Some of the most interesting filters—blur and distortion, for example—use many source pixels in the calculation of one destination pixel. For example, a distortion filter might use a pixel (r,s) and its neighbors from the working coordinate space in the ROI to produce a single pixel (r,s) in the domain of definition.

  • The domain of definition is calculated from values in a lookup table that are provided by the sampler. The location of values in the map or table are unrelated to the working space coordinates in the source image and the destination. A value located at (r,s) in a shading image does not need to be the value that produces a pixel at the working space coordinate (r,s) in the domain of definition. Many filters use values provided in a shading image or lookup table in combination with an image source. For example, a color ramp or a table that approximates a function, such as the arcsin function, provides values that are unrelated to the notion of working coordinates.

Unless otherwise instructed, Core Image assumes that the ROI and the domain of definition coincide. If you write a filter for which this assumption doesn’t hold, you need to provide Core Image with a routine that calculates the ROI for a particular sampler.

See “Supplying an ROI Function” for more information.

Executable and Nonexecutable Filters

You can categorize custom Core Image filters on the basis of whether or not they require an auxiliary binary executable to be loaded into the address space of the client application. As you use the Core Image API, you’ll notice that these are simply referred to as executable and nonexecutable. Filter creators can choose to write either kind of filter. Filter clients can choose to use only nonexecutable or to use both kinds of filters.

Security is the primary motivation for distinguishing CPU executable and CPU nonexecutable filters. Nonexecutable filters consist only of a Core Image kernel program to describe the filter operation. In contrast, an executable filter also contains machine code that runs on the CPU. Core Image kernel programs run within a restricted environment and cannot pose as a virus, Trojan horse, or other security threat, whereas arbitrary code that runs on the CPU can.

Nonexecutable filters have special requirements, one of which is that nonexecutable filters must be packaged as part of an image unit. Filter creators can read “Writing Nonexecutable Filters” for more information. Filter clients can find information on loading each kind of filter in “Loading Image Units.”

Color Components and Premultiplied Alpha

Premultiplied alpha is a term used to describe a source color, the components of which have already been multiplied by an alpha value. Premultiplying speeds up the rendering of an image by eliminating the need to perform a multiplication operation for each color component. For example, in an RGB color space, rendering an image with premultiplied alpha eliminates three multiplication operations (red times alpha, green times alpha, and blue times alpha) for each pixel in the image.

Filter creators must supply Core Image with color components that are premultiplied by the alpha value. Otherwise, the filter behaves as if the alpha value for a color component is 1.0. Making sure color components are premultiplied is important for filters that manipulate color.

By default, Core Image assumes that processing nodes are 128 bits-per-pixel, linear light, premultiplied RGBA floating-point values that use the GenericRGB color space. You can specify a different working color space by providing a Quartz 2D CGColorSpace object. Note that the working color space must be RGB-based. If you have YUV data as input (or other data that is not RGB-based), you can use ColorSync functions to convert to the working color space. (See Quartz 2D Programming Guide for information on creating and using CGColorspace objects.)

With 8-bit YUV 4:2:2 sources, Core Image can process 240 HD layers per gigabyte. Eight-bit YUV is the native color format for video source such as DV, MPEG, uncompressed D1, and JPEG. You need to convert YUV color spaces to an RGB color space for Core Image.



펌 [http://developer.apple.com읽으면서 기억에 남는 내용을 정리 했습니다.
반응형



가끔 개인적으로  stdafx.h 는 골치 아프게 할때가 있습니다..

테스트 코드를 작성해서 시험해보거나, Code generation 툴을 이용해서 만들어진 코드에 작업하는 경우, 그리고 작성된 코드를 visual studio가 아닌,
개발환경( gcc , armcc 등등 ) 에서 cross compile 해야 하는경우 등이 대표적인 예입니다.


visual studio 에서 Win32 Project를 만들었을 경우,  stdafx.h 를 없애기 위한 절차는 다음과 같습니다.

1. 
프로젝트 프라퍼티( Property) -> C/C++ -> Precompiled Headers
: Create/Use Precompiled Header :Not Using Precompiled Headers 로 변경

2. 각 소스파일에서 include "stdafx.h" 를 없앤다.


3. 이렇게 변경을 하고 나면, 아마 이런 에러가 날것입니다.
unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup 

이 에러는 WinMain이 없다는 예기인데요.

3. 위와 같은 에러가 발생하면, Main이 들어있는 소스 파일을 확인해보자.

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)


Visual studio 에서 사용되는 CRT library가 _tWinMain을 호출하도록 되어있습니다.
그런데 우리가 Precompiled header를 없앴기 때문에, 이제 WinMain을 요구하는 것이죠.
그래서 위의 _tWinMain을 WinMain으로 변경하면 됩니다.
이때 주의 사항은 3번째 파라미터 인 LPSTR    lpCmdLine 입니다.
tWinMain에서는 LPSTR로 되어있어서 그냥 이름만 바꾸면 안되고, parameter 타입도 확인하셔야 합니다.

[WinMain 의 prototype]
 

int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow) 



여기까지 하고 나면 빌드 성공!!!!!

즐거운 프로그래밍 생활 하세요!


반응형

에플 개발 사이트에서 core animation 관련 내용을 발최 필요한 부분을 번역하였습니다.


What Is Core Animation?

Core Animation is a collection of Objective-C classes for graphics rendering, projection, and animation. It provides fluid animations using advanced compositing effects while retaining a hierarchical layer abstraction that is familiar to developers using the Application Kit and Cocoa Touch view architectures.

Dynamic, animated user interfaces are hard to create, but Core Animation makes creating these interfaces easier by providing:

- High performance compositing with a simple approachable programming model.
- A familiar view-like abstraction that allows you to create complex user interfaces using a hierarchy of layer objects.
- A lightweight data structure. You can display and animate hundreds of layers simultaneously.
- An abstract animation interface that allows animations to run on a separate thread, independent of your application's run loop. Once an animation is configured and starts, Core Animation assumes full responsibility for running it at frame rate.
- Improved application performance. Applications need only redraw content when it changes. Minimal application interaction is required for resizing and providing layout services layers. Core Animation also eliminates application code that runs at the animation frame-rate.
- A flexible layout manager model, including a manager that allows the position and size of a layer to be set relative to attributes of sibling layers.

Using Core Animation, developers can create dynamic user interfaces for their applications without having to use low-level graphics APIs such as OpenGL to get respectable animation performance.


Core Animation Classes 


Core Animation classes can be grouped into several categories:
  • Layer classes that provide content for display

  • Animation and timing classes

  • Layout and constraint classes

  • A transaction class that groups multiple layer changes into an atomic update

기본 Core Animation class들은 Quartz Core framework.에 포함되어있고, 추가적인 layer class들은 다른 framework에 포함될 수 있다.  Figure 1 " Core Animation Class" class 계층도를 이다.

Figure 1 Core Animation class hierarchy
 



Layer Classes

Layer class는 Core Animation의 기반이며 NSView나 UIView를 이용하는 개발자들에게 친숙한 추상화(abstraction)를 제공한다. - abstraction 을 class 추상화 로 생각하는 것이 좋을것 같음.
CALayer는 모든 Core Animaton layer들의 부모 클래스로서 기본 Layer의 기능을 제공한다.
 

View 클래스의 인스턴스(객체) 는  레이어 트리에서 제공하는 것처럼 레이어 계층구조를 만든다.

 - CALayer 인스턴스는 하나의 부모 레이어(Super layer)와 자식 레이어(Sub Layer)들에 대한 콜랙션(collection- 자료구조)을 갖고 있다. 

레이어들은 뷰(View)와 비슷하게 뒤에서부터 앞으로 그려지고 부모 레이어(Super Layer)를 로컬(local) 좌표계를 생성하는 것과 같이 상대적 위치나 형태를 취하게 된다. 
그러나, 레이어들은  회전(rotate),비틀림(skew), 크기변환( scale) , 투영(project)와 같은 변환 행렬을 레이어 컨텐츠(content)에 적용하는 것과 같은 좀더 복잡한 표현들을 제공한다. 

"Layer Geometry and Transforms" 는 레이어 도형(Geometry) 와 변환(transform)에 대해 좀더 자세하게 다루고 있다.

 CALayer는 Application Kit과 Cocoa Touch view class들로 분기하기에, 컨텐츠를 표현하기 위해 CALayer에서 파생(subclass)될 필요가 없다. 컨텐츠는 CALayer 인스턴스에 의해 아래와 같은 방법으로 출력된다.

  • Core Graphics 의 Image Representation 으로 직접 또는 델리게이션(delegation)을 통해서 레이어의 컨텐츠 속성(property) 세팅.
  • Core Graphics Image Context를 통해 직접 그리는 델리게이트( delegate)를 제공.
  • 여러가지 비쥬얼 스타일 속성 설정 제공
    • 모든레이어에 공통적으로 가지고 있는 속성으로 예를 들면,
    • 배경색( background color), 투명도(opacity), 마스킹(masking)등이다. 
      - Mac OS X 어플리케이션 역시 비쥬얼 속성( property)을 접근할 수 있으며 Core Image filter를 사용할수 있다.
  • CALayer 파생(상속, subclassing) 이나 좀더 켑슐화된 방법의 높은 수준의 기술을 통한 구현.



“Providing Layer Content” describes the available techniques for providing the content for a layer. The visual style properties and the order in which they are applied to the content of a layer is discussed in “Layer Style Properties.”

In addition to the CALayer class, the Core Animation class collection provides additional classes that allow applications to display other types of content. The available classes differ slightly between Mac OS X and iOS. The following classes are available on both Mac OS X and iOS:

  • CAScrollLayer class is a subclass of CALayer that simplifies displaying a portion of a layer. The extent of the scrollable area of a CAScrollLayer object is defined by the layout of its sublayers. CAScrollLayer does not provide keyboard or mouse event-handling, nor does it provide visible scrollers.

  • CATextLayer is a convenience class that creates a layer's content from a string or attributed string.

  • CATiledLayer allows the display of large and complex images in incremental stages.

Mac OS X provides these additional classes:

  • CAOpenGLLayer provides an OpenGL rendering environment. You must subclass this class to provide content using OpenGL. The content can be static or can be updated over time.

  • QCCompositionLayer (provided by the Quartz Composer framework) animates a Quartz Composer composition as its content.

  • QTMovieLayer and QTCaptureLayer (provided by the QTKit framework) provides playback of QuickTime movies and live video.

iOS adds the following class:

  • CAEAGLLayer provides an OpenGLES rendering environment.

The CALayer class introduces the concept of a key-value coding compliant container class–that is, a class that can store arbitrary values, using key-value coding compliant methods, without having to create a subclass. CALayer also extends the NSKeyValueCoding informal protocol, adding support for default key values and automatic object wrapping for the additional structure types (CGPointCGSizeCGRectCGAffineTransform and CATransform3D) and provides access to many of the fields of those structures by key path.

CALayer also manages the animations and actions that are associated with a layer. Layers receive action triggers in response to layers being inserted and removed from the layer tree, modifications being made to layer properties, or explicit developer requests. These actions typically result in an animation occurring. See “Animation” and “Layer Actions” for more information.

Animation and Timing Classes


한 레이어의 비쥬얼 프라퍼티들중 많은 것들이 Implicitly(자동,무조건적인) 에니메이션 가능하다. 에니메이션이 가능한 프라퍼티의 값을 간단히 변경하는 것으로 레이어는 자동으로 현재 값에서 새로 세팅된 값으로 에니메이션 한다. 예로 레이어의 숨김(hidden) 프라퍼티를 YES로 설정하면 레이어는 천천히 사라진다. 대부분의 에니메이션이 가능한 프라퍼티들은 사용자가 조작하거나 변경할수 있도록 기본적인 에니메이션을 가지고 있다. 에니메이션 가능한 프라퍼티의 전체 목록은 "Animatable Properties" 에 있다.



에니메이션 프라퍼티들은 explicit 에니메이션으로 사용할 수 있다. Core Animation 의 animation class 로 인스턴스를 만들고 비쥬얼 이펙트를 설정하여 explicit 에니메이션을 만들 수 있다.
explicit animation은 Layer에서 프라퍼티 값을 변경하지 않고, display 단에서 간단한 에니메이션을 한다. 
(
An explicit animation doesn’t change the value of the property in the layer, it simply animates it in the display.


제가 알아본 결과 : 
explicit animation 은 layer에 사용자가 원하는 에니메이션을 세팅 할 수 있는 기능으로,animation 되는 동안 layer의 property는 변경되지 않는 다고 합니다.
 

 


Core Animation provides animation classes that can animate the entire contents of a layer or selected attributes using both basic animation and key-frame animation. All Core Animation's animation classes descend from the abstract class 
CAAnimationCAAnimation adopts the CAMediaTiming protocol which provides the simple duration, speed, and repeat count for an animation.CAAnimation also adopts the CAAction protocol. This protocol provides a standardized means for starting an animation in response to an action triggered by a layer.

The animation classes also define a timing function that describes the pacing of the animation as a simple Bezier curve. For example, a linear timing function specifies that the animation's pace is even across its duration, while an ease-out timing function causes an animation to slow down as it nears its duration.

Core Animation provides a number of additional abstract and concrete animation classes:

  • CATransition provides a transition effect that affects the entire layer's content. It fades, pushes, or reveals layer content when animating. The stock transition effects can be extended by providing your own custom Core Image filters.

  • CAAnimationGroup allows an array of animation objects to be grouped together and run concurrently.

  • CAPropertyAnimation is an abstract subclass that provides support for animating a layer property specified by a key path.

  • CABasicAnimation provides simple interpolation for a layer property.

  • CAKeyframeAnimation provides support for key frame animation. You specify the key path of the layer property to be animated, an array of values that represent the value at each stage of the animation, as well as arrays of key frame times and timing functions. As the animation runs, each value is set in turn using the specified interpolation.

These animation classes are used by both Core Animation and Cocoa Animation proxies. “Animation” describes the classes as they pertain to Core Animation, Animation Types and Timing Programming Guide contains a more in-depth exploration of their capabilities.

Layout Manager Classes

Application Kit view classes provide the classic "struts and springs" model of positioning layers relative to their superlayer. While layers support this model, Core Animation on Mac OS X also provides a more flexible layout manager mechanism that allows developers to write their own layout managers.

Core Animation’s CAConstraint class is a layout manager that arranges sublayers using a set of constraints that you specify. Each constraint (encapsulated by instances of the CAConstraintclass) describes the relationship of one geometric attribute of a layer (the left, right, top, or bottom edge or the horizontal or vertical center) in relation to a geometric attribute of one of its sibling layers or its superlayer.

Layout managers in general, and the constraint layout manager are discussed in “Laying Out Core Animation Layers”

Transaction Management Classes

Every modification to an animatable property of a layer must be part of a transaction. CATransaction is the Core Animation class responsible for batching multiple animation operations into atomic updates to the display. Nested transactions are supported.


Core Animation 은 implicit transaction 와 explicit transaction  2가지 타입의 트랜젝션(transaction)을 제공한다. 
Implicit transaction은 쓰레드(thread)에서 active transaction 없이 레이어의 에니메이션가능한 속성이 수정되면 자동으로 생성된다.  그리고 쓰레드 루프(run-loop)에서 다음 수행(iterate)될때 자동으로 수행된다. 
Explicit transaction 은 어플리케이션이 레이어를 수정하기 전에 CATransaction class의 begin message 를 보내고  commit message를 할때 수행된다. 

 

Transaction management is discussed in “Transactions.”




Core Animation Rendering Architecture

Core Animation의 Layer와 Cocoa view사이에 명백하게 비슷한 점들이 있는 동시에 가장 큰 념적인 차이는 스크린에 직접 그리지는 않는다.

NSView와 UIView는 MVC(model-view-controller)디자인 패턴에서 뷰 오브젝트(view object)에 해당하고, Core Animation 의 Layer는 모델 오브젝트(model object)에 해당한다. Layer는 형체 정보(geometry), 타이밍(timing) 과 visual property, 그들이 제공하는 표시된 컨텐츠(content)를 켑슐화(encapsulate)하고 있으나, 실제 보여지는 것이 Layer의  기능은 아니다.


각의 레이어 트리에는 2개의 대응되는 트리가 있다. Presentation tree와 Render Tree이다.
그림1은 Mac OS X에서의 유효한 Core Animation layer class를 이용한 Layer트리의 예를 보여준다.
 

Figure 1  Core Animation Rendering Architecture



레이어 트리(Layer tree)는 각 레이어의 객체 모델 값(Value)들을 포함하고 있다. 이 값들은 레이어 프라퍼티(Layer property)에 설정한 값이다.

Presentation Tree 는 현재 에니메이션 위치의 값들을 가지고있다.
한 예로 새로운 값을 Layer의 backgroundColor에 설정하면, Layer tree의 값은 즉시 바뀐다. 그러나 Presentation tree에 해당하는 Layer의 backgroundColor 값은 presentation tree의 layer들이 화면에 반영되는 시점에 업데이트된다.
(interpolate 되는 시점이 rendering 직전이라고 이해하면 될것 같다).

레이어를 렌더링 할때 렌더 트리는 presentation-tree의 값을 사용한다. 렌더 트리는 어플리케이션의 엑티비티와는 독립적으로 구성가능하도록 하는 역할을 맡고있다.
렌더링이 어플리케이션 실행 루프에서 최소한의 영향을 주도록 분리된 프로세스나 스레드에서 실행된다.

프로세스내에서 animation이 수행되는 동안 Presentation Layer에 해당하는 CALayer의 인스턴스에 접근할 수 있다.
이는 현재 에니매이션되고 있는 상태를 가지고 새로운 에니메이션을 시키고자할때 매우 유용하다. 






Layer Geometry and Transforms

This chapter describes the components of a layer’s geometry, how they interrelate, and how transform matrices can produce complex visual effects.

Layer Coordinate System

The coordinate system for layers differs depending on the current platform. In iOS, the default coordinate system origin is in the top-left corner of the layer and positive values extend down and to the right of that origin point. In Mac OS X, the default coordinate system origin is in the lower-left corner of the layer and positive values extend up and to the right of that point. All coordinate values are specified as floating-point numbers. And any layers you create on a given platform use the default coordinate system associated with that platform.

Every layer object defines and maintains its own coordinate system, and all content in a layer is positioned relative to this coordinate system. This is true both for the layer contents itself and for any sublayers. Because each layer defines its own coordinate system, the CALayer class provides methods to convert point, rectangle and size values from the coordinate system of one layer to another.

Some layer-related properties measure their values using the unit coordinate space. The unit coordinate space is a way of specifying values relative to the bounds of the layer but without tying that property to the exact bounds values. A given x or y coordinate in the unit coordinate space is always in the range of 0.0 to 1.0. Specifying a value of 0.0 along the x axis yields a point on the left edge of the layer while specifying a value of 1.0 yields a point on the right edge of the layer. (For y values, which value is along the top edge and which value is along the bottom edge depends on the underlying platform and follows the same rules as previously described.) A point of (0.5, 0.5) yields a point in the exact center of the layer.

Specifying a Layer’s Geometry

While layers and the layer-tree are analogous to views and view hierarchies in many ways, a layer's geometry is specified in a different, and often simpler, manner. All of a layer’s geometric properties, including the layer’s transform matrices, can be implicitly and explicitly animated.

Figure 1 shows the properties used to specify a layer's geometry in context.

Figure 1  CALayer geometry properties


The position property is a CGPoint that specifies the position of the layer relative to its superlayer, and is expressed in the superlayer's coordinate system.

The bounds property is a CGRect that provides the size of the layer (bounds.size) and the origin (bounds.origin). The bounds origin is used as the origin of the graphics context when you override a layer's drawing methods.

Layers have an implicit frame that is a function of the positionboundsanchorPoint, and transform properties. Setting a new frame rectangle changes the layer's position and boundsproperties appropriately, but the frame itself is not stored. When a new frame rectangle is specified the bounds origin is undisturbed, while the bounds size is set to the size of the frame. The layer's position is set to the proper location relative to the anchor point. When you get the frame property value, it is calculated relative to the positionbounds, and anchorPoint properties.

The anchorPoint property is a CGPoint that specifies a location within the bounds of a layer that corresponds with the position coordinate. The anchor point specifies how the bounds are positioned relative to the position property, as well as serving as the point that transforms are applied around. It is expressed in the unit coordinate system-the (0.0,0.0) value is located closest to the layer’s origin and (1.0,1.0) is located in the opposite corner. Applying a transform to the layer’s parent (if one exists) can alter the anchorPoint orientation, depending on the parent’s coordinate system on the y-axis.

When you specify the frame of a layer, position is set relative to the anchor point. When you specify the position of the layer, bounds is set relative to the anchor point.

Figure 2 shows three example values for an anchor point.

Figure 2  Three anchorPoint values


The default value for anchorPoint is (0.5,0.5) which corresponds to the center of the layer's bounds (shown as point A in Figure 2.) Point B shows the position of an anchor point set to (0.0,0.5). Finally, point C (1.0,0.0) causes specifies that the layer’s position is set to the bottom right corner of the frame. This diagram is specific to layers in Mac OS X. In iOS, layers use a different default coordinate system, where (0.0,0.0) is in the top-left corner and (1.0,1.0) is in the lower-right.

The relationship of the frameboundsposition, and anchorPoint properties is shown in Figure 3.

Figure 3  Layer Origin of (0.5,0.5)


In this example the anchorPoint is set to the default value of (0.5,0.5), which corresponds to the center of the layer. The position of the layer is set to (100.0,100.0), and the bounds is set to the rectangle (0.0, 0.0, 120.0, 80.0). This causes the frame property to be calculated as (40.0, 60.0, 120.0, 80.0).

If you created a new layer, and set only the layer’s frame property to (40.0, 60.0, 120.0, 80.0), the position property would be automatically set to (100.0,100.0), and the bounds property to (0.0, 0.0, 120.0, 80.0).

Figure 4 shows a layer with the same frame rectangle as the layer in Figure 3. However, in this case the anchorPoint of the layer is set to (0.0,0.0), which corresponds with the bottom left corner of the layer.

Figure 4  Layer Origin of (0.0,0.0)


With the frame set to (40.0, 60.0, 120.0, 80.0), the value of the bounds property is the same, but the value of the position property has changed.

Another aspect of layer geometry that differs from Cocoa views is that you can specify a radius that is used to round the corners of the layer. The cornerRadius property specifies a radius the layer uses when drawing content, clipping sublayers, and drawing the border and shadow.

The zPosition property specifies the z-axis component of the layer's position. The zPosition is intended to be used to set the visual position of the layer relative to its sibling layers. It should not be used to specify the order of layer siblings, instead reorder the layer in the sublayer array.

Transforming a Layer’s Geometry

Once established, you can transform a layer's geometry using matrix transformations. The CATransform3D data structure defines a homogenous three-dimensional transform (a 4 by 4 matrix ofCGFloat values) that is used to rotate, scale, offset, skew, and apply perspective transformations to a layer.

Two layer properties specify transform matrices: transform and sublayerTransform. The matrix specified by the transform property is applied to the layer and its sublayers relative to the layer's anchorPointFigure 3 shows how rotation and scaling transforms affect a layer when using an anchorPoint of (0.5,0.5), the default value. Figure 4 shows how the same transform matrices affect a layer when an anchorPoint of (0.0,0.0). The matrix specified by the sublayerTransform property is applied only to the layer’s sublayers, rather than to the layer itself.

You create and modify CATransform3D data structures in one of the following ways:

  • using the CATransform3D functions

  • modifying the data structure members directly

  • using key-value coding and key paths.

The constant CATransform3DIdentity is the identity matrix, a matrix that has no scale, rotation, skewing, or perspective applied. Applying the identity matrix to a layer causes it to be displayed with its default geometry.

Transform Functions

The transform functions available in Core Animation operate on matrices. You can use these functions (shown in Table 1) to construct a matrix that you later apply to a layer or its sublayers by modifying the transform or sublayerTransform properties respectively. The transform functions either operate on, or return, a CATransform3D data structure. This enables you to construct simple or complex transforms that you can readily reuse.

Table 1  CATransform3D transform functions for translation, rotation, and scaling

Function

Use

CATransform3DMakeTranslation

Returns a transform that translates by '(tx, ty, tz)'. t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1].

CATransform3DTranslate

Translate 't' by '(tx, ty, tz)' and return the result: * t' = translate(tx, ty, tz) * t.

CATransform3DMakeScale

Returns a transform that scales by `(sx, sy, sz)': * t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1].

CATransform3DScale

Scale 't' by '(sx, sy, sz)' and return the result: * t' = scale(sx, sy, sz) * t.

CATransform3DMakeRotation

Returns a transform that rotates by 'angle' radians about the vector '(x, y, z)'. If the vector has length zero the identity transform is returned.

CATransform3DRotate

Rotate 't' by 'angle' radians about the vector '(x, y, z)' and return the result. t' = rotation(angle, x, y, z) * t.

The angle of rotation is specified in radians rather than degrees. The following functions allow you to convert between radians and degrees.

CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180 / M_PI;};

Core Animation provides a transform function that inverts a matrix, CATransform3DInvert. Inversion is generally used to provide reverse transformation of points within transformed objects. Inversion can be useful when you need to recover a value that has been transformed by a matrix: invert the matrix, and multiply the value by the inverted matrix, and the result is the original value.

Functions are also provided that allow you to convert a CATransform3D matrix to a CGAffineTransform matrix, if the CATransform3D matrix can be expressed as such.

Table 2  CATransform3D transform functions for CGAffineTransform conversion

Function

Use

CATransform3DMakeAffineTransform

Returns a CATransform3D with the same effect as the passed affine transform.

CATransform3DIsAffine

Returns YES if the passed CATransform3D can be exactly represented an affine transform.

CATransform3DGetAffineTransform

Returns the affine transform represented by the passed CATransform3D.

Functions are provided for comparing transform matrices for equality with the identity matrix, or another transform matrix.

Table 3  CATransform3D transform functions for testing equality

Function

Use

CATransform3DIsIdentity

Returns YES if the transform is the identity transform.

CATransform3DEqualToTransform

Returns YES if the two transforms are exactly equal..

Modifying the Transform Data Structure

You can modify the value of any of the CATransform3D data structure members as you would any other data structure. Listing 1 contains the definition of the CATransform3D data structure, the structure members are shown in their corresponding matrix positions.

Listing 1  CATransform3D structure

struct CATransform3D

{


  CGFloat m11, m12, m13, m14;

  CGFloat m21, m22, m23, m24;

  CGFloat m31, m32, m33, m34;

  CGFloat m41, m42, m43, m44;

};

 

typedef struct CATransform3D CATransform3D;




 

The example in Listing 2 illustrates how to configure a CATransform3D as a perspective transform.

Listing 2  Modifying the CATransform3D data structure directly

 CATransform3D aTransform = CATransform3DIdentity;

// the value of zDistance affects the sharpness of the transform.

zDistance = 850;

aTransform.m34 = 1.0 / -zDistance;




Modifying a Transform Using Key Paths

Core Animation extends the key-value coding protocol to allow getting and setting of the common values of a layer's CATransform3D matrix through key paths. Table 4 describes the key paths for which a layer’s transform and sublayerTransform properties are key-value coding and observing compliant.

Table 4  CATransform3D key paths

Field Key Path

Description

rotation.x

The rotation, in radians, in the x axis.

rotation.y

The rotation, in radians, in the y axis.

rotation.z

The rotation, in radians, in the z axis.

rotation

The rotation, in radians, in the z axis. This is identical to setting the rotation.z field.

scale.x

Scale factor for the x axis.

scale.y

Scale factor for the y axis.

scale.z

Scale factor for the z axis.

scale

Average of all three scale factors.

translation.x

Translate in the x axis.

translation.y

Translate in the y axis.

translation.z

Translate in the z axis.

translation

Translate in the x and y axis. Value is an NSSize or CGSize.

You can not specify a structure field key path using Objective-C 2.0 properties. This will not work:

myLayer.transform.rotation.x=0;

Instead you must use setValue:forKeyPath: or valueForKeyPath: as shown below:

[myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"]




 [펌]http://developer.apple.com


 

반응형

key 값과 value 로 data를 관리하는 형태는 상당히 편리하고 유용한 기법입니다.

최근 iCloud에서 이런 key /value 관리 기법을 사용하여  내가 구입한 책 정보, 현재 읽고있는 책의 북마크 , Contact 정보 등을 
관리하고 보관 update 한다고 스티브 잡스 님이 예기 하여 약간 화제가 되고 있는 기술입니다.

우선 iOS 의 경우에는 Objective-C의 언어 적인 특징으로 key-value 기능 지원이 자연스럽게 구축되어있는 상황이라고 보여집니다.  (NSResponsible, NSObject , NSProxy 정보에 기술되어있습니다.)


key-Value 컨셉을 C++에서 비슷한 성격의 클래스를 만들수 있지 않을까 해서 ,  디자인/ 구현 해보고자 아래와 같이 구상했습니다.

우리가 class를 설계 할때 대부분 class의 기능을 생각하고, 필요한 속성을 찾고 이를 멤버변수로 정하고, 멤버변수에 접근하는 API를 설계해서 추가한다.
그러면 아래와 같은 형태가됩니다.

class TitleBox
{
...
public:
   void SeBounds(int x,int y,int w,int h);
   void GetBounds(int *x,int *y,int *w,int*h);
   void SetBgColor(RGB col);
   void GetBgColor(RGB * col);
   void SetText(string &text);
   string &GetText();
   
protected:
  string m_Text;
  Rectangle m_Bounds;
  RGB m_bgColor;
};

이렇게 설계가 되고 나면, 그다음에 이 class를 사용해서 뭔가를 만들기 시작하는데,
한참 모듈을 만들다 보면 "아 Text Color 도 변경이 되어야 겠네!!" 하게 됩니다.

그래서 Text Color를 변경하는 API를 추가하고, 멤버 변수도 추가하죠.

그리고 한참 작업하다보면, Icon 추가하는 기능도 필요하게 되고, 
BgColor 대신 bg image를 사용하고 싶어질때도 있고, 그때 마다 API를 추가하거나 변경하고,
해당 API를 사용하는 모든 곳을 찾아서 다시 수정해야 합니다.

또... 멤버 변수의 종류가 점점 늘어나면 늘어날 수록 API 개수는 거의 2배정도로 늘어나게 되고, 
이를 관리하는 것도 힘들어지게 되죠.

그래서 개발자들은 이를 획기적으로 개선할 수 있는 방법들을 하나 둘씩 생각하기 시작합니다.

그래서 control의 속성을 나타내는 멤버 변수들을 묶는 컨셉이 나오게 됩니다.
이를 attribute 나 property 라는 이름으로 설명하곤하는데요. property라고 하겠습니다.

그러면서 property의 내용을 속성마다 일일히 멤버 변수를 정의 하는 것이 아니라,
STL의 map 과 같이 key와 value 로 관리하는 방법을 취하게 됩니다.

property.set("bounds.x",10);
property.set("bounds.y",10);
property.set("bounds.w",10);
property.set("bounds.h",10);
property.set("bg.color",RGB(100,210,113));
property.set("bg.image","user/bg_ship.jpg");

property.get("bounds.x",&cx);


이런 형태를 취하게 됩니다.

이로 인해서 class의 확장이나 기능 변경시에 API의 변경 폭이 줄어들게 되어, 유지 보수에 매우 효과적인 결과를 나타내게 됩니다.

이와 더불어 부가적인 효과로 control을 조작할때 더이상 해당 control의 class를 알 필요가 없어지게 되었습니다.
단순한 기능의 경우 property만 parameter로 넘겨받아서 property의 속성값을 확인하면 되기 때문에 모듈간의 dependency가 줄어들게 된 것입니다.

[Button.h]----------------------------
class Button
{
 void SetText();
};
--------------------------------------


[ButtonUI.c]--------------------------

#include "Button.h"

class ButtonUI
{
protected:
   Button * m_pButton;   //<--- 이와 같이 실제로 Button class를 알아야만 조작이 가능해 집니다.
public:
   void ChangeText();
};

ButtonUI::ChangeText()
{
    m_pButton->SetText();
}
--------------------------------------
그런데 만약 Property를 이용하게 된다면,
ButtonUI는 더이상 Button class를 알 필요가 없어지고, Property 만 control로 부터 얻어올 수 있으면 property만 조작하는 것이 가능해 집니다.

이는 class factory 형식을 이용하여, class의 instance를 생성해주는 모듈과 함께 사용된다면,
class간의 의존성을 획기적으로 줄일 수 있게 됩니다.

그리고 data를 접근하는 기법이 통일되어 여러가지 형태로 활용이 가능해 지게 됩니다.


XML이나 script같은 engine을 활용하여 property를 조작하는 부가적인 기능도 만들 수 있게되고,
property만 따로 registry에 저장하여 , 현재 상태를 임시로 저장했다가 다시 실행할때 동일한 형태로 불러오는 것도 가능해집니다.





반응형
불확실성과 화해하는 프로젝트 추정과 계획(마이크 콘) 이라는 책의 13번째 파트 에 해당하는 내용입니다.


릴리즈 계획이 뭐길래? 왜?  <-- 요거 제목으로는 어울리지 않죠? ㅎㅎ 릴리즈에 대해서 다들 알고 있을 건데.. 왜라니.. 쩝. ㅋ 

릴리즈 계획 과정은 이터레이션보다 더 긴 기간을 커버하는 아주 높은 수준의 계획을 생성하는 과정이다.
릴리즈를 내놓는 데는 통상 3개월에서 6개월의 기간이 소요되며, 이터레이션 길이가 얼마냐에 따라서 3회에서 12회 이상의 이터레이션이 필요하다.

첫 번째로 릴리스 계획은 제품 책임자와 팀원들로 하여금 릴리스 가능한 제품이 나오려면 얼마나 많은 작업이, 그리고 얼마나 오랜 시간이 필요할지 결정할 수 있도록 해준다. 제품이 더 빨리 릴리스 될수록(그리고 릴리스 시점에 제품의 질이 좋으면 좋을수록), 회사는 프로젝트로부터 더 빨리 수익을 거둘 수 있게 된다.
  -- 이런 내용들이 관리자들이 좋아하는 내용이죠? ^^;;

두 번째로 릴리스 계획을 통해 얼마만큼의 기간 동안, 어떤 기능이 개발될 것인지를 예측할 수 있다. 많은 회사들이 이 정보를 사용해 다른 전략적 계획들을 수립한다.

세 번째로 릴리스 계획은 개발팀이 어디로 가야할지를 보여주는 이정표 구실을 한다. 릴리스라는 개념이 없다면, 개발팀은 한 이터레이션에서 다음 이터레이션으로 끝없이 옮겨 다니게 될 것이다. 릴리스 계획 덕에 이터레이션들은 하나의 만족스로운 총체로 결합될 수가 있다. 이는 굳이 애자일 프로세스가 아니더라도, 반복적인 프로세스라면 기본적으로 고려해야할 사항이다. 
이런 계획이 없다면 프로젝트가 목적지 없이 표류할 가능 성이 생기고, 또 완료를 하더라도 기대했던 방향이 아닐 수도 있다.
그러므로 릴리스 계획이 필수적이며 이로인해서 프로젝트가 잘못된 길로 가는 걸 막아줄 수 있다.... 랍니다. ㅋ

릴리즈 계획
릴리스 계획 과정에서는 얼마만큼의 작업이 완료 될것인가를 결정해야 한다. 
날짜를 정해놓고 얼마만큼의 일을 할 수 있을지 생각해보는 것이 프로젝트의 시작일 수도 있고,사용자 스토리들을 만들어 둔 다음 그것들을 구현하는데 얼마나 오래 걸릴지를 생각해 보는 것으로 프로젝트를 시작할 수도 있다.
개발팀이 최초의 답을 얻고 나면 그 답은 해당 프로젝트에 대한 조직의 목표에 비추어 평가된다.
결국 제품을 개발하고 나면 기대한 만큼의 돈을 벌 수 있을 것인가? 아니면 돈을 절약할 수 있을 것인가? 시장에 성공적으로 진입할 수 있을 것인가? 만일 아니라면, 프로젝트 수행 기간을 더 늘리거나 줄여서 목표를 성취할 수 있을지도 모른다.

릴리스를 내놓기 위해 얼마나 많은 일을 해야 할지, 그리고 어떤 사용자 스토리들을 포함할지를 결정하는 것은 아주 직관적인 프로세스이다. 계획된 이터레이션 숫자에 개발팀의 예상 속도나 알려진 속도를 곱하면 얼마나 많은 일이 필요한지를 결정할 수 있다.

그 수치에 맞춰서 사용자 스토리의 수를 결정하면 된다. 가령 6개월 뒤에 새로운 제품을 내놓아야 한다고 해보자, 두 주짜리 이터레이션을 사용하기로 했다면, 릴리스 시점까지 13번의 이터레이션을 돌아야 할것이다.
개발팀의 속도가 스토리 점수나 이상적인 작업일 기준으로 20이라면, 전체 프로젝트의 규모는 13x20= 260점이 될 것이다. 제품 책임자와 개발팀은 그 점수를 놓고 모든 스토리들을 토론 해 본 다음 그 우선순위를 정해 260이 넘지 않는 한도 내에서 가장 가치 있다고 여겨지는 스토리들을 구현하기 위해 노력할것이다. 릴리스 계획은 보통 프로젝트 기간 동안 개발될 사용자 스토리의 목록 형태로 문서화된다.

여기쯤 읽을때 이런 생각을 해봤습니다.
위에서 개발팀의 속도를 20이라는 결과를 얻기 위해서는 무엇이 필요할까? 라는 것입니다.
이론상으로는 너무나도 쉬운 답을 얻을 수 있습니다. 실제로 팀원들과 스토리 보드 작성과 이터레이션 작성을 한 내용을 가지고 평가를 하면 됩니다.

하지만 제가 진행해본 결과( 전문 프로젝트 메니져가 아니라 너무 미숙 했을 수도 있지만 ) 정확한 추정이 힘들다는 것을 알게 되었습니다.

1. 전체 제품에 들어가야 하는 정확한 스토리를 뽑아 내기가 힘들다는것.
2. 프로젝트를 진행하면서 튀어나오는 이슈들이 발생할때 이것들이 스토리로 들어가기에 문제가 있는 경우들.
3. 스토리나 이터레이션 수행에 거짓이 있을때.( 보고를 위해 빈약한 부분을 채워 넣거나, 혹은 빼먹거나 하는 것들).

1번과 2번은 사실 프로젝트 수행 미숙에 해당하는 내용으로 볼 수도 있습니다.
3번은 너무나도 취약한 부분입니다. 부서내에서 업무 수행 보고를 부풀려 해야 하거나 할 때가 있습니다.
이런 문제들이 개입되다보면, 결국 이 개발팀의 속도 추정치가 불확실 해지고, 이는 전체 프로젝트 스케쥴에 큰 영향을 미치게죠.

그렇다 보니 개발 스케쥴을 신뢰 할 수 없게 되고, 관리자는 임의대로 스케쥴을 조정하게 되는 악 순환이 반복될 가능성이 있습니다.

당연히 개발팀장 역시 자신이 보고한 개발 스케쥴에 대해서도 자신감이 없으니 강력한 주장(?)은 더더욱 힘들게 됩니다.
저 역시 이런 오류들을 격다보니, 정확한 팀의 속도를 추정은 불가능 하더군요.


그래서 향후 새로운 프로젝트를 진행할 시에는 3번과 같은 경우는 없도록 해야겠다는 걸 뼈저리게 느꼈답니다.


릴리스 계획 과정 동안 어떤 개발자가 어떤 사용자 스토리나 작업을 수행할 것인지 명시하는 계획을 만들거나, 이터레이션 동안 어떤 작업이 어떤 순서대로 이뤄져야 하는지를 명시하는 계획을 만들지는 않는다. 릴리스 계획 과정동안 그 정도로 자세한 계획을 만드는 것은 위험한 일이다. 누가 무슨 일을 어떤 순서대로 할 것이냐 하는 문제는 그 작업을 할 사람이 결정하는 것이 좋고, 가능한 한 뒤로 미뤄두는 것이 좋다. 릴리스 계획에 명시되는 것은 사용자에게 전달될 기능의 명세인 사용자 스토리이지 실제로 수행될 개별적 작업들이 아니다. 
그런 것들을 릴리스 계획에 포함시키는 것은 너무 이른 일이다.
사용자 스토리들 가운데에는 개별적인 엔지니어링 작업들로 분할하기에는 충분히 이해되지 않은 스토리들도 있을 수도 있다. 
14장[이터레이션 계획 과정] 에서도 살펴보겠지만, 개발팀은 결국 릴리스 계획에 포함된 사용자 스토리들을 개별적인 작업들로 분할하게 된다. 하지만 그러한 분할 작업은 해당 스토리가 속한 이터레이션을 시작할 때까지는 하지 않는다.
 핵심이 될만한 키워드라서 강조 했습니다.  사실 프로젝트 계획을 세우다보면 너무 세부 사항까지 들어가게 되는데 이를 막고자 하는 예기 인듯 합니다.

만일 프로젝트나 조직 그리고 작업 환경이 허락한다면 릴리스 계획안에 부가적인 정보들을 당연히 포함시킬 수 있다. 일례로, 계획 이면에 깔려있는 어떤 핵심적인 가정들을 릴리스 계획에 명시해 둘 수도 있다. 그런 가정들로는 누가 개발팀에 포함되어야 하고, 이터레이션 길이는 얼마나 되어야 하고, 첫번째 이터레이션이 언제부터는 시작되어야 하고, 마지막 이터레이션은 언제까지 끝나야 한다는 등의 가정이 있을 수 있겠다. 제 21장 [계획과 소통]에서는 릴리스 계획에 대한 의견을 서로 나눌때 포함 시키면 좋은 부가적인 정보들에 대해서 설명한다.


만족 조건 결정 -> 사용자 스토리 추정 -> 이터레이션 길이 결정           -> 스토리 선정 및 릴리스 날짜 결정  
             ↑                                            속도 추정                                                          |
             |                                            사용자 스토리들 간의 우선순위 결정                       |
             +-----------------------------------------------------------------------------+


만족 조건 결정
릴리스 계획과정을 시작하기 전에 프로젝트의 성패 여부를 판정할 기준을 아는 것이 중요하다.
대부분의 프로젝트의 경우 가장 결정적인 기준은 절감되거나 창출되는 돈의 양이다. 프로젝트가 이런 재정적 목표를 만족할 것인지를 판단하기 위해 대부분의 프로젝트들은 일정과 범위 그리고 자원이라는 3대 기준을 사용한다. 그것은 제품 책임자가 정하는 만족 조건들이라는 것이 일정과 봄위 그리고 자원에 관한 목표들로 정의된다는 것을 의미한다.

제품 책임자는 릴리스 계획 과정에서 행해지는 미팅 때마다 이들 각각에 대한 목표들을 꺼내 보여줄 것이다. 가령 제품 책임자는 네 개의 테마에 대해(스토리 점수 기준으로 200점에 달하는)인원 추가 없이 3개월 안에 개발 완료를 바랄수도 있다. 각자의 기준들에 대해 전부 목표를 정해둘 수도 있지만, 보통은 하나의 기준이 지배적으로 작용한다. 즉, 일반적인 프로젝트들은 날짜를 맞추는 것을 목표로 하거나 아니면 기능을 맞추는 것을 목표로 한다는 것이다. 일정 중심적인 프로젝트는 특정한 날짜까지는 릴리스가 나와야 하는 프로젝트이며, 어떤 기능이 포함되어야 하느냐는 그렇게 중요하지 않다.
기능 중심적인 프로젝트는 가능한한 빨리 릴리스를 내놓고자 하는 프로젝트이긴 하지만, 어떤 기능이 제품에 포함되느냐가 보다 더 중요한 프로젝트이다.

만족 조건 결정이라는 것이 책의 내용으로도 잘 이해가 안되는 부분이군요. 과연 만족할만한 조건이란 것이 위에서 나열한 것들로 결정할 수 있는가? 그럼 일정이 중요하다고 한다면 만족할만한 조건이란 무엇인가? 예가 없으니 너무 막연하군요.


스토리와 릴리즈 날짜 선정

이 시점에는 개발팀의 이터레이션 당 속도를 알고 있는 상태일 것이고, 얼마나 많은 이터레이션이 필요할지에 대한 기본적인 가정은 되어 있는 상태일 것이다. 그렇다면 릴리스가 만족 조건들을 충족하도록 계획될 수 있는지 살펴볼 순서이다.
프로젝트가 기능 중심적이라면 모든 필요 기능들의 추정치를 합한 다음 그 값을 예상 속도로 나눈다. 그렇게 하면 필요한 기능 구현을 완료하는 데 필요한 이터레이션의 횟수를 구할 수 있다.
프로젝트가 일정 중심적이라면 달력을 보고 이터레이션의 횟수를 정한다. 이터레이션의 횟수를 추정된 속도로 곱하면 얼마나 많은 스토리 점수를 릴리스 안에 넣을 수 있을지 알 수 있다. 그리고 그 만큼의 점수나 이상적 작업일을 사용자 스토리의 우선순위 리스트에 적용하여 얼마나 많은 기능을 지정된 시간 안에 구현할 수 있을지를 알아낸다.
그 다음 물어야 할 질문은 릴리스 계획이 얼마나 상세해야 하는가이다.
어떤 팀들은 각 이터레이션 안에 무엇을 개발해야 하는지가 잘 드러나는 릴리스 계획 쪽을 선호한다. 어떤 팀들은 다음 릴리스까지 어떤 기능들을 개발해야 하는지 정도만 간단히 결정하는 쪽을 선호한다. 각 이터레이션 안에서 무엇을 해야 하는가는 나중에 결정하겠다는 것이다. 이 중 어떤 방식을 택할것이냐 하는 것을 릴리스 계획 과정에서 토의하고 결정하여야 한다.

각각의 접근 법에는 나름대로의 장단점이 있다. 분명한 것은, 특정한 기능을 특정한 이터레이션에 배정하는 작업은 더 많은 시간을 필요로 한다는 것인다. 하지만 그정도로 상세하게 작업하게 되면 여러 팀들이 협력하여 일을 진행해야 할 경우 유리하다. 한편,작업을 특정한 이터레이션에 할당하는 과정을 생략하면 상세함은 떨어질지라도 시간은 덜 잡아먹는다. 더욱이 어떤 작업을 어떤 이터레시션에 배정할 것인지를 미리 결정하더라도 이터레이션이 실제로 시작되는 시점보다는 적은 지식을 가진 상태에서 하게되는데, 프로젝트 진행과정에서 더 많은 지식을 축적하다 보면 계획은 변경되게 마련이다. 그사실에 비추어 본다면, 작업을 특정한 이터레이션에 배정하기 위해 시간과 노력을 들이는 것은 바람직하지 않다. 물론 프로젝트에 따라서는 그런 사전 작업을 할만한 가치가 있는 경우도 있다. 
필자가 적절한 타협점이라고 생각하는 방법은 , 첫 번째 이터레이션부터 세 번째 이터레이션까지는 각 이터레이션에서 어떤 작업을 수행할지를 미리 정하고, 릴리스 계획의 나머지 부분에 대해서는 하지 않는 것이다. 맨 처음 이터레이션에 작업을 할당해 두는 것은 당연히 의미가 있다. 이터레이션이 곧바로 수행될 것이라면 더더욱 그렇다.
전형적인 릴리스 계획 과정 동안에는 아주 많은 타협적인 질문들과 가정적인 질문들이 제기된다. 그러므로 다음 릴리스와 그 이터레이션동안 무엇을 넣고 무엇을 뺄지를 능숙하게 처리하기 위한 손쉬운 방법이 필요하다. 가장 좋은 방법은 모든 사람들이 배석한다는 가정하에, 사용자 스토리나 기능이 적힌 3x5 인치짜리 카드나 포스트잇 카드를 놓고 작업하는 것이다. 소프트웨어와는 달리 카드는 실체적이며 쉽게 공유될 수 있다.
릴리스를 계획하기 위해서 제품 책임자는 그가 생각하기에 제일 우선순위가 높아서 첫 번째 이터레이션에 들어가야 한다고 생각되는 항목들을 고른다. 카드는 어떤 스토리가 어떤 이터레이션에 들어가야 되는지 명확하게 드러나도록 배열된다.

그림.이터레이션에 들어갈 작업들을 열로 나누어 배열하기.
여기 그림이 이터레이션이 가로로 배열되고, 세로로 스토리들이 배열된 그림이 들어옴


릴리스 계획의 갱신

릴리스 계획을 만들어 두고 어딘가에 처박아 둔 다음 건드리지 않으면 곤란하다. 릴리스 계획은 수시로 점검되어야 하며 주기적으로 갱신되어야 한다. 개발팀의 속도가 일정하게 유지되고 이터레이션 계획 과정에서 뭔가 깜짝 놀랄 만한 사건이 발생하지 않으면 네 주나 여섯 주 정도는 릴리스 계획을 갱신하지 않고 놔두어도 괜찮지 않을까 생각할 수도 있다. 하지만 많은 프로젝트들은 이터레이션이 끝날 때마다 릴리스 계획을 재점검한다는 규칙을 지켜서 좋은 성과를 내고 있다.

사용자 스토리 선정
이번 릴리스에 약 48점 만큼의 스토리를 둘 수 있는 상황에서,
팀원들은 제품 책임자가 가장 낮은 우선순위를 준 "시스템 관리자는 사용자 그룹과 권한을 설정할 수 있다."는 스토리가 시스템에 반드시 필요한 스토리라는 사실을 지적하였다. 이 스토리는 3점짜리이다. 이스토리를 릴리스에 포함시키면 스토리 점수 총합은 49점이 되어 48점을 넘어버린다. 
48점이라는 것도 역시 추정이기 때문에 49점을 그대로 수용할 수도 있지만, 49점을 수용하지 않기로 개발팀이 결정했다고 한다면,
1점만큼의 스토리를 릴리스에서 빼야 한다. 그래서 8점짜리 스토리를 빼버리기로 결정하였다. 이로서 41점이 되었는데 남은 자리에 3점짜리 스토리를 추가할 수도 있게 되었다.
하지만, 제품 책임자는 41점으로 줄어든 만큼 개발 팀이 일정을 1점 만큼 앞당길 수 있다면, 추후에 8점짜리 스토리를 제품일정에 추가할 수 있을 거라 생각하여 추가로 3점짜리 스토리를 포함하지 않고 놔두었다.

여기서 41점 짜리로 그대로 놔둔것은 매우 좋은 선택인것 같군요.
첫번째로, 48점 짜리 릴리스를 41점으로 줄이고 일정을 당길 수 있다면, 계획보다 많은 리소스를 줄일 수 있을것입니다.
두번째로, 41점 짜리 릴리스가 되어 7점이 아깝다고 생각 할 수도 있겠지만, 사실 새로 추가하려는 3점 짜리는 이미 우선순위에서 밀린 3점짜리 스토리라는 것입니다. 즉, 프로젝트상 8점 짜리 스토리보다 우선순위가 밀리는 것인데, 그다지 중요하지 않은 3점 짜리가 이번 릴리스에 들어감으로 해서 8점짜리 스토리가 들어간 다음 릴리즈 시기를 앞당길 수 있는 기회를 없애버릴 수 있기 때문이죠.


이 글을 읽기 전까지는 저도 스토리와 이터레이션과의 관계에만 몰두해서 프로젝트를 진행하면서 스토리와 이터레이션을 단지 TODO 관리 정도로 밖에 사용을 못했는데( 사실 이것도 굉장히 효과가 있었습니다.)
프로젝트 전반적인 흐름과 어떻게 매칭을 해나가야 하는지에 대해 좀더 깊게 생각해보게 되었습니다.




반응형
system 내의 binary 호환성을 갖추기 위해서는 가장 먼저 고려해야 할 사항이 바로 ABI를 맞추는 것이다.
 
ABI 란? 
Application Binary Interface 의 약자로, 바이너리(binary), 즉 실행파일이나 라이브러리 간의 저수준(low level)의 인터페이스를 의미합니다.
호출형식이나 데이터 형식이 동일한 모듈들끼리만 모듈내의 함수 호출이나 데이터 사용이 가능해 지는 것이 당연하겠죠?
 
ABI를 결정하는 가장 큰 요소는 Compiler입니다. 
C++ Compiler의 경우, 각 compiler별로 name mangling 규칙이 다른데요.
이때문에 서로다른 compiler에서 만들어진 바이너리간의 호출이 불가능해질 수도 있게 됩니다.
                 name mangling 참조  
 
Compilervoid h(int)void h(int, char)void h(void)
Intel C++ 8.0 for Linux _Z1hi _Z1hic _Z1hv
HP aC++ A.05.55 IA-64
IAR EWARM C++
GCC 3.x and higher
Clang 1.x and higher[3]
GCC 2.9.x h__Fi h__Fic h__Fv
HP aC++ A.03.45 PA-RISC
Microsoft Visual C++ v6-v10 (mangling details) ?h@@YAXH@Z ?h@@YAXHD@Z ?h@@YAXXZ
Digital Mars C++
Borland C++ v3.1 @h$qi @h$qizc @h$qv
OpenVMS C++ v6.5 (ARM mode) H__XI H__XIC H__XV
OpenVMS C++ v6.5 (ANSI mode)   CXX$__7H__FIC26CDH77 CXX$__7H__FV2CB06E8
OpenVMS C++ X7.1 IA-64 CXX$_Z1HI2DSQ26A CXX$_Z1HIC2NP3LI4 CXX$_Z1HV0BCA19V
SunPro CC __1cBh6Fi_v_ __1cBh6Fic_v_ __1cBh6F_v_
Tru64 C++ v6.5 (ARM mode) h__Xi h__Xic h__Xv
Tru64 C++ v6.5 (ANSI mode) __7h__Fi __7h__Fic __7h__Fv
Watcom C++ 10.6 W?h$n(i)v W?h$n(ia)v W?h$n()v
 

 

ABI는 calling convention,  데이타 타입, 사이즈(size),argument , 등등에 대한 내용이 있습니다.

 

인텔의 경우 iBCS라는 인텔에서 정의한 표준을 정의 하고 있습니다.

 

 

 

 
 
EABI 란 ? 

Embedded ABI 

 

 

EABI( 임베디드 애플리케이션 바이너리 인터페이스 )는 임베디드 운영 체제 와 함께 사용하기 위한 파일 형식 , 데이터 유형, 레지스터 사용, 스택 프레임 구성 및 임베디드 소프트웨어 프로그램 의 기능 매개변수 전달에 대한 표준 규칙을 지정합니다 .

EABI를 지원하는 컴파일러는 다른 컴파일러에서 생성된 코드와 호환되는 개체 코드를 생성하므로 개발자는 한 컴파일러로 생성된 라이브러리를 다른 컴파일러로 생성된 개체 코드와 연결할 수 있습니다. 자체 어셈블리 언어 코드를 작성하는 개발자는 호환 컴파일러에서 생성된 어셈블리와 인터페이스할 수도 있습니다.

EABI는 임베디드 시스템의 제한된 리소스 내에서 성능을 최적화하도록 설계되었습니다. 따라서 EABI는 복잡한 운영 체제에서 커널과 사용자 코드 간에 이루어지는 대부분의 추상화를 생략합니다. 예를 들어, 더 작은 실행 파일과 더 빠른 로딩을 허용하기 위해 동적 연결을 피할 수 있으며, 고정된 레지스터 사용을 통해 더 컴팩트한 스택과 커널 호출을 허용하고, 권한 있는 모드에서 응용 프로그램을 실행하면 장치 드라이버를 호출하는 간접적인 작업 없이 사용자 지정 하드웨어 작업에 직접 액세스할 수 있습니다. EABI의 선택은 성능에 영향을 미칠 수 있습니다. 

널리 사용되는 EABI에는 PowerPC , Arm EABI   MIPS EABI 포함됩니다. C 라이브러리와 같은 특정 소프트웨어 구현은 보다 구체적인 ABI 형성하기 위해 추가적인 제한을 부과할 있습니다 가지 예는 ARM GNU OABI EABI이며 ARM EABI 하위 집합입니다.

 
 
Link: en.wikipedia.org
An embedded-application binary interface (EABI) specifies standard conventions for file formats, data types, register usage, stack frame organization, and function parameter passing of an embedded software program.
 
 
 
 
 
 
반응형

Framework 개발에서 조직과 관련된 part article에 재미있는 내용이 있어서 공유합니다.

 

 

Conways Law

- 여러분이 하나의 컴파일러를 만들기 위해 4개의 팀을 만든다면, 여러분은 4단계로 구분된 컴파일러를 얻게 될것이다.

 

이 내용이 무슨 예기인가 하면,

팀 구조가 소프트웨어의 구조가 된다는 것입니다. 따라서 당연히 팀을 구성한 후 요구사항을 분석한다면, 팀 구조에 맞춰 분석이 이뤄지기 때문에, 팀 구조 그대로 소프트웨어 구조가 나올 수 밖에 없다는 예기….

 

때문에 소프트웨어가 어떤 특성을 가지고 있는지 파악되기도 전에 소프트웨어의 큰 구조를 정해버리는 것과 같은 오류를 범한 것과 같다는 의미 입니다..

 

그래서 팀을 구성하기 이전, 프로젝트의 도메인 전문가나 구성원 전체가 모여, 프로세스를 정제한 후에 프로세스에 맞게 조직을 구성할 필요가 있다는 의미입니다.

 

 

[조직 구조에 따른 설계방법]

 

만약, 이미 조직이 구성되어있다면, 조직 구조와 문화를 이해해서 적합한 프레임워크를 구성해야 한다.

 

-       팀의 크기를 고려할 것

만약 프레임워크를 개발하는 팀은 작은 반면에 프레임워크를 사용하고자 하는 팀이 많다면 모든 팀의 요구사항을 들어주기는 거의 불가능하다그렇기 때문에 파레토의 법칙인 80/20 룰에 의거해서 프레임워크를 구성해야 된다. 프레임워크 사용자들이 가장 많이 활용하고 사용하는 부분들을 집중적으로 만들어야 한다.

반면 프레임워크를 구성하는 팀의 여유가 있어, 충분히 많은 기능을 설계할 수 있다면, 많은 요구사항들을 수렴할 수 있기 때문에 모듈간의 일관성을 유지하는데 초점을 두고 구축해야 한다.

일관성을 유지하기 위해서는 끊임없이 프로토타입을 만들고 Feedback을 받아 설계를 정제해야 한다.

 

-       조직의 문화를 고려해라.

만약 조직이 고객중심의 문화를 가지고 있는 화사라면, End-2-End 시나리오들을 먼저 추출한 후 시나리오를 잘 지원하기 위한 형태로 프레임워크를 설계해야 된다.

반면 기술을 중요하게 생각하는 하위 레벨의 회사라면, 기술의 변화를 쉽게 수용할 수 있게 확장성을 중요시 여겨 설계해야 한다.

 

-       조직의 의사 결정 메커니즘을 고려해라.

개별적인 맨 파워들을 중시하는 회사라면 대부분 Time to market을 잘 지원할 수 있어야 되므로 빠른 의사 결정이 지원하는 것에 중점을 두고 설계해야 한다. 또한 계층적인 조직구조를 가진 회사는 서로 간의 이질적인 의사 표현 방법을 통합하고 상호 운영하는데 초점을 맞추어야 할 것이다.

 

 

 

 

+ Recent posts