NY** project를 리뷰하려고 이전 메일을 찾아보던 중에, project 진행 간 인상적이었던 부분들을 정리했던 내용이 있어 다시 한 번 공유합니다.


abstract class를 상속(inherits)하여 구현하는 예제입니다.

Controller 생성자에 $controller를 전달한 뒤 하이라이트 코드와 같은 형태로 상속이 가능합니다.

$scope injecting하기 위해서 두 번째 param를 전달합니다.

이를 이용하면 duplicate code between controllers 문제를 풀 수 있습니다.

 

'use strict';
angular.module('Diary')
// base controller containing common functions for add/edit controllers
.controller('Diary.BaseAddEditController',
['$scope', 'DiaryService',
function ($scope, DiaryService) {
$scope.diaryEntry = {};
$scope.saveDiaryEntry = function () {
DiaryService.SaveDiaryEntry($scope.diaryEntry);
};
// add any other shared functionality here.
}])
.controller('Diary.AddDiaryController',
['$scope', '$controller',
function ($scope, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
}])
.controller('Diary.EditDiaryController',
['$scope', '$routeParams', 'DiaryService', '$controller',
function ($scope, $routeParams, DiaryService, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
$scope.diaryEntry = data;
});
}]);


Reference

http://jasonwatmore.com/post/2014/03/25/angularjs-a-better-way-to-implement-a-base-controller

'Javascript' 카테고리의 다른 글

Ionic 2 Unit test  (0) 2017.07.31
Service workers.  (0) 2017.07.06
npm lite-server  (0) 2017.07.06
Calculate distance between two geolocations.  (1) 2017.06.28

Zipper를 개발하면서 WPF 개발 practice를 정리해 보았습니다.

개념적인 부분 위주로 다루겠습니다.


WPF

Windows Presentation Framework.

뭔가 거창하지만 .Net 진영의 Winform의 버전업이라고 보시면 될 것 같습니다.

RIA(Rich internet application) 및 WindowsPhone7을 위한 platform인 Silverlight의 부모격이며, UWP 등의 현재 MS platform의 근간이기도 합니다.


MS가 ASP.NET Webform에서 MVC로 바뀌면서 패러다임 및 기술의 큰 변화를 이루었고, Winform을 WPF로 변경하면서도 그렇습니다.

UI는 XML베이스의 xaml(재믈이라고 읽습니다.)로 작성합니다.

로직은 전통적인 방식의 code_behind 형태로 개발할 수도 있으나, MVVM이라는 패턴을 권장하고 있습니다.



MVVM pattern

Model - View - ViewModel의 약자입니다.

익숙한 MVC와 크게 다르지 않습니다만, View와 Model을 완벽하게 분리할 수 있다는 점이 특징입니다.

이를 위해서는 Data binding, Command(Behavior)라는 개념이 필요합니다.


이를 통해서 xaml designer와 programmer는 서로의 영역을 침범하지 않고 app을 개발할 수 있습니다.


출처: http://hackersstudy.tistory.com/71



MVVM Light

이러한 MVVM pattern을 지원하기 위한 다양한 library가 존재합니다.

대표적으로 MVVM Light를 들 수 있으며, 지난 NY**에서 사용한 MVVM Cross도 그 일종입니다. (Alex는 후자를 좋아하더라고요. )


MVVM pattern에 따른 개발에 필요한 추상 class 및 helper들을 제공하며, IoC 기능도 지원합니다.

예를 들면, ViewModel의 base가 되는 ViewModelBase, IoC를 위한 SimpleIoc, Command를 지원하기 위한 RelayCommand 등이 있습니다.



IoC

Inversion of Control.

해석하기 참 애매하네요, 제어 반전??


이건 도저히 짤게 넘길 수 없는 주제이네요.

아래의 link를 살펴 봅시다.


https://msdn.microsoft.com/en-us/library/ff921087.aspx


