피파온라인

요즘 내가 하는 유일한 게임은 피파온라인. 한번 손대면 끝도 없이 계속 플레이 하게되는 RPG게임과 달리 한 경기로 깔끔하게 마무리 되는 스포츠게임은 시간 부담없이 즐길 수 있다는 장점이 있다. 탄력 받으면 여러게임을 연달아 하기도 하지만.
 
피파온라인에서 나의 등수는 대략 82000등이다. 그럭저럭 중상위권(?)에 속하는 등수라고 할 수 있고, 승률은 대략 51.5%, 골득실은 대략 +30골. 빨간 유니폼이 마음에 들고 4-4-2 포메이션을 고집하는 관계로 영국대표님 혹은 맨유를 선택해서 게임을 즐기고 있다.
 
재밌게 하다가 이 게임을 지우게 될 때가 있다. 바로 매너와 배려라는 것을 전혀 모르는 초딩(?)을 만났을 때! 오늘 점심을 먹고 식후땡(?)으로 피파온라인을 몇 게임 했다. 나보다 등수는 하위권이였으나 승률과 골득실은 훨씬 뛰어난 친구와 게임을 즐기게 되었는데, 이 친구가 게임 중에 하는 소리가 가관이다. 골이 들어 갈때마다 혼자 “골”, “굿” 이러면서 슬슬 약올리기 시작하더니  나중에는 “그 실력으로 날 이기려고?”, “ㅉㅉㅉ” 이라고 혼잣말을 즐기고 있었다. 기억하고 싶지 않은 건지, 기억이 안나는 건지 그 밖에도 반말을 포함하여 상대방의 기분을 상하게 하는 말들을 지치치도 않고 혼자서(!) 열심히 쏟아냈다.

이럴 때 나는 철저히 침묵으로 일관한다. 어차피 대응해봐야 나도 똑같이 초딩(?)이 되어버린다는 생각이 들어서. 하지만 초딩(?)의 철 없는 몇 마디에 기분이 상하는 걸 보면 나도 아직 한참 어린 것 같다. 그렇게 기분이 상하고 나면 부질없음을 깨닫고 차분히 책으로 돌아간다.

만행

만행 1
현각 지음, 김홍희 사진/열림원
만행 2
현각 지음, 김홍희 사진/열림원

몇달 전 선애누나가 이 책을 읽으시면서 대략의 줄거리를 이야기 해주셨는데 그 것을 듣고 난 꼭 이 책을 읽고 싶었다. 꼭 사서 읽고 싶었는데 절판되어서 결국 못 구하다가 선애누나에게 빌려서 3일만에 읽어버렸다. 나 스스로 최근 종교에 대해서 많은 고민을 하고 있었기 때문에 현각스님이 천주교 집안에서 태어나 스님이 되기까지의 이야기가 너무나 궁금했다.

현각 스님이 되기 전의 폴은 호기심이 왕성한 아이였다. 그는 성경을 수도 없이 읽었고 신실한 믿음을 가지고 있었으며 예수님의 뜻을 따라 남을 돕는 삶을 살고자 노력했다. 폴은 카톨릭계 학교에 다녔는데 수녀님들은 그의 질문에 당황하고 힐책할 뿐 납득할만한 대답을 주지 못한다. 그 질문이 내가 기독교에 가지고 있는 것과 너무나 비슷했기 때문에 나 역시 책을 읽으면서 수녀님들의 대답이 실망스럽게 느껴졌다.

이를테면 “불신지옥”에 관한 것이나, 태어날 때 부터 불행을 가지고 태어나는 아이들에 대한 것이다. 하나님은 아이들을 사랑하신다고 하는데 태어날 때 부터 마약에 중독되어 태어나는 아이, 에이즈에 감염되어 태어나는 아이, 먹고 살기도 힘든 가난한 환경에서 태어나는 아이들을 어떻게 이해할 수 있을까? 폴의 의문을 접하며 나는 김혜자님의 <꽃으로도 때리지 마라>에서 그녀가 아프리카의 처참한 상황을 바라보며 외쳤던 외마디가 들려오는 듯 했다.

