2015년 3월 31일 화요일

CodeSchool의 angular.js 강의에 사용된 예제 코드

Codeschool의 angular.js 강의는 free course로 따라만 하면 쉽게 angular.js에 대해 이해할 수 있다. 이 강의를 모두 수강한 후 CodeSchool의 다른 강의를 돈을 지불하고 들어야 하겠다라는 생각을 할 정도로 정말 좋은 강의이다.

CodeSchool은 안타깝게도 샘플코드를 내려 받을 수 없다는 것이 가장 안타깝다. 그래서 공부한 내용을 정리하는 차원에서 샘플코드를 남겨둔다.
총 5개의 챕터로 구성되어 있는데 그 중 3번째 챕터까지의 샘플 코드이다.

파일은 index.html, app.js, style.css이며 angular.min.js과 bootstrap은 다운받아 압축을 풀어 css, fonts, js 폴더를 같은 폴더에 둔다.
index.html은 view를 담당하고, app.js는 controller와 data를 담당한다. controller는 view와 data와의 연결, 그리고 임시 변수와 view와의 연결을 담당한다.
style.css는 required 태그로 지정된 것들의 coloring을 담당한다. 여기서는 review form에 입력할 때 invalid이면 빨간색, valid이면 녹색으로 border색을 지정한다.


index.html

<!DOCTYPE html>
<html ng-app="gemStore">
<head>
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" href="style.css" />
    <script type="text/javascript" src="angular.min.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>

<body ng-controller="StoreController as store">
<!--  Store Header  -->
<header>
    <h1 class="text-center">Flatlander Crafted Gems</h1>
    <h2 class="text-center">– an Angular store –</h2>
</header>

<!--  Products Container  -->
<div class="list-group">
    <!--  Product Container  -->
    <div class="list-group-item" ng-repeat="product in store.products">
        <h3>{{product.name}} <em class="pull-right">{{product.price | currency}}</em></h3>

        <!-- Image Gallery  -->
        <div ng-controller="GalleryController as gallery"  ng-show="product.images.length">
            <div class="img-wrap">
                <img ng-src="{{product.images[gallery.current]}}" />
            </div>
            <ul class="img-thumbnails clearfix">
                <li class="small-image pull-left thumbnail" ng-repeat="image in product.images">
                    <img ng-src="{{image}}" />
                </li>
            </ul>
        </div>

        <!-- Product Tabs  -->
        <section ng-controller="TabController as tab">
            <ul class="nav nav-pills">
                <li ng-class="{ active:tab.isSet(1) }">
                    <a href ng-click="tab.setTab(1)">Description</a>
                </li>
                <li ng-class="{ active:tab.isSet(2) }">
                    <a href ng-click="tab.setTab(2)">Specs</a>
                </li>
                <li ng-class="{ active:tab.isSet(3) }">
                    <a href ng-click="tab.setTab(3)">Reviews</a>
                </li>
            </ul>

            <!--  Description Tab's Content  -->
            <div ng-show="tab.isSet(1)">
                <h4>Description</h4>
                <blockquote>{{product.description}}</blockquote>
            </div>

            <!--  Spec Tab's Content  -->
            <div ng-show="tab.isSet(2)">
                <h4>Specs</h4>
                <blockquote>Shine: {{product.shine}}</blockquote>
            </div>

            <!--  Review Tab's Content  -->
            <div ng-show="tab.isSet(3)">
                <!--  Product Reviews List -->
                <ul>
                    <h4>Reviews</h4>
                    <li ng-repeat="review in product.reviews">
                        <blockquote>
                            <strong>{{review.stars}} Stars</strong>
                            {{review.body}}
                            <cite class="clearfix">—{{review.author}}</cite>
                        </blockquote>
                    </li>
                </ul>

                <!--  Review Form -->
                <form name="reviewForm" ng-controller="ReviewController as reviewCtrl" ng-submit="reviewForm.$valid && reviewCtrl.addReview(product)" novalidate>

                    <!--  Live Preview -->
                    <blockquote >
                        <strong>{{reviewCtrl.review.stars}} Stars</strong>
                        {{reviewCtrl.review.body}}
                        <cite class="clearfix">—{{reviewCtrl.review.author}} on {{reviewCtrl.review.createdOn | date}}</cite>
                    </blockquote>

                    <!--  Review Form -->
                    <h4>Submit a Review</h4>
                    <fieldset class="form-group">
                        <select ng-model="reviewCtrl.review.stars" class="form-control" ng-options="stars for stars in [5,4,3,2,1]" title="Stars" required >
                            <option value="">Rate the Product</option>
                        </select>
                    </fieldset>
                    <fieldset class="form-group">
                        <textarea ng-model="reviewCtrl.review.body" class="form-control" placeholder="Write a short review of the product..." title="Review"></textarea>
                    </fieldset>
                    <fieldset class="form-group">
                        <input ng-model="reviewCtrl.review.author" type="email" class="form-control" placeholder="jimmyDean@example.org" title="Email" required />
                    </fieldset>
                    <fieldset class="form-group">
                        <input type="submit" class="btn btn-primary pull-right" value="Submit Review" />
                    </fieldset>
                </form>
            </div>

        </section>
    </div>

</div>
</body>
</html>



app.js

