Starling performance test

Project/Programming 2012. 1. 10. 21:58

package {
	import starling.events.Event;
	import starling.core.Starling;
	import starling.display.Sprite;
	import starling.display.Button;
	import starling.textures.Texture;
	import starling.display.DisplayObject;
	import starling.display.Image;
	import starling.utils.deg2rad;
	import flash.display.Bitmap;


	public class Demo extends Sprite {

		[Embed(source = "f60.png")]
		private var MyBitmap:Class;
		
		private var _myTexture:Texture;
		private var _arrButterflys:Vector.<Butterfly>;

		public function Demo() {
			// addedToStage 이벤트에 대한 리스너 추가
			addEventListener( Event.ADDED_TO_STAGE , onAddedToStage);
		}


		private function onAddedToStage(e:Event):void {
			var myBitmap:Bitmap = new MyBitmap() as Bitmap;
			_myTexture = Texture.fromBitmap(myBitmap);

			var len:int = 800;
			
			_arrButterflys = new Vector.<Butterfly>(len, false);
			
			for (var i:int = 0; i<len; i++) {
				var fly:Butterfly = new Butterfly(_myTexture);
				
				fly.alpha = Math.random();
				fly.destX = Math.random()*stage.stageWidth;
				fly.destY = Math.random()*stage.stageHeight;
				
				fly.setVertexColor(0, Math.random()*0xFFFFFF);
				fly.setVertexColor(1, Math.random()*0xFFFFFF);
				fly.setVertexColor(2, Math.random()*0xFFFFFF);
				fly.setVertexColor(3, Math.random()*0xFFFFFF);
				
				fly.x = Math.random()*stage.stageWidth;
				fly.y = Math.random()*stage.stageHeight;
				fly.rotation = deg2rad(Math.random()*360);
				
				fly.pivotX = fly.width >> 1;
				fly.pivotY = fly.height >> 1;
				
				_arrButterflys[i] = fly;
				addChild(fly);
			}

			stage.addEventListener(Event.ENTER_FRAME, onFrame);
		}
		
		private function onFrame(e:Event):void{

			var len:uint = _arrButterflys.length;

			for (var i:int = 0; i < len; i++){

				// move the sausages around
				var fly:Butterfly = _arrButterflys[i];
				
				fly.x -= ( fly.x - fly.destX ) * .1;
				fly.y -= ( fly.y - fly.destY ) * .1;

				if (Math.abs(fly.x - fly.destX)<1 && Math.abs(fly.y-fly.destY) < 1){
					fly.destX = Math.random()*stage.stageWidth;
					fly.destY = Math.random()*stage.stageHeight;
					fly.rotation = deg2rad(Math.random()*360);
				}
			}
		}

		public override function dispose():void {
			removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			_myTexture.dispose();
			super.dispose();
		}
	}
}

import starling.display.Image;
import starling.textures.Texture;

class Butterfly extends Image{
	
	public var destX:Number = 0;
	public var destY:Number = 0;
	
	public function Butterfly(inTexture:Texture):void{
		super(inTexture);
	}
}

    

설정

트랙백

댓글

[Starling-07] MovieClip 클래스를 이용한 애니메이션

Project/Programming 2012. 1. 9. 00:49
Flash에서 애니메이션이라고 하면 역시 MovieClip이지만 Starling에도 MovieClip 클래스가 있다. 물론 애니메이션을 위한 클래스지만 Starling의 MovieClip은 화면에 표시할 수 있는 것이 비트맵 이미지 또는 색상을 지정한 사각형 뿐이다. 따라서 MovieClip라는 이름은 같지만 Starling의 MovieClip은 프레임마다 할당된 비트맵을 표시하는 클래스인 것이다.

또한 Starling MovieClip의 자식 객체를 관리하거나 프레임에 스크립트가 들어가는 기능은 없다. 이 점도 Flash Player의 MovieClip과는 크게 다르다. (Starling은 표시 목록의 관리는 Sprite의 책임이다. 한편, MovieClip은 Image 클래스에 타임 라인 기능을 더한 Image의 서브 클래스다. MovieClip이 Sprite의 하위 클래스인 Flash Player와는 달리, 양쪽의 역할은 분리되어 있다.)


스프라이트 시트와 TextureAtlas
MovieClip의 각 프레임을 볼 때 GPU는 표시 프레임에 할당된 텍스처, 셰이더에서 사용할 수 있도록 준비가 이루어진다. 이 때 텍스처가 프레임마다 물리적으로 다른 비트맵 파일이면 프레임을 진행할 때마다 텍스처 전환이 발생한다.

텍스처 전환 처리에는 당연히 시간이 걸린다. 또한 텍스처의 GPU에 업로드가 필요할 때 추가 오버헤드가 증가한다. 일반적으로 이 문제를 해결하기 위해 각 프레임의 텍스처를 하나의 파일에 정의한다. 이 것을 스프 라이트 시트라고  한다.

아래 그림은 Starling 샘플에 포함된 스프라이트 시트의 일부를 자른 것이다.




여러 프레임에 해당하는 텍스처가 1개의 파일로 되어 있으면 GPU를 이용해서 사용 위치를 바꾸는 것만으로 텍스처 자체를 전환하지 않고 렌더링 처리가 가능하다. 따라서 고속 프레임을 업데이트할 수 있다.

또한 Stage3D에서 취급할 수 있는 텍스처의 폭은 2의 계승이라는 규칙 때문에, 그 이외의 너비 텍스처는 Starling 내부에 여분의 사전 처리가 발생한다. 하지만 스프라이트 시트의 경우 표시되는 텍스처가 더 큰 텍스처(스프라이트시트)가 아니기 때문에 개별 텍스처 너비 사이즈를 걱정할 필요가 없다.

이 것을 최적화한 1단계가 TextureAtlas다. TextureAtlas는 여러 스프라이트시트를 하나의 파일에 정리한 것이다. 동시에 여러 애니메이션을 재생하는 경우 특히 유용하다. TextureAtlas를 만들기 위해, 차기 버전의 Flash Professional CS6에서 지원되는 것 같다. 벡터 애니메이션 스프라이트시트로 내보내기 기능을 기다리거나 Texture Packer 등의 도구를 이용하면 된다.


TextureAtlas 로드
TextureAtlas를 사용하여 프레임마다 각각 TextureAtlas의 어떤 영역을 표시할지 정보가 필요하다. 따라서 다음과 같은 형식으로 각 프레임의 텍스처 정보를 지정하게 되어 있다. 도구를 사용하여 TextureAtlas를 생성하는 경우 이러한 XML 파일도 동시에 생성된다.

  
  
  
  


TextureAtlas 태그 imagePath 속성은 TextureAtlas의 파일 이름이다. SubTexutre 태그의 name 속성은 애니메이션의 고유 이름 뒤에 프레임 번호를 추가한 것이다. 나머지 x, y, height, width에서 텍스처로 사용 영역을 지정한다. (실제로 SubTexture는 텍스처의 일부를 처리하는 클래스가 있다) TextureAtlas가 준비되면 다음과 같은 프로그램에 포함한다.
[Embed (source = "atlas.png")]
private static const MyBitmap:Class;
 
[Embed (source = "atlas.xml"mimeType = "application / octet - stream")]
private static const MyXml:Class;

이러한 정보는 TextureAtlas라는 클래스에서 함께 관리한다. TextureAtlas(PNG 파일)은 일단 Texture 클래스 로딩하면서 XML 파일과 함께 TextureAtras 생성자에 전달한다. TextureAtlas 객체에서 고유 이름을 지정하여 Texture(실제로는 SubTexture의) 벡터를 얻을 수 있다. 이 때 사용하는 메소드가 getTextures()다.
import starling.textures.TextureAtlas;

	private function onAddedToStage(e:Event):void {
		// 텍스처 아틀라스로드
		var myTexture:Texture = Texture.fromBitmap(new MyBitmap);
		// 텍스처 아틀라스의 영역 정보 가져오기
		var myXml:XML = XML(new MyXml);

		// TextureAtlas 인스턴스 생성
		var myTextureAtlas:TextureAtlas = new TextureAtlas(myTexture,myXml);
		// "walk_"를 식별 이름으로 가진 Texture 벡터 생성
		var frames:Vector. = myTextureAtlas.getTextures("walk_");

		// ... 앞으로는 아래에 계속
	}

벡터의 첫 번째 텍스처의 크기가 애니메이션의 영역을 결정한다. 애니메이션 여기까지 왔으면 나머지는 MovieClip의 인스턴스를 생성하면 된다. MovieClip 생성자의 인수에서 얻은 텍스처 벡터를 지정한다.
import starling.display.MovieClip;

	private var myMovieClip:MovieClip;

	private function onAddedToStage(e:Event):void {
		//... 위에서 계속

		// MovieClip 객체의 생성
		myMovieClip = new MovieClip(frames);

		// 애니메이션 재생 시작
		Starling.juggler.add(myMovieClip);
		addChild(myMovieClip);
	}

알겠지만, Tween뿐만 아니라 MovieClip의 재생도 Juggler을 사용한다. MovieClip도 IAnimatable의 서브클래스다. Juggler에 MovieClip을 추가하면 재생이 시작된다. 재생을 제어하는​​ 세 가지 메소드가 포함되어 있다.
myMovieClip.play();
myMovieClip.pause();
myMovieClip.stop();

pause()를 실행한 다음에 play()를 실행하면 현재 상태부터 재생되지만 stop()을 실행한 다음에 play()를 호출하면 처음 부터 다시 재생된다. 애니메이션은 default로 반복 재생된다. 이 설정은 loop 속성을 설정하여 바꿀 수 있다. 재생 여부 isPlaying 속성을 확인한다. 애니메이션이 끝까지 재생되면 movieComplete 이벤트가 발생한다. 재생이 완​​료되면 다음 작업으로 이동하고자하는 경우에 사용할 수 있을 것이다.
myMovieClip.addEventListener(Event.MOVIE_COMPLETED, onMovieComplete);

애니메이션이 반복되는 경우에는 재생이 완​​료될 때마다 movieComplete 이벤트가 발생한다. MovieClip의 부모 Sprite가 Stage에서 제거되면 MovieClip 재생을 중지해야한다. 그래서 다음과 같은 코드를 추가한다.
addEventListener(Event.REMOVED_FROM_STAGE,onRemovedFromStage);

	private function onRemovedFromStage(event:Event):void {
		Starling.juggler.remove(myMovieClip);
	}

Juggler의 remove() 메소드는 MovieClip뿐만 아니라 Tween도 삭제할 수 있다. 또 다른 MovieClip 사용 MovieClip의 생성자의 두 번째 파라미터에 임의의 프레임 속도를 지정할 수 있다.
// 40 fps를 지정
myMovieClip = new MovieClip (frames, 40);

MovieClip마다 다른 프레임 속도를 지정할 수 있다. 재생중인 프레임 속도는 fps 속성에서 가져올 수 있다. 또한 fps 속성 값을 설정하여 프레임 속도를 변경할 수도 있다. 그리고 모든 프레임에 대해 별도의 재생 시간을 지정할 수 있다. 아래는 5 번째 프레임을 2 초 동안 재생하도록 설정하는 예다.
myMovieClip.setFrameDuration(5, 2);

나중에 프레임을 추가하거나 삭제할 수도 있다. 이를 위해서 addFrameAt() removeFrameAt() 메서드를 사용한다. 아래는 5 프레임 애니메이션을 10번 째 프레임에 추가하거나 5 프레임을 제거하는 것이다. 
myMovieClip.addFrameAt(5, frames [10]);
myMovieClip.removeFrameAt(5);

프레임의 텍스처를 바꿀 수도 있다. setFrameTexture() 메소드를 사용하면 된다.
myMovieClip.setFrameTexture(5, frames [10]);

프레임에 소리를 연결할 수도 있다. setFrameSound() 메서드를 사용한다.
[Embed (source = "step.mp3")]

private static const StepSound:Class;
 
myMovieClip.setFrameSound (5, new StepSound() as Sound);

이제 5번 째 프레임이 표시되는 타이밍에 지정한 소리가 재생된다. 프레임에 직접 스크립트를 연결할 수는 없다. 그 대신 Juggler.delayCall() 메서드를 사용할 수 있다. 이상에서 Starling 애니메이션의 기본은 끝이다. Starling 표현의 유연성은 CPU 렌더링보다 미약하다. 그러나 빠른 렌더링을 안정적으로 해야할 경우에 선택하면 적당할 것이다.


원본 : http://cuaoar.jp/2011/12/movieclip-starling.html


 


package {
	import starling.events.Event;
	import starling.display.Sprite;
	import starling.display.DisplayObject;
	import starling.display.Image;
	import starling.textures.Texture;
	import starling.textures.RenderTexture;
	import starling.textures.TextureAtlas;
	import starling.display.MovieClip;
	import starling.core.Starling;

	public class Demo extends Sprite {

		[Embed(source = "patch.png")]
		private var MyBitmap:Class;

		[Embed(source = "patch.xml",mimeType = "application/octet-stream")]
		private var MyXml:Class;
		
		private var _arrMovieClips:Array;


		public function Demo() {
			// addedToStage 이벤트에 대한 리스너 추가
			addEventListener(Event.ADDED_TO_STAGE,onAddedToStage);
		}
		private function onAddedToStage(e:Event):void {

			// 텍스처 아틀라스로드
			var myTexture:Texture = Texture.fromBitmap(new MyBitmap());

			// 텍스처 아틀라스의 영역 정보 가져오기
			var myXml:XML = XML(new MyXml());

			// TextureAtlas 인스턴스 생성
			var myTextureAtlas:TextureAtlas = new TextureAtlas(myTexture,myXml);

			// "walk_"를 식별 이름으로 가진 Texture 벡터 생성
			var frames:Vector.<Texture>=myTextureAtlas.getTextures("patch_");

			// MovieClip 객체의 생성
			
			_arrMovieClips = [];
			var count:int = 20;
			for(var i:int=0;i<count;i++){
				var myMovieClip = new MovieClip(frames, 60);
				myMovieClip.x = 20+((stage.stageWidth-90)/count)*i;
				myMovieClip.y = stage.stageHeight - myMovieClip.height >> 1;
				Starling.juggler.add(myMovieClip);
				_arrMovieClips.push(myMovieClip);
				addChild(myMovieClip);
				
			}
			
		//	myMovieClip.setFrameDuration(5, 2);

		//	myMovieClip.addFrameAt(5,frames[10]);
		//	myMovieClip.removeFrameAt(5);
		}

		private function setAlign(inTarget:DisplayObject):void{
			inTarget.x = stage.stageWidth >> 1;
			inTarget.y = stage.stageHeight >> 1;
		}

		public override function dispose():void {
			removeEventListener(Event.ADDED_TO_STAGE,onAddedToStage);
			super.dispose();
		}
	}
}

    

