들어가며...
UI를 개발해 본 모든 개발자들이 느끼겠지만 UI 개발은 다른 분야의 개발보다 복잡하고 까다롭습니다. 수년간 여러 어플리케이션을 개발하며 이러한 문제를 접하였고 많은 생각을 가지게 되었습니다. UI 분야의 개발이 왜 까다로운지 또한 그 해결방안은 무엇인지에 대해 논하고자 합니다. 이 문제는 최근에 참여한 프로젝트의 예를 들어 설명하겠습니다.
최근 POI를 관리하는 관리툴 개발에 참여하였습니다. POI(Point Of Interest)란 GPS상의 좌표를 의미하는데 우리말로는 '흥미있는 지점' 으로 해석할 수 있습니다. 즉, 주요 관공서, 건물, 상점 등 우리가 네비게이션을 이용하여 찾아가는 목표 지점을 의미합니다. 이러한 POI를 관리하는 도구가 POI관리툴입니다. POI관리툴은 맛집이나 주변지 상점등을 검색하거나 네비게이션에서 경로안내를 하는데 필요한 데이터를 제공합니다.
프로젝트 상황
기존 POI관리툴은 델파이로 만들어졌습니다. 고객은 델파이로 유지보수할 인력 수급에 어려움을 겪고 있었고 마침 기간계 시스템이 자바 기반의 시스템으로 변경됨에 따라 POI관리툴도 자바 기반으로 재개발하기로 하였습니다. 비주얼베이직이나 델파이와 같은 데스크탑 어플리케이션 개발 플랫폼이 있지만 이들은 C계열의 언어이므로 인력 수급에 문제가 있습니다. 그러나 Eclipse RCP(Rich Client Platform) 플랫폼은 자바 언어로 개발이 가능하여 자바 개발 인력도 쉽게 접근 가능하다는 장점이 있어 새로운 POI관리툴 개발에는 Eclipse RCP를 사용하기로 하였습니다. 더구나 기간계 시스템이 자바로 되어 있으므로 기간계 시스템과의 연계도 자연스럽게 이루어질 수 있습니다.
Eclipse RCP는 자바기반 개발도구인 Eclipse IDE의 기반 플랫폼입니다. 즉 개발자들이 많이 사용하는 Eclipse IDE는 RCP로 되어 있다는 의미입니다. 그만큼 화면이 유려하고 풍부한 API를 제공한다고 볼 수 있습니다. RCP는 플러그인 기반의 플랫폼으로 확장이 용이하고 Eclipse Workbench의 기능 뿐만 아니라 3rd Party에서 제공하는 다양한 플러그인도 활용 가능합니다. 예를 들어 어플리케이션에 그래픽 기능을 넣고 싶으면 GEF(Graphical Editing Framework)를, 모델링 기능을 넣고 싶으면 EMF(Eclipse Modeling Framework)를 사용하면 됩니다.
결국 자바 기반이며 데스크탑 어플리케이션을 위한 기반 플랫폼으로는 Eclipse RCP 만한 것이 없는 것 같습니다. 저는 Eclipse Plugin 강의도 진행하고 있는데 최근에 수강생이 몰리는 현상은 이와 무관하지 않을 것입니다. 그만큼 RCP에 대한 수요는 점점 늘어 전통적인 도구인 비주얼베이직이나 델파이를 대체하지 않을까 하는 생각이 듭니다.
개발 플랫폼을 RCP로 결정하고 나서 고객의 요구사항과 기존 UI를 분석해 보았습니다. POI관리툴의 주 사용자는 POI를 입력하는 사람입니다. 이 사용자는 POI 입력하고 관리하는 것을 실수없이 정확하게 해야 합니다. 그러다 보니 가능한 한 많은 정보를 한 화면에서 보길 원하였습니다. 예를 들면 POI 입력 화면 이외에 검색화면, 지도화면, 주변지역 사진 등을 동시에 화면에 열어놓고 사용해야 합니다.
그러나 기존 툴은 그러한 요구사항을 제대로 반영하지 못했습니다. 하나의 윈도우 안에서 내부 화면으로 이를 처리하다 보니 많은 정보를 한 번에 볼 수가 없었습니다. 왜 델파이는 하나의 윈도우 안에서 모든 기능을 구겨넣었을까 하는 의문이 들었지만 각설하고 이 요구사항의 처리는 RCP 기반에서는 쉽습니다. 여러개의 윈도우 화면을 별도의 SWT Shell로 구현하면 됩니다. 더불어 이벤트 리스너 방식을 사용하여 각 윈도우의 변경사항이 다른 윈도우에 영향을 주고 받게 하였습니다. 프로토타입 형태로 이런 모습을 보여주니 고객은 만족해 하며 당장 각 사용자에게 모니터를 추가해 주어야겠다고 하였습니다.
그러나 더 큰 문제는 절대적으로 많은 화면량 그리고 복잡한 화면 구성에 있었습니다. 이러한 많은 화면량은 줄일 수도 없었습니다. 왜냐하면 POI를 중심으로 해서 다양한 이해관계자가 존재하기 때문입니다. 각 이해 관계자 별로 POI에 대한 관리의 주제가 다르고 주제가 다르므로 공통 UI로 통합 할 수 없었습니다.
이러한 문제는 코드의 품질과도 직결됩니다. 수많은 반복적인 코드가 양산되리라는 것은 불을 보듯 뻔한 일입니다. 또한 제한된 기간 내에 이렇게 많고 복잡한 화면개발을 마칠 수 있을지 의문이 들었습니다. 설상가상으로 상당수의 팀원들이 자바는 알지만 RCP 기술을 처음 접한다는 것입니다.
UI 컴포넌트의 필요성
위에서 제시한 문제를 해결하기 위해서는 반복적인 코드를 줄이고 특정 기술에 대한 진입점을 낮추어야 합니다. 즉, 구조화에 따른 화면설계가 필요하며 각 단위화면은 컴포넌트화 되어야 합니다. 이것이 과연 가능한가에 대해 알아보겠습니다.
일반적인 엔터프라이즈 환경에서 어플리케이션을 설계할 때 Layer 기반의 아키텍처를 따릅니다. 이 아키텍처는 컴포넌트 기반의 설계를 전제로 합니다. 각 레이어는 하나 이상의 컴포넌트들로 구성되며 레이어 간의 의존관계는 아래로만 가능합니다. 이러한 방식은 여러 엔터프라이즈 환경에서 적용하고 있는 일반적인 방법입니다. 그 이유는 기술구조와 관심사를 분리할 수 있고 운영 유지보수에 커다란 잇점을 가지고 있기 때문입니다.
Layer 아키텍처는 각 레이어 별로 관심사 및 기술구조가 다릅니다. 데이터 접근 레이어는 데이터 및 자원의 입출력에 관심이 있고 프레젠테이션 레이어는 사용자 경험을 어떻게 구현할 것인지에 관심이 있으며 비즈니스 로직 레이어는 순수하게 업무 로직에만 집중합니다.
설계 입장에서 각 레이어를 살펴보겠습니다. 프레젠테이션 레이어를 제외한 나머지 레이어는 관심사가 명확하고 실행환경 즉 Runtime Platform이 거의 정해져 있으므로 설계시에 여기에 영향을 받지 않습니다. 따라서 이 레이어들은 컴포넌트화 하기 쉽습니다. 문제는 프레젠테이션 레이어인데 경험상 프레젠테이션 레이어는 컴포넌트화 하기 어렵습니다. 그 이유를 나열하면 다음과 같습니다.
사용자가 직접 대면하는 레이어입니다. 따라서 변덕이 심한 사용자의 요구사항에 흔들리기 쉽습니다.
Runtime Platform이 다양합니다. Thin Client 형태의 웹기반이 될 수도 있고 Rich Client가 될 수도 있습니다. 또한 스마트 폰을 비롯한 모바일 기기가 등장하면서 실행환경이 더욱 다양해졌습니다. 이와같이 다양한 Platform을 모두 만족시켜주는 프레젠테이션 컴포넌트를 설계하기는 거의 불가능에 가깝습니다.
프레젠테이션 레이어에 해당하는 Framework 및 기술이 매우 다양하며 기술에 종속적인 설계를 할 가능성이 높습니다. 예를 들어 Struts Framework 기반에서 설계된 프레젠테이션 컴포넌트가 REST 기반의 Jersey 프레임워크 또는 Rich Client 기반에 적용되기는 어렵습니다.
이와같이 위에서 제시한 문제를 해결하기 위하여 프레젠테이션 레벨의 컴포넌트화가 필요한데 프레젠테이션 레이어에서는 불행하게도 컴포넌트화가 어렵습니다. 그러나 길이 아주 없는 것은 아닙니다. 우선 프레젠테이션 구현 기술을 고정하고 Rich Client 기반의 Runtime Platform을 사용하면 어느정도 가능합니다. 그리고 제한적이지만 다양한 Runtime Platform에 대한 요구사항은 구현기술 조합으로 풀면 됩니다.
예를 들어 프레젠테이션 기술을 RCP(Rich Client Platform)으로 고정하고 멀티 Runtime Platform을 위하여 RCP-RAP 기술 조합으로 단일소스 전략으로 간다면 여러 실행환경(데스크탑-Web)에서 UI컴포넌트화가 가능합니다.
위에서 언급한 프로젝트 사례에서는 다행히 RCP라는 Rich Client 기술을 사용하기로 결정하였으므로 프레젠테이션 레이어의 컴포넌트(이하 UI컴포넌트라고 함)를 설계하기가 쉽습니다.
그럼 왜 Rich Client 플랫폼에서는 UI 구성요소를 컴포넌트화 하기 쉬울까요? 그것은 Rich Client에서는 상태를 유지하기 쉽기 때문입니다. 그림과 같이 Web UI 즉 Thin Client 플랫폼은 요청이 발생하고 화면을 만든 후 이를 Client에 전달하고 끝내는 방식으로 되어있습니다. 반면에 Rich Client는 화면이 만들어 지면 요청이 끝나도 화면 인스턴스는 계속 존재합니다. Runtime에 UI인스턴스가 계속 유지되면 UI의 행위 및 인접 UI간의 상호작용 등 관련 로직을 쉽게 캡슐화 할 수 있습니다. 이 차이로 인해 Rich Client가 UI 를 컴포넌트화 하기 쉽습니다.
따라서 프로젝트에서는 RCP 플랫폼 기반 위에 하나의 계층을 추가하여 UI컴포넌트 영역을 두기로 하였습니다. 즉, SWT와 JFace 계층 위에 UI컴포넌트를 두어 UI컴포넌트는 SWT/JFace를 사용하고 POI관리툴 Application은 UI컴포넌트로 화면을 렌더링하고 동작을 정의합니다.
UI컴포넌트 식별/설계
프로젝트의 상황에서 절대적으로 많은 수의 화면과 복잡한 화면이 문제입니다. 그래서 구조화를 하기 위해 가능한 한 모든 화면을 분석해 보았습니다. 화면을 분석해 보니 몇가지 패턴들을 발견할 수 있었습니다.
화면이 아무리 복잡하고 다양해도 기본적으로 '타이틀 + 화면컨트롤' 조합으로 되어 있습니다. 이 단위 화면은 비즈니스와는 무관합니다.
업종 단위화면과 같이 많은 화면에서 반복적으로 노출되는 화면 덩어리가 있습니다. 이 단위화면은 비즈니스와 관련있으며 화면내의 컨트롤들 간에는 밀접한 연관성이 있습니다.
그래서 이러한 단위화면들을 UI컴포넌트로 식별하여 구조를 설계하였습니다. 구조는 크게 UI컴포넌트와 UI컨트롤로 나누어 지며 UI컴포넌트는 여러개의 UI컨트롤로 화면을 구성합니다. 컴포넌트 내의 각 컨트롤은 Event Handler에 의해 상호작용이 가능합니다. 또한 UI컴포넌트에 특정 비즈니스를 적용하기 위하여 UI컴포넌트에 Injection 가능한 Business Provider를 정의하였습니다.
한편 UI컴포넌트에서 조합될 수 있는 단위 UI컨트롤을 식별하였습니다. 각 단위UI컨트롤은 독립적으로 실행되며 다른 UI컨트롤과는 관련성이 없습니다. 그리고 UI컨트롤의 동작이나 Validation 로직을 은닉화시켜 단위UI컨트롤 내에서만 실행되게 합니다.
UI컴포넌트 효과
일반적으로 Eclipse RCP로 개발한다고 하면 크게 화면의 틀을 만드는 API와 화면을 상세하게 그리는 API를 혼합하여 사용합니다. 즉, 메뉴나 뷰, 에디터와 같은 큰 화면 구조는 Eclipse에서 제공하는 Workbench를 사용하고 상세UI는 SWT/JFace를 사용하여 개발합니다. 위에서 설계한 UI컴포넌트는 SWT/JFace 위의 계층으로 존재합니다. 따라서 UI컴포넌트를 이용하여 개발을 하면 직접 SWT/JFace를 사용하지 않아도 됩니다.
이 말은 다시 예기해서 개발자가 RCP의 기술을 잘 몰라도 UI컴포넌트만 잘 알면 화면을 그릴 수 있다는 말입니다. 이러한 점은 아키텍처에서 커다란 의미를 지니게 됩니다. RCP 기술에 대한 진입장벽이 상당히 높다는 점은 잘 알려진 사실입니다. 만일 상당수의 개발자들이 RCP를 잘 모른다면 이는 커다란 리스크로 작용합니다. 이러한 상황에서 UI컴포넌트 구조를 제시하면 상당부분 리스크를 축소시킬 수 있습니다. 실제로 위에서 언급한 프로젝트에서 반 이상의 팀원들이 RCP 기술을 잘 모르는 상태에서 개발을 진행해야만 했습니다. 그러나 결과적으로 UI컴포넌트를 도입하면서 부터 크게 무리없이 각자 화면개발을 진행할 수 있었습니다.
UI컴포넌트를 도입하면 실질적으로 낼 수 있는 효과는 다른데에 있습니다. 즉 절대적인 코드량을 줄일 수가 있다는 것입니다. 실제로 UI컴포넌트를 프로젝트에 적용해 보니 UI관련 코드량을 1/5로 줄일 수 있었습니다. 그 이유는 아래에서 확인해 볼 수 있습니다.
간단한 UI코드를 테스트해 보았습니다. 그림과 같은 화면을 만들기 위해 우선 SWT API를 사용하여 코드를 작성 해 보았습니다. 약 80~90라인으로 이 화면을 만들 수 있었습니다.
이번에는 같은 화면을 UI컴포넌트를 사용하여 코드를 작성 해 보았습니다. 딱 10라인이 나왔습니다. 동일한 화면인데도 코드량이 많이 줄었습니다. 이 말은 개발 공수가 줄어든다는 의미입니다. 또한 화면이 절대적으로 많고 복잡도가 있는 프로젝트에서는 개발기간 단축에 절대적으로 기여할 수 있다는 것을 의미합니다. 실제로 프로젝트에 적용해 보니 개발해야 될 화면(약 70여개)이 상당히 많았음에도 예상되는 일정 보다 여유있게 단축시킬 수 있었습니다.
UI컴포넌트 발전방향
실제 프로젝트에 적용해 본 결과 UI컴포넌트의 개념과 그 효과는 상당히 고무적입니다. 그러나 설계 측면에서 약간의 아쉬움이 남습니다.
첫번째는 설계의 일관성입니다. 프로젝트 초반에 UI컴포넌트를 나름의 기준을 가지고 설계하였습니다. 이것을 실제 화면개발에 적용하면서 UI컴포넌트 구조도 계속 업그레이드 해 나갔습니다. 그러나 모든 일이 그렇든 항상 예외 상황이 발생하기 마련입니다. 프로젝트 초/중반에는 이러한 예외 사항이 발생하면 시간이 좀 걸리더라도 원칙을 가지고 UI컴포넌트를 재설계하는 수준까지 변경을 하였습니다. 그러나 프로젝트 막바지에 이르러서는 시간적 문제와 막대한 영향도로 인해 UI컴포넌트 레벨의 재설계를 하지 못했습니다. 그래서 예외코드가 발생할 수 밖에 없었습니다. 시간이 좀 더 있었더라면 이러한 부분도 구조적으로 처리 할 수 있지 않을까 하는 아쉬움이 남습니다.
두번째는 UI컴포넌트 설계 방향입니다. 초기에는 단일 UI컴포넌트 인스턴스는 다른 UI컴포넌트 인스턴스와는 독립적으로 동작한다고 생각 했었습니다. 그러나 실제로 적용해 보니 UI컴포넌트 간에도 상호 영향을 끼치는 부분이 상당히 있었습니다. 이 부분은 일반적으로 이벤트 리스너 패턴을 사용하는데 이 패턴을 UI컴포넌트 바깥에서 적용할 수 밖에 없었습니다. 따라서 차후에 UI컴포넌트를 설계할 기회가 다시 생긴다면 이러한 부분까지 UI컴포넌트 구조에 반영할 생각입니다.
앞으로 설계할 UI컴포넌트는 Event Provider와 Event Listener가 추가될 것입니다. 즉, 다른 UI컴포넌트에 영향을 주는 이벤트가 있을 경우 Event Provider가 이를 처리하고 이벤트를 받는 입장의 UI컴포넌트는 Event Listener가 담당합니다. 그리고 사용자 및 다른 리소스로 부터 받는 이벤트는 Event Handler가 처리합니다. 실제 비즈니스를 처리하는 모듈은 Inner Processor입니다.
마치며...
지금까지 UI개발의 문제점을 프로젝트 사례를 들어 설명하였습니다. UI 개발의 가장 큰 문제점은 컴포넌트화 혹은 모듈화가 어렵다는 점입니다. 그러하다 보니 항상 백엔드의 개발 보다 프론트엔드 개발이 복잡하고 난이도가 있으며 무엇보다도 개발 공수의 상당 부분 차지한다는 것이 문제였습니다. 그러나 프론트엔드의 구조화 및 정제화는 몇가지 전제조건이 있다고 가정하면 어느정도 가능하다는 것이 이번 글의 결론입니다. 그것은 최근 진행하였던 프로젝트의 결과가 증명하고 있습니다. 따라서 Rich Client 플랫폼이라는 가정이 존재하면 그것이 자바 언어든 스크립트 언어든 컴포넌트화가 가능하다고 봅니다.