(function() {
    var app = angular.module('gemStore', []);

    app.controller('StoreController', function() {
        this.products = gems;
    });

    app.controller("TabController", function() {
        this.tab = 1;

        this.isSet = function(checkTab) {
            return this.tab === checkTab;
        };

        this.setTab = function(setTab) {
            this.tab = setTab;
        };
    });

    app.controller('GalleryController', function(){
        this.current = 0;

        this.setCurrent = function(imageNumber){
            this.current = imageNumber || 0;
        };
    });

    app.controller("ReviewController", function(){

        this.review = {};

        this.addReview = function(product){
            this.review.createdOn= Date.now();
            product.reviews.push(this.review);
            this.review = {};
        };
    });

    var gems = [{
        name: 'Azurite',
        description: "Some gems have hidden qualities beyond their luster, beyond their shine... Azurite is one of those gems.",
        shine: 8,
        price: 110.50,
        rarity: 7,
        color: '#CCC',
        faces: 14,
        images: [
            "images/gem-02.gif",
            "images/gem-05.gif",
            "images/gem-09.gif"
        ],
        reviews: [{
            stars: 5,
            body: "I love this gem!",
            author: "joe@example.org",
            createdOn: 1397490980837
        }, {
            stars: 1,
            body: "This gem sucks.",
            author: "tim@example.org",
            createdOn: 1397490980837
        }]
    }, {
        name: 'Bloodstone',
        description: "Origin of the Bloodstone is unknown, hence its low value. It has a very high shine and 12 sides, however.",
        shine: 9,
        price: 22.90,
        rarity: 6,
        color: '#EEE',
        faces: 12,
        images: [
            "images/gem-01.gif",
            "images/gem-03.gif",
            "images/gem-04.gif"
        ],
        reviews: [{
            stars: 3,
            body: "I think this gem was just OK, could honestly use more shine, IMO.",
            author: "JimmyDean@example.org",
            createdOn: 1397490980837
        }, {
            stars: 4,
            body: "Any gem with 12 faces is for me!",
            author: "gemsRock@example.org",
            createdOn: 1397490980837
        }]
    }, {
        name: 'Zircon',
        description: "Zircon is our most coveted and sought after gem. You will pay much to be the proud owner of this gorgeous and high shine gem.",
        shine: 70,
        price: 1100,
        rarity: 2,
        color: '#000',
        faces: 6,
        images: [
            "images/gem-06.gif",
            "images/gem-07.gif",
            "images/gem-08.gif"
        ],
        reviews: [{
            stars: 1,
            body: "This gem is WAY too expensive for its rarity value.",
            author: "turtleguyy@example.org",
            createdOn: 1397490980837
        }, {
            stars: 1,
            body: "BBW: High Shine != High Quality.",
            author: "LouisW407@example.org",
            createdOn: 1397490980837
        }, {
            stars: 1,
            body: "Don't waste your rubles!",
            author: "nat@example.org",
            createdOn: 1397490980837
        }]
    }];
})();


style.css

.ng-invalid.ng-dirty {
    border-color:red;
}
.ng-valid.ng-dirty {
    border-color:green;
}

2015년 3월 30일 월요일

node.js의 module export 및 import 방법

node.js에서 다른 javascript 파일의 function을 불러 쓰기 위해서는 function을 정의한 파일에서는 export, function을 사용하는 파일에서는 import해야 한다. 파일은 하나의 모듈에 대응되어, 모듈을 import한다는 것은 한 파일을 import한다는 것과 같은 의미이다.

다음이 function을 정의한 파일에서 function을 export하는 예이다.

- math.js
var exports = module.exports = {};
exports.plus = function(a, b) {
    return a+b;
};

exports.minus = function(a, b) {
    return a-b;
};


위의 코드는 아래와 같이 바꿔도 된다. (하지만, 개인적으로 위 방법이 더 좋다)
module.exports = {
    plus: function(a, b) {
        return a+b;
    },
    minus: function(a, b) {
        return a-b;
    }
};

위의 함수를 사용하는 파일의 예는 다음과 같다.

var math = require("./math.js"); //사용할 파일명의 상대 경로
var sum = math.add(1,2); //함수 호출하기



function만을 export할 수 있는 것이 아니라, 아래와 같이 변수도 export가 가능하다.

var exports = module.exports = {};
exports.val = 0; //변수 초기화 및 export

2015년 3월 22일 일요일

Hapi를 활용한 Web Front-end 개발 간단 소스 코드

hapi를 이용해서 Web front-end 개발을 하기 위한 간단 소스 코드는 다음과 같다.

var Hapi = require('hapi');
var server = new Hapi.Server();
server.connection({port:8080});
server.route({
    method: 'GET',
    path: '/home',
    handler: {
        file : 'index.html'
    }
});
server.start(function () {
    console.log('Server running at:', server.info.uri);
});


index.html 파일이 entry point이다.

2015년 3월 20일 금요일

REST API 테스트를 위한 HTTP 클라이언트 앱


Windows와 Linux에서 쉽게 사용할 수 있는 free HTTP Client app 중 가장 대표적이며, 추천할 만한 것은 Command Line Interface(CLI) 툴인 curl과 Chrome 브라우저의 app인 DHC 이다. 초기에 DHC를 사용하다가 curl 코드를 이용해 script를 만들어 자동화된 테스트를 수행하는 것이 좋다.

1. curl

가장 널리 사용되는 REST API 테스트를 위한 HTTP client app으로 가장 대표적인 것은 curl이다. curl은 CLI 툴로 HTTP만이 아니라 HTTPS, FTP, SSL 등을 지원한다. CLI 툴이기 때문에 쓰기 불편할 수 있지만 script 형태로 많은 테스트 케이스를 정의하여  자동화된 테스트를 수행하기 용이하다.

curl 다운로드


2. DHC Chrome 앱

