Languages/Java2014/09/05 12:23

이펙티브 자바(Effective Java)의 2판이 다시 번역되어 재출간되었습니다. 출판사는 인사이트입니다. 





원래 대웅출판사에서 번역되어 출간되었다가 절판된 것을 이번에 인사이트에서 다시 번역해서 출간했습니다. 원래 번역본을 전혀 참고하지 않은, 전면적인 재 번역입니다. 


참고하시라고, 118페이지의 본문을 발췌해 보았습니다. 


규칙 16은 계승을 위한 설계와 문서를 갖추지 않은 “이질적(foreign)” 클래스의 하위 클래스를 만들 때 생기는 문제점을 설명하고 있다. 그렇다면 계승을 위한 설계와 문서를 갖춘다는 것은 어떤 의미일까?


우선, 메서드를 재정의하면 무슨 일이 생기는지 정확하게 문서로 남겨야 한다. 다시 말해, 재정의 가능 메서드를 내부적으로 어떻게 사용하는지(self-use) 반드시 문서에 남기라는 것이다. public이나 protected로 선언된 모든 메서드와 생성자에 대해, 어떤 재정의 가능 메서드를 어떤 순서로 호출하는지, 그리고 호출 결과가 추후 어떤 영향을 미치는지 문서로 남기라는 것이다. (재정의 가능하다는 것overridable은 public 또는 protected로 선언된 비-final 메서드라는 뜻이다.) 좀 더 일반적으로 이야기하자면, 재정의 가능 메서드가 호출되는 모든 상황을 문서로 남기라는 것이다. 예를 들어, 후면(background) 스레드가 호출할 수도 있고, static 초기화 구문(initializer) 안에서 호출할 수도 있다.


관습적으로, 재정의 가능 메서드를 어떤 식으로 호출하는지는 메서드 주석문 마지막에 명시한다. 주석은 “이 구현은”이라는 문구로 시작한다. 릴리스에 따라서 달라질 수 있다는 뜻으로 하는 말은 아니며, 메서드 내부 동작 원리에 관한 주석이라는 뜻이다. 아래에 java.util.AbstractCollection 명세에서 가져온 예제를 보였다.


170페이지, 규칙 26 관련 본문도 한번 보겠습니다.


컴파일러는 프로그램의 형 안전성을 입증할 수 없을지 모르지만, 프로그래머는 할 수 있다. 무점검 형변환(unchecked cast)을 하기 전에 개발자는 반드시 그런 형변환이 프로그램의 형 안전성을 해치지 않음을 확실히 해야 한다. 위에서 문제가 되고 있는 배열 elements는 private 필드이고 클라이언트에 반환되지 않으며 다른 어떤 메서드에도 전달되지 않는다. push 메서드에 전달되는 원소만이 배열에 저장되며, 그 타입은 전부 E다. 따라서 무점검 형변환을 해도 아무런 문제가 없다.


무점검 형변환이 안전함을 증명했다면, 경고를 억제하되 범위는 최소한으로 줄여야 한다(규칙 24). 위의 예제의 경우, 생성자에 있는 코드라고는 무점검 배열 생성을 하는 코드가 전부이므로 생성자 전체적으로 경고를 억제해도 무방하다. 경고를 억제하는 어노테이션을 추가하고 나면 Stack 클래스는 아무 문제없이 컴파일 될 것이며, 명시적인 형변환이나 ClassCastException이 발생할 걱정없이 사용할 수 있게 된다.


Java 1.8이 공개된 시점이지만, 이 책의 많은 부분은 아직도 유효한 교훈들을 담고 있습니다. 최신 Java와 많이 달라진 부분에는 제한적이지만 주석이 달려 있어서, 1.8에서 해결된 것이 무엇인지 살펴볼 수 있도록 약간의 배려도 하고 있습니다.


저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/559 관련글 쓰기

  1. casino bonus  삭제

    2014/10/04 19:11TRACKBACK FROM casino bonus

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

  2. scottalanciolek.com  삭제

    2014/10/04 19:43TRACKBACK FROM scottalanciolek.com

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

  3. short.is  삭제

    2014/10/05 12:55TRACKBACK FROM short.is

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

  4. http://opisy-gg.info.pl  삭제

    2014/10/05 20:18TRACKBACK FROM http://opisy-gg.info.pl

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

  5. http://www.provimi-rolimpex.pl  삭제

    2014/10/05 20:40TRACKBACK FROM http://www.provimi-rolimpex.pl

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

  6. ectonica  삭제

    2014/10/06 00:03TRACKBACK FROM ectonica

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

  7. super real  삭제

    2014/10/18 05:26TRACKBACK FROM super real

    Extremely Agile :: 이펙티브 자바(Effective Java) 2판 재출간(인사이트)

소중한 의견, 감사합니다. ^^

  1. 지나가던개발자

    예로 보여주신, Item17대목요...

    Inheritance를 계승이라 번역하시고, foreign class를 '이질적 클래스'라고 하셨는데..
    inheritance는 이제 '상속'이라는 말로 통용되고,
    foreign class는 이전 아이템(16)의 주제를 보면 '패키지 외부의 클래스' 정도로 이해되는데..

    다른 의도가 있으셨던 건가요?

    2014/09/22 15:19 [ ADDR : EDIT/ DEL : REPLY ]
    • 내가 설계하지 않은 클래스라는 의미를 좀 더 잘 전달할 용어를 찾았던 것인데, 지금 다시 살펴보니 좀 오버한 것 같기도 합니다. 그래서 가급적이면 영어 원문을 병기하였사오나, 혼란이 있으셨다면 사과드립니다.

      2014/09/24 11:54 [ ADDR : EDIT/ DEL ]

Languages/Java2014/08/04 23:44

Java 1.8부터 ::를 통한 메서드 참조가 가능하기 때문에 (이런 참조는 전부 Functional 계열의 인터페이스를 통해 처리됩니다) 자료형 토큰 (MyClass.class 같은 것들) 사용을 줄일 수 있습니다. 


다음의 enum 자료형 예제를 보시죠. 각 상수에 해당 상수가 나타내는 Mode의 객체를 반환하는 기능이 들어 있는데, 자료형 토큰 없이도 생성자를 넘기고, 해당 생성자에 따라 객체를 만들 수 있습니다.


생성자는 Supplier<T> 인터페이스를 통해 참조할 수 있습니다. 이 인터페이스는 T get() 메서드를 가지고 있습니다. 


interface Encoder {

void init();

void setQuality(int quality);

int getFrameSize();

void encode(Bits bits, float[] data);

}


class NarrowBandEncoder implements Encoder {

@Override

public void init() {

// whatever

}


@Override

public void setQuality(int quality) {

// TODO Auto-generated method stub

}


@Override

public int getFrameSize() {

// TODO Auto-generated method stub

return 0;

}


@Override

public void encode(Bits bits, float[] data) {

// TODO Auto-generated method stub

}

}


class WidebandEncoder implements Encoder {

@Override

public void init() {

// whatever

}


@Override

public void setQuality(int quality) {

// TODO Auto-generated method stub

}


@Override

public int getFrameSize() {

// TODO Auto-generated method stub

return 0;

}


@Override

public void encode(Bits bits, float[] data) {

// TODO Auto-generated method stub

}

}


class UltraWidebandEncoder implements Encoder {

@Override

public void init() {

// whatever

}


@Override

public void setQuality(int quality) {

// TODO Auto-generated method stub

}


@Override

public int getFrameSize() {

// TODO Auto-generated method stub

return 0;

}


@Override

public void encode(Bits bits, float[] data) {

// TODO Auto-generated method stub

}

}


enum EncodingMode {

NARROW_BAND(NarrowBandEncoder::new),

WIDE_BAND(WidebandEncoder::new),

ULTRA_WIDE_BAND(UltraWidebandEncoder::new);

private Supplier<? extends Encoder> encoder;

private EncodingMode(Supplier<? extends Encoder> supplier) {

this.encoder = supplier;

}

public Encoder createEncoder() {

return this.encoder.get();

}

}



저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/557 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 잘 보고 갑니다. 오늘도 활기찬 하루 되시길요. ^^

    2014/08/04 23:54 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Java2014/06/13 23:41

그런데 이 밤중에 저는 왜 이런 짓을 하고 있는 걸까요? (수줍)