이를 위한 개발 패턴으로는 Service Locator pattern과 Dependency Injection(DI) pattern이 있습니다.

개발한 Zipper에서 실제 App 부분을 MVVM light를 통한 service locator pattern을 사용하였고, Unit test에서는 Dependecy injection pattern을 이용하였습니다.



MUI Template

WPF를 통해 UI 표현력을 크게 향상시켰음에도 불구하고, 기본적인 그 형태는 기존의 것 (Winform)과 큰 차이를 느끼기 어렵습니다.

WPF가 공개되고 Morden UI (or Metro UI라고 불리우는)를 Windows8을 통해서 크게 대중화시켰던 MS의 제품의 그러한 design을 손쉽게 적용할 수 있도록 MUI Template이 제공됩니다.


쉽게 이와 같은 UI를 만들 수 있다는 거죠.


https://github.com/firstfloorsoftware/mui/wiki


Conclusion

WPF는 관심사의 분리를 완벽하게 해낸 의미 있는 framework입니다.

실제 개발 과정에서 개발자는 VisualStuio를 통해, 디자이너는 Blend라는 툴을 이용해 완벽하게 따로 작업할 수 있습니다.


초기 웹에 대한 붐이 일었을 때, Html과 javascript 및 ASP, PHP 코드가 뒤섞인 환경에서 개발자와 디자이너는 앙숙일 수 밖에 없었습니다.

내가 다 개발해 놓으면 디자이너가 기능을 망가뜨리고, 디자이너가 UI를 잘 꾸며 놓으면 개발자가 layout을 흐트려 놓는...


이렇게 틀을 잘 만들어 놓았기에 이어서 UWP나 Xamarin이나 이를 근간으로 할 수 있었습니다.

xaml이 XML을 근간으로 하다 보니 Microsoft 진영의 mark up 언어의 parsing 속도는 Java 진영에 비해서 월등하다는 소문을 들은 적도 있습니다. :)



또한, 개발에 대한 pattern도 바뀌었습니다.

저는 게으른 개발자로서 application을 개발하면서, 수시로 app을 실행해 보고 테스트해 보는 작업이 피하고 싶었습니다.

그리고 그러한 고민을 하던 선배들이 그 방법을 검토해왔고, 그러한 practice들을 만들어 왔습니다.


흐름에 뒤쳐지지 않기 위해서가 아니라 더 나은 개발을 위해서 그리고 더 나은 결과를 만들어 내기 위해서 이러한 패턴의 습득은 선택이 아닌 필수라고 생각합니다.


MV* pattern이나 IoC는 비단 .net platfrom에서만 도입된 개념이 아니고, Java나 혹은 javascript framework에도 적용이 됩니다.

AngularJs도 controller 선언할 때 참조할 service 등을 나열하는 것으로 의존성을 해결하고 있습니다.


이는 또한 product의 완성도를 높이는 가장 높은 방법 중 하나입니다.


KEMP.Zipper란?

KEMP engine (Mars ver)에서 운용할 binary를 압축하는 application입니다.

본연의 압축 기능 이외에 지난 버전에서 문제된 Customizing의 어려움, serialize 요소 부재 등을 해결하기로 하였고,

지난 UWP project에서 활용한 MVVM pattern을 적용시켜보기 위해서, WinForm이 아닌 WPF platform의 practice를 만들어 보기로 하였습니다.


기능 개발 외적인 목표

새로운 platform으로 개발하는 만큼, 또한 TDD에 대한 관심과 경험이 어느 정도 쌓인 만큼, project진행 간 기능 개발 외적인 목표를 두었습니다.

 1. TDD를 하자

 2. WPF를 하자

 3. CLI를 만들어 보자

 4. Resource 통합 관리를 해보자

 5. WPF application 개발 practice를 만들어 보자


결과적으로 WPF는 ModernUI(MUI) Template을 적용하는 등의 목표 대비 추가 달성을 하였으나,