Chrome App이며, REST API 테스트에 최적화된 GUI 툴이다. 직관적으로 사용할 수 있으며, HTTP URL, method, Header, body를 customize할 수 있고, 그 값을 저장할 수 있다. 또한 프로젝트나 서비스 단위로 테스트 세트를 구성하여 재사용하는 것도 용이하다. 설정을 기억함에도 불구하고, 많은 테스트 케이스를 자동으로 수행하는 기능은 제공하지 않는다. 테스트 케이스를 만들면, curl 코드가 자동으로 생성된다.

DHC 앱 설치 










2015년 3월 18일 수요일

Hapi.js + MongoDB (on Windows)

Hapi.js와 MongoDB를 붙여서 사용하는 예제가 없거나, 제대로 실행이 되지 않는 경우가 많고, 특히 Windows에 대한 내용은 극히 적어 그 방법을 정리해 본다.
아래의 예제는 schema가 없거나 훨씬 자유로운 경우이며, 좀더 schema를 갖추어 MongoDB와 연동하는 경우는 Mongoose를 사용한다.
Mongoose는 다음에 다시한번 다루어보자.


1. OS가 32bit인지 64bit인지 확인

1) 아래의 방법으로 command prompt를 실행시킨다.

  • Win7: Windows key + 'R'을 누르고 'cmd'를 입력한 후 Control+Shift+enter key를 눌러 실행
  • Win8: Windows key + 'X'를 누른 후 'A' 키 입력 


2)command prompt를 열어 아래 명령을 입력하여 32bit인지 64bit인지 확인한다.

> wmic os get osarchitecture


2. Windows 버전 MongoDB 설치

MongoDB download site에서 적합한 version의 MongoDB 설치 파일을 다운받는다. 32bit의 경우 최신 버전에서 지원안할 경우, 이전 버전(Previous Release)을 설치한다.


3. MongoDB를 Windows 서비스로 등록

1) 아래의 방법으로 command prompt를 관리자 모드로 실행시킨다.

  • Win7: Windows key + 'R'을 누르고 'cmd'를 입력한 후 Control+Shift+enter key를 눌러 실행
  • Win8: Windows key + 'X'를 누른 후 'A' 키 입력 

2) 관리자 모드로 MongoDB data와 log를 저장할 folder를 만든다. 여기서 folder위치는 D:\data라 가정하자.

> mkdir D:\data\db
> mkdir D:\data\log


3) MongoDB configuration file을 만든다. 아래와 같이 command prompt에 입력한다. 이때 mongoDB가 설치된 위치를 C:\Program Files\MongoDB Standard라고 가정한다.

>echo logpath=D:\data\log\mongod.log> "C:\Program Files\MongoDB Standard\mongod.cfg"
>echo dbpath=D:\data\db>> "C:\Program Files\MongoDB Standard\mongod.cfg"


4) Windows 서비스로 등록한다. 여기서 주의할 것은 =와 그 뒤의 값(" ") 사이에 여백 한칸이 반드시 필요하다는 것이다.

>sc.exe create MongoDB binPath= "\"C:\Program Files\MongoDB Standard\bin\mongod.exe\" --service --config=\"C:\Program Files\MongoDB Standard\mongod.cfg\"" DisplayName= "MongoDB" start= "auto"

위의 과정을 모두 마치면 아래와 같은 메시지가 command prompt에 나타난다.

[SC] CreateService 성공


5) 아래 명령을 통해 MongoDB(서비스 이름)가 시작하도록 해보자.

>net start MongoDB


참고로, 서비스를 제거하는 것은 아래 명령을 사용하면 된다.

>sc.exe delete MongoDB


6) 폴더를 하나 만들고, 간단한 node.js 코드를 구현해 MongoDB에 연결을 해보자.

아래와 같이 mongodb 모듈을 설치한다.
>npm install --save-dev mongodb

아래 코드를 index.js 파일에 구현한 후 'node index'로 실행시킨다.



MongoDB에 연결되면 'We are connected'라는 메시지를 볼 수 있다.



지금부터는 MongoDB와 hapi.js를 이해하기 위한 sample 예제이다.

4. 사용할 database와 collection 만들기 

db명을 'taskdb'이고 collection명을 'tasks'라고 가정한다.

1) mongo.exe를 실행한다.

>cd C:\Program Files\MongoDB Standard\bin
>mongo.exe

2) 사용할 database를 생성한다.

mongodb prompt>use taskdb

3) collection을 만들며, 값을 추가한다.

mongodb prompt>var i = {task : "send an email to my boss", description : "CC colleagues"}
mongodb prompt>var j = {task : "submit the paper", description : "Hurry!"}
mongodb prompt>var k = {task : "attend the daily meeting", description : "Room 3"}
mongodb prompt>db.tasks.insert(i);
mongodb prompt>db.tasks.insert(j);
mongodb prompt>db.tasks.insert(k);

다음 명령을 통해 collection이 잘 생성되고 값이 잘 추가되었는지 확인한다.

mongodb prompt>show collections
mongodb prompt>db.tasks.find()


5. sample Hapi.js + mongoDB 코드 

1) 빈 folder를 만들고 hapi project를 만든다.

>npm init
>npm install --save-dev hapi boom joi hapi-mongodb


2) 아래 예제 코드를 이용해 index.js를 구현한다.




6. 테스트

command prompt를 이용해 잘 동작하는지 확인한다.

>curl http://localhost:8080/tasks"
>curl http://localhost:8080/task/xxxxxxx
>curl -X POST -H "Content-Type: application/json" -d "{\"task\":\"Fix bug 1\", \"description\":\"Absolute\"}" -i http://localhost:8080/tasks
>curl -X DELETE http://localhost:8080/tasks/xxxxxxx -i