/*

 * Source.java

 */

final class Source {


private final int[] array;

private int index;

Source(int[] array) {

this.array = array;

this.index = 0;

}

static Source min(Source a, Source b) {

if ( a.index < a.array.length && b.index < b.array.length ) {

if ( a.array[a.index] < b.array[b.index] ) {

return a;

} else {

return b;

}

} else if ( a.index >= a.array.length ) {

return b;

} else {

return a;

}

}

int getValue() {

return this.array[this.index];

}


void advanceIndex() {

++this.index;

}

boolean isEmpty() {

return ( this.index >= this.array.length );

}

}


/*

 * Main.java

 */

import java.util.Arrays;

import java.util.Random;


public class Main {

private static Random generator = new Random();

private static int[] getSortedArray(int length) {

int[] ret = new int[length];

for ( int i = 0; i < length; ++i ) {

ret[i] = generator.nextInt(1000);

}

Arrays.sort(ret);

return ret;

}

public static int[] threeWayMergeSort(int[] a, int[] b, int[] c) {

Source one = new Source(a);

Source two = new Source(b);

Source three = new Source(c);

int[] ret = new int[a.length + b.length + c.length];

int retIndex = 0;

while ( !one.isEmpty() || !two.isEmpty() || !three.isEmpty() ) {

Source min = Source.min(one, Source.min(two, three));

ret[retIndex++] = min.getValue();

min.advanceIndex();

}

return ret;

}

public static void main(String[] args) {

int[] a = getSortedArray(100);

int[] b = getSortedArray(100);

int[] c = getSortedArray(100);


int[] result = threeWayMergeSort(a, b, c);


                for ( int i = 0; i < result.length; ++i ) {

System.out.printf("%4d ", result[i]);

if ( ((i+1)%10)==0 ) System.out.println();

}

}

}


이런거 짜보라고 했는데 칠판에 코드 못 그렸으면 열좀 받았겠죠? 네 그래서 한번 해봤습니다 ㅎㅎ 사실 면접 볼때 이런 유형의 문제가 나오면 제일 먼저 드는 생각은 "이거 못풀면 진짜 개망신이겠군..." 이죠 (발그레) 그러다 진짜 못풀면 하루 종일 잠이 안온다능...

저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/551 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/JavaScript2014/02/12 09:23

사실 AngularJS는 JavaScript로 동적으로 생성된 페이지에 어울리는 기술이라기 보다는, 고정된 페이지를 Template으로 만들어 데이터를 채우고자 할 때 편리한 기술이죠. 그럴 때는 정말 편하게 개발을 진행할 수 있습니다. 그렇다면, jQuery UI에서 제공하는 다이얼로그 창 같은 곳 안에 AngularJS 컨트롤러가 만들어 내는 데이터를 채우고 싶다면 대관절 어떻게 해야 하는 걸까요? 





이 문제를 좀 더 정확하게 이해하려면, 다음과 같은 가정들을 이해해야 합니다. 


  1. 한 페이지 안에 다이얼로그 창은 여러개 뜰 수 있다.
  2. 각각의 다이얼로그 창은 기본적으로 같은 HTML 코드를 사용한다.
  3. 각 다이얼로그 창이 표시하는 자료는 다이얼로그 생성시에 전달되는 데이터에 따라 달라질 수 있다

따라서 각각의 다이얼로그 창은 마치 하나의 클래스 (동일한 HTML 템플릿 코드) 에서 생성되는 서로 다른 객체와도 같다고 볼 수 있습니다. 

기술적으로 보자면 다이얼로그 창을 띄우는 것은 다음과 같은 과정을 통해 실현된다고 정리할 수 있습니다. 차례대로 살펴보죠. 

  1. 다이얼로그 창을 띄우기 위한 링크를 클릭한다
  2. 컨트롤러가 바인딩된 HTML 템플릿 코드를 만든다
  3. 해당 HTML 템플릿 코드를 다이얼로그 창 안에 올린다

1과 3은 잘 알려진 기술(jQuery와 jQueryUI같은)로 실현 가능합니다만, 2번은 조금 어렵죠. 그럼 1번부터 순서대로 살펴보도록 하죠. 

페이지 전체를 AngularJS로 구성했다면, 아마 다이얼로그 창을 띄우는 코드 자체도 AngularJS 템플릿 안에 묻어들어가 있을 가능성이 높을 겁니다. 아래의 코드처럼요.
<td><a ng-click="showPortsPopup(switch.id)">{{switch.id}}</a></td>
아래와 같이 구현하고픈 분들도 계실거 같긴 한데요.
<td><a onClick="showPortsPopup('{{switch.id}}')">{{switch.id}}</a></td>
문제는 이렇게 하면 잘 안된다는 겁니다. AngularJS는 일반 JavaScript 핸들러(onClick같은)와 AngularJS 마크업을 혼용하는 것을 허용하지 않고 있어요. 그러니 onClick보다는 ng-click을 사용하는 것이 바람직하죠. 그러니 위쪽 코드를 써야 합니다. 그런데 이렇게 하게 되면, 팝업을 띄우는 코드, 그러니까 showPortsPopup의 구현은 AngularJS 컨트롤러 안에 있어야 해요. 위의 switch가 정의된 $scope 객체에 바인딩된 컨트롤러 안에 말이죠. 