폴은 어려서 부터 진리를 찾고 싶어 했기에 예일 대학에 진학하여 본격적으로 철학과 신학을 파고 들었다. 그 과정에서 그는 키르케고르, 쇼펜하우어 등의 많은 철학자를 만났으나 명확힌 진리를 찾지 못하고 방황한다. 그후 하버드 대학원에 진학한 폴은 우연히 한국의 숭산스님의 이야기를 듣고 매료되어 한국을 찾고 종국에는 스님이 되어 폴이 아닌 현각이 되었다.

참선을 통해 자기 안에서 진리를 찾는 선불교의 스님이 된 현각은 오히려 자신이 수행자로서 참선을 하는 것이 예수님의 뜻을 이해하고 예수님의 뜻대로 사는 것에 도움이 된다고 이야기 한다. 어떤 종교집단에 소속되어, 어떤 형식을 따르는 것이 중요한 것이 아니라 예수나 부처와 같은 성인의 가르침을 따라 마음과 행동을 일치시켜 남을 돕는 삶을 사는 것이 중요한 것이 아닐까 하는 생각이 든다.

현각의 스승인 숭산스님은 세계에 현존하는 4대 생불로서 어린아이 같은 맑은 눈과 순수한 미소를 가진 분이라고 한다. 책을 읽으면서 나도 그분을 뵙고 싶고, 그 분의 설법을 들어보고 싶다는 생각이 들었다. 또한 불교라는 종교에 대한 강한 호기심이 생겨 현각스님과 숭산스님의 쓴 책을 읽어볼 계획이다. 진리란 무엇일까? 무엇이 올바른 삶일까?

SWT/JFace

이 글에서는 SWTJFace가 대략 무엇인지, 그리고 이클립스에서 차지하는 위상은 어떤 것인지에 대해서 개괄적으로 이야기하겠습니다. JFace는 일종의 프레임워크이다 보니 공부를 상당히해야 코딩이 가능하지만, SWT를 이용한 코딩은 AWT/Swing으로 UI를 작성해 보신 분이라면 쉽게 적응하실 수 있으리라 생각됩니다. 구조에 큰 차이가 없습니다.

SWT는 Standard Widget Toolkit의 약자로 이클립스에서 UI를 표현하는데 사용되는 API 입니다. SWT가 나오기전에는 AWT와 Swing을 사용했습니만, 써보신 분은 아시겠지만 UI가 어설프고 예쁘지가 않습니다. SWT의 특징은 현재 사용중인 OS에 어울리는 미려한 UI를 제공한다는 것입니다. JNI를 이용해 호스트 운영체제가 제공하는 사용자 인터페이스를 불러서 사용하기 때문이죠. 이클립스를 윈도우, 리눅스에서 각각 실행해보면 SWT와 Swing의 차이를 확인할 수 있습니다. Swing을 사용한 어플리케이션은 윈도우에서나 리눅스에서나 적당히 비슷하면서도 적당히 어설픈 UI를 보여줍니다.