위에서 POST 명령의 경우 Linux에서는 아래와 같이 실행한다.
>curl -X POST -H "Content-Type: application/json" -d '{"task":"Fix bug 1", "description":"Absolute"}' -i http://localhost:8080/tasks



TL;DR

Hapi와 MongoDB를 windows에서 한번 돌려보자. 앞으로 hapi.js를 공부하기 위한 기본 틀 역할을 한다.





<참조>
1. BUILDING A REST API USING HAPI.JS AND MONGODB
2. hapi-mongodb: A simple Hapi MongoDB connection plugin
3. Getting started with MongoDB and node.js on Windows
4. Install MongoDB on Windows
5. Getting Started with MongoDB

2015년 3월 16일 월요일

REST API 구현을 위한 hapi.js와 express.js의 초간단 비교

REST API 서버 구현을 위해 node.js를 검토한다면 node.js 단독으로 사용하기 보다는 REST API 구현을 도와주는 모듈을 함께 사용하는 것이 좋다. 가장 많이 사용되는 모듈은 단연 express.js이다. 지원하는 plugin 수에서도 압도적이고, 인터넷 상의 문서도 많다. MEAN stack처럼 하나의 package로 사용하는 경우도 많아 자연스럽게 express.js가 검토된다.
hapi.js는 express.js에 비해 넓게 쓰이고 있지 않은 반면 매우 강력한 강점을 가지고 있다. 매우 직관적이고 구조화된 mapping을 하고 있다는 것이다. 소위 ‘configuration over code’라는 장점을 가지고 있는 것이다. 이것만으로도 express.js가 아닌 hapi.js를 써야 할 이유가 있다고 생각한다.
다음은 express.js를 통해 routing을 하는 예이다.

위의 코드를 보고 직관적으로 어떤 URL이 어떤 handler에 연결되어 있는지 파악하기 쉽지 않다.
아래 hapi.js를 통해 동일한 동작을 하는 코드를 살펴보자.

hapi.js를 사용한 코드가 express.js에 비해 path와 handler의 mapping관계를 직관적으로 보여준다.
hapi.js 홈페이지의 getting started는 내용이 너무 부족하다. hapi.js에 대해 잘 알 수 있는 관련 문서도 많지 않다. 앞으로 참고할만한 hapi.js 관련한 자료를 만들어 보자



참고
Node.js Framework Comparison: Express vs. Koa vs.Hapi

2015년 3월 11일 수요일

훌륭한 소프트웨어 개발자가 되기 위한 조건

스마트폰을 정리를 하다가 2년 전 IIT(India Institute of Technology) 델리, 뭄바이, 첸나이에서 소프트웨어를 전공하는 학생들을 대상으로 강의했던 사진을 보게 되었다.  학문으로 소프트웨어를 연구하지 않고, 실무로 개발을 하는 내가 세계가 주목하는 천재들(참고로 IIT는 ‘세 얼간이’의 배경이 되는 학교)을 대상으로 소프트웨어 개발에 대해 강의를 했다는 것이 새삼 뿌듯했다. 

IIT Delhi

가장 인상에 남은 장면은 우리나라 공사현장과 같은 열악한 학교 환경, 그리고 강의가 끝난 후 질문을 하기 위해 줄을 서서 기다리던 그 학생들의 빛나던 눈동자이다. 지적 호기심이 그들의 눈을 빛나게 만든 것인지, 아니면 그냥 피부가 검어서 상대적으로 빛나게 보였던 것인지 확실치 않지만, 분명한 것은 질문하기 위해 줄 서서 기다릴 정도의 지적인 호기심을 가지고 있는 학생들이 많았다는 것이다. 

 

소프트웨어 개발자로 살아오면서 느끼는 것은 적당히 뛰어난 개발자가 되는 것은 쉽지만, 훌륭한 개발자가 되기란 쉽지 않다는 것이다. 개발에 대한 정보를 얻기란 너무나 쉬워서 금방 기술을 익히고 사용할 수 있으나,  자신의 기술적 결정에 대해 그것이 적절한지 스스로 피드백을 할 수 있고, 그 결정을 논리적으로 설명할 수 있는 수준이 되기란 쉬운 일이 아니다. 

난 이것은 얼마나 열심하느냐의 문제가 아니라 생각한다. 그것은 끊임없는 지적인 호기심을 갖고 있느냐의 문제라 생각한다. 새로운 언어, Framework, 툴, 방법론을 배우는 것이 즐거운 놀이가 아닌 일이라고 느껴진다면, 아마도 훌륭한 개발자가 되기는 쉽지 않을 것이다. 지금 이 순간에도 수 많은 개발자들이 소프트웨어를 일이 아닌 놀이라고 생각하며, 일터에서만이 아니라 집에서도 끊임없이 새로운 기술을 배우고, 자신만의 프로젝트에 이를 적용하고 있다. topcoder, stackoverflow, github에서 그런 개발자들을 쉽게 만나볼 수 있다. 고등학교 때부터 프로그램을 능수능란하게 짜지 않았어도, 수학 천재가 아니어도, 우린 훌륭한 개발자가 충분히 될 수 있다. 만약 우리가 진심으로 프로그래밍을 즐기고 있고 더 잘 할 수 있는 방법에 대해 관심이 많다면 말이다.

2015년 3월 7일 토요일

Basic Web application model with node.js

 

As a ‘web’ novice, understanding the application model and typical architectures is very difficult since there are too many references, languages, jargons and opinions. ‘Loy Fielding’s great article is so far away from this chaotic situation.(Loy fielding’s article is still great from software architect’s perspective). Even if I am still a web novice, bravely I am trying to explain the current web application model.