irisApp.controller('CntlSwitches', ['$scope', '$http', '$timeout', '$iris', '$compile', function($scope, $http, $timeout, $iris, $compile) { // ... omitted ... $scope.showPortsPopup = function(id) { var e = angular.element('#hiddens>div.ports').clone(); e.append('<ng-include src="\'tpl/ports.html\'"></ng-include>'); var newScope = $scope.$new(); $compile(e)( newScope ); newScope.id = id; e.dialog({ title: 'Ports of the switch ' + id, width: 800, close: function(event, ui) { newScope.goon = false; } }); }; // ... omitted ...

위에 정의된 showPortsPopup 메서드의 코드를 보면, 다음과 같은 일을 하고 있는 것을 볼 수 있어요. 먼저 HTML 문서 안에 있는 div 하나를 angular.element()를 사용해 가져온 다음에 복제(clone()) 합니다. 이 div는 페이지 안에 있긴 하지만 숨겨진(hidden) div이고, 안이 비어 있어요. 그러니 그 안에 무엇을 채우기 좋죠. 이렇게 만들어진 '새로운' div 안에다 <ng-include> 디렉티브를 붙입니다. 이 디렉티브는 '컴파일'되는 순간에 해당 태그가 포함된 HTML 요소 안에 ports.html이라는 파일에 수록된 템플릿을 역시 '컴파일'해서 집어 넣어요. 만일 해당 템플릿 안에 컨트롤러가 있다면, 컴파일되는 순간에 새로운 컨트롤러가 생겨서 바인딩되겠죠. 그럼 이런 컴파일 작업은 어떻게 하느냐. 위의 코드에서 보듯, AngularJS의 $compile 서비스를 사용해서 한다는 것이 핵심입니다. 컴파일할 때 새로운 scope 객체를 만들어 넘겨주는 부분이 있는데, 만들어진 다이얼로그 마다 별도의 분리된 스코프를 갖도록 해 주기 위해서 그렇게 합니다.

이 작업이 끝났다면 이제 jQuery UI의 dialog() 메서드를 사용해서 다이얼로그를 띄워주면 되는데요. 위의 코드를 보면 newScope.id와 newScope.goon이라는 필드를 제어하는 부분이 있죠. 그런데, 컨트롤러가 정의되고 실행되고 나면 컨트롤러가 내부적으로 scope 객체에 이런 저런 메서드를 갖다 붙이는 것이 일반적이거든요. 그럼 이렇게 필드를 직접 제어하는 대신 그런 메서드를 호출하면 되는 것 아닐까요? 그런데 그렇게 하면 잘 안되더군요. (여러 가지 이유가 있는데 그 이유에 대해서는 여기서 언급하지 않겠습니다.) 그러니 필드를 통해 컨트롤러 내부 코드에 필요한 인자를 전달하도록 하는 것이 가장 안전합니다. 

그럼 이제 ports.html 템플릿을 한 번 살펴보죠. 
<div ng-controller="CntlPorts">
<table class="horizontal_table mark_2th_row" width="100%">
<caption><span>Ports:</span><span type="links"></span></caption>
<thead>
<tr>
	<th>#</th><th>Link Status</th><th>TX Bytes</th>
	<th>RX Bytes</th><th>TX Pkts</th><th>RX Pkts</th>
	<th>Dropped</th><th>Errors</th>
</tr>
</thead>
<tbody>
	<tr ng-if="ports.length==0"><td colspan="8">No ports</td></tr>
	<tr ng-if="ports.length>0" ng-repeat="port in ports">
	<td>{{port.portNumber}}</td><td>{{port.status}}</td>
	<td>{{port.transmitBytes}}</td><td>{{port.receiveBytes}}</td>
	<td>{{port.transmitPackets}}</td><td>{{port.receivePackets}}</td>
	<td>{{port.receiveDropped + port.transmitDropped}}</td>
	<td>{{port.receiveErrors + port.transmitErrors}}</td>
	</tr>
</tbody>
</table>
</div>
CntlPorts라는 이름의 컨트롤러가 붙어 있는 것을 보실 수 있는데요. 그 컨트롤러의 코드는 아래와 같습니다.

irisApp.controller('CntlPorts', ['$scope', '$http', '$timeout', function($scope, $http, $timeout) { // initialize some data internal to this controller. $scope.ports = []; // define getData method. $scope.getData = function() { // scope.id is set externally. $http.get('/wm/core/switch/'+$scope.id+'/port/json') .success(function(data) { $scope.ports = []; _.each(data[$scope.id], function(port) { port['status'] = 'UP'; $scope.ports.push( port ); }); }) .error(function(){ $scope.ports = []; }); // go-on flag will be externally set. if ( $scope.goon != false ) $timeout(function(){ $scope.getData(); }, 1000); }; // fire once. $scope.getData(); }] );

주기적으로 데이터를 서버에서 긁어오도록 정의된 컨트롤러인데요. 컨트롤러 동작을 id와 goon이라는 필드를 사용해서 하고 있죠. 간단하죠?




저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/542 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. angular strap의 modal을 사용하셔면 좀 더 깔끔한 방법으로 사용하실 수 있습니다

    2014/02/26 06:16 [ ADDR : EDIT/ DEL : REPLY ]
    • 좋은 정보 감사합니다. :-) 잘 읽어보겠습니다.

      2014/02/26 17:22 [ ADDR : EDIT/ DEL ]
  2. 링크를 빼먹었네요
    http://mgcrea.github.io/angular-strap/##modals

    2014/02/26 06:17 [ ADDR : EDIT/ DEL : REPLY ]

Languages/JavaScript2014/02/11 10:22

AngularJS로 이런 저런 프로그래밍을 하다 보면, jQuery에서 처리하는 이벤트를 AngularJS 컨트롤러의 메서드 호출로 연결해줄 필요성도 간혹 생기죠. 





가령 어떤 div가 화면에 표시되는 순간, AngularJS 컨트롤러의 특정 메서드를 호출해서 실행시키고 싶다고 해 보죠. 이런 작업은 두 가지 측면에서 어려운데요. 


  1. div가 화면에 표시되는 순간을 잡는 jQuery 이벤트가 없다
  2. AngularJS 컨트롤러 안에서, 특정한 jQuery 이벤트 발생시에 실행할 코드를 정의하는 방법을 모르겠다


우선, 첫 번째 문제부터 해결해 봅시다. div가 화면에 표시되는 순간을 잡는 jQuery 이벤트는 없는 것이 확실합니다만, show() 메서드를 사용하면 흉내는 낼 수 있죠. 


$('div.content > div.topology').show( 0, function() {

$(this).trigger('displayed');

});


위의 코드는 어떤 일을 하는 코드인가요? 아마 잘 아시겠습니다만, content 클래스가 적용된 div 안에 있는 div 가운데 topology 클래스가 적용된 div를 찾아서 show()를 호출해 화면에 표시한 다음, 해당 element에 대해 'displayed'라는 trigger를 발생시키라는 의미입니다. 


그렇다면 이제 AngularJS 컨트롤러 코드 안에서, 해당 element에서 'displayed' 트리거가 발생했을 때 특정한 메서드를 실행하는 코드만 잘 넣어주면 되겠군요. 


// topology controller definition.

myModule.controller('CntlTopology', 

['$scope', 

 function($scope) {

// define getData method

$scope.render = function() {

// 중간 생략

};

angular

  .element('div.content > div.topology')

  .bind('displayed', function() {

$scope.render();

});

}]

);


그러니까 저 빨간 부분과 같은 코드를 작성하면 컨트롤러의 메서드 render()를 호출할 수 있게 된다는 것인데요. 간단히 요약하자면 content 클래스가 적용된 div 안에 있는 div 가운데 topology 클래스가 적용된 div에서 'displayed' 트리거가 발생하면 $scope.render()를 호출하라는 의미입니다. angular의 element() 메서드가 jQuery 객체를 처리할 수 있기 때문에 만들 수 있는 코드죠.


근데 사실 애초에 아래와 같은 코드를 사용했으면 컨트롤러쪽 코드는 수정하지 않았어도 됩니다. 그러니 어떤 쪽으로 코딩하실지는 취향에 따라서 알아서 선택하시길. 


$('div.content > div.topology').show( 0, function() {

angular.element(this).scope().render();

});


참 쉽죠? (풉)




저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/541 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. angular.js의 controller에서는 dom에 대한 핸들링을 직접하지않는 것이 원칙입니다.
    dom핸들링이 필요하면 directive를 통해서 하도록 하는 것이 권장됩니다.
    근데 div가 표시되는 순간이 왜 필요한지 모르겠습니다.(예시를 위한 용도?) 일반적으로는 모델데이타의 특정값 기준으로 처리를 하는 것이 대부분일 것 같습니다.

    2014/02/26 06:08 [ ADDR : EDIT/ DEL : REPLY ]
    • 아. 그건 제가 구현하는 Application 내부적인 필요에 의해서인데요. 감춰져 있다가 특정한 순간에만 표시되는 DIV가 있거든요. 그 DIV가 표시되는 순간에만 동작해야 하는 로직이 있어서, 어쩔수 없었습니다.

      2014/02/26 17:22 [ ADDR : EDIT/ DEL ]

Languages/JavaScript2014/02/09 16:15

요즘 많은 분들이 AngularJS를 도입하고 계신데요. 저도 써보니 AngularJS를 사용하면 코드의 양을 굉장히 줄일 수 있는데다, 속도도 빨라서 기존의 다른 JavaScript 프론트엔드들을 대부분 폐기하게 되더군요. 





AngularJS의 대표적 특징 가운데 하나는 Model 데이터와 View를 자동으로 연동시켜 준다는 것인데요. Model 데이터 상에 변경이 생기면 View도 거의 동시에, 자동적으로 갱신된다는 것입니다. 예제를 하나 들어서 살펴볼까요?


가령 아래와 같은 HTML 파일을 하나 만들었다고 해 봅시다. 


<html ng-app="testModule">

    <head>

        <script src="http://code.angularjs.org/1.2.11/angular.min.js">
        </script>

        <script src="script.js"></script>

    </head>

    <body>

    <ul ng-controller="Count">

        <li ng-repeat="name in names">{{name}}</li>

    </ul>

    </body>

</html>


이 파일에 등장하는 ng-app이나 ng-controller, ng-repeat 같은 키워드에 대해서 자세히 설명은 하지 않겠습니다만, 이렇게만 이해해 둡시다. 


  • ng-app은 모듈을 정의할 때 쓰인다. 여기서는 testModule이라는 모듈을 하나 정의했다. 
  • ng-controller는 데이터와 뷰 사이의 연결을 관장하는 컨트롤러를 정의할 때 쓰인다. 여기서는 Count라는 컨트롤러를 하나 정의했다. 보통 프로그래밍 언어에서 '이름'은 그 이름이 유효한 '유효범위(scope)'를 갖는데, 컨트롤러가 정의되면 해당 컨트롤러가 그 유효범위 구실을 한다고 이해해두면 좋다. 
  • ng-repeat는 모델 데이터에 따라 어떤 특정 태그를 반복해서 표시하고 싶을 때 사용한다. 여기서는 names라는 배열 안에 등장하는 모든 name들에 대해서 li 태그를 표시하기 위해 사용했다. 
  • {{name}}은 모델 데이터를 사용해 실제 화면에 표시되는 HTML 문서의 내용을 만드는 치환자라고 생각하면 된다. Angular 식 용어로 하자면, 마크업(markup)이다. 


자. 일반적인 MVC 패턴에서 데이터와 뷰 사이의 연결을 만들어 주는 것은 보통 컨트롤러입니다. 여기서는 <ul> 에만 적용되는 컨트롤러 Count를 정의했습니다. 이 컨트롤러의 소스코드는 아래와 같습니다. 


var myModule = angular.module('testModule', []);


myModule.controller('Count', function($scope, $timeout) {

    $scope.names = [];

    $scope.cnt = 0;

    

    $scope.increase = function() {

        $scope.names.push(++$scope.cnt);

    }

    

    $scope.interval = function() {

        $timeout(function() {

            $scope.increase();

            $scope.interval();

        }, 1000);

    }

    

    $scope.increase();

    $scope.interval();

  });


위의 소스코드를 보시면 Count라는 이름의 컨트롤러를 정의하고 있는 것을 보실 수 있는데요. 이 컨트롤러는 $scope와 $timeout 서비스(service)를 사용하여 정의되는 함수(function)로서, $scope는 해당 컨트롤러가 나타내는 유효범위를 제어해주는 서비스이고, $timeout은 타이머에 기반한 제어 로직을 구현할 수 있도록 하는 서비스라고 생각하시면 되겠습니다.


또한 위의 코드를 보면, Count 컨트롤러가 하는 일이 다음과 같음을 알 수 있는데요.


  1. 일단 $scope 범위 안에 names라는 배열과 cnt라는 변수를 생성한다.
  2. $scope 범위 안에 increase라는 함수와 interval이라는 함수를 생성한다. increase가 하는 일은 names 배열을 1만큼 증가시키는 것이고, interval이라는 함수가 하는 일은 주기적으로 increase와 interval 함수가 재실행될 수 있도록 하는 것이다.
  3. increase 함수와 interval 함수를 최초 실행한다.

이 두 소스를 각각 index.html과 script.js 파일로 저장해 놓고 chrome같은 브라우저로 index.html 파일을 열어보면, 화면에 <ul> 목록이 표시되는 것을 볼 수 있습니다. 재미있는 것은 script.js 안에서 names 배열의 크기가 1초마다 증가하도록 해 두었기 때문에, 브라우저상에 표시되는 <ul> 목록도 1초마다 계속 늘어난다는 것이죠. 


$scope.increase 함수를 다음과 같이 변경하면 좀 더 재미있는 광경을 보실 수 있습니다. (응?)


$scope.increase = function() {

        $scope.names.push(++$scope.cnt);

        if ($scope.names.length > 10) {

          $scope.names.splice(0,1);

        }

    };




저작자 표시 비영리 변경 금지
Posted by 이병준
TAG angularJS

TRACKBACK http://www.buggymind.com/trackback/540 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 마라나타

    음.. 잘보았는데요.. 익스플로러7에서는 안돌아가는거 같습니다.. ㅠㅠ
    해결법있나요

    2014/02/23 20:48 [ ADDR : EDIT/ DEL : REPLY ]
    • 익스플로러 7은 .... 모르겠습니다 ㅎㅎ
      요즘은 IE 7 지원을 하지 않는 추세인 듯 해서 저도 테스트하지 않았습니다.

      2014/02/26 17:20 [ ADDR : EDIT/ DEL ]

Languages/JavaScript2014/01/06 09:37

이전 글에서 "2014년에 배우고 싶은 프로그래밍 언어는?"이라는 제목의 설문조사를 실시했었습니다. 예상했었습니다만, JavaScript가 압도적(?) 1위를 차지했는데요. 웹 세상에서 JavaScript라는 언어가 차지하는 비중이 얼마만큼인지를 잘 보여주는 결과였던 것 같습니다. 


http://ayudawordpress.com/insertar-javascript-en-wordpress/



SEE ALSO: 2014년을 함께할 프로그래밍 언어는?


그래서 이번 글에서는 알아두면 생산성을 높일 수 있는 JavaScript 프로젝트들을 소개하려고 합니다. (jQuery같은 정말 보편적으로 사용되는 프로젝트는 뺐습니다.) 이중에는 라이브러리도 있고, 완전한 프레임워크(framework)도 있습니다. 일별하신 다음에 용도에 맞게 가려 쓰시면 좋을 것 같구요. 제 취향에 따라 고른거라 공신력은 없습니다. 더 공신력 있는 자료를 원하시면 이 페이지 마지막에 있는 링크를 참고하세요. 


사실 "JavaScript를 배워야하는 다섯 가지 이유들"이라는 글을 쓰려고 준비하면서 이런 저런 자료들을 찾아 봤었는데, 인상적인 문구 하나를 발견하고 나서는 포기했습니다. 이런 글이었죠.


"어쨌든 결국에는 배워야 할 언어니까 배워야 한다."


1. Angular.js


최근 가장 주목받고 있는 MVC 프레임워크죠. angularjs.org 가 웹사이트 주소입니다. 웹 사이트 대문부터가 코드들로 가득한 것이 심상치 않은데요. 일단 이 프레임워크를 사용하면 HTML과 Application 로직을 바인딩하기 위한 코드의 양이 엄청나게 줄어듭니다. View-Model 간 interaction을 처리하기 위해 우리는 그동안 정말 많은 삽질을 해야 했는데요. 그런 수고를 줄여주는 것이죠. 


다만 Angular.js를 사용하려면 HTML 코드에 HTML이 아닌 코드들이 뒤섞이게 되는 문제가 있는데요. Presentation이 Model과 완전히 분리되어야 한다는 원칙이 좀 손해를 보게 되는 것이죠. HTML 문서와 응용 로직 사이의 결합도가 증가하기 때문인데요. 저는 개인적으로 이런 식의 프로그래밍을 싫어합니다만 HTML 디자인을 담당하는 개발자나 도구가 Angular.js를 수용하게 되면 개선될 수도 있겠습니다. 


2. Underscore.js


JavaScript 개발시 생산성을 높여주는 다양한 API를 포괄하는 라이브러리입니다. Python과 유사한 Functional Programming을 할 수 있도록 도와줍니다. 그 이외에도 기능들이 많습니다. 웹사이트는 underscorejs.org 입니다.


3. D3.js


SVG를 활용한 이 엄청난 시각화 도구는 다양한 형태의 인포그래픽을 JSON 형태의 데이터를 사용해 실시간으로 렌더링할 수 있도록 해 줍니다. 그야말로 시각화의 끝판왕. 데이터를 보다 효과적으로 렌더링하는 목적을 달성하기 위해서는 반드시 배워야 하는 도구 중 하나. 웹사이트는 d3js.org


4. Node.js


Node.js는 JavaScript라는 언어의 적용범위를 Front-end에서 Backend 서버 개발로까지 확장시켰습니다. 이 프로젝트 덕분에 JavaScript는 범용적 언어라는 지위를 획득하게 되었다고 봐도 과언이 아닌데요. 이 플랫폼을 사용하면 웹 서버를 비롯한 다양한 형태의 서버를 아주 쉽게 만들 수 있을 뿐 아니라, 과거 독립적인 응용 프로그램에서나 가능했던 일들을 JavaScript로도 할 수 있게 됩니다. 웹사이트는 nodejs.org 


5. two.js


SVG, Canvas, WebGL을 사용해 2차원의 이미지를 그릴 수 있도록 해 줍니다. 현재는 도형만 그릴 수 있습니다만 (텍스트나 이미지는 지원하지 않습니다.) 추후 더 확장될 것으로 예상됩니다만, 어쨌든 현재로는 그렇습니다. 웹 사이트를 가 보면 굉장히 다양한 (그리고 흥미진진한) 예제들을 발견할 수 있는데요. 어떤 것은 D3.js의 영역과 겹치고, 어떤 것은 아닙니다. 용도를 잘 구별해서 사용하는 것이 좋을 듯. 웹사이트 주소는 http://jonobr1.github.io/two.js/ 입니다. 


6. Zebra


데스크탑 응용 프로그램에서 흔히 발견할 수 있는 그리드, 탭, 메뉴, 폼 등등의 요소를 포함하는 응용을 JavaScript로도 작성할 수 있도록 해 줍니다. 웹사이트는 https://github.com/barmalei/zebra 입니다.


7. Formula.js


엑셀이나 구글 스프레드시트에서 사용 가능한 함수들을 JavaScript에서도 사용할 수 있도록 해 주는데요. 이 웹 사이트에 가보면, 이 라이브러리에 포함되어 있는 함수가 여러분의 브라우저에서도 지원되는지 자동으로 테스트 해 주기 때문에 개발에 활용하기가 편합니다. 엑셀 매니아라면 환영할 만한 라이브러리. 웹사이트는 http://stoic.com/formula/ 입니다. 


8. Chart.js


JavaScript로 차트를 그려야 한다면 피해갈 수 없는 라이브러리. 차트를 그리고 싶은 욕구가 샘솟도록 만드는 예쁜 차트들을 제공함. 웹사이트는 http://www.chartjs.org/ 


9. Parallel.js


JavaScript로 멀티코어 프로그래밍을 할 수 있도록 해 주는 라이브러리. 단 여러분의 브라우저가 WebWorker를 지원해야 함. 이 라이브러리를 사용하면 Map-Reduce 같은 프로그래밍 모델을 JavaScript 안에서 사용할 수 있게 됩니다. 단 물리적으로 분리된 시스템이 아니라, 여러 코어 상에서죠. 웹 사이트는 http://adambom.github.io/parallel.js/


10. Meteor


웹-앱을 손쉽게 만들 수 있도록 도와주는 오픈 소스 프레임워크. 웹-앱 개발자라면 반드시 검토해봐야 할 프레임워크 가운데 하나. https://www.meteor.com/


11. jQuery mobile


모바일 기기가 대세인 작금의 상황에 이 라이브러리를 빼먹고 넘어가면 섭섭할 듯. 터치에 최적화된 웹 프레임워크. jQuery == JavaScript 라고 생각하는 사람도 많은 상황이라, 현재 JavaScript 시장의 대세는 역시 jQuery. 모바일에서도 무시할 수 없기 때문에 jQuery 이야기는 안하려고 했으나 어쩔 수 없이 (Orz) 웹사이트는 http://jquerymobile.com/


12. Grunt


JavaScript를 사용한 개발과정을 자동화하고 싶다면? 프로젝트 관리를 자동화 하고 싶다면? JavaScript 프로젝트에도 빌드 도구를 도입하고 싶다면? 그렇다면 현재 대안은 딱 하나 뿐입니다. Grunt 상에서 실행되는 어마어마한 양의 플러그인 수가 Grunt의 인기를 반증합니다. 웹사이트는 http://gruntjs.com/


이 이외에도 많사오니 아래의 링크를 참고하세요. 지금 GitHub에서 가장 인기있는 JavaScript 프로젝트 100개의 리스트를 확인할 수 있습니다. (2013년 말 기준) 1위는 Grunt. 


http://www.takipiblog.com/wp-content/uploads/2013/11/Javascript.jpg


http://www.takipiblog.com/2013/11/20/we-analyzed-30000-github-projects-here-are-the-top-100-libraries-in-java-js-and-ruby/



저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/533 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. anydeveloper

    정말 유익한 글 써주셔서 감사드립니다. 앞으로도 좋은 글들 많이 부탁드립니다~ :-)

    2014/01/06 13:38 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Python2014/01/01 11:42

1. 다양한 기능을 갖춘 언어가 필요하다면 


"실용주의 프로그래머(Pragmatic Programmer)"라는 책을 보면 일년에 하나 정도의 새 언어를 배우라는 조언이 있어요. Peter Norvig라는 사람이 쓴 "Teach Yourself Programming in Ten Years"라는 에세이를 봐도, 적어도 여섯 개의 "종류가 서로 다른" 언어를 10년간 배우라는 조언이 있지요. 뒤집어 이야기하면, 세상에는 여섯 가지 부류의 언어가 있다는 이야긴데요. 대충 정리해보면 다음과 같습니다. 


http://www.smallanimaltalk.com/2013/04/worlds-cutest-python.html


(1) 클래스 추상화(class abstraction)를 제공하는 언어

(2) 함수형 추상화(functional abstraction)를 제공하는 언어 

(3) 문법 추상화(syntactic abstraction)을 지원하는 언어 

(4) 선언적 명세(declarative specification)를 지원하는 언어

(5) 코루틴(coroutine)을 지원하는 언어 

(6) 병렬수행(Parallelism)을 지원하는 언어 


다른건 잘 모르겠고 (1), (2), (5)는 지원되면 좋겠다고 생각하는데요. 객체지향 언어는 이미 업계 대세니까 당연한거고, 함수형 추상화는 요즘 유행인데다 거의 모든 언어가 함수형 추상화를 지원하기 위해 삽질중이라 더더욱 그렇죠. Python은 (1), (2), (5)를 지원합니다. 객체지향 언어이자, 함수형 프로그래밍 언어이기도 하죠. 파이썬의 함수와 함수형 프로그래밍에 대해서는 http://docs.python.org/2/howto/functional.html 이 문서를 참고하면 좋겠습니다. 


사실 위의 여섯가지 속성을 거의 전부 만족시키는 언어도 있긴 한데요. Python의 미래라고 보는 사람도 있는 Julia입니다. http://julialang.org/ 


SEE ALSO: Java를 배워야 할 다섯가지 이유

SEE ALSO: 새로운 언어를 더 빨리 배우려면?


2. 생산성이 중요하다면


Python과 다른 언어의 성능을 비교하는 논쟁은 다양하게 있어 왔습니다. 한 가지 얻을 수 있는 결론은, Python의 성능이 나쁘지 않다는 겁니다. http://stackoverflow.com/questions/672857/is-python-slower-than-java-c 하지만 우리가 언어를 선택하는 기준이 꼭 성능 뿐만인 것은 아니죠. Python의 가장 큰 장점은 생산성입니다. https://pythonconquerstheuniverse.wordpress.com/2009/10/03/python-java-a-side-by-side-comparison/ 물론 어떤 언어의 생산성을 단순히 언어의 문법적인 측면만으로 논하는 것은 좀 위험한 일이긴 합니다만, Python의 문법이 보다 간결한 프로그래밍을 가능케 하는 것은 사실입니다. 


3. 프로그래밍 습관을 고치고 싶다면


파이썬은 들여쓰기(indentation)로 프로그래밍을 하는 드문 언어 가운데 하나입니다. C/C++/Java 등의 일반적인 프로그래밍 언어들은 보통 {와 }를 사용해서 구문의 범위를 구별하죠. 들여쓰기로 프로그래밍을 하면 {와 }를 쳐 넣지 않아도 되니까 프로그래밍 하기가 좀 편해지긴 하겠습니다만 코드가 길어지면 가독성이 점차로 떨어지게 되는 문제도 있습니다. 대체 어디서부터 어디까지가 함수인지를 명확하게 알기 어렵다는 문제도 있죠. 


그래서 파이썬으로 프로그래밍을 하다 보면 의식적으로 함수 하나의 길이를 줄이게 되는데요. (너무 길어지면 정말 정신 사나워지거든요.) 그러다보면 코드는 좀 더 테스트하기 쉬운 단위로 분할되죠. 이런 종류의 리팩터링(refactoring)을 의식적으로 하게 된다는 것은, 프로그래밍을 처음 배우는 사람 뿐 아니라 프로그래밍을 굉장히 오랫동안 해 온 사람에게도 유익한 것이죠. (Python 프로그램의 가독성이 다른 프로그램보다 높다는 사람이 있는데요. 아마 이런 종류의 반강제적 리팩터링과 간결한 문법 덕분에 그런 주장이 가능한 것이 아닐까 생각합니다.)


4. 초대형 프로젝트에 사용되는 dynamic 언어를 배우고 싶다면 


Python은 초대형 프로젝트에서 널리 사용되고 있는 동적 프로그래밍 언어이기도 합니다. http://www.ozytive.com/2012/10/13/10-reasons-why-you-should-learn-python/ 그러니, 초대형 프로젝트를 진행할만한 여력이 있는 회사에 취직하고 싶다면, Python을 알아두는 것이 좋겠어요. 이런 것은 단순히 프로그래밍 언어 유행을 따라가느냐 마느냐의 문제는 아니죠. 


5. 배우기 쉬운 dynamic language가 필요하다면


Python은 분명 배우기 쉬운 dynamic language입니다. 거기다 거대한 개발자 커뮤니티를 갖고 있죠. (Python의 역사는 꽤 오래 되었습니다.) 거기다 문서화도 충실하게 잘 되어 있어서, 아주 쉽게 배울 수 있는 언어이기도 합니다. (아마 기본적인 문법서 한권 정도를 본 다음 doc.python.org의 HOWTO 문서를 읽으면 바로 프로그래밍을 시작하실 수 있을 겁니다. 저는 일주일 걸렸습니다.) 


이것은 Python의 기본적인 문법이 기존 프로그래밍 언어와 크게 다르지 않기 때문이기도 하고, 가능한 자연어에 가깝게 느껴지는 문법적 구조를 채택하고 있기 때문이기도 합니다. Julia는 이점에서 Python과는 좀 다릅니다. 코드를 보면, 뭘 하는 코드인지 한 눈에 확 들어오질 않아요. (물론 다르게 생각하시는 분들도 있긴 하겠습니다만. :-P)



저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/530 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 블로그 내용 잘 보고 갑니다.

    2014/01/01 15:14 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Java2013/12/31 11:56

1. Garbage Collection이 필요하다면


메모리 할당/반환을 처리하는 것이 너무 지겹고 고단하다면, Java를 배워야 할 필요가 있을지 모릅니다. 잘 잘려진 대로, Java는 메모리 할당과 반환에 대한 작업을 Garbage Collector를 통해 알아서 처리해 줍니다. 그 성능이 걱정되신다구요? Java는 만들어진 지 오래된 언어이고, JVM의 성능을 최적화하기 위해 오랫동안 애써 왔습니다. 그 이야기는, Java의 JVM이 제공하는 Garbage Collector의 성능이 이제 믿을만한 수준까지 도달했다는 의미이기도 합니다. (물론 Java에서도 메모리 누수 현상, 즉 Memory Leak은 발생할 수 있으므로 이를 피하기 위해서는 코딩할 때 주의해야 합니다. Effective Java 2nd Edition을 참고하세요.) 


물론 잘 최적화된 C/C++ 바이너리와의 성능을 비교하는 것은 어불성설입니다. 하지만 C++로 작성한다고 무조건 성능이 더 나을거라는 생각은 버리는 것이 좋습니다. 대체적으로, 높은 성능을 내는 것은 무슨 무슨 언어를 쓴다고 공짜로 따라오는 것이 아니라, 프로그래머의 노하우, 패턴, 최적화 등등이 함께 결합되어야 가능하기 때문입니다. 


http://neuroph.sourceforge.net/index.html



2. 어떤 라이브러리를 쓸까 고민하기 싫다면


Java에는 이미 굉장히 큰 규모의 라이브러리가 번들링되어 있습니다. 이 라이브러리들만 잘 사용해도 대다수의 작업은 무리없이 처리할 수 있습니다. 게다가, 관련된 오픈소스 프로젝트들도 많아서, 용도에 맞는 써드 파티 라이브러리를 선택할 때 자유도가 굉장히 높습니다. '무슨 무슨 일을 하는 라이브러리는 파이썬이나 C++ 밖에 없어요. 그러니 우리는 프로젝트를 C++로 진행해야...'와 같은 상황이 생길 여지가 별로 없다는 것이죠. 


굳이 예를 하나 들자면.... 여러분은 GPU 코어를 사용해 시스템 처리 성능을 높이는 방법론인 CUDA를 알고 계실 겁니다. 예전 같으면 이처럼 시스템에 아주 가깝게 다가가 있는 기능을 사용하는 프로그램을 작성할 때 C/C++ 말고는 선택할 수 있는 언어가 거의 없었겠지만, 이제 자바 사용자는 JCUDA(http://www.jcuda.org/)를 사용해서 CUDA 프로그래밍을 할 수 있습니다. 


3. 높은 이식성이 필요하다면


JVM마다 성능이 조금씩 달라지는 일은 있습니다만, 대체로 Java 프로그램의 이식성은 JVM에 의해 보장됩니다. Java 표준을 충실히 따르는 프로그램을 개발했다면, 거의 모든 플랫폼에서 재컴파일 없이도 프로그램을 돌릴 수 있습니다. 아, 물론 Microsoft VM을 사용하는 프로그램을 짰다면 그것은 예외. (묵념) 


4. 수평적 규모 확장성이 요구된다면


Hadoop을 아십니까? 이제 데이터 처리에 있어 수평적 규모확장성(horizontal scalability)이 필요할 때, Hadoop 기반의 플랫폼은 무슨 업계 표준인 것 처럼 받아들여지고 있는 실정이죠. 놀라운 것은, Hadoop이라는 플랫폼이 Java로 작성되어 있다는 것입니다. 그 말은, 시스템에 요구되는 높은 확장성을 달성할 때 중요한 것이 더 이상 언어가 아니라는 점이며, Java가 그러한 성능 요구사항을 달성할 수 있는 수준으로 진화했다는 사실입니다. 어쨌든, Hadoop이 필요하다면 여러분은 Java를 배우는 것이 좋습니다. 물론 다양한 언어 바인딩(binding)들이 나오고 있는 실정이지만 말이죠. 


물론 수평적 규모 확장성을 달성하는 방법이 Hadoop만 있는 것은 아닙니다. Hazelcast(http://www.hazelcast.com/)도 한번 구경해 보세요. Java 기반의 미들웨어가 어디까지 진화해 있는지 느끼실 수 있을 겁니다.


5. 좀 더 편하게 개발하고 싶다면 


Java 개발자들에게 있어서 Eclipse란 어떤 존재인가요? (물론 요즘은 C++/Python 등 다양한 언어의 개발 환경도 Eclipse로 통합되고 있는 실정이긴 합니다만.) 아마 대다수의 Java 개발자는 (저 포함) Eclipse 없는 개발은 상상도 하지 못할지 모르겠군요. 이 놀라운 IDE 덕분에, Java 개발자들의 개발 생산성은 vi로 코딩하고 Make로 빌드하던 초창기에는 상상도 할 수 없을 차원으로 높아졌습니다. 


게다가 여러분은 지금, Android 개발 까지도 진행할 수 있을 만큼 진보된 Eclipse를 사용하고 있습니다. 게다가 Marketplace 기능을 통합한 Eclipse는, 새로운 개발 지원 기능의 통합을 믿을 수 없을 만큼 신속하게 수행할 수 있도록 해주죠. Eclipse는 Java 개발자들의 생산성을 높여줄 뿐 아니라, Java 언어에 대한 진입 장벽 또한 낮추고 있습니다. 


SEE ALSO: 파이썬(Python)을 배워야 할 다섯가지 이유



저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/529 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 비밀댓글입니다

    2013/12/31 18:22 [ ADDR : EDIT/ DEL : REPLY ]
  2. 어? 왜 비밀글이 되었지??

    2013/12/31 18:23 [ ADDR : EDIT/ DEL : REPLY ]
    • 항상 좋은 글 잘 보고있습니다. 이번 주제는 JAVA의 필요성에 대해 말씀해 주셨는데요 위와같은 사항으로 고민중인 C/C++ 프로그래머라면 개인적인 소견이지만 JAVA보다는 C#도 어떨까 싶습니다.
      1) 자동화된 메모리관리
      2) JAVA와 유사한 라이브러리들과 MSDN
      3) C/C++과 유사한 문법
      4) C/C++의 dll링크가 가능 (C++의 속도와 C#의 편의성 두 이득을 동시에...)
      5) 윈도우 뿐 아니라 리눅스에도 모노를 통해 점점 확장성이 생기고 있음
      6) 스마트폰 게임을 개발중이라면 유니티에서 제공하는 기본 언어(물론 자바도 가능하지만 C#쪽이 더 낫다더군요.. JAVA쪽 유니티는 경험하지 못했습니다.)
      ---
      코멘트 해주신 내용 다시 붙였습니다. 감사합니다.

      2013/12/31 18:38 [ ADDR : EDIT/ DEL ]

Languages/Python2013/09/30 16:44

이 방법은 http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python에 공개된 방법입니다. 아래에는 결과만 보여드립니다. 


import itertools
def erat2( ):
    D = {  }
    yield 2
    for q in itertools.islice(itertools.count(3), 0, None, 2):
        p = D.pop(q, None)
        if p is None:
            D[q*q] = q
            yield q
        else:
            x = p + q
            while x in D or not (x&1):
                x += p
            D[x] = p


이 함수를 실행하는 함수를 다음과 같이 정의합니다. 


def get_primes_erat(n):
  return list(itertools.takewhile(lambda p: p<n, erat2()))


실행해 보면 다음과 같은 결과를 얻습니다. 


>>> get_primes_erat(1000)

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,

 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163

, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251

, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349

, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443

, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557

, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647

, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757

, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863

, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983

, 991, 997]

>>>


제일 신속한 방법이라고 알려져 있습니다. 



저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/474 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Python2013/09/27 16:30

파이썬 프로그래밍을 하다보면 가끔 'NoneType' object is not iterable 이라는 오류를 만나게 될 때가 있습니다. 물론 이 오류 메시지는 


for i in something:

   ...


위의 코드에서 'something'이 'for'를 적용할 수 없는 객체인 경우에도 만나게 됩니다만, 가끔은 이런 경우에도 만날 수 있습니다. 가령 위의 for 문 안에서 뭔가를 한다고 해 봅시다. 


for i in something:

  ret = do_something(i)

  do_another_something(ret)


그런데 do_something() 메소드 내부 코드가 다음과 같이 구현되어 있다고 해 봅시다.


def do_something(i):

  if some_condition(i):

    return some_result_of_processing(i)


그러니까 이 메소드는 i에 대해서 어떤 조건이 만족되면 뭔가를 리턴하지만, 그 조건이 만족되지 않을 경우에는 아무것도 리턴하지 않습니다. 심지어 None 조차도 리턴하지 않고 있죠. 이런 경우에 종종 for 문 안에서 ret = do_something(i)를 하는 순간 'NoneType' object is not iterable이라는 오류가 발생하곤 합니다.


따라서 위의 do_something 함수처럼 뭔가를 반환해야 하는 함수인데, 아무것도 반환하지 않게 되는 경우가 생기지 않도록 주의해야 되겠습니다. 그렇지 않으면 오류 메시지의 뜻이 무엇인지 해석하는 데 한참 걸리게 될 수 있으니까요.




저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/473 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. guest

    python은 리턴 값이 없으면 None type을 리턴합니다. 그래서 None type은 iteration 할 수 없다고 하는 것이지요...

    2013/12/13 16:47 [ ADDR : EDIT/ DEL : REPLY ]

Languages2013/09/13 11:08

요즘 통계 데이터 분석과 시각화 도구로 R이라는 언어가 각광받고 있습니다. 그러나 이 언어는 진입 장벽이 다른 언어보다 조금 높은 편인데요. 아마 시각화 관련된 부분이 큰 비중을 차지해서가 아닐까 싶습니다.


그런데 이런 부분에 대한 갈증을 해소해 줄 만한 책이 인사이트에서 나왔습니다. R Graphics Cookbook 입니다. "데이터 시각화를 위한 실용 레시피"라는 부제를 달고 나왔습니다. 




책을 읽어보지 못했으므로 내용에 대해서는 뭐라 말씀드리기 그렇습니다만, R Cookbook이라는 또다른 서적과 함께 읽으신다면 꽤 충실한 안내서 역할을 해 줄 것으로 기대합니다. 


요즘 인포그래픽스다 뭐다 해서 관련 분야가 뜨고 있는 만큼, 배워두면 좋겠죠? 이런 것도 다 그릴 수 있답니다. 








저작자 표시 비영리 변경 금지

'Languages' 카테고리의 다른 글

R 언어 시각화, 어떤 책으로 배워야 할까?  (0) 2013/09/13
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/467 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Java2013/04/17 11:51

JAR file can be dynamically loaded from a running Java program. The dynamic loading is relatively easy. 


public class JarLoader {


@SuppressWarnings("unchecked")

private static Class<OFController> loadJar(String path) {

if ( !path.endsWith(".jar") ) {

// this is not a jar file.

return null;

}

String basename = Basename.get(path, "jar");

File file = new File(path);

if ( file.exists() ) {

ClassLoader loader;

try {

loader = URLClassLoader.newInstance(

new URL[] { file.toURI().toURL() },

JarLoader.class.getClassLoader()

);

return (Class<OFController>)
                                    Class.forName( basename, true, loader );

} catch (MalformedURLException e1) {

return null;

} catch (ClassNotFoundException e) {

Logger.stderr("basename " + basename + " is not found");

e.printStackTrace();

return null;

}

}

return null;

}


public static OFController getController(String path, int num_of_instances) {

Class<OFController> ctrl = loadJar(path);

if ( ctrl == null ) {

return null;

}

try { 

Constructor<OFController> constructor = 

ctrl.getConstructor(new Class[]{ int.class });

return constructor.newInstance( num_of_instances );

} catch (NoSuchMethodException e) {

Logger.stderr("Cannot find constructor for " + path);

return null;

} catch (SecurityException e) {

Logger.stderr("You are not authorized to open " + path);

return null;

} catch (InstantiationException e) {

Logger.stderr("Cannot instantiate controller from the given jar "
                                          + path);

return null;

} catch (IllegalAccessException e) {

Logger.stderr("You are not authorized to access constructor for "
                                           + path);

return null;

} catch (IllegalArgumentException e) {

Logger.stderr("You have passed wrong argument to " + path);

return null;

} catch (InvocationTargetException e) {

Logger.stderr("Wrong invocation target for " + path);

return null;

}

}

}


Above code is from a working system. Basically, all you need to look is the URLClassLoader, loadJar method, and codes  that actually call the constructor of the loaded class. 




In implementing this class, We have used a utiliy class called 'Basename'. As we set the name of the Jar file to the complete path of the class including package name (for example, xxx.yyy.SimpleClass), the class 'Basename' is critical in extracting the class name that would be instantiated. 


public class Basename {

public static String get(String path, String extension) {

String[] delimited = path.split("/");

String filename = delimited[ delimited.length - 1 ];

return filename.substring(0, filename.lastIndexOf("." + extension));

}

}


May the force of JAR files be with you!


저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/462 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Java2013/04/15 11:16


Java NIO and reactor pattern.Java NIO and reactor pattern. http://www.moparscape.org/smf/index.php?topic=460976.0


The key component of java NIO is java.nio.channels.Selector. With this, you can easily monitor a specific set of events happening from underlying channels. With this, you can easily write codes to create a socket, bind the socket, listen the socket, and accept a new client connection. 


Following is an example code from a working system. 


Selector accept_selector = Selector.open();


ServerSocketChannel tcp_server = ServerSocketChannel.open();

tcp_server.socket().bind(new InetSocketAddress(6633));

tcp_server.configureBlocking(false);

tcp_server.register( accept_selector, SelectionKey.OP_ACCEPT );


//

// start accept loop

// 

int accept_seq = 0;

while ( !quit ) {

int r = accept_selector.select();


if ( r > 0 ) {

// accept set is ready

Set<SelectionKey> keys = accept_selector.selectedKeys();

for ( Iterator<SelectionKey> i = keys.iterator(); i.hasNext(); ) {

SelectionKey key = i.next();

i.remove();


if ( key.isAcceptable() ) {

int seq = ++accept_seq;

SocketChannel sw_channel = tcp_server.accept();

sw_channel.configureBlocking(false);

sw_channel.socket().setTcpNoDelay(true);

sw_channel.socket().setPerformancePreferences(0,2,3);


some_thread_object.addClient( sw_channel );

}

}

}

}



Above code is very simple, so I think no further explanation is needed. One thing to note is that you can also apply this kind of convention to the socket read. After creating sw_channel, you might pass the channel to a thread that monitors a set of connections. Then, the thread does 'select' on the set of connections, check if there are some readable connections. On the readable connections, you can actually perform 'read'. 


void addClient(SocketChannel client) {

synchronized ( guard ) {

try {

// ...

client.register( 

read_selector.wakeup(), 

SelectionKey.OP_READ | SelectionKey.OP_WRITE, 

null /* attachment */

);

} catch (ClosedChannelException e) {

// channel is closed. 

try {

client.close();

} catch (IOException e1) {

// does nothing.

}

}

}

}


Above code is to register a ClientChannel object to a 'read_selector' object, that the thread object has as its private member. One thing to note is, how the 'guard' object is used to prevent deadlock at client.register() and read_selector.select() call. This is an idiom, so please follow it. 


while ( !quit ) {

try {

// guard idiom to prevent deadlock at client.register() call

synchronized (guard) {}


int r = read_selector.select();

if ( r > 0 ) { // there's something to read.


Set<SelectionKey> keys = read_selector.selectedKeys();

for ( Iterator<SelectionKey> i = keys.iterator(); i.hasNext(); ) {

SelectionKey key = i.next();

i.remove();

try { 

if ( !key.isValid() ) {

// do something

key.cancel();

conn.close();

continue;

}

if ( key.isWritable() ) {

// do something

}

if (  key.isReadable() && !handleReadEvent(conn) ) {

// do something

key.cancel();

conn.close();

}

} catch ( CancelledKeyException e ) {

e.printStackTrace();

continue;

}

}

}

} catch (IOException e) {

e.printStackTrace();

// just break this watcher.

return;

}

}


Above codes are from the run loop of  'some_thread_object'. Basically, this loop monitors a set of channels that read and write is possible. Once the selector selected a set of keys (each key is mapped to one SocketChannel object) that are readable or writable, you should check teach channel is actually readable using key.isReadable(), or writable using key.isWritable(). If they return true, that means you are able to read from or write to the channel. 


May the NIO be with you!


저작자 표시 비영리 변경 금지
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/461 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/C++2012/09/25 08:00

To remove the cost of frequently creating threads, we sometimes use thread pool. Basically, we save threads in thread pool in suspended status that waits for a signal. (All the threads are put into the pool after they are started and being suspended.) 


If we have to use a thread, we retrieve a thread from the pool, and assign some thread-specific data to the thread and give it a signal to wake up from the suspended status and to finish the job assigned to the thread. 


Below, I showed a declaration of PooledThread, which is a class for thread objects that would be maintained by a thread  pool. 


// pooled_thread.h


class PooledThread : public BJLEE::CThread {


    int id;


    // page to process

    void* data;

    void* context;


    volatile bool quit;


    BJLEE::CCond wait;


public :


    PooledThread(int pid)

        : CThread(false), id(pid), data(0), context(0), quit(false)

    {}


    void signal() {

        wait.lock();

        wait.signal();

        wait.unlock();

    }


    void shutdown() {

        quit = true;

        wait.lock();

        wait.signal();

        wait.unlock();

    }


    int get_id() { return id; }


    void set_data(void* d) { data = d; }

    void set_context(void* c) { context = c; }


    // callback that a subclass must define.

    virtual void process(void* context, void* data) {}


protected:

   void run(void* arg);

};


In implementing this class, I have used BJLEE::CThread class which is a wrapper class for POSIX pthread. (I will not show its implementation here.) By inheriting the class and implementing its pure virtual function 'void run(void* arg)', we can easily implement a pthreaded functions.  The 'run' method is initiated when we call 'void start(void* arg)' method. The argument given to this method is relayed to 'void run(void* arg)' as its parameter.


And I also used the BJLEE::CCond class which is a wrapper class for POSIX pthread-based conditional variable. By acquiring a lock to this object (by calling lock() method) and calling 'wait' method(), a owner thread of this object get into the suspended status. The thread is waken up by other threads that call 'signal()' or 'broadcast()' method after acquiring the lock to the object. 


In this PooledThread class, there are 'signal()' method which is used to a thread to wake up its suspended status, implemented using CCond object. 


'set_data()' and 'set_context()' method are to pass user-specific data to the thread before calling 'signal()'. 


// pooled_thread.cc


#include "pooled_thread.h"

#include "thread_pool.h"


void

PooledThread::run(void* arg) {


    ThreadPool* pool = (ICONThreadPool*)arg;


    wait.lock();

    while ( !quit ) {

        pool->initialized( id );

        wait.wait();


        process(context, data);


        pool->back(this);

    }

    wait.unlock();

}



Above is the implementation of 'void PooledThread::run(void* arg)'. As you can see, using the thread pool pointer given by the argument, it gives a notification that this thread is initialized and ready to accept a 'signal()' call. The 'signal()' method defined in the PooledThread class is to give a wake up call to the thread that is suspended in waiting status by calling 'wait.wait()'. 


Without the 'pool->initialized( id )', it is impossible to prevent a user of the thread pool to get a thread pointer that is not initialized yet from the thread pool. 


// thread_pool.h


class ThreadPool {


    friend class PooledThread;


    std::list<PooledThread*> threads;

    BJLEE::CCond threads_lock;


    // 128 is the max number of threads that this pool can hold :-P

    volatile int init_status[128];


    void initialized(int num) {

        init_status[num] = 1;

    }



public :


    ThreadPool() {}


    template <typename SUB>

    void init(int capacity) {


        for ( int i = 0; i < 128; ++i ) {

            init_status[i] = 0;     // not initialized

        }


        threads_lock.lock();

        for ( int i = 0; i < capacity; ++i ) {

            SUB* obj = new SUB(i);

            obj->start(this);


            threads.push_back( obj );

        }

        threads_lock.unlock();


    }


    template <typename SUB>

    SUB* get(void* context, void* data) {

        threads_lock.lock();

        while ( threads.empty() ) {

            threads_lock.timedwait(1000);

        }

        SUB* ret = dynamic_cast<SUB*>(threads.front());

        threads.pop_front();

        threads_lock.unlock();


        while ( init_status[ ret->get_id() ] == 0 ) {

            /* spin lock until the thread is in the initialized status */

        }


        ret->set_context( context );

        ret->set_data( data );

        return ret;

    }


    template<typename SUB>

    void back(SUB* obj) {

        threads_lock.lock();

        threads.push_back(obj);

        threads_lock.signal();

        threads_lock.unlock();

    }

};


Above is the implementation of ThreadPool class. It's so simple that I would not explain about it any further.


Below, I showed the test program (which shows you the use case of the ThreadPool class) for this implementation.


#include "pooled_thread.h"

#include "thread_pool.h"


class TT : public PooledThread {

public :


    TT(int id) : PooledThread(id) {}


    void process(void* ctx, void* data) {

        using namespace std;


        struct timeval now1, now2;


        gettimeofday(&now1, NULL);

        unsigned long now1m = now1.tv_sec * 1000000 + now1.tv_usec;


        int sum = 0;

        for ( int i = 0; i < 1000000; ++i ) {

            sum += i;

        }


        gettimeofday(&now2, NULL);

        unsigned long now2m = now2.tv_sec * 1000000 + now2.tv_usec;


        printf("elapse = %lu \n", now2m - now1m);

    }

};


int main()

try

{

    ThreadPool p;


    p.init<TT>(5);


    int num = 1000000;


    int data[num];

    for ( int i = 0; i < num; ++i ) {

        data[i] = i;

    }


    for ( int i = 0; i < num; ++i ) {

        TT* tt = p.get<TT>(0, &data[i]);

        tt->signal();

    }


    sleep(1);

}

catch ( BJLEE::CThreadEx& e )

{

    cout << e << endl;

}



저작자 표시 비영리 변경 금지

'Languages > C++' 카테고리의 다른 글

C++ Thread Pool  (1) 2012/09/25
valgrind, gprof를 사용한 프로파일링  (0) 2012/08/28
배열(array) 선언의 묘미  (0) 2012/06/12
MSVCP100D.dll  (0) 2011/02/17
[C/C++] 쓸만한 메모리 디버깅 툴이 없을 떄  (0) 2010/07/13
cgdb : 텍스트 기반의 gdb 인터페이스  (0) 2007/12/18
Posted by 이병준
TAG C++, pool, Thread

TRACKBACK http://www.buggymind.com/trackback/430 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 어린이들, 수원박물관에 푹 빠지다

    5월 5일(일), 제91회 어린이 날이다. 수원의 곳곳에서는 어린이날을 기념하는 많은 행사가 열렸다. 수원시 영통구 창룡대로(이의동) 265에
    [소셜미디어 위기관리] 채선당에서 남

    2013/05/06 17:38 [ ADDR : EDIT/ DEL : REPLY ]