TypeScript 언어 핵심 요약 사항

TypeScript 핵심 요약은 ES6 에 추가된 기능과 중복된 항목이 있다. TypeScript 는 Javascript 의 슈퍼셋(Superset)이라고 하지만, 아직 ES6 를 완벽하게 지원하지 않는다. 그래서 본 글의 핵심 요약은 TypeScript 에서 추가된 기능이자 ES6 와 중복된 내용이 있다.

ES6 의 새로운 기능은 다음의 링크에서 참고하기 바란다.

TypeScript 2.1 최신이고 아직 꾸준히 업데이트 중이며, 1.8 버전을 기준으로 비교된 ES6 와 호환 테이블이다.

TypeScript 의 모든 언어 사양은 아래의 링크를 참고하기 바란다.


1. var vs let 키워드

var 키워드는 Javascript 의 그 var 키워드와 동일한 역할을 한다. var 키워드는 function scope 단위로 할당이 된다. 그래서 아래의 예제와 같이 원하지 않는 결과를 얻을 수도 있다.

일반적으로 사용하는 방법은 Javascript 의 var 와 동일하게 사용하면 되고, TypeScript 에서는 되도록 let 을 쓰도록 권장하고 있다.

var 키워드

for (var i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
10
10
10
10
10
10
10
10
10
10

let 키워드

for (let i = 0; i < 10 ; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
0
1
2
3
4
5
6
7
8
9

2. Indexable 타입

C# 의 인덱서와 동일한 역할을 하는 Indexable 타입이 있다. Cars 인터페이스가 배열/컬렉션 객체가 아니지만, 마치 배열/컬렉션 객체의 아이템을 가져오는 것처럼, 인덱서를 사용할 수 있다.

interface Cars {
    [num: number]: string;
}

let cars: Cars;
cars = ["Cadillac", "Benz", "BMW", "Audi"];

console.log(cars[0]);

3. Hybrid 타입

인터페이스에 함수를 인터페이싱 하는 방법 중의 하나다. (start: number): string; 는 익명 함수를 선언하고 있고, reset() 은 명시적으로 함수를 선언하고 있다. <Counter> 는 캐시팅을 명시적으로 지정하였으며 counter 변수는 Counter 객체로 캐스팅 된다.

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

4. protected 키워드

객체지향언어의 protected 키워드와 동일한 역할을 한다. 클래스 맴버가 상속받은 자식 클래스에만 노출이 된다.

class Person {
    protected name: string;

    constructor(name: string) {
        this.name = name;
    }
}

class Student extends Person {
    constructor(name: string) {
        super(name);
    }

    say(): void {
        console.log(this.name);
    }
}

let student: Student = new Student("POWERUMC");

student.say();
student.name = "POWERUMC"; // Error

5. Optional and Default 파라메터(Parameters)

Optional 파라메터(Parameters)

기본적으로 TypeScript 는 Javascript 함수처럼 가변적인 매개변수를 지정하여 함수를 호출할 수 없다. (아래 6번에서 가능한 방법을 설명한다.) 여타 객체지향언어처럼 매개변수와 타입에 맞게 호출하는 것이 객체지향언어의 규약이다.

마찬가지로 TypeScript 에서도 함수를 호출하려면 타입에 맞아야 한다.

function test(src:string, dest:string): boolean {
    return src === dest;
}

test("P", "P");
test("P");          // Error

이를 Optional 매개변수로 만들기 위해서 dest? 로 지정하면 된다. dest? 매개변수에는 undefined 가 된다.

function test(src:string, dest?:string): boolean {

    console.log(dest);
    return src === dest;
}

test("P", "P");
test("P");          // Ok

Default 파라메터(Parameters)

Default 파라메터로 만들기 위해 dest = "" 와 같이 리터럴 상수값을 선언하면 된다.

function test(src:string, dest = ""): boolean {

    console.log(dest);
    return src === dest;
}

test("P", "P");
test("P");          // Ok

6. 가변적인 매개변수(Rest Parameters)

...restOfName 처럼 매개변수 이름 앞에 ...을 붙이면 가변적인 매개변수가 된다.

function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
function buildName(firstName: string, ...restOfName: string[]) {
    return firstName + " " + restOfName.join(" ");
}

let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

7. 오버로드(Overloads)

첫 번쨰 pickCard 함수는 명시적으로 object 리터럴로 감싸고 number 타입을 반환하는 함수이고, 두 번째 pickCard{suit: string; card: number; } 타입을 반환하는 함수이다.

세 번째 pickCard 함수가 메인 함수인데, 타입을 체크하여 각각 처리 후 결과를 반환하는데 반환 타입이 다르다는 것을 알 수 있다.

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; };
function pickCard(x): any {
    if (typeof x == "object") {
        let pickedCard = Math.floor(Math.random() * x.length);
        return pickedCard;
    }
    else if (typeof x == "number") {
        let pickedSuit = Math.floor(x / 13);
        return { suit: suits[pickedSuit], card: x % 13 };
    }
}

let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

8. 제네릭(Generics)

C# 의 '제네릭(Generics)' 또는 C++ 의 '템플릿(Tempaltes)' 는 코드 재사용성을 높이고, 타입 안정성, 그리고 성능에서 큰 이점을 준다.

TypeScript 또한 이러한 이점을 그대로 얻을 수 있다.

제네릭 함수(Generic Functions)

function identity<T>(arg: T): T {
    return arg;
}
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <T>(arg: T) => T = identity;
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: <U>(arg: U) => U = identity;
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: {<T>(arg: T): T} = identity;
interface GenericIdentityFn {
    <T>(arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn = identity;

제네릭 클래스 (Generic Classes)

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

9. Nullable Types

let s = "foo";
s = null; // error, 'null' is not assignable to 'string'
let sn: string | null = "bar";
sn = null; // ok

sn = undefined; // error, 'undefined' is not assignable to 'string | null'
function f(x: number, y?: number) {
    return x + (y || 0);
}
f(1, 2);
f(1);
f(1, undefined);
f(1, null); // error, 'null' is not assignable to 'number | undefined'
class C {
    a: number;
    b?: number;
}
let c = new C();
c.a = 12;
c.a = undefined; // error, 'undefined' is not assignable to 'number'
c.b = 13;
c.b = undefined; // ok
c.b = null; // error, 'null' is not assignable to 'number | undefined'

10. for..of 과 for..in 구문(statements)

for..in 구문은 배열의 키 값을 반환하는 한편, for..of 구문은 배열의 항목을 반환하는 다른점이 있다.

따라서 for..of 구문을 사용하는 것을 권장한다.

let list = [4, 5, 6];

for (let i in list) {
   console.log(i); // "0", "1", "2",
}

for (let i of list) {
   console.log(i); // "4", "5", "6"
}

11. 데코레이터(Decorators)

데코레이터(Decorators)는 C# 의 특성(Attributes), Java 의 어노테이션(Annotations) 와 같이 클래스나 함수에 선언적으로 정보를 지정할 수 있다.

reflect-metadata 모듈을 이용하면 런타임에 리플랙션을 이용하여 이 데코레이터의 정보를 얻어와서 처리를 하는 방법도 있다.

function f() {
    console.log("f(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

function g() {
    console.log("g(): evaluated");
    return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("g(): called");
    }
}

class C {
    @f()
    @g()
    method() {}
}
f(): evaluated
g(): evaluated
g(): called
f(): called


Posted by 땡초 POWERUMC

댓글을 달아 주세요

Javascript-OOP-AOP-IoC / 자바스크립트 객체지향 프로그래밍

자바스크립트 객체지향 프로그램을 쉽게 하기 위한 소스 코드를 github 에 공개(https://github.com/powerumc/Javascript-OOP-AOP-IoC)했다.

자바스크립트로 객체지향 프로그래밍을 잘 하려면 배워야 하는 것들이 참 많다. 함수형 프로그래밍과 자바스크립트의 prototype 기반의 chain, 함수를 인스턴스로 사용하고, 객체지향적인 몇 가지 자바스크립트 패턴을 익혀야 하는 데, 쉽지만은 않을 것이다. C

가장 간단한 객체지향 코드를 보자. 이 코드는 Program 클래스를 상속 받은 Outlook 클래스가 있고, run() 메서드로 실행하는 코드다.

function INHERITANCE(PARENT, CLASS) {
	for(var p in PARENT) if(PARENT.hasOwnProperty(p)) CLASS[p] = PARENT[p];

	var PROXY 					= function() { };
	PROXY.prototype 			= PARENT.prototype;
	CLASS.prototype				= new PROXY();
	CLASS.prototype.constructor = CLASS;
}

var Program = (function() {
	Program.prototype.version = "1.0.0";

	return Program;
});

var Outlook = (function() {
	INHERITANCE(Program, Outlook);
	function Outlook() {
		Program.apply(this, arguments);
	}

	Outlook.prototype.run = function() { console.log("[" + this.version + "] Running... "); }
	
	return Outlook;

})(Program);

var outlook = new Outlook();
outlook.run();

너무 성급하게 이해하지 않아도 된다.

조금이라도 쉽게 Javascript 객체지향을 하기 위해 만든 라이브러리를 공개했으니...

설치

  • npm
npm install javascript-oop-aop
  • bower
bower install javascript-oop-aop-ioc

1. 기초

이 라이브러리를 이용하면 매우 쉽게 클래스를 선언할 수 있습니다. oop.class(...) 를 사용합니다.

oop.class( [parents,] classInfo )

  • 클래스 선언
var Program = oop.class({
	say: function() { return "Hello"; }
});

var p = new Program();
p.say();

// return "Hello"
프로퍼티 선언
  • 기본적인 프로퍼티 선언
// Define class.
var Program = oop.class({
	say: function() { return "Hello"; },
	name: "엄준일"
});

var p = new Program();
console.log("My name is ", p.name);

// output
My name is 엄준일
  • 사용자 정의 get/set 프로퍼티 선언
var Program = oop.class({
	say: function() { return "Hello"; },
	name: "엄준일",
	age: { get: function()      { return this._age; },
		   set: function(value) { this._age = value; }
});

var p = new Program();
p.age = 35;
console.log("My age is ", p.age);

// output
My age is 35

2. 상속

oop.class( parents, classInfo )

  • 부모 클래스 상속하기
// Define parent class
var Program = oop.class({
	version: "1.0.2",
	show: function() { 
		console.log("openning window."); 
		/* some code.. */
	}
});

// Define class.
var Outlook = oop.class( Program, {
	run: function() { console.log("running outlook program."); }
});

// Run code.
var outlook = new Outlook();
console.log("version " + outlook.version);
outlook.run();
outlook.show();

// Output
version 1.0.2
running outlook program.
openning window.
  • 자기 자신 참고 (this or self)
var Program = oop.class({
	version: "1.0.2",
	show: function() { 
		console.log("openning window.");
		/* some code.. */ }
});

var Outlook = oop.class( Program, {
	run: function(self) { // inject 'self' argument name.
		console.log("running outlook program.");

		// *** HERE ***
		// a method call inhertianced Program.show method.
		self.show();
	}
});

var outlook = new Outlook();
console.log("version " + outlook.version);
outlook.run();
//outlook.show();      remove this line.

// Output
version 1.0.2
running outlook program.
openning window.
부모 인스턴스 참조

var Program = oop.class({
	run: function() { console.log("run Program.") }
});

var Outlook = oop.class( Program, { // HERE inheritance Program class.
	run: function(base) \ 
		console.log("run Outlook.");  

		// *** HERE ***
		// You can call parent method from base keyword.
		base.run();
	}
});

// Output
// run Outlook.
// run Program.

3. 인젝션 (주입)

oop.inject( [argument], ... )

  • 매개변수 주입
var Program = oop.class({
	version: "v1.0"
});

var Outlook = oop.class( Program, {
	version: "v2.0",
	run: function(base, self) { 
		console.log("base version: "   , base.version)
		console.log("current version: ", self.version);
	}
});

var outlook = new Outlook();
outlook.run();

// Output
base version: v1.0
current version: v2.0
  • 컨테이너로부터 주입

4. 가로채기 - AOP

oop.interception( function, behavior )

oop.interceptionBehavior( before, after, exception, finally_ )

  • 클래스 또는 메서드 가로채기

    • 메서드 가로채기
var Program = oop.class({
	run: function(msg) { console.log("run Program. ", msg); }
});

// *** HERE ***
// Setup the interception a method
var p = new Program();
oop.interception( p.run, oop.behaviors.LoggingBehavior );

// Call a 'run' method.
p.run("Now running...");

// Output
------ enter interception ------
[Thu Nov 13 2014 09:29:41 GMT+0900 (KST)]  {}
run Program.  Now running...
------ end interception ------
  • 클래스 인스턴스 가로채기
var Program = oop.class({
	run: function()       { console.log("run Program.", msg); },
	terminate: function() { console.log("Terminated the Program.") }
});

// *** HERE ***
// Pass class instance arguments
var p = new Program();
oop.interception( p, oop.behaviors.LoggingBehavior );

// Call a 'run' method.
p.run("Now running...");
p.terminate();

// Output
------ enter interception ------
[Thu Nov 13 2014 09:29:41 GMT+0900 (KST)]  {}
run Program.  Now running...
Terminated the Program.
------ end interception ------
  • 사용자 정의 가로채기 (Behaviors)

    • 사용자 정의 가로채기 정의

가로채기 행위를 사용자 정의로 만드시려면 oop.interceptionBehavior 메서드를 호출합니다.

var customBehavior = oop.interceptionBehavior(
	function() { console.log("before"); },
	function() { console.log("after"); },
	function() { console.log("throw exception"); },
	function() { console.log("finally"); }
);

var Program = oop.class({
	run: function() { console.log("run Program."); }
});

var p = new Program();
oop.interception(p,  customBehavior);
p.run();

// Output
before
run Program.
after
finally

코드가 실행 중 예외가 발생할 경우 다음 처럼 exception 함수가 실행됩니다.

var Program = oop.class({
	run: function() { 
		console.log("run Program."); 
		throw "crashing... "; 
}});

var p = new Program();
oop.interception(p,  customBehavior);
p.run();

// Output
before
run Program.
throw exception crashing...   // HERE exception behavior.
finally


Posted by 땡초 POWERUMC

댓글을 달아 주세요

회사에서 Handlebars.java 와 관련된 이슈가 공유가 되었다.

Handlebars 가 Javascript 버전과 Java 버전의 #with helper 결과가 동일하지 않습니다.

우선 이 이슈 버그를 해결한 코드는 필자의 github 저장소 https://github.com/powerumc/handlebars.java.bug-fix 에 커밋 되어 있고, 원본 저장소의 이슈 번호 #314, Pull Request #315 에 등록 되었다.

Handlebars vs Handlebars.java

이 테스트에서 사용되는 handlebars 데이터는 다음과 같습니다.

{ "company": { "ko": "쿠팡",
               "en": "Coupang" }}

그리고 handlebars 템플릿은 다음과 같다.

{{#with company}}
  우리 회사는 {{ko}}
  My company is {{company.en}}
{{/with}}
- Javascript handlebars 결과
  우리 회사는 쿠팡
  My company is 
- Handlebars.java 결과
  우리 회사는 쿠팡
  My company is Coupang

문제 원인

Handlebars.java 를 반나절 정도 분석하고 나니 대충 (정말 대충) 어떻게 흘러가는 지 조금 이해가 되었다.

문제는 Handlebars.java 에서는 #with helper 에서 value 값을 resolving 하지 못하면 parent object (=context) 에서 찾는다. #with helper 에게 전달된 데이터를 model 이라고 하면 전달된 데이터 전체를 context 로 불린다. 그래서 model 의 parent 는 context 가 된다.

위의 상황을 보면 My company is {{company.en}} 와 같은 코드의 model 에서 {#with company}}company.en을 찾지 못해서 context 에서 company.en을 찾게 된다.

문제 해결 방법

문제의 원인을 파악했으니 코드를 디버깅해 알겠지만 튜닝 포인트가 매우 다양하다. #with helper 전체를 뜯어 고칠 수 도 있고, 내부적으로 CompositeValueResolver 를 튜닝하거나, 그 외에 다양한 방법으로 고칠 수 있다.

가장 간단하게 이 버그를 픽스하기 위해 또 반나절 정도를 적용해 보고, 가장 적은 코드로 튜닝할 수 있는 코드를 만들었다.

Options.java 코드에서 wrap(final Object) 메서드를 다음과 같이 픽스하였다. 딱 세 줄만 추가해 주면 된다.

public Context wrap(final Object model) {
  if (model == context) {
    return context;
  }
  if (model == context.model()) {
    return context;
  }
  if (model instanceof Context) {
    return (Context) model;
  }
  if (model.getClass() == LinkedHashMap.class) {  // 이 코드부터...
    return Context.newContext(model);
  }                                               // 여기까지 추가...
    return Context.newContext(context, model);
  }

그럼 아래의 이슈가 되는 테스트 코드가 무사히 통과하고,Handlebars.java 의 모든 테스트도 통과한다.

public class Issue314 extends AbstractTest {

  @Test
  public void withHelperSpec() throws IOException {
    String context = "{ obj: { context: { one: 1, two: 2 } } }";

    shouldCompileTo("{{#with obj}}{{context.one}}{{/with}}",     context, "1");
    shouldCompileTo("{{#with obj}}{{obj.context.one}}{{/with}}", context, "");
 }
}


Posted by 땡초 POWERUMC

댓글을 달아 주세요

인터넷 웹 서비스들이 느려졌다

HTML5 구현체가 속속 모습을 보이면서 웹 서비스들은 다양한 시도를 하고 있다. 과거에는 인터넷을 통해 콘텐트를 생산하여 전파를 했고, 이 콘텐트가 사람들을 모이게 했다. 웹을 통해 커뮤니케이션이 이루어 지면서 비슷한 관심사의 유저들에 의해 인터넷 커뮤니티가 속속 등장했다.

이것이 개인화로 이어지면서 개인이 운영하는 블로그가 많은 인기를 얻었다. 블로그를 열심히 잘 운영하면 사회 지위적인 약자도(a weak person), 잘 알려지지 못한 무림속의 전문가도 여러 사람의 관심을 받을 수 있는 발언권을 가질 수 있게 되었다. 웹 서비스가 자신을 PR하고 개인의 비즈니스 모델이 될 수 있음이 증명되었다.. 필자도 그런 부류 따위의 한 사람이다.

하지만 최근 인터넷 웹 서비스는 예전 보다 더 쾌적한 환경을 제공하는 지 의심이 된다. 방문하는 웹 사이트마다 괴롭다. 네트워크 대역은 더 용량은 더 커졌고, 개인 PC와 스마트폰의 CPU는 더 빨라짐에도 여전히 브라우저로 인터넷 서비스를 이용하는 것은 더 느려졌고 더 많이 기다려야 한다.

이런 몇 가지 주요 요인은 다음과 같이 정리된다.

1. Javascript 언어 본질적인 문제라기 보다

브라우저에서 동작하는 Javascript가 주요 원인이다. 브라우저에서 동작하는 Javascript는 운영 체제의 커널(kernel)이나 드라이버(driver)에 접근할 수 없으므로 가장 빠른 네이티브 함수를 사용할 수 없다.

Javascript 에서 thread(스레드)와 process(프로세스)를 그 외에 GPGPU(General-Purpose computing on Graphics Processing Units) 와 같은 네이티브 함수에 접근할 수 있다면, 브라우저는 '터보 엔진'을 장착한 것이다.

2. 또, 브라우저는 인터넷의 리소스를 동시에 다운로드 할 수는 있으나

Javascript는 동시에 처리할 수 없다. 

다운로드 받은 여러 개의 Javascript 파일은 빠르다고 소문난 크롬의 v8 엔진이 제공하는 context 객체에서 순차적으로 실행이 된다. 그 안에서 function을 만나면 scope 가 생성이 되는데, 이 scope을 병렬로 처리할 수 없고 blocking 되어 실행되어야 context안의 scope의 atomicity(원자성)이 보장된다. 풀어서 다시 정리하자면, javascript는 concurrents 일 수는 있으나 parallels 할 수 없다.

3. 이번 것은 필자가 제일 싫어하는 문제다.

HTTP/HTTPS는 stateless protocol 이므로 브라우저가 redirect/submit마다 매번 인터넷 리소스나 Javascript 를 reload 하게 된다. 브라우저 랜더링 성능을 향상시키기 위해 Javascript 파일을 HTML 문서 하단에 두는 추세이다. 그 결과 브라우저에 표현될 요소들은 모두 표시되었으나 자바스크립트 컴파일이 가장 마지막에 수행되므로 마우스나 키보드 동작 이벤트가 바로 발생하지 않는다. 

한 마디로, 굼떠진다. 브라우저의 화면은 다 떴는데, 마우스 휠과 움직임 그리고 클릭 같은 동작이 툭~툭~ 끊기거나 freezing 되어 버린다.

4. 프로그래밍 측면에서 오버 엔지니어링도 문제다.

웹 페이지에서 [AngularJS]와 같은 라이브러리를 사용하는 것도 성능 저하와 밀접한 관련이 있다. (nodejs 제외)

AngularJS 라이브러리는 공식 페이지에서 다음과 같이 소개한다.

HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications.

AngularJS의 가장 best practices 는 정적 페이지다. SPA(single page application)에 최적화 되어 있다. 하지만, 웹 응용 프로그램에 쓴다고 하더라도 문제가 될 것은 없다.

하지만 AngularJS를 MVC 웹 응용 프로그램과 같이 쓰게 되면 동일한 패턴을 관리하는 포인트가 하나 더 생긴다. 웹 응용 프로그램 레벨에서 MVC 패턴과 View 레벨에서 한번 더 AngularJS와 같은 MV(C) 패턴이 추가 된다. 필자 경험으로 웹 페이지에서 controlling이 필요한 view는 자주 보기 힘들다.

웹 페이지에서 model binding이 필요한 건지, view-model, templating이 필요한 건지 controlling이 필요한 건지, 다시 생각해 볼 수 있는 문제다.

결론

우리나라 속담에 '뱁새가 황새 쫓다가 가랑이 찢어진다'가 있다.

웹이 네이티브 쫓다가 가랭이 찢어진다. 인터넷 웹 서비스가 발전하고 있는 경향은 웹 브라우저에서 네이티브 데스크탑 응용 프로그램(desktop application)과 같은 사용자 경험(user experiences)을 제공하고 싶어 한다.

앞으로도 웹의 기술적인 진화는 네이티브 데스크탑 응용 프로그램 처럼 동작하기 위한 요소들이 추가될 것이다.

AJAX(asynchronous javascript and xml), web socket, web db, comet 과 같은 기술은 분명 웹을 진화시켰다. 하지만 웹 다워 졌다가 아니라, 네이티브 처럼 표현하기 위한 수단이 되었다. 그리고 지금은 많은 웹 서비스들이 네이티브 응용 프로그램을 웹 서비스로 그대로 옮겨 놓았다. 혁신적이기는 하지만 굳이 웹을 통해서 이용할 생각은 없다. 가끔 필요할 때 유용하게 이용하긴 하지만... 브라우저라는 sandbox 환경에서는 절대 네이티브와 같은 사용자 경험을 제공하지 못한다.

많은 모바일 네이티브 앱들이 브라우저에서 돌아가도록 갈아 탔고, 다시 네이티브로 귀환하는 경우를 가끔 본다. 모바일 브라우저에서 페이스북을 즐기긴 여간 까다롭지만, 페이스북 전용 앱을 사용하면 더 큰 재미를 얻는 느낌과 비유해도 될 것 같다.

아직 필자도 결론을 내릴 만큼 정리되지 않았다. 그리고 이런 추이를 지켜보는 것도 재미있다. 

다만 인터넷 웹 서비스는 네트워크 응답 속도와 체감 속도의 향상이 전부가 아니다. 사용자 경험 측면에서 좋은 성능을 내야 함이 분명한 결론이 될 것이다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. muy.kr 2014.04.08 02:11 신고 Address Modify/Delete Reply

    정말 좋은 정보네요.. 잘 보고 갑니다^^

  2. A TearDrop 2014.04.08 03:22 신고 Address Modify/Delete Reply

    잘보고갑니다

  3. 업글 2014.04.08 04:04 Address Modify/Delete Reply

    정말 도움이 많이 되었습니다.
    요즘 추세인 역동적이고 멋진 이펙트들로 느려지는 문제를 제외한다면 요즘 웹은 만들기가 참 편해져갑니다.
    단, 구형브라우저들을 다 버린다는 가정하에 말이지요 ㅋㅋ

  4. 이승근 2014.04.08 12:39 Address Modify/Delete Reply

    AngularJS 의 소개 글은 html은 정적페이지를 위해 최고이지 동적페이지 작성에는 좋지 못하다 따라서 AngularJS를 만들었다 라는 내용인데요.
    정적 페이지가 AngularJS의 best practices라고 말하지 않습니다.

  5. 이승근 2014.04.08 12:58 Address Modify/Delete Reply

    그리고 모든 이벤트 드리븐 기반의 프로그래밍 모델( event loop )에서, 이벤트 핸들러는 event thread에 대해 serialize되어야 합니다.
    이는 모든 UI프로그래밍에서 UI접근은 ui thread(aka main thread/event thread )에서만 수행되어야한다는 제약과 동일합니다. DOM객체를 UI객체로 생각하시면 다른 native 프로그래밍 모델과 크게 다를바는 없습니다.

    그리고 web worker를 제공해서 별도의 thread에서 computing logic을 수행 할 수 있습니다.


    "concurrents 일 수는 있으나 parallels 할 수 없다."
    라는 말은 무슨 의미로 작성하셨는지 이해하기가 어렵네요

    • 땡초 POWERUMC 2014.04.08 17:26 신고 Address Modify/Delete

      읽어 주셔서 고맙습니다.

      '그리고 모든 이벤트 드리븐'은 자바스크립트를 말하시는 건가요?
      이벤트 드리븐이 race condition 하는데, 핸들러가 왜 serialize가 필요한가요?

      그리고 concurrents와 parallels의 의미는 컴퓨터 사이언스의 사전적 의미와 동일합니다.

  6. 이승근 2014.04.08 18:16 Address Modify/Delete Reply

    자바스크립트를 포함 모든 이벤트 드리븐 프로그래밍을 말하였습니다.

    이벤트 드리븐이 race condition이라는 말은 어떤 의미로 하신건지는 모르겠네요,
    race condition은 제가 아는 한에서는,
    같은 자원을 동시에 2개 이상의 thread에서 접근하는 상황인데요,
    이벤트 드리븐 모델에서는 이벤트 자체가 하나의 큐를 통해서 serialize되므로 핸들러간 race condition이 발생하지 않습니다. 그런 의미로, serialize되어야 한다는 말이었구요, 핸들러 안에서 serialize가 필요하다는 말은 아니였습니다.

    그리고, 제가 아는 concurrents는 "동시에 수행 할수 있는"을 의미하고, 자바스크립트의 경우 보통 모두 이벤트 핸들링에 의해서 하나의 thread에 의해서 수행되고, 더구나 DOM이라는 객체 자체가 concurrent한 접근을 허용하지 않기 때문에 concurrent하다고 말하기 어려울듯하네요,

    parallel은 물리적으로 동시에 수행하는 CPU 파이프라인이나,
    물리적으로 여러대의 PC에서 컴퓨팅을 수행하는것에 대해 일컷는 말이라고 알고 있어서, 무엇을 말하려고 하셨는지 잘 이해하기가 어렵습니다.




    • 땡초 POWERUMC 2014.04.08 20:39 신고 Address Modify/Delete

      내용 잘 보았습니다.
      허나 이런 방식으로 논쟁을 계속 해야 할 지 모르겠네요.

      먼저 이벤트 드리븐의 직렬화에 대해서 아래의 링크로 보아도 무방하겠죠?
      https://www.artima.com/weblogs/viewpost.jsp?thread=84958
      같은 메모리 프레임 안에 있는 객체의 포인터 객체를 왜 직렬화 해야 하는지요?
      이벤트는 포인터 함수를 통해 위임을 하고, 이런 방식으로 프로그래밍 하는 것을 이벤트 드리븐으로 알고 있습니다.
      serialize는 네트워크 통신이나 프로세스간, 또는 이기종 간에 데이터를 전송하기 위해 직렬화하는데, 왠 이벤트 드리븐에서 직렬화 얘기가 나오는지 이해가 가지 않네요.
      이것과 관련된 내용이 있으면 링크좀 부탁 드립니다.

      concurrents, 즉 non-blocking을 concurrents로 표현한 것입니다.
      잘못된 비유인가요?

  7. 이승근 2014.04.08 20:47 Address Modify/Delete Reply

    용어 측면에서, synchronization을 썼어야 하는데, serialize를 잘못사용해서 답글을 이해하시는데 혼란을 드린것 같네요.
    결국 event handler는 event thread에 대해 synchronization되며, 이는 모든 event driven기반 프로그래밍 모델에 동일한 사항인데, 자바스크립트의 문제점이라고 하시기에 답글을 달았습니다.

  8. 성현 2014.04.08 20:53 Address Modify/Delete Reply

    잘보구감니다.
    개발당시 요구사항도 요즘은 네이티브처럼 만들어달라는데. 그리하면 정말 검나 느림 ㅡㅡ

  9. Rachel:) 2015.01.22 10:45 신고 Address Modify/Delete Reply

    좋은글 감사합니다! 잘읽고가요~~

필자가 github를 통해서 제공하는 자바스크립트 두 가지 패키지 모두 npm과 관련된 버그가 픽스 되었다.
각각 npm package 버전이 업데이트 되었고, nuget은 금주 중으로 패키지를 재배포 할 예정이다.
또한, Unity 게임 개발 및 Mono 개발에 필요한 MonoDevelop 한국어 버전도 몇 주 전 최신 저장소 코드로 업데이트가 완료 되었다.

Bugs related to npm both packages provided the author through the github has been fixed.
npm is updated each, nuget is a plan to re-distribute the package later in the week.
In addition, the update is complete code of the store also MonoDevelop Korean version a few weeks ago.


MonoDevelop 한국어 버전을 제공하면서 발생하는 (나만 알고 있는..) 한 가지 문제가 있는데, 아직 해결하지 못한 상태이나 곧 업데이트 후 push 예정이다. 벤더가 직접 배포하는 Xamarin Studio를 쓰는 분들은 MonoDevelop 소스 저장소에 머지되기 전에는 해결되지 않을 예정이다.

그리고 azure 클라우드를 통해 호스팅되는 monodevelop-korea.com 사이트가 곧 복구될 예정이다. (생각 없는 클릭 한 방이 사이트를 날려 버린답니다. ㅠㅠ)

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. wlthd 2014.02.21 13:30 Address Modify/Delete Reply

    역시 대단하시네요. 좋은 하루 되세요.

  2. mizix 2014.04.08 16:01 Address Modify/Delete Reply

    monodevelop-korea.com 사이트가 어서 복구되기를....

JS-Lambda 자바스크립트 라이브러리를 공개합니다.


JavaScript Array Extensions 자바스크립트 오픈 소스를 개발한 데 이어 JS-LambdaLGPL 라이센스로 공개합니다.

JavaScript 에서 람다 표현식(Lambda Expression)을 사용할 수 있도록 만든 라이브러리 입니다. 자세한 내용은 아래의 소스 코드를 참고 하시면 됩니다.

Github: https://github.com/powerumc/js-lambda

JS Lambda

  • It is possible lambda expression that can be used JavaScript.
  • you just got a function F();

Simple Examples

// Before  
function func(a,b) {
    return a + b;
}  
console.info( func(4,6) );


// ** After with JS-Lambda **  
var func = F("a,b => a + b");  
console.info( func(4,6) );  

// Result  
10

Or you can invoke directly

// Before  
function anonymousMethod(a,b) {
    return a + b;
}  
console.info( anonymousMethod(4,6) );  

// ** After with JS-Lambda **  
console.info( F("a,b => a + b")(4,6) );  

// Result  
10

Callback Examples

// Before  
function callback( func ) {
    if( func ) func();
}  

callback( function() { console.info('My name is Junil Um'); } );  

// ** After with JS-Lambda **  
callback(  F("() => console.info('My name is Junil Um');")  );  

// Result  
My name is Junil Um  

With jQuery

// Before  
var li = $("item li");  

li.each( function(i, o) {
    $(o).addClass("some");
} );


// ** After with JS-Lambda **  
var li = $("item li");  

li.each( F("(i, o) => $(o).addClass('some');") );  


Posted by 땡초 POWERUMC

댓글을 달아 주세요

Javascript Array Extensions

Array Extensions는 Node.js 와 브라우저에서 사용할 수 있는 배열 라이브러리이다.

요즘 자바스크립트(JavaScript) 를 만지는 날이 많아져서 JavaScript 로 뭘 만들 수 있을까 하는 생각에 기억을 더듬어 보니 JavaScript 에서 배열을 다루는 일이 많았다. jQuery의 selector 등으로 DOM을 다루는데 효과적이지만, 배열을 다룰 때는 모라는 점이 많았다.

인터넷에 찾아보면 자바스크립트(JavaScript)로 배열을 다루는 오픈 소스를 발견하였다. 그 중 가장 호감이 가는 자바스크립트(JavaScript) 오픈 소스를 발견하였다. 자바스크립트로 C#과 가장 비슷하게 Enumerable과 LINQ를 구현한 자바스크립트다.

사실, 필자가 만들고 싶었던 디자인이 linq.js와 비슷했지만, 역시나 이미 나와있으므로 좀 더 Lightweight 하게 쓰도록 만들어 보았다. 요 몇일 3~4일 동안 틈틈히 만들었고, 더 큰 디자인으로 갈 생각은 없다.

완성도를 좀 더 높이면 npm, nuget 등에서 패키지로 배포할 예정이다.

설치하기

Nuget

PM> Install-Package JS.Array.Extensions

Node.JS

$ npm install js-array-extensions

required('js-array-extensions');

from Github

Array Extensions는 Github를 통해 배포하고 있다.

https://github.com/powerumc/array-extensions

git 를 이용하여 다음과 같이 소스 코드를 받을 수 있다. 소스 코드를 받을 디렉토리로 이동한 후 다음의 명령을 실행하면 된다.

git init  
git clone https://github.com/powerumc/array-extensions.git  

사용 방법은 매우 간단하다. README.md 에 포함한 예제 하나만 보면 쉽게 이해할 수 있을 거라 생각한다.

var arr = Array.range(1, 10)
               .select(function(i) { return { number:i, name:"POWERUMC " + i } })
               .where(function(o) { return o.number >= 5 })
               .take(3);  

// results var arr  
POWERUMC 5  
POWERUMC 6  
POWERUMC 7  

현재까지 지원하는 Array Methods 는 십여가지가 넘지만 부족한 것 같아서 좀 더 보강할 계획이다. 함께 코드를 개선하실 분은 Fork 하셔서 작업 후에 저에게 알려주시면 됩니다.

  • any
  • first
  • firstOrDefault
  • firstOrNew
  • last
  • lastOrDefault
  • lastOrNew
  • where
  • select
  • foreach
  • orderBy
  • take
  • skip
  • sum
  • average
  • range and Array.range
  • union
  • clone

image-1

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 황정현 2013.06.17 17:51 Address Modify/Delete Reply

    자바스크립트 학습용으로도 좋네요. ^^


필자는 최근 자바스크립트(Javascript)를 자주 만지게 되면서 몇 가지 팁 또는 가이드 정보를 공유하고자 한다. 자바스크립트(Javascript)를 좋아하지만 잘 하지는 못한다. 그래서 먼저 개념적으로 잘못된 부분이 있으면 정중하게 미리 양해를 구하고자 한다.

1. 익명의 즉시 실행 함수로 스크립트를 시작하자

익명(Anonymous)의 즉시 실행 함수(Immediately Invoked Function Expression)는 다음의 코드와 같이 정의된다.

(function() {
       // ... 코드 생략 ...  
}());  

익명 함수(Anonymous Function)는 자바스크립트(Javascript)가 런타임(Runtime)에 구문을 해석하여 실행한다. 이는 외부의 접근을 제한함을 의미한다. 그러므로 외부 코드에서 익명 함수의 내부 코드를 임의적이나 악의적으로 수정할 수 없다.

즉시 실행 함수(Immediately Invoked Function Expression)는 선언과 동시에 실행이 된다. 익명 함수가 런타임에 사용될 준비가 되면 즉시 함수의 초기화 코드를 실행할 수 있기 때문이다. 예를 들어, 아래와 같은 코드는 악의적으로 전역 변수의 영향을 받지 않도록 함수(Function) 을 보호할 수 있다.

만약 익명 함수에 정의된 undefined 매개 변수에 진짜 undefined 가 전달되기를 기대하는 경우가 있는데, 즉시 실행 함수(Immediately Invoked Function Expression) 중간에 undefined = true 에 의해 원하는 결과를 얻을 수 없게 된다.

var undefined = true;  

(function(undefined) {
   console.info(undefined);
   console.info(undefined === true);  
})(undefined)  

// 실행 결과  
true  
true  

만약, 외부 코드에 의해 undefined 가 완벽하게 변경되길 바라지 않는 경우 다음과 같이 undefined 가 반환되는 결과를 매개변수로 사용하여 외부 코드에 의한 원치 않는 결과의 충격에서 보호할 수 있게 된다.

var undefined = true;  

(function(undefined) {  

console.info(undefined);  
console.info(undefined === true);  

})( function() {}() );  

// 실행 결과  
undefined  
false  

2. 모듈화 패턴은 한 가지만 사용하라

Javascript 를 모듈화하기 위한 패턴은 여러 가지 방법이 있다. 그런데 여러 패턴을 섞어 사용하다 보면 코드를 보기가 더 난해해 진다. 때문에 필자는 private과 public 접근 제한 방법을 제공하는 모듈 패턴(Module Pattern)을 주로 사용한다. [1]

이 외에도 효과적인 패턴들이 많이 존재하므로 적당한 패턴을 선정하여 모두가 함께 같은 패턴으로 사용하는 것이 현명할 것 같다.

var umc = umc || (function() {

    var privateFunction1 = function() {
        // ... 생략 ...
        return true;
    };

    return {
      "version"   : "3.0.0.0",
      "name"      : "Umc.Core Frameworks",
      "getObject" : function() {
          var result = (privateFunction1() ? "POWERUMC" : "HTTP://BLOG.POWERUMC.KR");
          return result;
      }  
};
})();  

console.info( umc.version );    // 결과 : 3.0.0.0  
console.info( umc.name );      // 결과 : Umc.Core Frameworks  
console.info( umc.getObject() );    // 결과 : POWERUMC     
console.info( umc.privateFunction1() );    // 오류  

[코드1] Self-Contained 모듈화 패턴

var umc = umc || (function() {  

   var _version = "3.0.0.0";
   var _name = "POWERUMC";
   var _getObject = function() { /* 코드 생략 };

   return {
      "version"   : _version,
      "name"      : _name,
      "getObject" : _getObject
   }  
})();  

[코드2] Imports 모듈화 패턴

var umc = umc || (function() {  

   var module = { };

   var _version = "3.0.0.0";
   var _name = "POWERUMC";
   var _getObject = function() { /* 코드 생략 };

   module.version = _version;
   module.name = _name;
   module.getObject = _getObject;

   return module;  
})();  

[코드3] Exports 모듈화 패턴

모듈 패턴(Module Pattern)을 정의하는 방법은 몇 가지가 있다.

  1. Self-Contained
    바로 위의 예시로 제시한 코드가 바로 Self-Contained 인데, public 함수를 직접 구현하는 방법이다.

  2. Imports-mixin
    아래와 같은 코드가 Imports 하는 방법으로 정의하는 모듈 패턴(Module) 패턴이다. 코드는 return 코드 부분만 보면 된다.

    1번과 2번의 경우는 함수가 익명(Anonymous) 함수로 정의 된다.

  3. Exports
    아래와 같은 코드는 module 을 외부로 공개하여 쉽게 확장이 가능하도록 한다.

3. 함수의 매개변수는 맨 먼저 초기화 하라

자바스크립트(Javascript)는 매우 관대하다. ‘오래 꽥꽥(Duck Typing)’은 동적 언어(Dynamic Languages)의 가장 큰 매력이라고 할 수 있다. 혹시라도 강아지가 ‘꽥꽥’ 거리면 자바스크립트는 강아지를 오리로 취급한다.

정의되지 않은 변수나 매개변수(Arguments), 아래의 코드 처럼 write("ERROR"); 와 같이 매개 변수의 개수가 맞지 않아도 너그럽게 실행이 된다. 하지만 코드에 정의되지 않은 undefined에 의해 실행은 얼마든지 오동작이 가능하므로, 가능하면 매개변수는 항상 올바르게 넘겨주지 않는다는 가정하에 작성하는 것이 좋다.

만약, message = message || "-";과 같이 초기화 또는 방어 코드가 없다면 로그는 ''Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : ERROR / undefined 와 같은 결과를 보여준다.

var write = function(category, message) {

    category = category || "INFO";
    message  = message  || "-";

    var date = new Date();;

    console.info( date + " : " + category + " / " + message );  
};

write("INFO", "시작 메시지");  
write("WARN", "경고 메시지");  
write("ERROR");  

// 실행 결과  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : INFO / 시작 메시지  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : WARN / 경고 메시지  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : ERROR / -  

4. 매개변수가 있지만 없어도 동작하도록 해라

함수의 매개변수는 맨 먼저 초기화 하라’ 에서 본 write("ERROR"); 와 같이 매개 변수가 맞지 않아도 잘 동작하도록 방어적인 초기화 코드를 작성하였다.

하지만, write(); 의도적으로 호출을 할 경우 다음의 코드처럼 올바르게 로그 기록이 남지 않게 된다.

write("실행 종료");  

// 실행 결과  
Sun Jun 02 2013 13:14:01 GMT+0900 (KST) : 실행 종료 / -  

category 에 로그 형식이 전달되어야 하는데, 로그 메시지 ‘실행 종료’가 category 항목으로 초기화되어 엉뚱한 결과가 나오게 된다.

이런 경우는 좀 더 매개 변수가 전달되는 가능성을 좀 더 열어두어, 매개 변수의 개수에 따라 매개 변수를 직접 할당하도록 하는 아래의 코드와 같은 방법을 사용하면 된다.

var write = function(category, message) {

    category = category || "INFO";
    message  = message  || "-";

    if( arguments.length === 1 ) {
        message = category;
        category = "INFO";
    }

    var date = new Date();;
    console.info( date + " : " + category + " / " + message );
}  

write("INFO", "실행 시작");  
write("WARN", "실행 중 경고");  
write("실행 종료");  
write();  

// 실행 결과  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / 실행 시작  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : WARN / 실행 중 경고  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / 실행 종료  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / -  

5. 띄어쓰기 스타일(Intent Style)은 반드시 K&R Style 을 사용하자.

K&R 스타일은 전세계의 커뮤니티에 따라 다르지만, C, C++, C#, Java 등의 언어에서 사용된다고 한다. 참고로, 마이크로소프트(Microsoft)가 추천하는 띄어쓰기 스타일은 ‘Allman Style’ 이라고 부른다.

위키피디아(Wikipedia)에 따르면 K&R 스타일은 다음과 같은 유래가 있다고 한다.

The K&R style, so named because it was used in Kernighan and Ritchie’s book The C Programming Language, is commonly used in C. It is also used for C++, C#, and other curly brace programming languages.

K&R 스타일의 이름의 유래는 Kernighan씨와 Ritchie씨의 저술서 The C Programming Language의 C 코드에서 일반적으로 사용했다. 또한 C++, C#, 그리고 중괄호(curly brace)를 사용하는 프로그래밍 언어에서도 K&R 스타일을 사용한다.

자바스크립트(Javascript)는 K&R 스타일의 띄어쓰기 스타일을 사용한다.

필자는 자바스크립트에서 K&R 스타일을 추천하는 것이 아닌, 반드시 K&R 을 쓰는 것이 좋다고 믿는다. 다음의 코드를 보면 왜 K&R 스타일을 사용하는지 알 수 있다.

// K&R 띄어쓰기 스타일  
function getdata\_1() {  
return {
    name: "POWERUMC"  
};
}  

// Allman 뜨어쓰기 스타일  
function getdata\_2()
{  
return
{
    name: "POWERUMC";
}
}  

console.info("getdata_1() - " + getdata_1());  
console.info("getdata_2() - " + getdata_2());  

// 실행 결과  
getdata_1() - [object Object]     // 올바른 결과  
getdata_2() - undefined     // 올바르게 return 되지 않은 결과  

결론

이 외에도 몇 가지 더 있지만, 자바스크립트(Javascript) 내공을 좀 더 쌓은 후에 더 정확하게 쓰는 것이 낫겠다고 생각하여 5개의 팁 정도를 공유했다. 하지만, 예제로 제시한 코드에 대해 성능적인 면이나 익명 함수 또는 즉시 실행 함수 등의 메모리 누수 등에 대해서는 언급하지 않을 예정이다.

내용면으로 부족한 부분이 있겠지만, 이 정도의 팁과 가이드면 바로 현업에서 깔끔하고 잘 동작하는 자바스크립트(Javascript) 코드를 작성하기에는 전혀 문제가 없다고 생각한다.

디자인 패턴(Design Pattern) 부분에서 더 많은 정보를 얻길 원한다면, 필자의 언급한 ‘Learning JavaScript Design Patterns A book by Addy Osmani Volume 1.5.2’ 를 참고하기 바란다.


  1. Module Pattern 참고 : Learning JavaScript Design Patterns
    http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript  ↩


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 2013.06.24 11:41 Address Modify/Delete Reply

    비밀댓글입니다

  2. 2015.05.22 23:56 Address Modify/Delete Reply

    비밀댓글입니다

    • 땡초 POWERUMC 2015.06.13 21:38 신고 Address Modify/Delete

      함수 안에 매개변수를 선언하는 것이 아닙니다.
      변수에 대입(assign) 하는 것이죠 ^^
      변수는 이미 함수 매개변수에 선언이 되어있으니까요.

  3. 2015.08.07 14:27 Address Modify/Delete Reply

    비밀댓글입니다

  4. 나그네 2017.09.15 13:13 Address Modify/Delete Reply

    [코드3] Exports 모듈화 패턴 에 name 오타가 있네요. 감사합니다

개발자에게 Visual Studio 11의 가장 큰 장점 중에 하나가 될 바로 코드 에디터 입니다. 특히 C++ 개발자에게 원성을 샀던 부실했던 C++ 코드 에디터는 기존의 C,#, VB.NET 과 동등할 정도로 코드 에디터의 구현에 충실해 다른 확장 도구의 도움 없이도 충분히 사용이 가능합니다. (Visual C++ 의 코드 에디터는 그 흔한 코드 컬러링도 기대 이하의 수준이었거든요)

   

C++ 코드 에디터

C++ 개발자에게는 C++ 코드 편집기의 컬러링과 인텔리센스는 정말 희소식일 것 같습니다. C++ 개발자는 기본적인 코드 작성에 Visual Assist 툴에 많이 의존하였었지만, 이제 외부 도구의 도움이 없이도 코드 작성에 어려움은 없을 것 같습니다. 

아래의 Visual Studio 2010과 Visual Studio 11의 C++ 코드 에디터를 그냥 눈으로 쓱 훑어보시기 바랍니다.

   

Visual Studio 2010의 C++ 코드 에디터

   

Visual Studio 11의 C++ 코드 에디터

   

   

   

C++/CLI 코드 에디터

특히 C++/CLI 를 자주 쓰는 분들에게는 더욱 특별할 수 있을 겁니다. C++/CLI 는 이전버전까지 예쁜 컬러링은 물론이거니와 인텔리센스도 작동하지 않는 암울한 환경에서 코드를 작성해야 했었습니다. 특히 C++/CLI 를 이용하여 C++ 코드를 단위 테스트할 때 무척 유용하였는데, 이번 컬러링과 인텔리센스 기능으로 더욱 활용도가 높아질 것 같습니다.

마찬가지로 Visual Studio 2010의 C++/CLI와 Visual Studio 11의 C++/CLI의 코드 에디터를 한번 보시죠.

   

Visual Studio 2010 C++/CLI 코드 에디터

   

Visual studio 11 C++/CLI 코드 에디터

C#, VB.NET 과 동급한 레벨로 인텔리센스와 코드 컬러링을 제공합니다. 그리고 Code Snippet도 제공되니 코딩이 한껏 즐거워지겠네요.

   

   

   

JavaScript 코드 에디터

JavaScript 는 웹 개발 환경에서 필수 언어로써, 개발 툴에서 JavaScript 인텔리센스 지원이 점점 좋아지고 있네요. Visual Studio 11 Beta 에서는 JavaScript 인텔리센스의 성능이 향상이 되거나 HTML5 등을 지원하는데요.

그 중, Lazy Initialize와 Lazy Loading 부분에서 상당히 만족할만한 수준으로 인텔리센스 기능이 좋아졌습니다.

   

JavaScript 코드 에디터에 대한 더 자세한 내용은 다음의 링크를 참고하십시오.

http://msdn.microsoft.com/en-us/library/bb385682(v=vs.110).aspx

   

JavaScript 코드 에디터의 인텔리센스가 얼마나 똑똑해 졌는지 아래의 예시를 보면서 비교해 보시기 바랍니다.

   

Visual Studio 2010 JavaScript 인텔리센스

인텔리센스가 C#, VB.NET 과 다르게 인텔리센스의 범위가 축소가 되지 않고 그냥 다~~~ 보여주지요.

   

   

Visual Studio 11 JavaScript 인텔리센스

JavaScript 인텔리센스가 C#, VB.NET 에서 사용하는 것과 똑같이 입력하는 문자에 따라 점점 인텔리센스 범위가 축소가 됩니다. 그리고 인텔리센스 상자 오른쪽에 시그너처도 함께 표시해 주네요.

   

   

JavaScript OOP 프로그래밍 인텔리센스

특히 JavaScript OOP 프로그래밍을 할 때는 인텔리센스의 도움을 많이 받게 되지요. Visual Studio 11 의 JavaScript 구문을 제대로 분석하여 인텔리센스를 제공해 주는 것 또한 막강한 Visual Studio 11 기능이라고 할 수 있습니다.

특히 Visual Studio 2010을 사용할 때 필자는 JavaScript OOP 프로그래밍을 절대 Visual Studio 2010에서 하지 않았답니다. 왜냐하면 제대로 인텔리센스를 보여주지 못하거나 올바른 인텔리센스 목록이 제공이 되지 않으면, 아차 하는 순간 코드가 동작을 안하거든요.

   

마찬가지로 Visual Studio 2010과 Visual Studio 11의 JavaScript OOP 인텔리센스를 비교해보시죠.

   

Visual Studio 2010 JavaScript OOP 인텔리센스

아주 간단한 JavaScript Initialize 패턴과 Simple Factory 패턴의 New() 메서드를 인식하지 못합니다. 물론 아래의 코드는 잘못된 코드가 아니겠지요.

   

Visual Studio 11 Beta JavaScript OOP 인텔리센스

Visual Studio 2010 JavaScript 인텔리센스에 비해 Visual Studio 11 Beta 는 Lazy Initialize 패턴과 Simple Factory 패턴 구문을 정확하게 분석하여 인텔리센스 목록에 New() 메서드를 깔끔하게 보여주고 있습니다.

   

   

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 미냉이 2012.03.14 15:45 Address Modify/Delete Reply

    와우 정말 희소식입니다 ㅡㅠ

외부 라이브러리에서 Javascript 인텔리센스 활성화 하기
 
Visual Studio 에서 추가된 기능입니다. 기존에 html(aspx) 페이지에서 <script src=””> 블록을 통해 Javascript 인텔리센스 기능이 제공이 되었지만, 여전히 문제였던 것은 Javascript 파일을 작성할 때, 외부 Javascript Function 의 인텔리센스 기능이 제공이 되지 않았습니다.
 
하지만, Visual Studio 2008 을 설치하시면 외부 Javascript Function 을 인텔리센스 기능으로 사용하실 수 있습니다.
 
크게 설명 드릴것도 없이 아래의 스크린샷 처럼 <reference> 주석을 통해 외부 Javascript Function 의 인텔리센스를 사용하기 위해 Import 할 수 있습니다.
 
[그림1] Jscript1.js 에 Function 이 선언된 모습
 
[그림2] Jscript2.js 에서 Jscript1.js Function 을 인텔리센스 기능으로 사용하는 모습
 
Reference
 
PS) 위 기능은 Visual Studio 2008 에서 추가된 기능인데, Reference 의 블로거는 Visual Studio SP1 에 추가된 기능인 것처럼 설명하네요. 참고하세요.

Visual Studio 2008 SP1 Adds JavaScript Formatting
http://weblogs.asp.net/kencox/archive/2008/08/13/visual-studio-2008-sp1-adds-javascript-formatting.aspx
 
만족합니다.
하지만, 여기에서 저는 한가지 고민을 하게 되었습니다.
 
 
그럼, Web Resources 스크립트는 어떻게 하나요?
 
이 문제로 약 하루 반나절 정도 생각을 해봤습니다. -_-; 물리적으로 URL 를 통해서 Javascript 파일에 접근할 수 있을 경우 위와 같이 사용할 수 있지만, Web Resources 는 이러한 URL 경로가 없기 때문에 위의 기능을 사용할 수 없습니다. 이 문제에 대해서 구글링을 해봐도 Web Resources 를 외부 Javascript 에서 Import 할 수 있는 방법을 없는 것 같습니다.
 
그래서 결론으로 아래와 같이 사용하시면 됩니다.
 
/// <reference path="C:\Documents and Settings\...경로생략...\JScript1.js" />
 
팁이라면 팁이 되겠네요. Web Resources 의 경우 큰 고민마시고, 파일 경로를 쓰시면 될 것 같습니다.
쩝…

2008-09-03 UPDATE ----------------------------------------------------
아래 댓글 달아주신 남정현님 말씀처럼
/// <reference name="xxx" assembly="xxx"/>

이런 방법이 있었네요^^ 감사합니다.

http://blogs.msdn.com/webdevtools/archive/2007/11/06/jscript-intellisense-a-reference-for-the-reference-tag.aspx 

근데 잘 되지 않는군요;; 쩝^^;

Posted by 땡초 POWERUMC

댓글을 달아 주세요