Traditional Web application model

Traditional Web application model is a client-server model. The model is as simple as we can very easily understand the roles. The client is so thin, because the role is ‘rendering’ html pages provided by the server.

20150308_135405 

The traditional model’s drawbacks are follows:

- Expensive. In aspect of business, server is an entity we have to spend money, whereas client is ‘free’. This model doesn’t take advantage of the free and very powerful entity.

- Difficult to support various kinds of clients. Sometimes, we need to consider supporting web browsers, traditinal web apps, interactive (one-page) web apps, and native apps. Some types of clients need to have its own UI/UX instead of html pages provided by the servers.

- Complicated from developer’s perspective despite the simplicity of this models. Everything the developer must implement is in the server. As you know, well- decoupled functions may improve productivity.

3-Box model

Let clients be in charge of presentation. That makes severs simpler. In addition, split the role of servers into providing data and providing ‘static’ resources such as files, HTML, and style sheets. The concept is as following picture.

 20150308_135413

3-Box Model with client-templates

File server and content delivery network(CDN) focus on providing static resources such as style sheets, scripts, HTML files, and other static files(image, video, and so on).  ‘bootstrapper’ is one of javascript files and does all the work gathering everything and putting the web page together. To do that, it has ‘template engine’  to download all the proper resources including HTML templates and JSON APIs, get JSON data, and then eventually put them together in web pages. The bootstrapper runs on the client for presentation of data.

Typical prodecures of 3-box model with client-templates are as follows:

  1. The client downloads a skeleton HTML page pointing to Javascripts including ‘bootstrapper’, CSS files, and empty body element from node.js server.
  2. The bootstrapper downloads necessary templates, and call JSON API to get data.
  3. The bootstrapper applies the returned data to the templates.
  4. The final HTML code fills the empty web page.
  5. Eventually the web page is rendered.

20150308_135433

Practical 3-box model

Usually to run web services, proxy web servers are necessary for operational purposes such as monitoring, caching, load balancing and protecting from hacking. In addition to the operational purposes, the web servers could be used as file servers since the performance to handle static files are better than node.js.

Ryan Dahl : "You just may be hacked when some yet-unknown buffer overflow is discovered. Not that that couldn't happen behind nginx, but somehow having a proxy in front makes me happy".

Therefore, the following model is practical in my opinion (keep in mind, there are many web application models to meet various businesses and requirements)

20150308_135448

<Reference>

- Learning node.js

- http://stackoverflow.com/questions/5534399/is-it-reasonable-to-put-nginx-in-front-of-nodejs-to-serve-static-assets

Account setting failure for Blogger.com on Windows Live Writer

As an offline blog editor, Windows Live Writer is still the most power tool, even though Microsoft stopped the maintenance. It supports almost all popular blog sites such as WordPress, SharePoint and Blogger.com.

To configure for Blogger.com, the following form must be filled out.

image

The Web address might be ‘http://xxxxx.blogspot.com’ . For instance, http://dakoostech.blogspot.com/ for this blog. User name and password might be a google account.

However, I encountered “The username or password is incorrect. Please try again.” error as follows.

image

To resolve this problem, you should go to a web page for “Less secure app configuration for google account” and  enable ‘Access for less secure apps’.

9

Then, try to configure the Windows Live editor again.

2015년 3월 6일 금요일

이 블로그는 어떤 언어를 사용하는 것이 좋을까?

Intech로부터 책에서 내가 쓴 챕터의 다운로드가 3000건이 넘었다는 연락을 받았다.
확인해보니 12개의 챕터 중 3번째로 많이 참조한 챕터였다. 맨 마지막 챕터라서 얼마나 읽을까 의구심을 가졌는데 역시 디지털 컨텐츠는 순서가 중요한 것이 아니라 'interest'가 더 중요하다는 것을 깨달았다. 그리고, 만약 한국어로 글을 썼다면 나의 챕터가 과연 얼마나 많이 읽혔을까 라는 생각을 했다. 힘들어도 글로벌 접근이 역시 중요하다.

누군가에게 읽히고 싶어서 글을 쓴다면 그 독자가 누구인지 고민을 해야 한다.
갓 시작한 이 블로그는 내 생각과 공부한 내용을 정리하기 위해 운영하는 것으로 현재의 타겟 독자는 나 혼자이다.
그런데, 아마도 점점 내용이 정리가 된다면 web 기술을 처음 시작하는 개발자나 학생에게 도움을 줄 목적의 글을 쓰게 될 것 같다. 나는 국내의 개발자나 학생만이 아니라 되도록 많은 사람들에게 도움을 주고 싶다. 그렇다면 영어가 좀 더 적당한 언어일 것 같다.


결론
1. 구글링으로 쉽게 찾을 수 없어서 고생해서 알아낸 내용은 다른 사람들에게도 도움이 될 가능성이 높으므로 되도록이면, 영문으로 작성을 하거나 한글/영문 버전으로 작성하자.
2. 디저털 세상에서는 'interest'가 더 중요하므로 블로그의 글을 한글과 영어를 혼용하는 것은 전혀 문제가 없다. 걱정하지 말자.

node.js 프로젝트 환경 설정(3/3): mocha와 gulp를 활용한 node.js 테스트 환경 설정

관련글: mocha를 활용한 node.js 프로젝트 테스트
이전글:
node.js 프로젝트 환경 설정(1/3): WebStorm과 node.js 설치
node.js 프로젝트 환경 설정(2/3): gulp를 활용한 node.js 개발 환경 설정


이전 글에서 사용한 소스와 테스트 코드를 사용하여 mocha 테스트를 gulp를 통해 관리하는 것을 해보자.