UX 설계 및 테스트 과정에 아쉬움이 남는 project였습니다.


Solution overview



 Project

Description 

Remark 

KEMP.Zipper.App

WPF app 

MVVM 

KEMP.Zipper.BetaApp 

WPF app (beta) 

개발자 UI 

KEMP.Zipper.CLI 

Command Line Interface 

Console에서 기동(미완) 

KEMP.Zipper.Configuration 

Define configuration 

AppSetting 대체 

KEMP.Zipper.Core 

Zip, Validation 

압축 및 유효성 검증 로직 구현 

KEMP.Zipper.Model 

Define model 

Model class 선언 

KEMP.Zipper.Resources 

Define resource 

Resource 통합 관리 

KEMP.Zipper.Test 

Test project 

 




KEMP.Zipper.App / BetaApp

과거에 사용 경험이 있던 MVVM light NuGet을 사용하였습니다.

전에는 단순 MVVM pattern 개발을 위해서 사용했는데, ViewModelLocator에서 IoC(Inversion of Control) 처리가 손쉽게 되어 ViewModel에 필요한 Service를 손쉽게 전달할 수 있었습니다.


MVVM light가 제공하는 ViewModelLocator에서 IoC처리에 대한 선언을 하고, ViewModel을 property로 노출시킨 다음, View에서는 ViewModelLocator에서 그 ViewModel의 property를 참조하여 Data binding을 수행합니다.

ViewModel의 생성자에서 필요로하는 service interface는 MVVM의 IoC를 통해서 제공됨으로써 별도의 처리가 필요치 않습니다.

Service와 ViewModel의 분리하여 테스트할 수 있는 장점이 생기게 됩니다.


Metro UI라고도 불리는 Modern UI Template을 적용하였습니다.


이 틀을 벗어나는 UI를 만들기 위해서 Template 자체의 source를 까서 수정해야 했다...


이 Template을 사용함으로써 기존의 Winform application과 시각적으로 큰 차별화를 이루었으나, UI Design이 꽤 제한되는 상황이라 이를 customize하느라고... 상당히 애를 먹었습니다 :-D

https://github.com/firstfloorsoftware/mui/wiki


KEMP.Zipper.Configuration

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="appStructureSection"
type="KEMP.Zipper.Configuration.AppStructureSection, KEMP.Zipper.Configuration" requirePermission="true"
restartOnExternalChanges="true"
allowLocation="true" />
</configSections>
<appStructureSection>
<angular>
<add rootFolder="client"
items="pages;app.js;route.json;index.html;" />
<add rootFolder="server"
items="BLP;Configuration;Configuration\AppSettings.xml;Metadata\...;" />
</angular>
<angular2>
<add rootFolder="client"
items="pages;app.js;route.json;index.html;" />
<add rootFolder="server"
items="BLP;Configuration;Configuration\AppSettings.xml;Metadata\...;" />
</angular2>
</appStructureSection>
</configuration>

자세한 내용은 아래의 link를 참고하시길 바랍니다.

요약하면 appStructureSection element에 대한 설계를 담고 있는 project이며, App.config로부터 해당 내용을 읽어들이는 logic을 포함하고 있습니다.

http://bandcy.tistory.com/entry/ConfigurationSection을-이용한-App-configuration


KEMP.Zipper.Core

public interface IZipper
{
event EventHandler<ProgressEventArgs> ProgressChanged;
void Zip();
void Validate();
string TargetPath { get; set; }
string ProjectPath { get; set; }
string ZipName { get; }
ValidationError[] Messages { get; }

void Serialize();
void Deserialize();
}

본 Application의 주가 되는 기능. 즉, Zip, Validation, Serialize/Deserialize 작업을 수행하는 project입니다.

또한, Zip Progress를 Event로 노출하여 progess의 진행률을 바깥 쪽에서 확인할 수 있도록 하였습니다.