설정

트랙백

댓글

[Starling-03] Flash 컨텐츠 표시의 기본

Programming/Framework 2012. 1. 5. 01:50
Starling은 Stage3D를 이용한 빠른 2D 드로잉을 실현하기 위해 설계된 framework이다. 이전 기사에서 개요와 간단한 사용법을 소개했다. Starling에서는 3가지 방법으로 애니메이션을 사용할 수 있다. 이 방법을 여러 번에 나눠서 소개한다. 기존의 애니메이션 방법과 비교해 보자.

개발 환경 준비
Starling의 개발 환경은 Flash Player 11과 AIR 3가 필요하다. 툴은 Flash Builer 4.6을 권장한다. Flash Professional CS5 또는 CS5.5를 사용하는 경우 다음 문서에서 소개하는 기능확장이 편리하다.
Flash Professional CS5 or CS5.5에 Flash Player 11 설정 MXP

그리고 Starling framework는 github에서 구할 수 있다.
PrimaryFeather / Starling - Framework / zipball

위 링크에서 다운로드한 zip에 포함되어 있는 SWC 파일을 경로에 추가하면 Starling 애플리케이션을 개발 할 수 있다. 또한 혼합 모드에 direct를 지정하지 않으면 제작에 성공해도 화면에 표시할 수 없다. 따라서 SWF 경우 wmode = direct를, AIR일 경우 <renderMode> direct </renderMode> 로 지정하는 것을 잊지 말아야한다.

Starling 인스턴스 생성
Starling로 렌더링하려면 먼저 Starling의 인스턴스를 생성한 다음 start() 메소드를 호출한다. 이 부분은 어떤 Starling을 개발에도 그대로 사용할 수 있다. 아래가 가장 간단한 예제이므로 사용해보자. fla 파일에서 document class로 사용하는 것이 편하다.

package{
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import starling.core.Starling;

        public class StartStarling extends Sprite{
		private var myStarling:Starling;

		public function StartStarling(){
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;

			// Starling의 인스턴스를 생성
			myStarling = new Starling(MyStarlingSprite,stage);
			// 그리기 작업을 시작
			myStarling.start();
		}
	}
}

Starling의 생성자 첫 번째 인수는 Starling의 Sprite다. 이 Sprite의 내용이 실제 화면 그리기에 사용된다. 그리기 정보는 Flash Player의 Sprite와 마찬가지로 자식 객체의 목록 구조와 같이 유지된다. 두 번째 인수는 표기 객체의 그리기 stage다. Starling 생성자는 5개의 인수를 가지지만 3 번째 이후 인수는 기본값을 가지고 있기 때문에 일반적으로 지정할 필요가 없다. 명시적으로 소프트웨어에서 3D 렌더링을 사용하려는 경우에는 5개의 인수를 작성할 수 있다. 마지막 인수가 혼합 모드를 지정한다.

// 5 번째 째의 인수로 그리기 모드를 지정 myStarling = new Starling (Game, stage, null, null, Context3DRenderMode.SOFTWARE );

이렇게 할 경우, 어떤 환경에서도 GPU로 렌더링 되지 않고 CPU로 처리하게 된다. 만약 실행 중에 소프트웨어 렌더링으로 대체되어 있는지 확인하고 싶다면 Starling 인스턴스 context.driverInfo 속성을 통해서 확인할 수 있다. 다음은 context3DCreate 이벤트를 사용하여 Stage3D를 초기화 한 후, 소프트웨어 렌더링의 프레임 속도를 절반으로 설정하는 예를 보여준다.

stage.stage3Ds[0].addEventListener (Event.CONTEXT3D_CREATE,onContext3DCreate); private function onContext3DCreate (event : Event) : void { if (Starling.context.driverInfo.toLowerCase() indexOf ( "software ")!=- 1){ Starling.current.nativeStage.frameRate = 30; } }

Starling 런타임 오류 검사를 수행하려는 경우에는 start()를 호출하기 전에 다음 설정을 추가한다.
myStarling.enableErrorChecking = true;

그러나 오류 검사 및 성능에 미치는 영향이 크기 때문에 디버깅 이외에는 설정하지 않는 것이 좋다. 기타 Starling 클래스의 기능은 다음 기회에 소개할 예정이다. 우선 온라인 문서는 이 곳에서 확인할 수 있다. Starling @ Starling Framework Reference

사용자 정의 Sprite 만들기

(참고 : 앞으로 Sprite와 같은 클래스 이름은 설명이 없는 한 모두 Starling 프레임워크에 종속된 클래스다. 익숙해질 때까지 실수에 주의가 필요하다.)

다음은 Starling의 생성자의 첫 번째 인자로 지정하는 Sprite 사용자 정의 클래스를 만든다. 만드는 단계는, 표시 오브젝트를 작성하고 Sprite에 addChild() 메소드를 추가하는 기존의 방식과 비슷하다. Stage3D의 그리기 단위는 삼각형이지만 Starling은 삼각형 2개를 기본으로 한다. 따라서 사각형에 해당하는 Quad 클래스의 인스턴스를 표시하는 방법에서 시작한다. 아래의 샘플은 화면에 사각형을 표시하는 것을 수행한다.