1. gulp-mocha 설치
아래와 같이 mocha-gulp 모듈을 설치한다.
$ npm install gulp-mocha --save-dev

2. gulpfile.js에 추가
gulpfile.js에 mocha-gulp를 추가하고 기존 task를 수정한다.


위의 내용이 추가된 gulpfile.js는 아래와 같다.


3. mocha 실행
아래와 같이 gulp task로서 mocha를 실행한다.
$ gulp test

node.js 프로젝트 환경 설정(2/3): gulp를 활용한 node.js 개발 환경 설정

이전글: node.js 프로젝트 환경 설정(1/3): WebStorm과 node.js 설치
다음글: node.js 프로젝트 환경 설정(3/3): mocha와 gulp를 활용한 node.js 테스트 환경 설정


* node.js 프로젝트를 새로 만들 때 (프로젝트 폴더를 만든 후) 여기서부터의 내용을 적용하자.
먼저, package.json을 node.js 프로젝트의 root에 만든다. (참조: [node.js] node 모듈 설치와 관리를 위한 package.json 활용 )

$npm init

mocha를 활용한 node.js 프로젝트 테스트에서 사용했던 프로젝트의 폴더와 파일을 다시한번 사용해서 gulp를 이용한 node.js 개발 환경 설정을 알아보자.

1. gulp를 global하게 설치
$ npm install --global gulp

2. 프로젝트 내에 gulp 모듈 설치
$ npm install --save-dev gulp

3. 필요한 gulp plugin 설치
필요한 plugin은 아래와 같다.
- 로깅, console에서의 coloring out 등을 지원: gulp-util
- javascript 파일의 잠재 defect check: gulp-jshint
- javascript 파일 여러개를 합쳐서 하나로 만들기 (HTTP request를 줄이기): gulp-concat
- 합쳐진 javascript 파일으 사이즈 줄이기: gulp-uglify
- javascript 파일 이름 바꾸기: gulp-rename
- 파일 size 알려주기: gulp-filesize
- 폴더 지우기: gulp-clean
- 파일이 변경되었는지 확인하기: gulp-watch
$ npm install --save-dev gulp-util gulp-jshint gulp-concat gulp-uglify gulp-rename gulp-filesize gulp-clean gulp-watch

4. gulpfile.js 작성
build를 위해 root 폴더 아래에 'build' 폴더를 만든다.
gulpfile.js을 프로젝트 root 폴더아래에 만든다. 아래와 같이 내용을 채워 본다.


watch는 파일을 모니터링을 하다가 변경이 생기면 정해진 task를 실행시킨다. 그리고 'default'는 wrapper task의 예를 보여준다.

5. gulp 실행
gulpfile.js가 있는 프로젝트 root 폴더에서 아래와 같이 task 명을 실행시켜서 어떤 결과가 발생하는지 확인해 보자.
$ gulp build

Webstorm의 경우엔 gulpfile.js위에서 오른쪽 마우스 버튼을 눌러 "show gulp tasks"를 실행하면 gulp task 창이 떠서 task들이 표시된다. 이때 'build'버튼을 누르면 아래와 같은 결과가 나와야 한다.

정리
1. gulp를 이용해서 프로젝트의 설정을 잡을 수 있다.
2. gulp plugin 중 유용한 것이 많이 있다. 확인해서 많이 사용해 보자.


다음글: node.js 프로젝트 환경 설정(3/3): mocha와 gulp를 활용한 node.js 테스트 환경 설정

mocha를 활용한 node.js 프로젝트 테스트

node.js가 설치되어있다는 가정하에 node.js 프로젝트를 mocha test framework의 사용방법에 대하여 알아보자.
먼저 테스트 대상이 될 예제 프로젝트의 구조는 다음과 같다.

project 폴더 아래에 'src' 폴더가 있고, 'src' folder아래에 sum.js 파일이 있다.
그리고 root 폴더에 package.json이 있다.


1. assertion 모듈 설치
테스트를 위해서는 assertion 모듈이 필요하다. assertion을 위해 chai 모듈을 설치한다.
# npm install chai --save-dev


2. mocha 모듈 설치
mocha test framework을 global로 설치한다.
# npm install mocha -g


3. 테스트 케이스 작성
BDD 스타일의 테스트 케이스를 작성한다. 프로젝트 root 폴더 아래에 'test'폴더를 만들고, 그 안에 test.sum.js 파일을 만들어 BDD 스타일의 테스트 케이스를 작성한다.



4. 테스트 수행
테스트의 수행은 프로젝트 root 폴더에서 테스트 폴더의 이름을 아래와 같이 지정해 주면 된다.
그러면 그 아래의 테스트 케이스가 모두 수행된다.
# mocha test

참조
1. mocha test framework: http://mochajs.org/
2. chai assertion 모듈: http://chaijs.com/guide/styles/
3. BDD: http://dakoostech.blogspot.kr/2015/03/behavior-driven-developmentbdd-test.html

[node.js] node 모듈 설치와 관리를 위한 package.json 활용

개발 단계에서 설치한 node 모듈은 배포 단계에 어떻게 할까? javascript 소스코드는 그대로 upload를 하고 node 모듈들은 다시 설치를 한다.
그런데 node 모듈을 하나하나 재 설치하지 않고, package.json을 활용해 한꺼번에 재 설치한다.
나중에 node_modules 폴더가 없어도 프로젝트 root 경로에 package.json파일이 있다면, 간단히 아래 명령으로 package.json 파일의 "devDependencies"에 명시된 버전의 모듈들이 설치된다.

npm install