IZipper를 상속받는 Zipper(AngularJs ver), Angular2Zipper(Angular2 ver)용을 구현하였습니다.


KEMP.Zipper.Model

ZipModel, ValidationError 등에 대한 선언을 담고 있습니다.

ZipModel은 사용자가 project path를 전달했을 때, 그 경로를 통해서 company, project 등의 기본적인 정보를 파악하는 기능을 가집니다.

보편적으로 DB작업을 하는 경우, Service, DAO tier에서 공통으로 사용하는 Model을 별도의 project로 분리하는 pattern을 자주 사용했던 패턴입니다.

습관적으로 본 project에서도 Model project를 별도로 분리하였으나, 완료한 현 시점 뒤돌아 보니 굳이 Core와 분리할 필요가 없었을 것 같습니다.


KEMP.Zipper.Resources

사용자에게 노출하는 문장을 통합 관리하기 위한 별도의 project

내부적으로 resource dictionary와 resource key를 인자로 sentence를 반환하는 기능만을 제공함. 이 key value pair를 MJ에게 전달하여 검수했으며, 그 결과를 손쉽게 적용할 수 있었습니다.

향후 다국어를 지원한다면, 당 project를 확장하여 제공하는 것으로 충분할 것으로 기대합니다.


KEMP.Zipper.Test

Project type은 Unit project이며, Test가 반복적으로 사용하는 상수는 별도의 Consts.cs 파일에 취합해 두고 참조하는 형태로 진행하였습니다.Model, Core, App 등의 project를 테스트하기 위한 목적의 project.

코드를 refactoring할 때마다, Run All 수행하면서 수정한 code의 side effect 여부를 체크하였습니다.



모두 녹색 불이 들어왔을 때의 짜릿한 기분이란!!


Slack의 활용

Project 진행 간 공지사항 및 issue 등을 별도의 #kempzipper라는 채널을 통해서 통합관리함으로써, 아 그게 뭐였던라…? 하던 궁금증을 손쉽게 찾아볼 수 있도록 하였습니다. 또한, 나중에 project에 참여한 member도 그 history를 손쉽게 파악 가능할 수 있었다고 생각합니다.

Members

 

@ally, @fireclon profile 사진 좀 바꿔요...


형상관리의 부재

이런 저런 이유로 형상 관리 시스템을 사용하지 않았는데, TDD에 의거하여 수시로 refactoring하다가 긴급하게 배포해야 할 타이밍에 배포할 수 없는 상황과 마주하게 되었습니다. 막판에 구두로 커뮤니케이션 한 부분에서 미스가 발생했습니다.

남은 시간 동안 마무리 할 수 없는 상황인지라, Beta라는 딱지를 달고 이전에 테스트했던 개발자 UI를 부랴부랴 복구하여 end user에게 전달했습니다.

Refactoring하면서 비난 받던 개발자 UI를 완전히 엎어버린게 얼마나 후회가 되던지...

잦은 refactoring을 수반하는 TDD는 형상관리가 필수적이다라는 것을 깨닫게 되었습니다.


개발자 UI라는 말은 듣기 싫지만, 이렇게 만드는 건 너무 편하다!!



회고

시간이 없어서 TDD를 못한다는 얘기는 자주 듣게되는 변명입니다.

그런데 저도 project 막바지에 App project 부분을 작업할 때, 시간이 없다는 핑계로 TDD를 못했습니다.

MVVM pattern에서 ViewModel에 대한 test practice를 좀 더 연구해 봐야겠습니다.

local file system에 대한 mock을 주입하는 것을 해 보지 못한 것도 매우 아쉬운 부분입니다.


이 화면을 만들기 위해서 나는 그렇게 고생을 했나 보다.


References

https://github.com/firstfloorsoftware/mui/wiki/Screenshots

https://mvvmlight.codeplex.com/


+ Recent posts