이클립스 플러그인을 제작할 때, SWT는 빈번히 사용됩니다. 마법사의 각 페이지나 Preference 페이지를 작성할 때 등등 세부 사용자 인터페이스를 정의할 때 SWT 코딩을 해야 합니다. 이클립스에서 UI를 제공하는 클래스는 다음과 같이 createContents() 메서드를 오버라이딩 함으로써 유저 인터페이스를 정의합니다. 이때 사용되는 것이 SWT 입니다.

 protected Control createContents(Composite parent) {
  // TODO Auto-generated method stub
  initializeDialogUnits(parent);
  // Get composite and set layout manager
  Composite composite = new Composite(parent, SWT.NONE);
  GridLayout layout = new GridLayout();
  layout.marginHeight = convertVerticalDLUsToPixels
    (IDialogConstants.VERTICAL_MARGIN);
  layout.marginWidth = 0;
  layout.verticalSpacing = convertVerticalDLUsToPixels(10);
  layout.horizontalSpacing = convertHorizontalDLUsToPixels
    (IDialogConstants.HORIZONTAL_SPACING);
  composite.setLayout(layout);

AWT/Swing과 다른 몇가지 SWT의 특징을 언급하고 JFace로 넘어가겠습니다. 우선 Widget간의 부모/자식 관계를 맺는 방법에서 차이가 있습니다. AWT/Swing에서는 다음과 같은 방법으로 부모 인스턴스에 자식 인스턴스를 추가합니다. 패널에 버튼을 추가하는 것을 예로 들 수 있겠습니다.

부모_인스턴스.add(자식_인스턴스);

반면에 SWT에서는 자식 인스턴스를 생성할 때 부모의 인스턴스를 첫번째 인자로 넘겨줍니다. 예제코드에서 Composite을 추가하는 부분을 참조하세요. 그리고 두번째 인자로 스타일 비츠(style bits)라는 것을 정의합니다. SWT.NONE, SWT.PUSH, SWT.CHECK 등이 스타일 비츠에 해당합니다. 이 상수들을 |로 묶어 Widget의 속성을 결정합니다. 물론 각 Widget마다 유효한 스타일 비츠가 정해져 있습니다. 마지막으로 언급할 것은 SWT가 실제 운영체제의 리소스를 사용하기 때문에 더 이상 쓰지 않을 때 해제해야 한다는 점 입니다. 대부분의 SWT Widget은 앞서 살펴본 것 처럼 생성자에서 부모를 지정하기 때문에, 부모를 폐기하면 자식도 폐기된다는 규칙에 의해서 문제가 되지 않습니다. 하지만 부모의 Widget 없이 생성된 SWT 오브젝트인 Font, Image, Color 등등은 사용하지 않을 때 직접 폐기해야 합니다.

JFace는 SWT를 보완하기 위해, 모델 기반 접근 방법(model-based approach)을 기반으로 더 적은 시간에, 더 이해하기 쉬운, 재사용 가능한 코드를 작성할 수 있도록 설계되었습니다. JFace는 UI를 효과적으로 작성하기 위한 일종의 프레임워크라고 할 수 있습니다. JFace 뷰어를 예로 들자면, JFace 뷰어가 제공하는 클래스를 상속해 정해진 절차를 따라서(!) ‘뚝딱뚝딱’ UI를 코딩하면 ‘짠!’ 하고 그럴듯한 하이퀄리티(?)의 UI를 화면에서 확인할 수 있는 것 입니다. JFace는 모델-뷰 구조로 구성되어있기 때문에, 이미 어플리케이션에서 사용하던 모델을 자연스럽게 사용할 수 있습니다. 물론 모델과 뷰사이의 연결을 담당하는 코드를 작성해야 하겠지만요. (e.g. ContentProvider , LabelProvider) JFace는 UI의 얼개에 해당하므로 SWT 역시 함께 사용해야 합니다. 

Wizard

아주 오랜만에 이클립스 플러그인에 관한 글을 다시 적게 되었습니다. 연구실에 남아있을 마지막 2주일 동안 그 동안 못다뤘던 부분들을 정리하려 합니다. 오늘은 마법사에 대해서 다루겠습니다. 마법사(Wizard)가 무엇인지는 각종 개발툴을 써보셨다면 이미 잘 알고계실 것 같습니다.  VICODE 사용자 메뉴얼을 존대말로 쓰다보니 탄력받아(?) 존대말로 쓰게 되었네요.

마법사는 여러 페이지로 구성되어 있습니다. 각 페이지는 프로젝트를 생성하는 등의 작업을 위한 일련의 단계를 표현합니다. 그리고 각 페이지는 자신에게 필요한 정보가 입력되었는지를 판단하여 마법사에게 알립니다. 마법사는 페이지의 상태에 따라 다음 페이지로의 이동가능 여부를 판단하여 UI에 반영하는 것이죠. 모든 페이지가 완료 상태에 도달하면 Finish 버튼이 활성화 되어 마법사를 종료할 수 있습니다. Finish 버튼이 클릭되면 마법사는 각 페이지에서 받은 정보를 바탕으로 원하는 작업을 수행하게 됩니다.

코드레벨에서 살펴보면 마법사는 마법사 클래스각 페이지에 해당하는 클래스의 집합으로 구성됩니다. 마법사 클래스는 페이지 클래스를 참조하고 있고  addpages() 함수에서 페이지 클래스를 마법사에 등록합니다.

지금부터는 코드를 가지고 상세구현 과정을 살펴보도록 하겠습니다. 이클립스 플러그인의 시작은 확장점입니다. 마법사를 추가할 수 있는 확장점은 총 3가지가 있는데, 이 글에서는 프로젝트 생성 마법사를 추가하는데 사용되는 org.eclipse.ui.newWizards를 사용하겠습니다. 다음코드는 확장을 정의한 plugin.xml 코드의 일부분입니다.

   <!– new project wizard –>
   <extension
         point=”org.eclipse.ui.newWizards“>
      <category
            id=”kr.ac.kaist.vicode”
            name=”VICODE”/>

      <wizard
            canFinishEarly=”false”
            category=”kr.ac.kaist.vicode”
            class=”kr.ac.kaist.vicode.wizard.NewProjectWizard
            finalPerspective=”kr.ac.kaist.vicode.perspective”
            hasPages=”true”
            icon=”icons/esterel_image.gif”
            id=”kr.ac.kaist.vicode.newprojectwizard”
            name=”VICODE Project”
            preferredPerspectives=”kr.ac.kaist.vicode.perspective”
            project=”true”/>
   </extension>

마법사 확장점에는 여러가지 속성이 있습니다. Perspective 관련 속성에는 VICODE perspective의 id를 정의하였습니다. canFinishEarly는 모든 페이지를 다 거치지 않아도 완료할 수 있는 마법사인지를 정의합니다. hasPages는 여러 페이지를 가진 마법사인지를 정의합니다. 예제로 보여드릴 VICODE 프로젝트 생성 마법사는 2페이지로 구성되어 있고 모든 페이지를 거쳐야 하므로 위의 코드와 같이 정의하였습니다.

먼저 마법사 클래스(NewProjectWizard)를 살펴보도록 하겠습니다.

public class NewProjectWizard extends Wizard implements INewWizard
{
 private WizardNewProjectCreationPage mainPage;
 private WizardInitialPage initialPage;

 private IProject newProject;

 public boolean performFinish()
 {
  createNewProject();
  initialPage.finish(newProject);
  return true;
 }

 public void addPages()
 {
  mainPage = new WizardNewProjectCreationPage(“New VICODE Project (1/2)”);
  mainPage.setDescription(“Create a new VICODE project in the workspace”);
  mainPage.setTitle(“Create VICODE Project”);
  initialPage = new WizardInitialPage(“New VICODE Project (2/2)”);
  initialPage.setDescription(“You can specify top module name and communication event.”);
  initialPage.setTitle(“Module declaration for hardware and Communication Event”);
  addPage(mainPage);
  addPage(initialPage);

 }

프로젝트 마법사 클래스는 Wizard 클래스와 INewWizard 인터페이스를 상속합니다. 예제 마법사의 목표는 두 페이지에 걸쳐 정보를 받아 들인 후 프로젝트를 생성하는 것 입니다. 총 2페이지로 구성되어 있는데, 첫번째 페이지는 구현하지 않고 이미 작성된 프로젝트 생성 페이지를 가져다가 사용하였습니다. 이 페이지는 단순히 프로젝트 이름과 저장위치를 지정할 수 있도록 구성되어 있습니다. 두 번째 페이지는 VICODE 프로젝트를 생성하는데 있어 필요한 정보를 입력받기 위해 직접 구현한 페이지입니다.

addPages() 메서드에서는 각 페이지의 인스턴스를 생성하고 초기화한 후에 addPage() 메서드를 호출하여 마법사에 각 페이지를 등록합니다. Finish 버튼이 클릭되면 호출되는 performFinish() 메서드에서 마법사 완료시에 필요한 일들을 기술합니다. 실제 프로젝트가 생성되는 코드는 첨부파일을 참조하시기 바랍니다.


지금부터는 두번째 페이지에 해당하는 코드를 살펴 보겠습니다.

public class WizardInitialPage extends WizardPage
{
 public void createControl(Composite parent)
 {
  Composite composite = new Composite(parent, SWT.NONE);
  GridLayout gridLayout = new GridLayout();
  gridLayout.numColumns = 1;
  composite.setLayout(gridLayout);
  createModuleNameGroup(composite);
  createCommunicationGroup(composite);
  setControl(composite);

  updatePageComplete();
  setMessage(null);
  setErrorMessage(null);

 }
 private void updatePageComplete()
 {
  setPageComplete(false);
  // 페이지의 완결성 체크
  if (moduleNameText.getText().equals(“”))
   return;
  // 페이지의 완결성 체크를 건너 뛰었다면 페이지를 완료상태로 변경
  setPageComplete(true);
  setMessage(null);
  setErrorMessage(null);

 }

마법사의 모든 페이지 클래스는 WizardPage 클래스를 상속합니다. UI를 정의하는 다른 클래스와 마찬가지로 createControll() 메서드에서 SWT로 사용자 인터페이스를 작성합니다. 마지막에 호출되는 메서드인 updatePageComplete()는 페이지에 필요한 정보가 입력되어 있는지를 판단하기 위해 제가 작성한 메서드 입니다. 이 메서드는 각 컨트롤에서 값이 변경될때마다 호출되어 페이지가 완료상태인지를 setPageComplete() 메서드를 호출하여 마법사에 알립니다.

이상으로 이클립스 플랫폼에서 마법사를 구현하는 방법에 대해서 말씀드렸습니다. 아래 첨부한 소스코드를 참조하시면 이해하시는데 도움이 될 것 같습니다.

bk20.java

리콜

사용자 삽입 이미지
요즘 내가 하고 있는 일은 유종의 미를 거두고 원할한 인수인계를 위해 내가 개발한 VICODE의 사용자, 개발자 메뉴얼을 작성하는 것이다. 간단한 예제에 대하여 개발하는 과정을 직접 따라가며 메뉴얼을 작성하던 중 사진 아래에 보이는 임베디드 보드를 활용하여 실제로 시스템을 구현하는 단계에 이르렀다.

VICODE의 핵심기능 중 하나는 임베디드 리눅스에서 돌아가는 소프트웨어와 임베드드 보드에 붙어 있는 FPGA의 하드웨어간의 인터페이스를 자동으로 생성하는 것이다. 하드웨어와 소프트웨어 사이의 연결통로를 자동으로 생성해주어 소프트웨어는 라이브러리를 사용하듯 API를 호출하여 하드웨어와 통신할 수 있도록 하는 것이다.

원하는 시나리오는 다음과 같다. 소프트웨어가 A()라는 함수를 호출하고 B()라는 함수를 호출하면 LED 1번에 찬란하게 빛이 들어와야 한다. 그러나 결과는 깜깜 무소식! 순간 내 머리속을 스치는 단어는 “리콜”. (석사학위논문은 지도교수가 6개월안에 취소할 수 있는데 우리는 이를 흔히 “리콜”이라고 부른다.) 순간 마음이 분주해졌다. 소프트웨어 버그였다면 비교적 금방 찾겠지만 소프트웨어와 하드웨어사이의 통신은 몇 단계를 거치기 때문에 무엇이 문제인지 찾기 힘들다. 결국 묵혀둔 연구노트를 펼쳐 원인을 발견하고 문제해결에 성공. 희망의 LED가 찬란하게 빛났다.

아직 연구실에서 해야할 일이 많지만 내가 원해서 하는 일이기에 즐겁게 하고 있다. VICODE를 이어서 개발하게 될 재호형이나 올해 연구실에 들어올 석사신입생들의 시행착오를 조금이라도 줄여줄 수 있다고 생각하니 뿌듯한 마음이 든다. 떠나는 뒷모습이 아름답도록(?) 남은 기간 내게 주어진 일들을 즐겁게 매듭짓자!