그리고, npm update 명령으로 node 모듈을 업데이트를 하더라도 "devDependencies" 에 명시된 버전으로 update가 된다.

이렇게 하기 위해서는 node 프로젝트를 최초로 만들때 다음과 같은 명령을 사용해 package.json을 만든다.

npm init


그 뒤 모듈 설치시에 -g 옵션없이 local로 설치하고, --save-dev 옵션을 추가하면 package.json 파일의 "devDependencies" 부분에 모듈 정보(이름, 버전)가 저장된다.

npm install grunt --save-dev


<결론>
1. 프로젝트 root에 npm init으로 package.json파일을 만들자.
2. node 모듈은 되도록 global이 아닌 local로 설치하고, 설치 시 --save-dev 옵션을 붙이자

2015년 3월 5일 목요일

Behavior-driven development(BDD)와 Test-driven development(TDD)의 차이

node.js의 test framework을 공부하다보니 낯선 BDD라는 용어가 등장했다. 예를 들어 유명한 mocha test framework은 TDD와 BDD를 지원하고, vows는 BDD를 지원한다고 한다. 이렇게 되면 BDD에 대해 공부해야 하는 상황. 그런데 BDD라는 용어를 가장 먼저 사용한 Dan North의 글 (한글 번역)이나 wikipedia의 글을 읽어봐도 모호하기만 했다.

여러 가지 자료를 찾아보고, infoq에서 진행한 Dan North를 포함한 몇 명의 Agile 전문가가 참여한 패널 토의를 읽어 보고 나서야 비로서 대강 BDD와 TDD의 차이를 나의 관점으로 이해하게 되었다.

이해한 내용을 간단히 정리하자면 아래와 같다.


1.Test-Driven Development의 용어로 인한 오해가 있다.
Test-Driven Development의 'Test'가 의미하는 바는 Verification(검증)이 아닌 Specification(요구사항 명세)에 가깝다. 즉, 테스트 케이스를 먼저 작성하고 코딩하는 것은 '요구사항 명세'를 개발자 관점에서 수행하는 것이다.
그럼에도 불구하고 'Test'라고 하면 쉽게 떠올리는 검증이라는 이미지로 인해, 아래와 같은 오해가 생긴다.
- 테스트 케이스는 개발자가 아닌 Tester에 의해 작성되는 것이라는 오해(TDD를 수행하는 개발자 조차)
- 테스트를 수행한다거나, 테스트 케이스를 작성한다고 하면, 개발 막바지라고 생각하는 오해(Waterfall 스타일에 익숙한 개발자, 매니저, 테스터, 고객)
- Acceptance 테스트에는 TDD가 사용되지 않는다는 오해
위의 오해를 피하기 위해 TDD와 TDD에서 사용하는 용어의 재 정의가 필요하다. 그것이 Behavior-Driven Development이다.

2. BDD는 TDD의 일종이다. 단지 TDD를 더 제대로 수행하기 위한 장치를 한 것이다.
TDD의 'T'가 의미하는 바가 Specification이라면, BDD의 'B'가 의미하는 바와 같다. 그런데, TDD는 요구사항보다 함수 검증에 집중되는 경향이 있고 BDD는 좀 더 요구사항에 집중한다. 예를 들어 TDD를 수행한다고 하면, 고객 요구사항이 아닌 내부 함수 테스트를 수행하는 경우도 흔하다. 이것은 TDD를 제대로 이해하지 않아서 생기는 문제이다. 그래서, BDD는 테스트 케이스의 명세나 툴을 통해 의도적으로 개발자에게 요구사항에 집중하도록 한다.


위와 같이 BDD와 TDD는 사실 다르지 않다. 이 내용을 정확히 이해한다면 TDD를 지원하는 test framework으로도 BDD를 수행할 수 있고, 반대로 정확히 이해하지 못한다면 BDD를 지원하는 test framework으로 흔히 하는 TDD 실수를 똑같이 저지를 수 있는 것이다. TDD를 제대로 수행하고 있다면, BDD를 지원하는 test framework을 굳이 사용하지 않아도 상관없다.


참조
1. Dan North의 BDD 소개글: http://dannorth.net/introducing-bdd/
2. Dan North의 BDD 소개글 번역: http://blog.jaigurudevaom.net/319
3. InfoQ의 Panel 토의: http://www.infoq.com/articles/virtual-panel-tdd-bdd
4. 마틴 파울러의 "Mocks aren't stubs" : http://martinfowler.com/articles/mocksArentStubs.html

2015년 3월 3일 화요일

[Reference] Understanding grunt

grunt is very similar to 'makefile' and 'ant'. As I know, 'makefile' runs 'make clean', 'make build', 'make all', and user-defined batch such as copy and remove files.
grunt also performs predefined sets of tasks automatically.

For javascript, you may want to make the following tasks batch.
- Linting with JSHint: Check potential defects of Javascript source code
- Concatenation: Concatenate several javascript files into one file to improve run-time performance
- Minification(uglify): make the size of javascript files smaller

The following is the best reference for grunt with the common tasks.

>> Understanding Grunt – Part 1: Installation, Linting, Concatenation, And Minification


[async.js] 막강한 flow 제어 - async.waterfall, async.series, async.parallel, async.auto

async.js는 callback이 너무 많아지는 javascript의 문제점을 해결할 수 있는 package이다. async.js를 사용하면 javascript asynchronous programming을 훨씬 용이하고 직관적으로 할 수 있다.

Learning node.js 책에 나와 있는 내용을 참고하여 이해를 해보자.

아래의 코드를 보면 javascript 코드에서 asynchronous task가 연속적으로 수행되는 경우 코딩도 쉽지 않고, 이해도 쉽지 않음을 알 수 있다.