package { import Starling.display.Quad; import Starling.display.Sprite; public class MyStarlingSprite extends Sprite { private var myQuad:Quad; public function MyStarlingSprite() { // Quad의 인스턴스를 생성 myQuad = new Quad(200,200); // 우선 채우기 색상을 지정 myQuad.color = 0xABCDEF; // Sprite에 Quad 인스턴스를 추가 addChild(myQuad); } } }

위 코드를 실행하면 사각형이 화면 왼쪽에 그려진다. 사각형을 화면 중앙에 표시하려면 다음과 같이 Quad의 좌표를 설정한다.

myQuad.x = stage.stageWidth - myQuad.width>> 1; myQuad.y = stage.stageHeight - myQuad.height>> 1;
단, 위의 코드는 stage 속성에 대한 액세스를 포함한다. 따라서 Sprite가 초기화가 끝나기 전에 실행되면 오류가 발생한다. 그래서 addedToStage 이벤트를 이용한다. 이 addedToStage 이벤트는 Starling 이벤트지만, Flash Player의 addedToStage 이벤트 처럼 Stage가 이용 가능하게 된 것을 알려준다.

package { import Starling.events.Event; import Starling.display.Quad; import Starling.display.Sprite; public class MyStarlingSprite extends Sprite { private var myQuad:Quad; public function MyStarlingSprite() { // addedToStage 이벤트에 대한 수신기를 추가 addEventListener( Event.ADDED_TO_STAGE , onAddedToStage); } private function onAddedToStage(e : Event ):void { // Quad의 인스턴스를 생성 myQuad = new Quad(200,200); myQuad.color = 0xABCDEF; myQuad.x = stage.stageWidth - myQuad.width >> 1; myQuad.y = stage.stageHeight - myQuad.height >> 1; // Sprite에 Quad 인스턴스를 추가 addChild(myQuad); } } }

원문 : http://cuaoar.jp/2011/12/starling-flash.html
    

설정

트랙백

댓글

[AS3] 좋은 코드를 작성하기 위한 길

Programming/ActionScript 3.0 2008. 12. 27. 11:30
플래시는 에니메이션 저작툴이라는 디자인적인 탄생 배경을 탈피하고 많은 프로그래머들이 매력을 느끼는 컴퓨터 프로그래밍 언어로 발전하였다. 나는 어린 시절 장래 희망을 물어보면 컴퓨터 프로그래머라고 이야기하던 시절이 있었다.(그때는 5.25인치 디스크 한 장에 게임 하나가 들어가던 시절이었는데 아마도 게임을 하면서 스토리를 내 마음대로 바꾸고 싶었던 것 같다.)

하지만 그런 꿈은 삶의 역경 속에서 잊혀지고 나아가 컴퓨터 프로그래머라는 직업이 돈이 되는 직업은 아니라는 것을 알았을 무렵에는 이내 나의 꿈은 컴퓨터 프로그래머가 아니었다고 부정하였다. 결국 부정하던 장래희망의 굴레에 나를 몰아넣은 것은 플래시라고 할 수 있다. 내가 플래시를 처음 접했을 때는 이런 형태로 발전할지는 꿈에도 몰랐었으니 고로 나는 플래시에게 사기를 당한 것이다. ^^


나는 배우는 과정에 서있다. 항상 플래시의 발전을 따라가느라 정신 없이 허우적거리는 생활을 반복하고 있으니 아마도 내가 플래시라는 툴에서 손을 놓을 때까지 이러한 배움의 길은 끝이 없을 듯싶다.

배우는 과정에서 느꼈던 좋은 코드를 작성하는 방법에 대하여 이야기 해 볼까 한다. 본 내용은 일본 잡지에 실린 연재 코너의 내용을 ActionScript 버전으로 본인의 생각을 덧붙여 작성한 것임을 밝혀둔다.

좋은 코드란?
좋은 코드는 조직이나 프로젝트, 프로젝트 메니저에 따라서 그 정의가 다르게 해석될 수 있다. 하지만 보편적으로 좋은 코드로서 바람직한 방향은 있다.

정확하게 동작하는 것.
정확한 결과값을 도출하는 것은 신뢰할 수 있는 코드다.

빠르고 효율적으로 동작 하는 것.
결과 값을 도출하는 방법은 여러 가지가 있을 수 있다. 좋은 코드는 적절한 퍼포먼스로 동작한다.

방어적으로 버그를 생산하지 않는 것.
방어적 프로그래밍 방법론에 기초하여 정상적인 값이 들어 올 것이라고 가정하지 않고 부정확한 값이 와도 문제가 발생하지 않도록 방어적으로 코드를 작성한다. 이것은 처음에 열거한 정확하게 동작하는 것을 도와준다.

유지보수를 하기 쉬운 것.
프로젝트는 단기간에 수명을 다할 수도 있지만 우리가 상상하는 것보다도 길게 생명을 유지하는 것도 많다. 유지보수성을 높이는 것도 좋은 코드에 있어서 중요하다.

다른 사람이 봐도 이해하기 쉬운 것.
현재 작성한 코드를 미래에 자신이 보는 것과 현재 타인이 보는 것은 비슷하다고 볼 수 있다. 미래에 자신이 봐도 이해할 수 있는 코드는 좋은 코드라 할 수 있다.

쓸데없는 부분이 없는 것.
쓸데없는 코드를 작성하는 개발자는 없을 것이다. 다만 코드의 구현과정에서 기능 추가 및 다른 로직과의 연동 과정에서 불필요하게 파생하는 코드들은 지양할 필요가 있다.


좋은 코드를 작성하면 무엇이 좋은가?
좋은 코드는 프로젝트를 추진하고 성공적으로 이끌기 위한 기본적인 요소가 된다. 프로그래밍의 달인들은 심플하고, 유지보수성이 좋고 안정적인 코드를 빠른 속도로 작성한다. 테스트가 어려운 코드를 테스트가 가능하고 검증할 수 있는 코드로 변경함으로써 품질이나 생산성을 수백 배 높이기도 한다. 이것은 프로젝트의 성공에 있어서 큰 요소이다. 물론, 좋은 코드가 있으면 반드시 프로젝트가 성공하는 것은 아니다. 개발 프로세스나 메니지먼트, 커뮤니케이션등으로 좌우되는 경우가 더 많지만 이런 것들을 제외한다면 개발에 있어서 좋은 코드의 힘은 크다고 볼 수 있다.

프로그래머로서의 평가가 높아진다.
좋은 코드를 작성하는 프로그래머는 대체적으로 프로그래머로서 신뢰한다. 프로그래머로서의 평가가 조직으로서의 실제 평가나 이익에 결합될지는 소속하는 조직의 평가 제도나 프로그램 이외의 일도 포함하여 정해지는 것이 현실이다. 그렇다고 좋은 코드를 쓸 수 있는 것이 마이너스 평가로 이어지지는 않을 것이다.

일에 대한 만족감이나 자신감을 가질 수 있다.
두 번 다시 손대고 싶지 않은, 유지보수가 불가능한 코드를 써본 적이 있을 것이다. 이러한 낮은 퀄리티의 일을 해 놓으면 일에 대한 만족감을 얻을 수 없다. 반면 자신의 의지로 적절히 좋은 코드를 작성함으로써 품질이 높고 안정된 소프트웨어를 개발했을 때는 그에 대한 만족감도 높고 자신감을 갖고 일에 임할 수 있다. 앞으로 오랜 시간을 프로그래머로써 살아갈 것이라고 생각한다면 좋은 코드를 쓸 수 있는 레벨을 목표로 하는 것은 합리적인 일이다.

사실 좋은 코드를 작성하기 위해서는 하루아침에 이룰 수 없다. 그렇다면 좋은 코드를 작성하기 위해 구체적으로 무엇을 어떻게 해야 하는지를 살펴보자.

코드 리딩 - 읽어라, 코드를 읽고, 읽고, 또 읽어라.
음악이나 회화, 건축의 세계에서도 자신만의 발상으로 작품을 완성시키는 예술가는 없다. 다른 사람들의 작품을 보고 영향을 받거나 좋은 곳을 훔치거나 해서 자신의 작품을 만드는 것으로 작품을 낳아 왔다.

프로그래밍도 같다. 좋은 코드를 작성 하려면 좋은 코드이건 나쁜 코드이건 간에 다른 사람이 작성한 코드를 평소에 의식하고 읽는 것이 중요하다. 플래시는 특히 많은 오픈 소스가 인터넷에 열려 있기 때문에 다른 사람이 작성한 좋은 코드를 언제라도 부담 없이 읽을 수 있다. ActionScript 중급 정도의 실력자이지만 구조를 어떻게 만들어야 하는지 막막한 분은 특히 주목할 필요가 있다. 이런 단계에 머물러 있는 분이라면 코드리딩을 통해서 한 단계 발전한 자신을 발견할 수 있을 것이다.

코드리딩의 좋은 점은 알아도 코드를 읽는 방법을 모른다면 시작하기 힘든 일이다. 아래의 간단한 코드를 보면서 이야기 해보자.

package classes.data{

    import flash.events.Event;
    import classes.data.*;
    import classes.net.SimpleXMLLoader;
   
    public class DProvider extends SimpleXMLLoader{ // [1] 여기부터
           
        private var _xmlUrl:String;   
        private var _keywords:Array;
       
        public function DProvider(inUrl:String):void { // [2] 여기부터
            _xmlUrl = inUrl;
            addEventListener(Event.COMPLETE, onLoadedXmlHandler);
            loadXML(_xmlUrl);
        }    // [2] 여기까지

        private function onLoadedXmlHandler(e:Event):void { // [3] 여기부터
            var xml:XML = XML(data);
            _keywords = [];
           
            var len:int = xml.item.length();
            for (var i:int = 0; i < len; i++)
            {
                // [4] 여기부터
                _keywords.push(createKeyword(xml.item[i]));
            }
        }    // [3] 여기까지
       
        private function createKeyword(inKeywordNode:XML):KeywordBase
        {
            var keyword:KeywordBase;
            switch(int(inKeywordNode.level)) {
                case 1: keyword = new Keyword1(inKeywordNode);
                break;
                case 2: keyword = new Keyword2(inKeywordNode);
                break;
                case 3: keyword = new Keyword3(inKeywordNode);
                break;
                case 4: keyword = new Keyword4(inKeywordNode);
                break;
            }
            return keyword;
        } // [4] 여기까지
       
        public function get keywords():Array { return _keywords.concat(); } // [5]
    } // [1] 여기까지
}

위 클래스는 본인이 실무에서 작업했던 태그클라우드에서 사용했던 코드이다. 클래스의 기능은 xml데이터를 불러들여 level 노드 값에 따라서 해당 클래스들을 배열로 생성하여 제공한다.

위 클래스 외적으로 사용된 클래스는 다음과 같은 기능을 포함한다.
SimpleXMLLoader : 단순히 xml 데이터를 불러오는 기능을 한다. loadXML 메소드가 포함되어 있다.
KeywordBase : 키워드 무비클립의 기본이 되는 기능을 제공한다. (마우스 다운, 오버, 아웃등)
Keyword1 ~ Keyword4 : KeywordBase 를 상속하는 각 레벨에 따라 디자인이 서로 다른 클래스들

코드리딩을 할 때는 기본적으로 nest 단위로 읽어 내려가면 된다. 중간에 나타나는 다른 클래스들은 현재 블록을 전체적으로 훑어 보면서 유추하도록 하자. 중간에 다른 파일을 열어 읽게 되면 현재 읽고 있는 흐름을 놓칠 수 있기 때문이다.

50줄도 안 되는 코드지만 이 코드만 가지고도 작업된 클래스들의 절반 이상은 이해할 수 있다. 복잡한 기능을 하는 클래스는 아니기 때문에 읽으면서 구조적으로 어떻게 작성이 되었는지 알 수 있을 것이라 믿는다. 이런 훈련을 반복 하다 보면 현재 읽고 있는 클래스 이외의 다른 클래스들도 머리 속으로 그리는 과정을 얻게 된다. 이를 통해서 하나를 보면 열을 알게 되는 경지에 다다를 수 있을 것이다. ^^

구글에서 코드 검색엔진을 통해서 웹에 있는 원시 코드들을 검색할 수 있는 서비스를 제공하고 있다. 자신이 원하는 기능의 클래스명이나 메소드명으로 검색해서 코드리딩 연습을 하는 것도 좋은 방법이다. 또한 많이 알려진 클래스나 패키지들은 구조적으로 잘 설계된 것들이 많이 있다. 구조적인 관점에서는 그런 것들을 분석해 보는 것도 큰 도움이 된다.

http://www.google.com/codesearch
인터넷상에 공개되어있는 Subversion(repository)나 archive파일 등을 기계적으로 빠르게 검색 할 수 있다.

좋은 이름을 붙이자.
우리가 프로그래밍을 하고 있을 때 가장 막히는 부분은 변수명, 메소드명, 클래스명 이름을 붙이는 것이다. 그만큼 좋은 이름을 붙이는 것은 중요하다. 좋은 이름을 붙이는 것이 중요한 이유는 위에서 언급했던 코드리딩에서도 느낄 수 있듯이 관련 기능에 부합하는 좋은 이름을 붙이지 않으면 코드를 읽기가 어려워진다.(생각해보니 위에서 예로 든 코드에서도 어려움을 느낀 분들이 있을 것 같다 ^^;)

그렇다면 좋은 이름의 조건이 있을 법하다.

좋은 변수명, 메소드명, 클래스명은 이름이 그 코드의 내용을 올바르게 나타내고 있다. 그러한 이름은 이름을 보는 것만으로도 코멘트를 읽을 필요도 없이 그 역할을 이해할 수 있다. 좋은 이름은 코드의 이해를 돕지만 나쁜 이름은 읽는 사람을 혼란 시키고 착각을 낳아 버그 발생을 조장한다.

위 코드를 예로 들면 onLoadedXmlHandler 메소드 명을 onComplete로 했을 경우에 어떤 것이 Complete 되었다는 것인지 인지하기 어렵다. 위 클래스의 경우는 단순한 클래스이지만 클래스의 내용이 많고 complete 핸들러 함수를 여러 개 포함하고 있을 경우에는 메소드의 중복이 발생할 수도 있다.

public function get keywords():Array { return _keywords.concat(); }
의 경우에는 keyword에 복수를 뜻하는 s를 붙임으로써 전달 받는 keyword가 하나가 아니라 복수이며 배열이라는 것을 유추할 수 있다. 이 밖에도 아래와 같은 방법이 있다.

어두 이외의 모음을 삭제 (image ->img)
강한 소리를 남긴다. (server -> svr)
약어의 이용 (database -> db)

일관성이 있다.
좋은 이름은 코드 전체에서 일관된 흐름을 가져야 한다.

대칭성을 유지하는 것
begin <-> end
write <-> read
on <-> off

단어의 조합의 일관성
scoreAvg
scoreAverage
avgScore
위 이름은 하나의 클래스에서 중복 사용하지 않을 것.

관용어에 따라서
언어, 프로젝트, 회사나 팀 마다 명명에 관한 관용어(관습)가 있다. 예를 들면 Java의 경우는 메소드명은 소문자로 시작하는 것이 관습이며, C#은 대문자, C++은 멤버 변수에 prefix로 m_를 붙이는 것이 일반적이다. 관용어에 따른 명명은 누가 보더라도 알기 쉬운 이름이라고 이야기 할 수 있다.(ActionScript의 경우는 보통 자바와 언어적 문법이 비슷하기 때문에 자바와 같은 명명 관용어를 사용하는 경우가 많지만 개인적인 취향에 따라 다르게 사용하는 경우가 대부분이다.)

코딩 표준에 따라서
위와 같이 좋은 코드의 조건을 채우기 위해서도 코딩 표준이나 명명 규약을 정해 팀 멤버 전원이 맞추는 것이 중요하다. 작업자 1명이 단기적으로 작업하는 프로젝트에서는 본인이 원하는 규칙을 사용하면 되겠으나 조직의 힘을 바탕으로 얻을 수 있는 큰 프로젝트의 경우는 협업의 중요성이 대두되므로 이러한 코딩 표준을 맞추는 것이 장기적으로는 바람직하다고 볼 수 있다.

좋은 이름을 붙이기 위한 습관
항상 좋은 이름을 붙이는 것을 의식한다.
좋은 이름을 붙이려면 우선 의식적으로 노력을 해야 한다. 이것은 A라는 이름이 좋은가? 아니면 B라는 이름이 좋은가를 항상 신중하게 검토해 보고 적절한 이름을 결정하는 프로세스를 반복할 필요가 있다.

코드의 리딩이나 리뷰
자신이 모르는 완전히 새로운 이름을 만드는 것은 코드를 분별없게 만들 가능성이 크다. 본인이 작성한 코드를 스스로 리딩해 보거나 다른 사람에게 리뷰를 함으로써 사용할 수 있는 이름을 조금씩 늘려간다. (본인 같은 경우는 아는 단어의 수준이 메롱이기 때문에 코드작업을 할 때 항상 사전을 열어놓고 작업을 하는 습관이 있다. 이때도 주의할 것은 일회성으로 모르는 단어를 만들어 명명하는 것 보다는 그 단어를 충분히 숙지한 상태에서 이름으로 사용하는 것이 바람직하다 – 간혹 내가 만든 이름을 내가 이해하지 못하는 어처구니 없는 경우가 발생 하기도 한다. 메롱;;)

좋은 변수명
설명적인 변수명
변수에는 값이나 오브젝트가 대입된다. 변수명을 보는 것만으로도 무엇이 어떠한 역할을 하는지 명확한 것이 좋은 이름이라 할 수 있다.

예를 들어
var n:int;                                                 // 무슨 수치?
var languages:Array = [“kr”, “en”];     // 무슨 언어?
var flg:Boolean = false;                      // 무슨 플래그?
var userAgent:UserAgent                  // 무슨 유저 에이전트?

위와 같은 변수명은 나중에 되돌아보면 변수의 역할을 알 수 없다. 아래와 같이 좀더 구체적이고 명확한 이름으로 해 두면 되돌아 보거나 다른 사람이 봐도 이해하기 쉬운 코드가 된다.

var orderCount:int;                                                // 오더수
var availableLanguages:Array = [“kr”, “en”];     // 이용 가능한 언어
var existsSameName:Boolean = false;           // 동성동명이 존재할까?(존재 true)
var unknownUserAgent:UserAgent                  // 미지의 유저 에이전트

다만 변수는 변수의 종류와 그 변수의 스코프(변수의 값을 참조할 수 있는 범위, 변수의 선언으로부터 시작되어 변수의 값을 참조할 수 없게 될 때까지의 범위)에 의해서 좋은 이름의 성질이 다르다. 스코프가 넓으면 다양한 곳으로부터 참조되므로 영향 범위가 크다고 할 수 있다. 따라서 보다 구체적인 이름이 요구된다. 종류별로 보면 아래와 같다.

필드 변수, 클래스 변수
필드 변수는 인스턴스 변수이다. 필드 변수, 클래스 변수는 로컬 변수등과 비교하면 변수의 스코프가 넓기 때문에 특히 그 변수의 의미를 올바르게 표현한 이름이 바람직하다.

메소드의 파라미터
파라미터명은 알기 쉽고 간결한 이름이 좋을 것이다. 파라미터명은 이용자가 API레퍼런스로 참조하거나 Eclipse, FlashDevelop등의 통합 개발 환경으로부터 변수명의 후보로서 이용되므로 극단적으로 짧은 이름을 붙이는 것은 피해야 한다.

로컬 변수
메소드 내에서 일시적으로 선언되는 변수이다. 스코프가 긴 것도 있지만 for문과 같이 짧은 것도 있다. 스코프가 긴 것은 필드 변수와 같이 변수의 의미를 올바르게 표현하는 구체적인 이름을 붙이는 것이 좋다. 스코프가 짧은 것은 아래와 같이 사용구분만 적당히 해주면 된다.

관용어에 따르는 또는 따르지 않는다.
배열의 내용을 순서대로 처리하는 루프 카운터 변수(i,j,k)등과 같이 잘 사용되는 관습적인 변수명은 그대로 관용어에 따르는 편이 알기 쉬운 코드가 된다.
// 루프 카운터의 변수명이 관습적이지 않고 너무 길다 [X]
for (var empCounter:int=0 ; empCounter < employes.size ; empCounter++) {
          var emp:Employee = employees[empCounter];
    ...
}

// 루프 카운터의 이름이 관습적으로 짧고, 가독성이 높다 [O]
for (var i:int=0 ; i<employes.size ; i++) {
         var emp:Employee = employees[i];
    ...
}


다만 예외적인 경우도 있다. 구체적인 이름을 변수명으로 하는 편이 알기 쉬운 경우는 그렇게 사용한다. 예를 들어 좌표계를 취급하는 경우에는 아래와 같이 사용하여 가독성을 높일 수 있다.
// i,j의 어느 쪽이 x좌표, y좌표인지를 모른다 [X]
for (var i:int=0 ; i<width ; i++) {
    for (var j:int=0 ; j<height ; j++) {
        var color:uint = getColor(i, j);
        ...
    }
}

// 변수명을 x,y로 했으므로 알기 쉽다 [O]
for (var x:int=0 ; x<width ; x++) {
    for (var y:int=0 ; y<height ; y++) {
        var color:uint = getColor(x, y);
        ...
    }
}

위 for문의 경우, 중첩되는 var y:int=0 변수 선언은 for문 밖에서 선언해 주는 것이 바람직하다. 중첩된 for문 안에서 x가 카운팅 될 때마다 메모리상에서는 y라는 변수의 어드레스를 매번 push해야 하는 불필요한 리소스 낭비가 발생하기 때문이다. (이 부분에 대한 논쟁 이슈가 있다. 이후에 이야기할 로컬 변수의 스코프 부분에서 로컬 변수의 스코프는 가능한 작게 한다는 변수의 의존성에 따른 대원칙에 위배되는 것이기 때문이다. 이것은 사용하는 상황에 따라 적절히 혼용하는 것이 좋을 것이다.)
var x:int;
var y:int;
for (x=0 ; x<width ; x++) {
    for (y=0 ; y<height ; y+) {
        var color:uint = getColor(x, y);
        ...
    }
}

변수명을 짧게 하는 편이 가독성이 향상되는 경우도 있다.
충분히 인지할 수 있는 범위인 경우로 루프내의 변수나 짧은 메소드 내의 변수처럼 일시적인 변수는 짧게 하는 편이 반대로 가독성이 향상되는 경우도 있다.
// 변수명 siteContactChangelog는 너무 길다 [X]
for (var i:int=0; i<siteContactChangelogs.length ; i++) {
    var siteContactChangelog:SiteContactChangelog = siteContactChangelog[i];
    siteNames[i] = siteContactChangelog.getSiteName();
    siteTitles[i] = siteContactChangelog.getSiteTitle();
    sitePicIds[i] = siteContactChangelog.getPicId();
    sitePicNames[i] = siteContactChangelog.getPicName();
}

// 변수명 log는 충분히 그 의미를 이해할 수 있기 때문에 가독성이 좋다.[O]
for (var i:int=0; i<siteContactChangelogs.length ; i++) {
    var log:SiteContactChangelog = siteContactChangelog[i];
    siteNames[i] = log.getSiteName();
    siteTitles[i] = log.getSiteTitle();
    sitePicIds[i] = log.getPicId();
    sitePicNames[i] = log.getPicName();
}

좋은 메소드명
좋은 메소드명은 이름으로부터 그 기능을 예상할 수 있다. 메소드는 처리를 담당함으로 메소드명은 동사+목적어 형태인 것이 많다. 아래는 자주 사용되는 메소드명의 예이다.
 메소드의 역할                                         메소드명
 값 취득에 관한 메소드                           getXXX
 값 세트에 관한 메소드                           setXXX
 생성에 관한 메소드                                create, build, make, generate
 초기화에 관한 메소드                            initialize, setupXXX
 파기에 관한 메소드                               destroy, dispose
 상태 확인에 관한 메소드                      contains, exists

인스턴스 메소드는 dataFormat.parse와 같이 오브젝트명으로 조합하므로 합쳐졌을 때는 중복 없게 의미가 통하는 이름으로 한다. 메소드와 클래스명도 이와 동일하다.
// parseDateString은 클래스명 DateFormat과
// date라는 이름이 중복되어 약간 장황
var dateFormat:DateFormat = new DateFormat("yyyy-MM-dd");
var startDate:Date = dateFormat.parseDateString("2008-04-01");

// 클래스명 DateFormat과 메소드명 parse로
// 무엇을 처리하는지 충분히 이해할 수 있음.
var dateFormat:DateFormat = new DateFormat("yyyy-MM-dd");
var startDate:Date = dateFormat.parse("2008-04-01");

좋은 클래스명
변수명이나 메소드명과 비교해서 클래스명은 가용 범위가 크기 때문에 적절하고 좋은 클래스명을 붙이는 것이 중요하다. 좋은 클래스명은 이름만으로 무엇을 실시하는 클래스인가를 알 수 있다.

클래스명이 잘 떠오르지 않을 때는 자신이 만들려고 하는 클래스의 역할을 제대로 정리 할 수 있는지 없는지를 판단해 보아야 한다. 1개의 클래스에 복수의 책무를 넣거나 역할이 애매한 기능은 없는지를 생각해보고 해당 클래스에서 해결하고자 하는 문제를 차분히 생각해보고 클래스명을 다시 선택할 필요가 있다.

클래스명의 어휘 설계 능력
이름 명명에 관하여 자신이 모르는 표현, 개념은 쉽게 생각하기 어렵다. 보다 나은 표현을 선택하려면 여러 가지 코드나 서적을 읽거나 실제로 코드를 쓰고 시험하는 것이 중요하다. 그 경험을 통해서 이름에 관한 어휘가 조금씩 늘어난다. 본인 같은 경우는 영어권의 개발자가 작성한 기능과 메소드명을 보면서 의미해석을 한다. 사실 프로그래밍 과정에서 이름을 짓는 것은 생활에서 보편적으로 사용하지 않는 단어들도 많이 존재한다. 하지만 그만큼 자주 사용되는 단어들은 한정되어 있기 때문에 틈나는 대로 기억을 되살려 사용해 보는 것이 중요하다.

좋은 패키지명
ActionScript의 패키지명은 클래스나 자원의 논리적인 그룹을 만들어 계층 구조를 나타낸다 이것은 주로 이름의 충돌을 막기 위해서 사용된다. 패키지명은 그룹의 논리적인 내용을 나타내는 간결한 명사를 선택한다.

간혹 클래스를 만들지 않고 라이브러리에서 특정 무비클립을 동적으로 참조하기 위하여 Linkage에 클래스명만 기입하여 사용하는 경우가 있다. 이럴 경우 클래스가 플래시 컨텐츠전역에 오픈 되기 때문에 팀의 협업에 있어서 클래스명의 충돌을 야기할 수 있다. 이럴 경우 해당 클래스가 없더라도 관련된 패키지명을 명시함으로써 그러한 충돌을 줄일 수 있다. 

처음부터 좋은 이름을 사용할 수 있는 사람은 없다. 좋은 이름에 대해서 의식적으로 사용하려고 노력하는 것이 중요하다. 누구라도 알기 쉽고, 이해하기 쉬운 코드라고 하는 것은 항상 의식하고 노력하다 보면 점차적으로 좋은 이름을 지을 수 있는 요령이 생길 수 있을 것이다.


스코프를 의식한 프로그래밍
사실 모든 프로그래밍에서 스코프는 존재한다. 의식적으로 스코프를 컨트롤 할 수 있으면 보다 좋은 프로그래밍 스타일에 가까워질 것이다. 이번에는 스코프에 대한 이야기를 해보자.

우선 스코프는 Wikipedia에 다음과 같이 정의되어 있다.
프로그래밍에서 스코프란, 어느 변수나 함수가 특정 이름으로 참조되는 범위, 어느 범위의 밖에 있는 변수 등은 통상 그 이름만으로는 참조할 수 없다. 이때 이러한 변수는 스코프 밖에 있어 보이지 않는다 라고 말한다.

스코프는 변수, 메소드, 클래스등이 보이는 범위다. 그렇다면 보인다는 의미는 무슨 뜻일까? 보인다라는 것은 프로그래밍상에 있다는 것이다. 변수이면 변수명을 지정해 값을 읽고 쓰기가 가능하고 메소드는 호출해 사용할 수 있는 범위에 있는 것이다.

사용할 수 있다라는 것은 바꾸어 말하면 그것에 의존한다라고 이야기할 수 있다. 하나의 코드를 변경하고 싶을 뿐인데 수십 곳을 수정할 필요가 있을 수 있다. 이것은 변경하고자 하는 코드가 여러 곳에 의존하고 있으면 이와 같은 변경이 다른 부분에 영향을 준다.

스코프 == 보이는 범위 == 사용할 수 있는 범위 == 의존하는 범위

변수나 메소드의 스코프를 작게 하는 것으로 보이는 범위가 작아져 사용할 수 있는 범위, 의존하는 범위도 작게 할 수 있다. 스코프를 작게 하는 것으로 보다 의존성이 적어 변경이 용이한 프로그램을 작성 할 수 있는 것이다.

기억해 두는 것을 줄이자.
의존이 작아지는 것 이외에도 스코프를 작게 하는 것으로부터 도움이 되는 것이 있다. 프로그래밍은 본질적으로 복잡한 것이다. 복잡함에 대한 대책으로서 문제 영역을 가능한 작고, 이해 가능한 상태로 취급하는 것이 중요하다. 스코프를 의식적으로 작게 하는 것으로 프로그래머가 기억해 두지 않으면 안 되는 것, 주의하지 않으면 안 되는 범위는 작아져서 쉽게 이해할 수 있게 된다. 이것이 스코프를 작게 하는 것의 본질이라고 할 수 있다.

로컬 변수의 스코프
로컬 변수란 메소드 내에서 선언된 일시적인 변수다. Java나 Ruby의 로컬변수는 선언된 장소로부터 스코프가 시작되어 선언된 블록이 끝나면 스코프가 종료된다. ActionScript 2.0 에서도 순차적으로 메모리 할당이 이루어 졌기 때문에 메소드 내에서 상위에 선언된 변수와 하위에서 선언된 변수가 서로 다른 영역 범위의 스코프를 갖기 때문에 컴파일 시에 충돌이 발생하지 않았다.(Java, Ruby와 동일)

반면 ActionScript 3.0에서의 로컬변수는 스코프의 시작은 컴파일러가 블록에 접근했을 때 블록 내의 위치와는 상관없이 미리 메모리 주소가 할당된다. 이는 컴파일 시에 메모리 할당이 한꺼번에 선행되어 스코프가 동일하기 때문에 변수명 중복 에러 메시지를 출력하는 것이다.

하지만 일반적인 프로그래밍 언어에서는 변수의 의존도를 최소화하여 프로그램의 변경이 쉽게 하기 위하여 [로컬변수의 스코프는 가능한 작게 한다.] 라는 것이 대원칙이다.

필드 변수의 스코프
필드 변수는 인스턴스 변수다. 필드 변수의 스코프는 private / public 등과 같은 키워드를 통해서 정해진다. ActionScript의 경우 필드 변수에 대한 가시성은 스코프가 작은 순서로 4개가 지원된다.
private    : 오브젝트 내에서만 변수에 액세스 할 수 있다.
internal    : 같은 패키지 내에서 액세스 할 수 있다.
protected : 오브젝트 내 그리고 하위 클래스로부터 액세스 할 수 있다.
public : 오브젝트 밖에서 액세스 할 수 있다.

필드 변수는 모두 private가 기본 전략이다. 필드 변수에 외부나 하위 클래스로부터 액세스 하고 싶은 경우에는 set/get 등 액세스용 메소드를 따로 만들어 공개하는 것이 캡슐화에 도움을 준다. 하지만 기본 전략이 바람직하다고는 하지만 상속에 따른 장황함을 배제하기 위해서 protected나 public 접근자를 사용하는 경우도 발생한다.

인스턴스 메소드의 스코프
인스턴스 메소드는 인스턴스에 속하는 메소드를 말한다. ActionScript에서 메소드의 스코프 가시성도 필드 변수와 같이 4개이다. 메소드의 접근 제한은 최소인 private로부터 시작하여 점차적으로 internal -> protected -> public으로 나아가는 것이 바람직하다.

메소드 파라미터의 정보량
스코프에서 조금 벗어난 이야기이지만 메소드의 인수로 건네주는 정보량을 어느 정도로 하는 것도 의존성이라는 관점에서 보면 중요한 선택이다.

예를 들면 아래의 두 코드는 사원 정보를 취득하는 메소드이지만 1번은 인수가 사원ID이고 2번은 인수가 사원 오브젝트이다. 이 두 개의 코드 중에 어느 쪽이 좋은 코드라고 할 수 있을까?
// [1] 인수가 사원ID인 경우
public function getEmployee(inEmpId:int):Employee {
    return empDao.findById(inEmpId);
}

// [2] 인수가 사원 오브젝트의 경우
public function getEmployee(inEmp:Employee):Employee {
    return empDao.findById(inEmp.getId());
}

일반적으로 1번이 인수의 정보량이 적기 때문에 의존이 적고 좋은 코드라고 할 수 있다. 반면 2번은 사원 오브젝트가 가지는 모든 정보로 액세스가 가능하기 때문에 의존이 커지게 된다. 필요한 것은 사원의 ID이므로 그것에만 의존하여 코드를 작성하는 것이 바람직하다.

메소드를 이용하는 측면에서 사원 ID만으로 메소드를 이용할 수 있는 것과 사원 오브젝트가 필요한 것은 전혀 다르다. 더욱이 2번 메소드 내에서 구체적인 처리는 사원 오브젝트의 사원 ID만을 사용해 사원 정보를 검색하고 있다. 이것이 문서화 되어 있지 않을 경우, 코드를 읽지 않으면 그 사실을 알지 못한다. 인수에 불필요한 정보가 포함되어 있으면 사원 ID가 포함된 사원 오브젝트를 건네주어야 한다는 암묵적인 요구가 발생하기 쉽다.

위와 같은 문제 때문에 메소드의 인수는 필요 최저한의 정보를 가지는 것이 의존성이 적고 좋은 코드라고 말할 수 있다.

다만 인수가 너무 많아지는 경우는 인수를 오브젝트로 변경하는 편이 좋다. 기준으로서 인수의 개수가 5개를 넘는 메소드는 인수를 오브젝트로 변경하는 것을 검토할 필요가 있다.

static 메소드
static메소드(클래스 메소드)는 클래스에 속하는 메소드이다. ActionScript에서는 static 키워드를 붙여서 선언한다. static 메소드의 가시성은 인스턴스 메소드의 가시성과 같다. 반면 다른 점은 static 메소드는 필드 변수에 액세스 할 수 없다. static 메소드는 메모리에 미리 할당이 되는 반면 인스턴스 변수는 오브젝트가 인스턴스화 된 시점에서 메모리 할당이 되기 때문에 static 메소드 내에서 인스턴스 변수를 참조할 방법이 없는 것이다.

필드 변수에서 보면 인스턴스 메소드를 static 메소드로 변경했을 경우, 자신이 영향을 주는 메소드가 줄어 들게 되어 결과적으로 스코프는 작아진다. 필드 변수에 액세스 할 필요가 없고, 오버라이드가 필요하지 않는 메소드는 static 메소드로 하는 편이 좋은 경우가 많다. 물론 무조건 static으로 하는 것이 좋은 것은 아니다. 인스턴스가 생성되지 않은 시점에서 메모리에 할당이 되기 때문에 사용하지 않는 클래스의 static 메소드가 메모리에 상주하는 메모리 차원에서의 단점도 있다.
// 인스턴스 메소드의 경우
private var count:int;                                                           ┓
...                                                                                           |
private function regexGroup(inRegex:String):String { |변수 count의 스코프
    // 필드에 액세스 가능                                                     |
    return "(" + regex + ")";                                                   |
}                                                                                             |
...                                                                                            ┛

//static 메소드로 변경했을 경우
private int count;                                                                  ┓
...                                                                                            ┛변수 count의 스코프
static private function regexGroup(inRegex:String):String {
    // 필드에 액세스 불가
    return "(" + regex + ")";
}
...     ―변수 count의 스코프


코드의 분할
몇 천행이 넘는 메소드로 너무 많은 기능을 포함하고 있거나 메소드를 너무 세세하게 분할하여 흐름을 파악하기 어려운 코드는 좋은 코드라 할 수 없다. 좋은 코드가 되기 위해서는 가독성이 좋고, 유지보수성이 우수한 것이라고 위에서 언급했다. 메소드를 적절한 단위로 분할하는 것은 좋은 코드를 만드는 것에 중요한 역할을 한다.

코드를 분할하면 무엇이 좋은가?

가독성의 향상
메소드 코드의 길이가 100줄을 넘으면 처리의 흐름을 읽는데 어려움이 있다. 반면 30행 이하이면 내용을 이해하는 것이 용이하다.

유지보수성의 향상
분할에 의해 변수의 스코프가 작아지거나 처리 기능이 본래 있어야 할 클래스나 메소드로 이동하는 것으로 의존관계가 정리되어 유지보수성이 향상된다.

재이용성 향상
코드를 분할하면 코드의 중복이 줄어들어 이용 가능한 부품으로서의 메소드나 클래스를 만들 수 있다. 이것은 OOP 언어에서 좋은 방법이다.

캡슐화를 지킬 수 있다.
객체 지향에서는 캡슐화라는 개념이 있다. 메소드나 클래스의 상속에 의한 구체적인 구현이나 오브젝트 상태를 몰라도 메소드를 호출하는 것만으로도 각각의 오브젝트가 처리를 이행해 주는 것이다.

클래스의 관점에서도 비슷한 이득을 얻을 수 있다. ActionScript는 타 언어보다 MVC 페턴을 예로 들면 view에 해당하는 클래스가 Model에 비해 상대적으로 비대하다. 따라서 구조 작업에 있어서 이러한 view 그룹을 어떻게 분할하느냐에 따라서 유지보수성의 성패를 좌우한다고도 볼 수 있다.

위에서 좋은 코드를 위한 방법에 관하여 이야기를 했다. 연재에 실린 내용과 그것을 ActionScript에 맞게 수정하는 관계로 문장이 다소 매끄럽지 않는 점이 있을 것이다. 그런 부분은  이해해 주길 바란다.

사실 플래시는 타 언어에 비해서 버그가 발생할 가능성이 크다. 그 이유는 플래시의 강점인 모션을 항상 고민해야 하는 작업이기 때문이다. 일반적인 언어에서는 어떤 오브젝트가 나타나고 사라지는 사이에 시간이라는 개념을 포함할 필요성을 인식하지 못하지만 플래시는 모션에 따라 그 사이에 시간이 존재할 수 있다. 모션이 있는 사이에 예측하지 않은 사용자 반응이 있을 경우에는 버그가 발생할 수 있다. 플래시 개발자는 항상 이런 부분까지 예상하고 방어적 프로그래밍을 해야 한다.

위에서 이야기한 좋은 코드를 작성하는 것은 플래시의 작업에 많은 도움을 주지만 그런 것이 플래시 개발의 모든 약점을 보완해 주지는 못한다. 때로는 일반적인 좋은 코드로서의 방향에 영향을 주지 않는 범위 내에서 플래시의 장점을 극대화 할 수 있는 방법을 고민 해야 하는 것이다.

간혹 좋은 코드를 작성하는 방법을 물어보시는 분들이 있다. 물론 그것이 모르는 부분을 빨리 이해할 수 있는 좋은 방법일 수 있지만 쉽게 얻은 지식은 지식으로 머물러 지혜로 발전하지 못하는 경우가 많다. 더구나 본인 또한 그 방법을 찾고자 고민하고 배워가는 입장이기 때문에 도움을 주지 못하는 경우도 있다.

또한 플래시의 발전은 지식에 목말라 스스로 지혜를 얻으려 노력했던 선배들의 도움으로 커왔다고 나는 믿고 있기 때문이기도 하다. 위에서 이야기 한 내용은 본인 또한 노력하는 부분이고 이 포스트를 읽는 분들도 지혜를 얻기 위해 노력하다보면 좋은 코드를 생산할 수 있을 것이라 믿는다.



    

설정

트랙백

댓글

Flickr Searcher 1.8 업로드

Project/Programming 2007. 5. 13. 13:49

사용자 삽입 이미지


사용자 삽입 이미지

사용자 삽입 이미지


Flickr의 Open API를 이용한 사진 검색 어플리케이션 'FlickrSearcher'
version 1.8

http://dicaland.cafe24.com/flickr/FlickrSearcher1_8.swf
====================================================================================================

FlickrSearcher1_8.exe

Version 1.8  Release date : 2007/05/13
Change log
1. photo 썸네일 클릭시에 나타나는 왼쪽 중앙에 있는 information 버튼의 가독성을 위하여 색 변경
2. Search history 기능 추가 : 특정 모드(tags, name, email, nsid)를 통해 검색한 history를 저장할 수 있도록 함.
(최근 검색한 검색어와 페이지 수를 통해서 되돌아 갈 수 있도록 함)
====================================================================================================


    

설정

트랙백

댓글

Flickr Searcher 1.7 업로드

Project/Programming 2007. 5. 10. 11:45
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지

Flickr의 Open API를 이용한 사진 검색 어플리케이션 'FlickrSearcher'
version 1.7

====================================================================================================
Version 1.7  Release date : 2007/05/10
Change log
1. 1.6에서 'VIEW AUTHOR PHOTOS'로 검색을 할때 search mode 'name'으로 이동하면서 textField 길이가 불규칙하게 변했던 버그 수정.
2. 정보 TextField를 선택가능 하도록 변경.
3. Photo Information에서 이미지의 exif 정보를 볼 수 있도록 기능 추가.
====================================================================================================
    

설정

트랙백

댓글

상황중심의 프로그래밍

Programming/Etc 2007. 3. 10. 20:54
스티븐 스필버그 감독은 영화 <뮌헨>을 발표한 후 알고 지내던 유태인 친구를 여러 명 잃었다고 고백했다. 영화 속에서 주인공은 이스라엘 정보기관 모사드의 도움을 받아 폭탄 제조, 문서 위조, 사건 뒤처리 등의 다양한 재주를 가진 6명의 요원으로 팀을 구성한 다음, 1972년 뮌헨 올림픽 선수촌에서 테러를 일으킨 검은 9월단의 배후 요원들을 한 명씩 살해한다.

하지만 시간이 흐르면서 주인공을 비롯한 요원들은 국가를 위한 복수와 비인도적인 살인 행위 사이에서 갈등을 겪게 되고 스스로의 생명마저 위협받자 깊은 회의에 빠져들게 된다. 스필버그 감독은 인간적인‘갈등’과‘회의’를 그렸을 뿐인데 열혈 유태인들은 그것조차 용납하기 어려웠던 모양이다.

아무튼 영화 속의 주인공은 복수의 대상 11명이 은거하고 있는 장소와 그밖에 필요한 정보를 얻기 위해서 일종의‘정보 브로커’와 거래를 한다. 그에게 거액의 돈을 주고 살해할 대상이 숨어 있는 장소에 대한 정보를 얻는 것이다. 재미있는 점은 주인공의 복수가 진행되는 동안 다른 나라의 정보조직에서도 똑같은 정보 브로커에게 접근해서 주인공과 동료들의 신원을 파악하려고 한다는 점이다. 이름도 없고, 얼굴도 없어서 어느 누구에게도 존재가 드러나지 않아야 하는 정보조직 세계의 요원들이 이렇게 ‘정보 브로커’라는 존재를 통해서 오히려 하나의 지점에서 만나는 현상이 벌어진다.


상황중심이란 개념 이해하기    

이렇게 다양한 독립적인 개체들이 자신의 목적을 위해서 공통적으로 통과할 수밖에 없는 지점, 혹은 수행할 수밖에 없는 행동을 상황중심 프로그래밍(Aspect Oriented Programming)에서는 접점(join point)라고 부른다.‘ 상황중심’이란 요즘 프로그래밍 세계에서 주목을 받고 있는 ‘Aspect Oriented’라는 표현을 나름대로 우리말로 옮겨본 것이다.‘ Aspect Oriented’라는 말이 국내에서는‘관점 지향’이라는 말로 표현되기도 하는데, 이것은 그 동안 ‘Object Oriented’를‘객체 지향’이라고 불러온 관성의 영향인 것으로 생각된다.

사실‘관점 지향’이라는 말은 의미가 분명하지 않을 뿐만 아니라 겉으로 드러나는 의미조차 정확하다고 보기 어렵다. ‘관점’을‘지향’한다니? 프로그래밍을 수행하는 사람이 자기 관점을 분명히 세우고 그것을 목표로 전진하라는 말인가?‘ 관점 지향’이라는 말이 국내 프로그래머 사이에서 일정한 합의를 이루고 있는 표현이라면 어쩔 수 없지만, 최소한 이 글에서는‘Aspect Object’를‘상황중심’으로 표현하고자 한다. 이렇게 해야 새로운 방법론이 전하고자 하는 의미가 분명하게 드러나기 때문이다.

상황중심 프로그래밍은 말 그대로 현재의 소프트웨어 코드가 처해 있는 특정한‘상황’에 초점을 맞추는 프로그래밍을 의미한다. 폭발적으로 늘어나는 수요를 감당하지 못해 심각한 위기를 맞이했던 소프트웨어 개발시장은‘모듈(module)’과‘객체(object)’라는 혁명적인 개념을 발견하면서 위기를 극복했다. 방대한 분량의 소프트웨어 코드를 모듈과 객체라는 작고 독립적인 부분으로 분리할 수 있었기 때문에 프로그래머들은 점점 더 복잡한 업무를 수행하는 코드를 만들어 낼 수 있었던 것이다. 하지만 독립적인 모듈과 객체의 수마저 기하급수적인 규모로 증가하면서 예전과는 전혀 다른 문제가 대두되었다.

모듈과 객체는 코드를 추상적이고 부분적인 캡슐로 분리해서 전체적인 코드에 대한 관리가 가능하도록 만들고 필요하면 재사용 할 수 있는 방법까지 제공했다. 즉 모듈과 객체는 코드의 부분을 떼어내서 추상화하는 방법을 제공한 것이다. 하지만 이러한 방법은 모듈과 객체를 가로지르며 존재하는 공통의 관심사(cross-cutting concern)를 효율적으로 추상화하는 방법은 제공하지 않았다. 공통의 관심사란 보안(security), 성능(performance), 기록(logging)과 같은 소프트웨어의 일반적인 속성에서부터 데이터 캐시(cache) 관리나 네트워크 프로토콜의 구현처럼 구체적인 기능에 이르기까지 다양하다.

이러한 공통의 관심사는 특정한 모듈이나 객체가 구현하는 기능에 국한되는 것이 아니라 소프트웨어 시스템 전체에 걸쳐 수평적으로 영향을 미친다. 잘 이해가 되지 않는 독자는 다음 예를 생각해 보면 도움이 될 것이다.


공통의 관심사    

인터넷 붐이 한창이던 90년대에 미국에서는‘수평적 시장(horizontal market)’과‘수직적 시장(vertical market)’이라는 표현이 자주 사용되었다. 수직적 시장이란 어떤 제품이 특정한 분야의 시장에 국한되는 경우를 의미한다. 예를 들어서 책, 의류, 자동차, 컴퓨터, 혹은 의료보험 시스템 등은 다른 분야와 겹치지 않는 자기 자신만의 시장을 형성한다.

이들은 모두 수직적 시장의 예이다. 하지만 웹브라우저와 같은 소프트웨어는 특정한 시장에 국한되지 않고 모든 수직적 시장들 사이에 공통적으로 존재하며 영향을 미친다. 그 자체로는 특정 품목에 대한 시장을 형성하지 않지만 여러 시장에서 동시에 존재하는‘공통의 관심사’가 되는 것이다.

영화 <뮌헨>에서 이스라엘의 모사드, 소련의 KGB, 미국의 CIA, 팔레스타인의 검은 9월단 등은 각자 겹치지 않는 고유의 영역을 구성하고 있지만, 그들이 어떤 인물의 은신처를‘검색’하기 위해서는 다양한 정보를 보유하고 있는‘정보 브로커’를 찾아가야만 했다. 각 국의 정보기관이 수직적 시장을 형성하고 있다면,‘ 정보 브로커’는 웹브라우저와 마찬가지로 수평적 시장을 형성하고 있는 셈이다. 이 경우에‘정보 브로커’는 여러 정보기관들을 가로지르며 공통적으로 존재하는‘공통의 관심사’로서의 역할을 담당한다.

오늘날의 프로그래밍 세계에서 수직적 시장을 구성하는 존재는 말할 것도 없이‘객체’들이다. 객체들은 저마다
주어진 일감을 구현하면서 일이 서로 겹치지 않도록 소프트웨어의 전체 영역을 분할한다. 이렇게 분할을 더욱 효율적으로 만들기 위해서 비슷한 일을 하는 객체를 한곳에 묶어서‘패키지(package)’라고 부르기도 한다. 지금까지 프로그래밍은 이러한 분할을 통해서 충분히 잘 이루어져 왔다.

하지만 이렇게 역할 분담을 통한 균형과 평화가 이루어진 상황에서도 여러 객체 사이에 존재하는‘공통의 관심사’는 존재하기 마련이다. 앞에서 예로 든 보안, 성능, 기록, 캐시, 프로토콜 등이 바로 그들이다. 이밖에 유닛테스트(unit test)나 테스트 자동화 등도 여기에 포함될 수 있을 것이다.

좀 더 이해를 돕기 위해서 하나의 구체적인 상황을 생각해보자. 소프트웨어의 사용자들이 항상 그렇듯이 개발자가 개발한 시스템을 이용하는 사용자 중에는 구체적인 데이터를 제시하지 않으면서 말로만“시스템이 느려 터졌다.

답답해서 못 쓰겠다.”라고 불평을 늘어놓는 사람이 있다. 소프트웨어를 제작하고 관리하는 입장에서는 이렇게 막연하게 불평만 늘어놓는 사용자처럼 속상한 존재가 없다.

구체적으로 어떤 기능을 사용할 때‘느린지’를 알아야 그가 겪고 있는 문제가 PC 하드웨어와 관련된 문제인지, 개발자가 만든 소프트웨어의 문제인지, 네트워크의 문제인지, 혹은 서버나 데이터베이스의 문제인지를 알 수 있고 그에 따른 해결책을 제시할 수 있기 때문이다(물론 사용자가 허락만 해준다면 그가 소프트웨어를 어떻게 사용하는지 직접 관찰할 수도 있을 것이다. 하지만 성격이 곱지 않은 월스트리트의 트레이더에게‘저는 소프트웨어를 제작한 사람인데요, 잠시 옆에서 PC를 사용하는 모습을 관찰해도 될 까요’라고 묻는 것은 자살 행위이다).

그렇지만 사용자가 데이터를 제공해 주지 않는다고 해서 손을 놓고 있을 수는 없으므로 우리는 필요한 데이터를 스스로 구해야 한다는 결론을 내리게 되었다. 그리하여 우리가 구현하기로 한 기능은 사용자가 소프트웨어에서 어떤 동작을 수행할 때마다 맨 처음 GUI의 이벤트 처리 메소드(event handler)에서 출발해서 서버와 데이터베이스에 이르는 과정에 존재하는 각 계층을 통과하는 데 걸린 시간을 측정한 다음 로그 파일과 같은 하나의 장소에 기록하는 것이었다.


스파이로그    

사용자가 GUI 화면에서 주식이나 채권 가격 같은 데이터를 입력하고 OK 버튼을 눌렀다고 해보자. 그러면 소프트웨어의 흐름은 GUI 계층, GUI 계층 아래에 존재하는 네트워크 계층, 실제 네트워크 전송, 서버에서 사용자의 요청을 받아들여서 적절한 컴포넌트( component)에게 전달하는 계층, 데이터베이스에 저장되어 있는 프로시저(stored procedure), 최종적인 데이터를 담고 있는 응답객체를 생성하는 계층, 응답 객체를 GUI 클라이언트에게 전송하는 계층, GUI가 서버의 응답을 받아서 처리하는 계층 등을 차례로 통과한다.

이 때 각 계층에서 소요된 시간을 측정해서 하나의 객체에 저장하는 것이다. 이렇게 처리시간이 기록된 객체는 각 계층을 통과할 때마다 다음 계층에게 전달되면서 값을 축적해 나간다. 필요한 처리 과정이 모두 끝나고 나면 이 객체에 저장된 값은 미리 지정된 포맷에 따라서 로그 파일에 기록되고 객체의 수명은 끝이 난다.

이제 사용자가 시스템의 성능에 대해서 밑도 끝도 없는 불평을 늘어놓으면 로그 파일에 저장되어 있는 데이터를 분석해서 실제로 성능에 문제가 있었는지, 만약 문제가 있었다면 어느 계층에서 문제가 있었는지를 파악할 수 있다.

이렇게 유용한 기능의 이름을‘스파이로그’라고 불러보자. 앞의 설명을 읽으면서‘흠 소프트웨어의 여러 계층을 관통하는 <공통의 관심사>를 설명하려고 애쓰고 있군’하고 생각하는 독자가 있다면 만점이다. ‘공통의 관심사(crosscutting concern)’라는 개념을 이해했다면 상황중심 프로그래밍의 98%를 거의 이해한 것과 다름이 없다.

이러한 스파이로그를 실제로 구현하는 방법은 어렵지 않다. 소프트웨어가 객체지향 기법에 따라서 계층별로 잘 분리되어 있다면 더욱 그러하다. 각 계층의 시작과 끝 부분에서 시간을 측정하는 데 필요한 동작을 수행하기만 하면 되기 때문이다. 하지만 그것이 가능하기 위해서는 최소한 두개의 전제 조건이 필요하다. 하나는 스파이로그를 구현하는 프로그래머가 각 계층의 입구와 출구를 정확하게 파악하고 있어야 한다는 점이고, 두 번째는 스파이로그를 구현하기 위해서는 입구와 출구에 해당하는 객체의 소스 파일이 수정되어야 한다는 점이다. 즉, 입구에 해당하는 위치에서는 앞의 계층에서 전달한 시간 측정용 객체를 받아들인 다음 들어온 시간(time stamp)을 찍고, 출구에 해당하는 위치에서는 같은 객체 위에 나가는 시간을 찍고 나서 뒤에 있는 계층에게 객체를 전달해 주는 것이다.

이런 방법은 기능적으로는 아무런 문제가 없지만 코드의 관리라는 측면에서 보면 문제가 많다. 한 가지만 예를 들자면 이런 식이다. 시스템에 A, B, C, D라는 네 개의 계층이 존재한다고 하자. 하나의 동작(operation)이 완성되려면 A, B, C, D, C, B, A라는 완성된 사이클이 그려져야하고, 스파이로그는 이러한 일곱 단계가 소비하는 시간을 각각 측정해서 기록한다.

그런데 나중에 누가 C 계층을 리팩토링해서 그것을 C1과 C2라는 두 개의 계층으로 분리했다고 가정해보자. 그리고 스파이로그의 존재를 의식하지 못한 그가 C1이 받아들인 객체를 C2에게 전달하는 것을 깜빡 잊었다고 하자. 이와 같은 본의 아닌‘실수’가 도입되는 순간 C1과 C2 사이의 고리가 끊어지면서 스파이로그의 기능은 동작을 멈출 수밖에 없다.

여러 계층이 공유하고 있는‘공통의 관심사’가 단지 한계층에서 발생한 실수 때문에 완전히 동작을 멈춘다는 것은 공정하게 들리지 않는다. 뿐만 아니라 스파이로그의 기능이 여러 소스 파일에 분산되면서 코드의 관리가 어려워진다는 단점도 존재한다. 이러한 상황은 서로 독립적으로 분할되어 있어야 하는‘객체’라는 존재를 중심으로 하는 프로그래밍 방법론으로는 명쾌하게 해결되기 어렵다.

객체는 본질적으로 다른 객체와 나란히 서 있도록 만들어진 존재이지, 다른 객체의 허리를 가로지르며 직교(orthogonal)하도록 만들어진 존재가 아니기 때문이다. 바로 이와 같이‘난처한 상황’에서 힘을 발휘하는 것이‘상황중심’의 프로그래밍이다.


제록스 팔로알토연구소에서 탄생    

상황중심 프로그래밍이라는 개념은 제록스 팔로알토 연구소에서 탄생한 것으로 알려져 있다. 현재 캐나다의 브리티시 콜롬비아 대학의 컴퓨터 사이언스 교수인 그레고르킥잘레스(Gregor Kiczales)는 팔로알토 연구소에서의 연구를 확장해서 현재 상황중심 프로그래밍 세계에서 대표적인 언어로 인정받고 있는 AspectJ를 설계했다. IBM에서도 HyperJ나 관심 변경 환경(Concern Manipulation Environment)과 같은 상황중심 프로그래밍 언어를 발표했지만, 현재 프로그래머 사이에서 널리 받아들여지고 있는 언어는 단연 AspectJ이다.

상황중심 프로그래밍에서 사용하는 개념은 크게 네 가지가 있다. 접점(pointcut), 안내(advice), 내부타입 선언(inter type declaration), 그리고 이들을 모두 묶어서 하나의 단위로 추상화하는 상황(aspect)이 그들이다. 상황중심 프로그래밍이나 이러한 개념들이 의미하는 바는 AspectJ의 홈페이지 등에서 쉽게 접할 수 있다. AspectJ에 대한 책도 이미 적지 않게 나와 있다. 여기에서 이들이 의미하는 바를 간단하게 살펴보자면 이렇다.

우선 접점(pointcut)은 공통의 관심사가 여러 개의 객체나 계층을 가로지를 때 그들과 만나게 되는 지점을 의미한다. 앞에서 살펴본 예에서는 각 계층의 입구와 출구가 접점에 해당하고, 더 앞에서 든 예에서는 모사드, CIA, KGB의 요원들이‘정보 브로커’와 만나는 상황 자체가 접점에 해당할 것이다. 접점은 상황중심 프로그래밍을 수행하는 프로그래머가 이미 존재하는 소프트웨어 시스템을 이해하고 있는 수준, 혹은 핵심을 짚어내는 안목에 따라 제대로 짚어질 수도 있고, 엉뚱한 곳이 접점으로 인식될 수도 있다. 어쨌든 프로그래머가 일단 접점을 골라냈으면 그 다음에 할 일은 그 곳에서 할 일을 정의하는 것이다.

그것이 안내(advice)이다. 상황중심 프로그래밍에서 안내는 객체지향 프로그래밍에서의 메소드에 해당한다고 생각하면 쉽다. 특정한 접점에 이르기 직전이나 혹은 직후에 어떤 일을 할 것인가를 정의하는 알고리즘이 안내의 내용을 이룬다.

내부 타입 정의(inter type declaration)는 약간 복잡하다. 이것은 자바 프로그래밍과 같은 기존의 프로그래밍 방식에 익숙한 사람들에게 개념적인 혼란을 초래하기 때문이다. 자바 언어를 예로 들자면, 어느 객체에게 새로운 인스턴스 변수(instance variable) 혹은 필드(field)를 추가하는 것은 언제나 소스 코드의 수정과 컴파일을 통해서 이루어진다.

프로그램이 실행되고 있는 도중에 새로운 필드를 내 마음대로 추가할 수는 없는 것이다. 자바 런타임(runtime) 내부에서 클래스 이름만 가지고 클래스의 인스턴스를 만들어내는 기능은 있지만 클래스에 이미 정의되어 있지 않은 필드를 더하는 기능은 없다.

그런데 상황중심 프로그램에서 사용하는‘내부 타입 정의’기능은 객체에게 새로운 필드를 동적으로 더하는 것을 가능하게 만든다. 이러한 기능이 필요한 이유는 이미 존재하는 다양한 객체와 계층을 가로지르면서 동작하는 알고 리즘을 작성하기 위해서는 주어진 객체의 정해진 틀을 뛰어넘는 능력이 필요하기 때문일 것으로 추측된다. 사실 필자 역시 상황중심 프로그래밍에 익숙하지 않기 때문에 섣불리 말하기는 어렵지만, 이러한 기능이 바람직한지에 대해서는 의문이 든다.

상황중심 프로그래밍을 구사하는 프로그래머가 어느 객체에게 내부 타입 정의 기능을 이용해서 동적으로 어떤 필드를 추가했다고 해보자. 그는 객체를 정의하고 있는 클래스에 새로운 필드를 사용하는 알고리즘을 추가할 수도 있다. ‘( 내부 타입 정의’기능을 통해서 추가한 필드가 퍼블릭으로 정의되어 있다면 기존의 자바 코드에서 접근하는 것이 가능하기 때문이다.)

이렇게 작성된 소스 코드를 나중에 읽는 다른 프로그래머는 (특히 그가 상황중심 프로그램의 존재를 인식하지 못하고 있다면) 도대체 이 코드가 사용하고 있는 필드가 어디에 정의되어 있는 것인지 알 길이 없다. 이런 식의 혼란은 미묘한 버그의 원인이 될 수 있다.

이런 측면에서 보자면 내부 타입 정의를 이용하는 것은 멀쩡한 객체에게 뼈를 깎고 살을 붙이는 성형수술을 시도하는 것, 혹은 객체의 유전자를 조작해서 없던 장기를 만들어 내는 것에 비유할 만하다. 수술이나 유전자 조작이 필요한 결과를 낳는다면 다행이지만, 잘못된 결과를 낳거나 그것이 남용된다면 차라리 하지 않느니만 못한 일이 될 것이다.

마지막으로, 객체지향 프로그래밍에서 클래스가 변수와 메소드를 한 곳에 묶어서 하나의 객체로 추상화하듯, 상황중심 프로그래밍에서 사용되는 접점, 안내, 내부 타입 정의를 한 곳에 묶어서 추상화하는 것은‘상황(aspect)’이다. 따라서 상황은 객체지향 프로그래밍에서 객체가 중심에 서있듯이 상황중심 프로그래밍에서 가장 중심에 서있는 개념이 된다(이것은 프로그래머들이 혐오하는‘중복’된 표현처럼 들린다. 하지만 달리 표현할 방법이 없다. 상황중심 프로그래밍에서 중심은 상황이기 때문이다).


출처 : 임백준(월스트리트 금융전문가) & 소프트웨어 산책외 다수 저자
    

설정

트랙백

댓글

C언어로 풀어본 사랑의 공식

Miscellaneous/Story 2007. 3. 10. 00:49
헤어진 후의 감정 = 만남의 빈도 * 현재의 감정 * (결혼 - 현재의 감정)

X = r * x * (1 - x)

1은 결혼, 0은 이별.
예) r=2.7 , x= 0.02
2.7 * 0.02 * (1 - 0.02) = 0.0529
2.7 * 0.0529 * (1 - 0.0529) = 0.1353
2.7 * 0.1353 * (1 - 0.1353) = 0.3159

공식의 정의 : 감정이 좋아졌다가 지나치면 다시 좋지 않는 과정을 거친
후 평행상태에 도달한다.


* 지금 보면 그 당시 참 여러가지로 돌파구를 찾고 있었구나 하는 생각이 든다. 뭔가 어색하고 앞뒤가 맞긴 맞는건지 모르겠지만 10대 후반 20대 초반에 이런 것으로 놀고 있었다니....이궁...;


main()

{

float x=0,r=0;

int count=0;

printf("R=> ");scanf("%f",&r);

printf("\\n");

printf("X=> ");scanf("%f",&x);

while(1){

x=r*x*(1-x);/* 연애에서 결혼까지의 공식 */

printf(" [%d]Next===>%f\\n",++count,x);

delay(200);

}

}

    

설정

트랙백

댓글

trace 예찬론

Programming/Etc 2007. 3. 9. 00:48
action script를 코딩하다 보면 중간 중간 내가 작성하는 코드가 syntax error가 없는지 수시로 체크를 하게 되는데 그 단위는 코드 100줄을 넘지 못한다. 코딩을 하면서 중간에 딴 생각을 하다가 엉뚱한 방향으로 흐르는 경우도 있고 손가락의 강약 조절과 위치 파악을 제대로 하지 못한 손가락의 잘못도 있다.(결코 내 잘못 아니란다 쿠쿠)

대부분 syntax error로 수정이 가능한 것들이나 가끔은 overflow의 문제로 한참을 헤매는 경우도 종종 있다. Overflow의 경우는 컴파일러가 정확히 어느 위치에서 overflow가 발생했는지를 알려주지 않는 과계로 중간 체크를 하지 않고 코드를 길게 늘리다 보면 쉽게 문제가 되는 부분을 찾기가 어려울 경우가 있다.

더군다나 overflow가 발생했다는(플래시는 255번 이상 스택이 쌓이면 overflow가 발생한다.) 것을 output 패널 창에 보여주면 그나마 다행이지만 컴파일러가 한참을 계산하고서야 문제를 알려줄 때면 가뜩이나 바쁜 와중에 뒷골이 땡긴다.

이런 문제는 반복문에서의 조건문이 무한하거나 undefined일 경우 흔히 발생하게 된다. 가끔 사이트를 돌아다니다 보면 이런 문제로 브라우저를 종료해야 되는 경우가 종종 보이는데 외부에서 xml 데이터를 받아와서 처리해야하는 구문이 있다면 xml이 로드된 시점에서 처리해야 하는데 그것을 간과한 듯 하다.

이런 문제를 미연에 방지하기 위해서는 수시로 단위별로 체크를 해야 한다. 어느 언어나 기본적으로 특정 값을 확인 할 수 있도록 print 내장 메소드를 제공하는데 플래시도 trace라는 구문을 제공한다. 언제나 감사함을 느끼는 놈이다.

개인적으로 생각해 볼 때 논리적인 error를 잡아내는 데는 trace 하나면 충분하다. 중간 중간 확인을 하고 진행한 코드라고 했을 때 문제가 발생하지 않은 시점과 문제가 발생한 시점을 파악하고 그 문제가 발생했던 부분을 훑어봐도 어디가 문제인지를 모를 때는 최초 문제가 발생한 부분의 상위부터 단계별로 trace로 문제가 될만한 변수들을 확인하고 넘어가면 어느 시점에서는 문제의 변수를 잡아낼 수 있다.

가끔 프로그래밍에 발을 들여놓은 분들을 보면 이러한 확인 절차 없이 무턱대고 코드를 작성하고 한꺼번에 컴파일을 하는 경향이 있는데, 이럴 경우에는 문제가 발생할 만한 곳을 찾기란 쉽지가 않다. 문제가 없는 부분과 문제가 발생한 부분을 쉽게 파악하지 못하기 때문이다.

물론 oop 개념의 프로그래밍을 한다면 이러한 문제를 파악하는데도 많은 도움을 받게 된다. 하나의 독립된 class로 문제를 최대한 잘게 쪼개놓으면 문제가 된 class를 쉽게 알아 낼 수가 있기 때문이다. 플래시 액션스크립트도 2.0으로 넘어오면서 어느 정도 oop개념을 도입했지만 실무에서 완벽한 oop 프로그래밍을 하기에는 쉽지가 않다. Oop 개념을 완전하게 이해하지 못한 이유도 있지만 큰 프로젝트가 아닌 경우에는 사실 그러한 개발 노력보다 시간이 더 중요한 경우가 허다하게 발생하기 때문이기도 하다.

그래서 나 또한 실무에서는 oop반 막무가내 코드 반을 섞어서 사용하고 있고 개인적인 놀이나 작업을 할 때는 되도록 oop에 신경을 쓴다. 물론 개인적인 놀이에서 그러한 것을 하다 보면 실무의 실질적인 프로젝트에서도 기억을 되살려 사용하기도 하니 그러한 놀이를 통해서 점점 oop의 필요성과 유용성을 인정하게 된다.

이야기를 하다 보니 이야기가 엉뚱하게 흐르고 있다. 이쯤에서 trace 한번 찍어보자.

var 엉뚱한변수:String = “#@$#@$@#@$#”;
trace(“엉뚱하게 이야기가 흐른 변수 = ” + 엉뚱한변수);

액션 스크립트를 떠나 존재하는 모든 프로그래밍 언어에서 print 구문이 없었다면 아마도 지금도 어셈블리어로 코딩을 하고 있을지도 모르겠다. 생각해 보니 프로그래밍도 커뮤니케이션이다.

trace(“나 여깄어…너 거기있니”);
trace(“나 여기있고 너 거기있구나”);

trace를 사랑합시다. ^^
    

설정

트랙백

댓글

취미라는 것

Miscellaneous/Story 2007. 3. 7. 02:19
나는 취미가 상당히 많은 편인 것 같다. 나의 취미 놀이는 아래와 같다.

볼링
볼링을 처음 접하게 된 것은 대학교 입학하기 전이었던 것 같다. 그 때는 인터넷이 막 태동을 시작하던 시절이었는데, 컴퓨터로 먼 지방 사람들과 이야기를 하는 것을 PC통신이라고 이야기했었다. 그때 잘 나가던 통신사는 천리안, 나우누리, 하이텔등이 있었고 뜻(?!)이 맞는 사람들과 함께 사설 PC통신 방을 만들어 시샵이라는 운영자로 활동 하기도 했었다. 그때만 해도 모뎀 2400, 9600등으로 통신을 하던 시절이라 밤마다 전화기 선을 뽑아 모뎀에 연결하고 부모님에게 혼날까 봐 모뎀에서 나는 삐삐~지지직 소리를 줄이기 위해 모뎀에 있는 작은 스피커에 휴지를 틀어막고 조마조마하게 통신을 했었다. 나중에 천리안 사용 요금이 10만원가량(그때는 작은 돈이 아니었다)이 나와서 혼이 났던 기억이다.

그 시절에 천리안에 볼링 클럽이 지역마다 있었고 평택이 고향인 나는 친구의 친척형의 권유로 천리안 상주 볼링클럽 평택 창단 맴버로 볼링을 시작하게 되었다. 볼링을 처음 접하는지라 공을 뒤로 던지는 묘기도 보이고 옆 레인을 넘나들기도 하면서 배우게 되었는데 그렇게 한참 배우다가 군대를 가면서 볼링과 멀어졌고 다시 볼링 공을 사고 시작한 것은 사회 초년생인 2004년쯤이었던 것 같다.

서울로 올라와서는 평택에 공을 두고 와서 한동안 하지 않다가 작년 말부터 다시 볼링 공을 가져와서 주중 한 두 번 정도 신림동에 있는 볼링장에서 볼링을 치고 있다. 혼자 하기 때문에 한번 볼링공을 잡으면 보통 6게임 정도를 치는데 그것도 오랜만에 치게 되면 온 몸이 쑤신다.(왕년에는 연속 13게임까지 처 본 적이 있다 그때는 기어서 집으로 갔던 것 같다..ㅎㅎ)

가끔은 미친듯이 스페어도 없이 붙여서 작은 갤러리를 모으기도 하지만 그날, 게임마다 점수는 들쑥날쑥이다.

사진
사진은 처음 올림푸스 4000z를 구입하고 사진을 찍다가 니콘 5700으로 기변을 하고 다시 시그마 sd9, 그리고 다시 니콘 d70으로 와서 정착을 했다. 사진은 나에게 많은 여유와 즐거움을 주는 것 같다.

사진기를 자주 만지기 전에는 보이는 사물에 대한 특별한 감정이 없었던 것 같은데 사진이라는 것이 신기하게도 작은 사물에 대해서도 의미가 생기고 사각 프레임으로 세상을 바라보게 만든다. 이 취미는 올해 다시 본격적으로 착수할 생각이다.

인라인
인라인은 사실 취미라고 할 정도로 자주 타지는 못한다. 나른한 캐나다에 있을 때 주말이면 할꺼리를 찾아 방황을 하다가 친구들과 함께 인라인을 타게 되었다. 지금 가지고 있는 인라인도 그때 구입했던 k2 인라인이다. 우리는 주말이면 스탠리파크에 가서 인라인과 자전거를 탔는데 한국의 가족 단위의 공원 풍경과는 다르게 젊은 연인들과 혼자 여유를 즐기는 사람들이 많았던 기억이다. 공원 옆으로 바다가 있어 더욱 느낌이 새로웠다. 그때 인라인을 타다가 자갈밭에 굴러서 생긴 왼손의 흉터는 아직도 보기 게 남아 있다.

자전거
자전거는 작년 중순쯤에 시보레 미니벨로를 구입하면서 타게 되었다. 차는 있지만 서울에서 생활하다보니 차가 있으면 더 불편한 도시인지라 거의 평택에 방치해 놓는다. 그러다보니 답답할 때면 어딘가 가고 싶은데 쉽게 발길이 떨어지지 않아서 페달을 밟을 생각을 하게 되었다.

회사와 집이 가까운 관계로 생활패턴이 일찍 끝나서 집에 오면 밥을 먹고 한숨 자고 일어나 새벽에 여러가지 일들을 하고 다시 늦은 새벽에 잠이 드는 경우가 종종 있는데 어느날은 새벽 2시경에 자전거를 타고 한강 시민공원에 가보고 싶다는 생각을 하게 되었고 나는 곧바로 실행에 옮겼다.

낮에 타는 것보다 한여름 시원한 밤 공기를 마시며 혼자만의 여유를 느끼는 것도 내가 살아있고 자유롭다는 것을 느끼게 한다.

그렇게 한강시민공원에 가서 벤치에 앉아 음악을 듣다가 다시 집으로 돌아오게 되었는데 돌아오는 중에 내리막길에서 브레이크를 잡지 않고 내려오다가 도로에 생긴 웅덩이를 발견하지 못하고 핸들을 놓치고는 그대로 도로에 다이빙을 했다. 다행이 뒤에서 따라오던 차가 없어서 2차 대형 사고는 면했지만 넘어지면서 왼쪽 팔꿈치와 왼쪽 어깨 그리고 등에 심한 찰과상을 입었다. (그 와중에도 일어나서 자전거 망가진 곳이 없는지를 살폈다는 ;)

그렇게 집으로 자전거를 끌고 걸어오다가 생각해 보니 집에 상처에 바를 연고도 없고 소독약도 없는 게 아닌가, 그래서 오는 길에 엉뚱하게 편의점에 들려서 아주머니에게 약도 파냐고 물었다.(무식한 난 편의점에서 세상에 모든 물건을 다 파는 줄 아는 모양이다) 그랬더니 예전에 사용했던 연고를 찾아보겠다고 하시며 여기저기 뒤적거리다가 테이블에 있는 물건들 다 떨어뜨리시고;; 결국 못찾겠다고 하시는데 어찌나 고맙고 미안스럽던지, 그냥 나오기 뭐해서 음료수 한통(?!)을 사서 나와 집으로 돌아왔다.

집에 돌아와 홀딱 벗고 거울에 상처를 보니 예사롭지가 않다. 박혀있는 돌과 흙 모래라도 처리해야 겠다는 생각에 수돗물에 샤워를 했는데, 아파 죽는 줄 알았다. 그렇게 샤워를 하고 침대에 누우려니 바로 눕지도 못하고 잠도 못자고 출근을 했던 터였다. 그 때가 가장 더운 8월 중순 한여름이었기 때문에 내 상처는 아무는데 오랜 시간이 걸렸다. 아침에 옷 입는 시간만 30분 넘게 소요됐다. 나의 엉뚱한 충동에 무진장 고생했던 기억이다. ^^;

낚시
낚시는 예전에 바다낚시가 좋아 가끔 바닷가에 가서 낚시를 하곤 했는데(제대로 된 물고기 하나 잡지는 못했다) 작년 말쯤에 웹 서핑을 하다가 알게 된 루어낚시에 사로잡혀서 일단 장비를 구입했다. 쿠쿠 구입하고 나니 겨울인지라 구입한 장비로 제대로 낚시 한번 가보지 못했다. 올해 날씨가 좋아지면 한번 나가볼 생각이다.

루어 낚시는 붕어 낚시와는 다르게 지루한 감이 없어서 좋아보였다. 루어라고 불리는 가짜 미끼를 가지고 낚시를 하게 되는데 가짜 미끼를 던져 슬슬 감게 되면 외래어종인 배스가 먹이로 착각하고 물어 낚는, 낚시라기 보다는 스포츠에 가깝다. 보통 배스 낚시로 불리기도 한다.

흐르는 강물처럼에 보면 줄이 긴 낚시로 강에서 낚시를 하는 장면이 포스터에서 나오는데 바로 그 낚시가 이러한 루어낚시의 한 형태라고 할 수 있다. 영화에서 나온 낚시는 플라잉 낚시인데 바람결에 따라서 긴 낚시줄을 날려서 수면 위에 미끼를 튕기면 그것을 물고기가 물어 낚는 형태이다.

우리나라에서는 플라잉 낚시 보다는 대가 짧은 루어낚시로 주로 배스를 낚는다.

프로그래밍
프로그래밍은 취미이기도 하고 하는 일이기도 하다. 일을 취미로 하는 사람은 비교적 행복한 삶을 살고 있다고 생각을 한다. 누구는 집에서도 일을 하냐고 하지만 그 것이 재미있어 이곳에 왔고 그 재미를 통해서 자기 개발과 생각을 하나하나 결과물로 만들면서 즐거움을 느끼며 산다.

프로그래밍의 미학에 대한 것도 어느 정도 느끼고 있지만 아직 충분히 느낄 만큼의 실력이 되지 않기 때문에 나름대로 노력을 하고 있다. 나는 그림과 음악과 시와 같은 세상에 art라고 불리는 것들의 하나의 이미지를 통해서 소통하고 싶은 생각을 어려서 때부터 했었다. 어쩌면 그러한 일환으로 프로그래밍을 통해서 그런 것에 좀더 다가가고 싶은 것인지도 모르겠다.

쓰다 보니 평생 혼자 살 놈처럼 보인다. 올해는 여자친구에게 사랑받기가 취미로 등극하길 바라면서 그만 자야겠다.

    

설정

트랙백

댓글

Artificial Intelligence(Max-Min CRI of Fuzzy System)

Project/Programming 2007. 3. 3. 01:44
구현시 느낌점

※ 이 프로그램에서는 결론부에서 6개의 버튼을 일일이 CLICK해 봄으로써 해당 조건부의 Y값으로 결론부의 범위를 자르게 하였습니다. 이유는 처음에는 조건부의 6개의 버튼중, 또는 비 퍼지값을 임의로 넣었을 때 입력값에 의하여 조건부에 그려짐과 동시에 결론부에도 일괄적인 처리를 통해서 그림을 뿌려지게 하려 하였으나 Paint 메소드가 컴퓨터 내에서 스레드의 형태로 화면에 그림을 뿌려주기 때문에 순차적인 접근으로 일괄적으로 결론부의 그림을 화면에 모두 뿌릴수 없었습니다. 그래서 다소 번거롭지만 각각의 조건부에 해당되는 결론부를 처리할 때 해당되는 결론부 버튼을 클릭함으로써 값을 얻게 하였습니다.

※ 결론부의 잘려진 그림을 그릴 때 직선의 방정식을 이용하여 각각의 X 또는 Y 좌표의 포인트를 계산하려 하였으나 컴퓨터 화면상의 픽셀은 세로, 즉 Y 픽셀은 위로 갈수록 값이 작아지기 때문에 직선의 방정식을 그대로 이용하면 원하는 픽셀의 결과를 얻을 수 없었습니다. 그래서 X를 구하기 위한 식 x=( ((x2-x1)/(y2-y1))*(y-y1) )+x1 의 식을 변형하여 y2와 y1의 위치를 변경하여 시도를 해 보았으나 그것 역시도 주어진 y값에 의해서 원하는 x픽셀을 찾지 못하였습니다. 이 과제에서 주어진 조건은 극히 제한적이기 때문에 y값이 0.25,0.5, 0.75, 1.0을 갖을 때를 switch문을 이용해서 x값을 찾도록 하였습니다.

※ 잘려진 결론부의 그림들을 모두 합하여 y좌표의 max값을 통한 x좌표의 회전값을 이용해서 무게중심을 구해야 합니다만 잘려진 각각의 도형들의 선들이 만나는 지점을 찾는 것이 어려웠습니다. 처음부터 직선의 방정식을 이용해서 잘려진 부분의 x값을 찾을 수 있었다면 약간의 조건문과 반복문으로 max 값만의 line을 축출할 수 있었을 텐데 저는 그렇게 하지 못하여 각각의 잘려진 부분의 무게중심들을 구하여 모두를 더한 값을 잘려진 부분이 있는 결론부의 수로 나눈 값을 최종 결과값으로 출력하도록 하였습니다.

※ Max-Min CRI 알고리즘의 개념은 극히 단순하지만 그것을 프로그램으로 구현하는 과정은 어려웠습니다. 특히 수학의 직선의 방정식과 컴퓨터의 픽셀을 연결하는데 연구가 필요하다고 느꼈습니다.




* 대학교 시절 인공지능 시간에 만들었던 퍼지 알고리즘 객체지향 언어의 장점을 활용하지 못하고 무작정 손가락 가는대로 만들었던 것 같다.
사용자 삽입 이미지
<초기 실행시 화면>

사용자 삽입 이미지
<조건부 2의 버튼을 눌렀을 때의 화면>


사용자 삽입 이미지
<비퍼지값 3을 입력 하고 Setting을 누르고 결론부 1부터 6까지 누른 상태 화면>


사용자 삽입 이미지
< Max-Min Result 버튼을 누른 상태 화면>



사용자 삽입 이미지




    

설정

트랙백

댓글

무결점에 도전하는 아름다운 사람들의 이야기

Programming/Etc 2007. 2. 27. 02:53
 지금의 고등학교에서는 문과와 이과를 구분하여 수업을 듣고 있는지 모르겠으나 나의 고등학교 시절에는 문과와 이과를 나누어 ‘가벼운 수학’과 ‘깊이 있는 수학’으로 구분하여 수업을 들었던 기억이다. 수학이 싫다는 단순한 생각에서 이과가 아닌 문과를 지망하게 되었지만 수학은 여전히 나의 기대에 부합하지 않고 문과에서 날 괴롭혔다.
 
 그러했던 나의 선택에 그나마 스스로에게 최선을 다 하겠다며 수학 시간에 학내 도서관에서 빌린 소설책을 선생님 몰래 보면서 스스로를 위한 하곤 했다…^^; 지금은 직장생활로 인해서 전문서적을 보는 것으로 책 읽기를 대신하고 있으니 평소에 소설을 책 한 권 접하기가 쉬운 일이 아니다.
 
 그래서 얼마동안 이 두 가지 토끼(전문 서적 & 에세이 & 소설)을 잡을 욕심으로 가벼운 프로그래밍 관련 서적을 구입하여 읽었다. 읽다 보니 임백준이라는 저자의 책들을 읽게 되었는데 그 중 4권을 소개해 볼까 한다.
 
 먼저 저자 임백준은 삼성 SDS와 미국 루슨트 테크놀로지에서 소프트웨어 엔지니어로 근무했으며 월간 마이크로소프트웨어에 컴퓨터 칼럼을 연재했고 인터넷 신문 “프레시안”에 시사 칼럼을 쓰고 있는 저자다.
 책은 초판발행일자 기준으로 정리 하였다.

1. 행복한 프로그래밍 – 컴퓨터 프로그래밍 미학 오디세이
사용자 삽입 이미지

: 책 제목에 ‘프로그래밍’이라는 말이 들어가면 사람들은 대개 기술적이거나 전문적인 내용을 다루는 책을 떠올리기 마련이다. 하지만 ‘행복한 프로그래밍’이라는 제목에서 필자가 중점을 둔 부분은 “프로그래밍”이라는 명사가 아니라 “행복한”이라는 형용사다. 다시 말해서 이 책은 특정한 기술이나 전공 지식을 담은 책이 아니라 컴퓨터 프로그래밍 속에 들어 있는 미학을 전달하려는 소프트한 얘기를 담고 있는 책이다. –서문중에서
해바라기 씨앗의 배열을 닮은 피보나치 수열은 매우 아름답지만, 그것을 컴퓨터 프로그램으로 옮기는 것이 별로 어려운 일이 아니라는 사실은 나중에야 알게 됐다. 그 때에는 화면에 나타나는 숫자들을 바라보는 것만으로도 황홀감을 느낄 지경이었다 – “영혼을 녹여서 만드는 아름다운 공식” 중에서…



2. 누워서 읽는 알고리즘 – 생각하는 방법을 알려주는 알고리즘 이야기
사용자 삽입 이미지
: 이 책은 어렵고 복잡한 알고리즘을 ‘쉽게 풀어서’ 설명한 책이 아니다. 오히려 맛있는 읽을거리를 만들기 위해서 알고리즘과 같은 기술적인 내용을 ‘동원한’ 책이다. 나는 새로운 알고리즘 이론을 소개하는 것도, 독자들에게 알고리즘을 ‘강의’ 하는 것도 아니다. 즉 ‘공부’와는 아무런 상관이 없다. 나는 실전 프로그래밍을 업으로 삼고 있는 사람들과 함께 가볍게 ‘수다’를 떨면서 우리가 매일 수행하는 ‘일’이 얼마나 재미있는지, 얼마나 아름다운지 그리고 얼마나 창조적인지 확인하고 싶었다 – 서문 중에서
짧은 시간이 흐르고, 화면에 나타나는 결과를 보았을 때 필자의 가슴은 그만 철렁 내려앉고 말았다. 화면에 나타난 것은 정상적인 페이지가 아니라 페이지 수가 이미 최대 값에 도달했으므로 더 이상의 페이지를 열 수 없다는 오류 메시지였다. 모든 경우에 대해서 완벽하게 동작하는 것처럼 보였던 알고리즘안에 조용히 숨어 있던 버그가 드디어 모습을 들어낸 순간이었다 – ‘재즈로 여는 아침의 향기’ 중에서



3. 나는 프로그래머다 – 무결점에 도전하는 아름다운 사람들의 이야기
사용자 삽입 이미지
: 인생에 있어서 도전이란 결코 입맛에 딱 맞는 방식으로 찾아오지 않는다. 그것은 언제나 두 발을 전부 땅에서 떼서 허공에 몸을 완전히 맡겨야 하는, 따라서 상당한 불편함과 두려움을 수반하는 방식으로 찾아온다. 어렵지만 마음에 쏙 드는 일자리를 만났을 때, 어렵지만 풀어 보고 싶은 문제를 만났을 때, 어렵지만 한 번 걸어 보고 싶은 길을 만났을 때, 어렵지만 한 번쯤 말을 꼭 걸어 보고 싶은 이성을 만났을 때, 필요한 것은 앞뒤를 재고 따지는 ‘계산’이 아니라 최선을 다해서 허공에 몸을 맡기는 ‘용기’다. – 서문 중에서
이 책은 IT 각 분야에서 종사하는 7분이 모여서 만든 책이다. 김용준, 김종호, 원은희, 유영창, 이춘식, 임백준, 허광남, 임백준을 제외한 분들은 책을 많이 써보지 않은 분들이라 그런지 문장이나 형식이 자연스럽지 못하다는 느낌이 많이 들었던 것 같다. 임백준의 글이 가장 읽기 편했다. (길들여 진 것일까..;;)





4. 임백준의 소프트웨어 산책 – 소프트웨어에 대한 새로운 시선 그리고 통찰력
사용자 삽입 이미지
: 이 책은 공부를 목적으로 하는 책이 아니다. 프로그래밍과 조금이라도 관련이 있는 사람이라면 이 책을 한 손에 들고 다른 한 속으로는 새우깡이라도 먹으면서 마치 소설책처럼 읽을 수 있기를 바라면서 글을 썼기 때문이다. 사실 이 책은 소설을 담고 있다는 점에서 실제로 ‘소설책’이기도 하다. 깊이와 짜임새를 향한 결심은 지켜내지 못했지만 독자들이 이 책을 재미있게 읽을 수 있기를 바라는 마음에서 아예 소설을 한 편 쓰기도 했다. 말하자면 프로그래머가 프로그래머를 위해서 프로그래밍을 주제로 쓴 소설인데, 책의 뒤에 실려 있다 – 서문중에서
“어려운 문제를 드디어 풀어냈다는 성급한 기대가 K씨의 심장을 빠르게 뛰게 만들었다. 사실 프로그래머가 이와 같은 ‘유레카’의 순간에 느끼는 순백의 열정은 사랑에 빠진 청춘의 감격과 별로 다를 것이 없다. 적어도 그 순간만큼은 세상의 모든 사물이 그 자리에서 동작을 멈추고 시간이 정지한다. – 프로그래머 K씨의 하루 중에서




 이렇게 4권의 책을 읽게 되었다. 임백준은 프로그래밍에 숨어 있는 미학을 발견하고 프로그래밍을 통해서 세상을 이해하려는 노력을 하고 있다. 현재는 뉴욕 월스트리트에서 금융 소프트웨어를 개발하고 있다고 한다. 책의 서문이나 내용을 보면 알 수 있겠으나 대부분의 책들은 프로그래밍이나 컴퓨터 언어에 대한 해박한 지식을 요구하거나 강요하지 않는다. 그렇다고 프로그래밍과 전혀 관련이 없는 사람들이 읽기에는 공감이 가는 성격의 글이 아니기에 권하고 싶은 마음은 없다.
 
 작년 Macromedia conference MAX 2005 KOREA에서 스피커로 나왔던 Jared Tarbell은  “프로그래밍은 시와 같다”, “프로그래밍은 아트다” 와 같은 이야기를 한 적이 있다. 임백준이 프로그래밍에서 발견한 미학이라는 것이 이런 의미에서의 아름다움이 아닐까 하는 생각이 든다. 나 자신도 구조적으로 잘 짜여진 짧지만 많은 의미를 담고, 아름다울 만큼 창의적인 결과를 표현하는 프로그램을 보면 ‘아름답다’라는 표현이 가장 적절하다는 생각이 든다.
 
 얼마 전에 모 출판사에서 나에게 책을 쓸 것을 권한 적이 있다. 판매금액의 10%를 받는 조건으로 책을 쓰면 어떻겠냐는 이야기였다. 금전적인 문제를 떠나 내가 쓴 책이 일반 서점에서 독자들에게 판매될 수 있다는 것을 생각하니 결정도 내리지 않은 시점인데도 흥분되는 일이 아닐 수 없었다.
 
 며칠 동안 고민하다가 일단 샘플을 하나 만들고 간단한 구조로 내용을 담아 보았다. 그런데 가만히 내가 만든 소스와 내가 쓴 글을 보고 있으니 책으로 세상에 내놓기에는 쓰레기 같아 보였다. 소스는 순전히 개인적인 습관과 입증되지 않은 구조와 알고리즘으로 낙서를 해놓은 것 같은 느낌이 들었다.
 
 임백준의 책 속에 이런 내용이 있다. “자신이 만든 프로그램으로 만든 전투기를 직접 자신이 조정할 수 있는 용기가 있는가” 결코 쉬운 일이 아닌 듯 싶다. 더군다나 인터넷이 아닌 인쇄물로 한번 세상에 내놓으면 수정할 수도, 업데이트 할 수도 없는 책을 출간한다면 잘못된 정보를 통해 위와 같은 질문에 ‘예’라고 대답한 사람들의 사고들을 내가 어찌 감당할 수 있겠는가 싶었다. 그래서 다음날 출판사 담당자에게 기회가 되면 다음에 쓰겠다고 정중히 거절을 했던 일이 있었다. 지금도 나는 그때의 결정을 잘 했다고 생각한다.
 
 프로그래밍이 아름다음을 갖으려면 그것을 만드는 사람의 흥미와 재미, 열정과 인내가 필요한 작업이 아닐까 싶다. 혹시나 나는 인내가 어려워 가벼운 흥미와 재미를 쫓고 그것을 열정이라 자찬하고 있는 것은 아닐런지...;
    

설정

트랙백

댓글