async.waterfall
위처럼 asynchronous task가 순차적으로 실행되어야 하는 경우 async.waterfall이 사용된다.



async.series
async.series는 async.waterfall과 유사하면서도 약간 다르다. function의 결과는 다음 function의 argument로 passing되지 않는다. 대신 마지막에 호출되는 callback의 두번째 argument인 array에 추가된다. 즉, 각 function의 결과는 array에 저장되어 마지막 callback에 넘겨진다.

위 코드의 결과는 다음과 같다.
{ numbers: [ 1, 2, 3 ], strings: [ 'a', 'b', 'c' ] }

async.parallel
async.parallel은 위의 async.waterfall이나 async.series와 달리 병렬적으로 실행되는 task의 flow를 제어한다.

아래의 코드를 보면 이해가 쉬울 것이다. 병렬적으로 수행되어야 할 task들이 실행되고, 마지막에 반드시 callback이 실행된다.


위 코드의 결과는 다음과 같다. (위의 async.series 예제 코드와 같다)
{ numbers: [ 1, 2, 3 ], strings: [ 'a', 'b', 'c' ] }

async.auto
async.auto는 asynchronous flow control을 맘대로 할 수 있는 일종의 끝판왕이다.

병렬, 직렬 처리를 유연하게 할 수 있다는 장점이 있다.

이 코드의 결과는 다음과 같다.
{ numbers: [ 1, 2, 3 ], strings: [ 'a', 'b', 'c' ], assemble: { numbers: '1, 2, 3', strings: '\'a\', \'b\', \'c\'' } }

추가 참고 사이트
https://github.com/caolan/async

2015년 3월 2일 월요일

빠른 Front-end UI 개발을 위한 WebStorm Live edit 설치

Front-end coding을 하는 순간 browser를 통해 그 결과를 즉시 확인하기 위한 툴을 WebStorm이 제공하고 있다.
Live edit는 Chrome의 extension을 통해 동작하므로 Chrome을 사용해야만 한다.
그 설치 및 설정 방법은 다음과 같다.

1. WebStorm 설정
1) File > Settings를 열어 Build, Execution, Deployment > Debugger > Live edit
2) Update 주기를 manual(default)에서 Auto로 변경

2. Chrome의 JetBrains extension 설치
1) Chrome을 실행하여 확장 프로그램 검색으로 'JetBrains IDE Support'를 찾아 설치한다.

3. 사용해 보기
1) WebStorm에서 프로젝트를 만들어 javascript 파일을 추가하여 아래의 샘플 코드를 붙여 넣는다.

그리고 index.html 파일을 만들어 아래 코드를 붙여 넣는다.

2) Debug 모드로 javascript 파일을 실행시킨다.
3) Chrome을 열어 http://127.0.0.1:8000으로 접속한다.
4) Chrome의 설정 메뉴 옆의 "JB" 아이콘을 오른쪽 마우스 클릭하여 "Inspect in WebStorm"을 선택하면 화면의 Debug중이라는 표시가 된다.


이제 WebStorm의 Html 코드를 수정해 보자.
Hello World대신 Bye World로 수정한 후 Chrome을 보면 즉시 Bye World로 바뀌어 있음을 알 수 있다.

Live edit는 Front-end단 UI 개발에 적합하며, Javascript 코드의 수정에는 즉각 대응하지 않는다는 점을 명심하자.

node.js 프로젝트 환경 설정(1/3): WebStorm과 node.js 설치

Windows 8.1 64bit에서의 WebStorm과 node.js 설치 스텝을 간략히 정리해 보자

1.WebStorm 설치
1) 자신의 License 키 복사
JetBrains 사이트에 로긴하면 구매한 License 키가 보인다. 키 위에서 클릭하면 클립보드에 복사된다.

2) WebStorm 다운로드: WebStorm 다운로드 사이트에서 Windows용 최신 버전을 다운로드 한다.

3) 다운로드 받은 WebStorm 설치

4) WebStorm 실행 후 License key입력
키입력 창이 나오면 WebStorm 구매시 등록한 아이디와 복사한 License 키를 입력한다.

5) WebStorm 초기 설정(개인적 취향)
- Keymap: Visual Studio, IDE Theme 및 Editor color/font: Darcula

2.Node.js 설치
1) node.js 사이트로 가서 64 bit용 Windows Installer와 source code 압축 파일을 다운로드 받는다.
2) Windows Installer를 통해 설치한다.
3) command 창 (Windows 키+R --> cmd 명령)을 실행하여 'node -v'을 확인한다.
D:\myproject> node -v
v0.12.0
4) 다운받은 node.js 소스코드의 압축을 풀어 향후 참조할 folder에 저장한다.

3. WebStorm 설정
1) WebStorm을 실행하여 프로젝트를 새로 시작한다.
2) File > Settings으로 설정창을 연다.
3) Languages and Frameworks > Node.js and NPM을 선택한다.
4) Node Interpreter에 설치한 node.exe의 위치를 입력한다.
(default 위치 - C:\Program Files\nodejs\node.exe)
5) Node.js Core Modules의 소스코드 위치에는 압축을 푼 node.js 소스코드의 root folder를 지정한다.
6) Languages and Frameworks > Javascript > Libraries 에서 node.js관련된 항목이 모두 check되어 있는 것을 확인한다. (core modules, global)

다음글 :
node.js 프로젝트 환경 설정(2/3): gulp를 활용한 node.js 개발 환경 설정
node.js 프로젝트 환경 설정(3/3): mocha와 gulp를 활용한 node.js 테스트 환경 설정