#PARAN SILVERLIGHT#
  • Tistory
    • 관리자
    • 글쓰기
Carousel 01
Carousel 02
Previous Next

'Inforamtion Technology'에 해당되는 글 281건

  • 2017.08.30 팟캐스트 나는 프로그래머다 2탄
  • 2017.08.29 코딩의 기술
  • 2017.08.16 Polyglot programming
  • 2017.08.09 TDD process from Test Driven Development
  • 2017.05.25 Clean coder / Rober c. Martin
  • 2017.04.06 Art of Readable code - Ch1 코드는 이해하기 쉬워야 한다.
  • 2017.02.16 Background worker - Test project with WPF
  • 2015.07.14 C# Basic 다시 공부
  • 2014.11.25 MVC4 Could not load type 'System.ServiceModel.Activation.HttpModule'
  • 2014.02.21 Class Web system vs AJAX web system

팟캐스트 나는 프로그래머다 2탄

BOOKS 2017. 8. 30. 13:35
  • 1부 기술
    1. 컴퓨터 과학의 세계
      • 프로그래밍
        • 베어메탈 - 언어와 하드웨어 사이에 존재하는 소프트웨어 계층(ex JVM)이 따로 없이 언어에서 하드웨어를 직접 제어
        • 정적 언어 : 프로그램 내에서 타입이 제대로 사용되었는지 코드를 컴파일할 때 검사 / 자바나 C 
        • 동적 타입시스템을 사용하는 언어: 코드를 실제로 실행할 때 검사하면 / 루비나 파이썬
        • 강한 타입 시스템 : 프로그래머가 타입과 관련된 실수를 저질렀을 때 언어가 가차없이 에러를 발생
        • 약한 타입 시스템 : 언어가 알아서 타입 변환을 수행한다. 
      • 개발자와 컨퍼런스
        • 콘퍼런스에 참여하는 것은 동기부여라는 측면에서 엄청난 도움이 된다.
        • 열정 + 해당 기술과 관련된 실천과 고민 => 관심에 초점이 생긴다. 
        • 위에 것이 없다면 집에서 유투브 동영상을 보는 것이 낫다. 
        • 열정 => 예습 => 철판깔고 네트워킹 => 정리 => 발표
      • 좋은 프로그래머의 자질
        • 머릿속으로 궁리하기 / 코드가 전개되는 모습을 머릿속으로 정밀하게 궁리 , 바둑의 수를 계산
        • 빈틈없이 생각하기    / 깊은 추상, 명확한 개념, 반복된 훈련, 경험의 축적
        • 커뮤니케이션 능력    
          • 명확하지 않은 이야기에서 본질을 파악
          • 복잡한 놀리나 추상적인 개념을 상대방이 이해할 수 있게 설명
          • 타인의 감정을 이해하는 공감능력
        • 커뮤니케이션이 뛰어나면서 코딩을 못하는 사람은 본적이 없기도 하다. 
        • 독서를 통해 키울수 있다. 
    1. 풀스택 개발자의 꿈, Node.js
      • 스탠바이
        • Node.js의 엔진이 V8은 특성상 여러 스레드와 CPU를 같이 사용하지 못한다.
      • 치명적인 매력, 생산성
        • I/O가 큰 작업들, DBMS의 트랜잭션이 되게 긴 쿼리를 처리하는 경우에는 쥐약
        • 짦은 이벤트 단위로 많은 트레픽을 받는 서버의 경우에는 Node.js를 매력적으로 활용
        • 게임의 유저 상태를 업데이트하는 잛은 이벤트만 존재하는 경우에는 효과적으로 트래픽을 받을 수 있다.
      • Node.js와 RDBMS
        • 전통적인 데이터 베이스들은 다 트랜잭션 개념을 가지고 있다. 비동기가 될 수 없음. 그래서 Node.js와 맞지 않다.
        • 정말 데이타 무결성이 필요한 거면 Node.js를 안 쓰는 것이 맞을 것 같다. 
    2. 해킹에서 보안까지
      • 제로데이 취약점 시장
        • 제로데이 : 그 즉시 대응할 수 없는 보안 이슈 , 대중은 보안 패치가 완료될 떄까지 타경을 받는다. 
        • 많은 기업이 보안 문제를 해결학 위해 제보를 받고 상금을 지급하는 버그 바운티라는 제도를 운영한다.
    3. 데이타 과학 , 생활 데이타로 시작하라
      • 데이타 분석의 시작
        • 데이터에서 통찰로 이어지는 과정에서 필요한 것은 사소한 실천 , 그것 하나뿐이었다. 사소하게 데이타를 모으는 작업 
      • 빅데이터와 스몰데이타
        • 자기도 정확하게 이해한 것이 아니면서 함부로 어려운 용어를 들먹이면서 함수 언어에 대한 진입장벽을 세우지 마라
      • 데이타 과학
        • 통계를 좀 알아야하고, 프로그래밍도 좀 알아야하고
        • 그렇게 될 때까지 그렇게 된 것처럼 행동하라, Fake it till you make it
      • 머신 러닝
        • 약빤 알고리즘 , 머신 러닝 알고리즘은 동적이고, 피드백을 받으며 개선되어 나간다.
        • 개발자도 머신러닝 알고리즘을 자연스럽게 활용하는 시대가 아니 활용해야만 하는 시대가 무서운 속도로 다가오고 있다.
    4. 빅데이터와 인공지능 연구의 꽃 , 자연어처리
      • NLP(Natural Language Process) 는 빅데이터와 머신러닝을 모두 아우르는 인공지능 분야의 꽃
      • NLP의 관건은 보유하고 있는 데이타 양
        • 누가 얼마나 더 많은 데이타를 보유하고 있느냐가 NLP 연구에 있어서 승부의 열쇠
        • 구글은 웹 전체에서 수집된 결과를 알고리즘을 통해 점수를 부여하고 , 이를 바탕으로 사용자들에게 노출
        • 네이버는 기본적으로 자사의 포탈 내부의 데이터를 우선적으로 노축시키는 정책
    5. 알고리즘, 개발자의 자기계발 전략
      • 알고스팟
        • 게일 라크만 멕도웰 - Cracking the coding interview 
        • 들어가기 어려운 회사 일수록 철저하게 문제풀이 능력을 평가하는 질문으로, 알고리즘은 문제풀이 능력이다.
        • 문제 풀이 능력을 평상시에 취미처럼 기르는 사람들은 모든 회사의 문을 마음대로 열어젖힐 수 있는 황금열쇠를 손에 쥐다. 
        • 즐거움을 추구하는 것이 목적이다. 놀이가 일이 되는 순간 지구력도 사라진다.
      • 한국과 미국의 첨단 기술 스택
        • 기술 스택 전체를 구성하는 윤관을 이해하는 것이 그 안에 담긴 제품 하나하나에 대해서 아는 것보다 더 중요하다. 
        • 커다란 아키텍처의 윤곽과 코드베이스 내부에 있는 알고리즘의 미세한 흐름을 동시에 이해하고 다룰 수 있어야 한다. 
        • 미세한 코딩만 고집하고 큰 그림을 이해하지 않으려는 개발자는 성장할 수 없고 
        • 코딩의 미세한 감각을 상실한 채 거대한 그림만 상상하는 사람은 입개발로 빠질 수밖에 없다. 
      • 개발자와 알고리즘
        • 알고리즘 대회에서 푸는 문제들과 현실적인 개발셰게에서 마주치는 문제는 완벽하게 직접적인 상관은 없지만 , 분명히 현실 세계에서도 도움이 된다. 
        • 알고리즘 : 수학적인 문제를 해결하거나 컴퓨터 프로세스를 완결하기 위해서 차례로 뒤따르는 단계으 집합
        • 미국의 IT회사들은 특정 기술에 정통한 사람을 찾지 않는다. 기본적인 능력, 즉 문제를 해결하는 알고리즘을 능력을 갖춘 상태에서 새로운 기술을 빠르게 습득할 숭 ㅣㅆ는 사람을 찾는다. 
      • 손코딩 , 뇌컴파일, 눈 디버깅
        • 고수는 생각한 다음 코딩을 하고 하수는 코딩을 한 다음 생각은 한다. 
        • 현대 소프트웨어 프로젝트는 당현히 팀 스포츠다
        • 마음을 확짝열고 자기 실력을 인정하고 타인을 존경하고, 배우려고 노력하고, 질문하거나 도움을 청하는 것을 부끄러워하지 않는 B팀은 어느 정도 시간이 지나면 A급들이 존경해 마지 않는 A급 개발자의 일원이 되어 있다. 
      • 알고리즘 문제
        • 미국에서 개발자가 회사를 옮겨다니려면 트리플릿 정도의 문제는 해결할 힘이 있어야 한다. N제곱 해가 떠오르지 않아도 해결책을 향해서 조금씩 다가가는 모습만 보여워도 충분하다. 그리고 그 아이디어를 코드로 적을 수 있으면 좋다. 
        • 문제를 잘 풀기 위한 방법은 매일 조금씩 훈련하고 공부가 아니라 놀이라 생각하는 것

  • 2부 커리어
    1. 글로벌 기업 코딩 인터뷰
      • 무언가 아웃풋을 내라
        • 시간 복잡도라 공간 복잡도에 대한 개념이 기본적으로 같이 제시 .좀 더 적은 메모리와 좀 더 적은 시간으로 동일한 시간으로 해결할 수 있겠는가?  일단 동작하는 어떤 아웃풋을 내는 것도 굉장히 중요하다. 
      • 코딩 인터뷰 패턴 이해하기
        • 코딩은 뒷전이고 계속 회의실에서 뜬 구름 잡는 친구들이 잘하는 경우가 맞죠. 정확하게 이해를 하고 설계하면 코딩을 그냥 설계를 코드로 옮기는 작업에 불과하니까 일을 더 잘하게 되는 거죠. 어떻게 이런 설계 실력을 쌓을 수 있는가?  코딩 리뷰, 코딩 인터뷰 책을 보라. 탑코더 사이트. 
      • 인터뷰에 영향을 미치는 + 알파
        • 채용을 핸던 사람들의 공통점은 문제를 주면 해결을 한다는 것. 우아한 방식으로 답을 주는 사람이 매력있다. ^^
        • 똑같은 실력이면 더 호감이 가는 사람, 좀 더 열정적이 사람에게 마음이간다. 
        • 공학이라는 것은 현실의 문제를 푸는 것이기 때문에 트레이드 오프를 보는 게 굉장히 중요. 솔루션에 여러 가지 옵션이 있을 텐데, 각각의 옵션에 장단점을 분석하고, 현재 주어진 요구사행에서 제일 좋은 옵션들을 선택하는 과정을 보여주는 것
        • 인터뷰여하고 마치 토론식으로 내가 지금 짜는 코드는 앞으로 이런 이유 댸문에 이러게 짜려고 하고, 이런 로직으로 짜려고 한다고 하면서 풀어가자. 
        • 코딩 인터뷰는 단순히 기술 실력만이 아니라, 문제를 풀어가는 전체적인 과정을 본다 => 커뮤니케이션 스킬을 본다.
        • 코딩 인터뷰는 2~3개월 전부터 대비
    1. 삶의 선택지, 해외 취업
      • 일주일에 최소 한,두번은 자택 근무를 한다. 
      • 아이들이 커가는 시간을 함꼐 할 수 있다는 것. 한국에서는 일을 위해서 가정을 포기하는 것이 너무 당연시 되고 있다.
      • 미국의 경우는 일정보다는 품질이 우선시 됩니다.
      • 좋은 석사보다는 이수하기 쉬운 석사학위를 찾는 것이 한가지 포인트 이수하면서 직장을 구할 수 있다.

    2. 디지털 노마드로 사는 법

  • 3부 삶
    1. 어린이 소프트웨어 교육의 방향성
    2. PC방 알바에서 구글 개발자로
      • 그릇이 큰 사람은 자기 눈에 보이지 않을지라도 궁극의 실력을 갖춘 사람들, 즉 창조하는 사람을 마음에 담는다. 상상 속에서 그들에게 묻고, 대화하고, 실력을 엿보면서 자기 노력의 자양분으로 삼는다. 그들에게 건강한 열등감을 느끼면서 자기 자신을 행한 채찍질을 멈추지 않는다. 
      • 수많은 기술고 언어가 눈앞에 왔다 갔다 하지만 그런 것들의 껍질을 벗겨내고 속에 있는 본질을 모려고 노력해야 합니다. 
    3. SI가 살맛나는 세상을 위하여


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

코딩의 기술

BOOKS 2017. 8. 29. 15:03

1. 읽기 좋은 코드를 작성하는 기술

    • 결정문의 사용해서 If 문을 제거 /  예상 값을 배열에 9까지 경우의 수로 저장해서 해결 . 재미 있네. 

enum Hand {

Rock = 0,

Scissors = 1,

Paper =  2

};


enum Result {

Win,

Lose,

Draw

};


Result judgement(Hand my, Hand target){

if (my ==target) return Draw:

if (my == Rock && target == Scissors) return Win ; 

if (my == Scissors && target == Paper) return Win ; 

if (my == Paper && target == Rock) return Win ; 

return Lose;

}


Result judgment(Hand my, Hand target){


static const Result result[3][3] = {

//바위 , 가위 보 (상대방)

{Draw, Win, Lose }. // 바위(자신)

{Lose, Draw, Win }, // 가위

{Win, Lose, Draw }  // 보 

};

return result[my][target];

}


2. 간단한 설계를 위한 원칙과 패턴

    • 직접하지 말고 명령하라. /위임하라. 
    • 상속보다는 이양을 사용 / Template pattern => Strategy pattern

// 상속으로 설계 

Class Robot {

public update(){}

public move(){}

}


Class CleanRobot : public Robot{

virtual void move() override {}

}

Class CombatRobot : public Robot{

virtual void move() override {}

}



// 위양으로 설계

Class Robot {

RoboBehavior* behavior_;


// Creator

Robot(RobotBehavior* behavior) :

behavior_ (behavior} {}


void update()

{

behavior_->move();

}

}


// Robot Behavior interface , Strategy pattern

Class RobotBehavior {

virtual void move()

};


class CleanerBehavior : public RobotBehavior {

virtual void move() override{

//clean

}

}


class CombatBehavior : public RobotBehavior {

virtual void move() override{

//battle

}

}


// Create Instance

Robot cleanerRobot(new CleanerBehavior());

Robot combatRobot(new CombatBehaviro());


    • 상속 관계는 '컴파일할 때 결함' 합니다. 실행 중에는 구현 객체를 변경하지 못한다. 
    • 이양을 사용하면 실행 중에도 구현 객체를 변경할 수 있다. 
 //Change behavior
ClearnerRobot.changeBehavior(new combatBehavior());

  • 다른 유형의 로봇클래스를 만들고 싶을 때로 행동과 관련한 플래스를 재사용할 수 있다.
// create super robot and reuse behaviro
SuperRobot superRobot(new combatBehavior());
 
    • 상속은 부모 클래스로부터 '기능상혹'을 의미하지만 , 추상 인터페이스는 '역할 구현'을 의미한다. 


3. 객체 지향 설계의 원칙

    1. 단일 책임의 원칙(SRT, Single Responsibility Principle)  - 클래스를 변경해야 되는 이유는 한가지
    2. 개방. 폐쇠의 원칙(OCP, Open-closed principle) - 확장에 관해서는 열려있고, 변경에 대해서 닫여있다.
    3. 리스코프 치환 원칙 (LSB, Liskov Substitution Principle) - 부모를 클래스로 치환한 상태에서도 정상 작동해야 한다. 
    4. 인터페이스 분리 원칙(ISP , Interface Segregation Principle) - 클래스의 사용자에게 불필요한 인터페이스는 공개하지 말라
    5. 의존 관계 역전 원칙(DIP, Dependency Inversion Principle) - 상위 모듈은 하위 모듈에 의존하지 않는다.
    6. 데메티르 법직 - 직접적인 친구(자기자신, 자신이 가지는 클래스 , 매개변 수로 전달한 클래스)와만 관련한다. 
      • Singleton pattern을 사용하면 이 법칙을 위반한다. => Logger 같은 클래스는 이법칙의 예외일 것 같은데. 이 법칙은 참고로만.


  • 디자인 패턴
    • State pattern과 Strategy pattern은 구현방법이 거의 비슷하지만, 사용하는 상황이 다르므로 구분해서 사용한다. Gog의 디자인 패턴은 구현 방법으로 패펀을 구분해놓은 것이 아니다. 
  • 생성자를 완전한 상태 만들기
    • 호출된 시점에 완전한 상태 , 별도의 초기화 함수를 호출하거나 Setter를 사용해서 설정해야 작동하는 클래스는 주의
    • 어떤 순서로 맴버 함수를 호출해도 문제없이 작동하게 한다. 호출 순서에 제한이 있는 클래슨 사용자에게 부담, 그리고 버그의 원인
  • 멤버 함수 호출 수서와 관련한 대처 방법
    • 상속을 사용한 예 (Template Method pattern)
Class Game {
void run() {
initialize();
while (isRunning()) {
udate();
draw();
}
finalzie();
}

virtual void initialize();
virtual bool isRunning();
virtual void update();
virtual void draw();
virtual void finalize();
};
    • 이양을 사용한 예(Strategy pattern)

Class Game {
virtual void initialize();
virtual bool isRunning();
virtual void update();
virtual void draw();
virtual void finalize();
};

Class GameRunner{

Game* game_;
GameRunner(Game* game) : game_(game) {
}

void run(){
game->initialize();
while(game_->isRunning()){
game_->update();
game_->draw();
}
game_->finalize();
}
}

  • 결합을 생각
    • 결합의 좋고 나쁨은 해당 클래스의 단위 테스트가 얼마나 간단할지 생각해보면 쉽게 판다. 
    • 테스트가 어려운 클래스는 독립성이 낮고, 부적절한 결합 상태일 가능성이 크다. 
    • 부적절한 결합이 발견되었다면 , 추상 인터페이스를 추가함으로써 직접적인 결합 관계를 끊어버린다. 
  • 코드의 수명
    • 재사용할 가치가 있는 부분은 시간을 들여 설계, 코드를 재사용할 수 있게 설계하는 것은 상당한 시간과 노력이 필요. 
    • 항상 비용대비 효율성을 고민
  • 작업의 편의성
    • 코드의 단순함 보다는 작업의 편의성/ 쉽게 공동 작업을 할 수 있는 설계를 하고, 변경 또는 수정할 때 실수가 발생하지 않도록 설계
  • 하나의 방법에 대한 집착
    • 객체 지향을 사용하는 것이 항상 좋은 선택은 아님, 특징에 맞는 프로그래밍 언어와 개발환경을 선택 => 함수형 프로그래밍 등등
    • 여러 언어를 조합하는 경우도 많음 , 목적을 달성하기 위해 가장 효율적인 방버이 무엇일까?를 생각
  • 최소한의 코드만 작성
    • 어떻게 코드를 작성할지가 아니라 => 어떻게 하면 코드를 작성하지 않을까가 중요 / 부수코드를 만들지 말자.. 
  • 원칙과 패턴에 너무 얽매이자 보면 이상한 집착이 생겨서 단순한 코드도 복잡하게 만드는 경향이 있다. 
  • 원칙을 사용한 경유와 사용하지 않을 경우, 클래스를 분할하는 경우와 분할하지 않은 경우 중에 단순한 쪽을 선택
  • 고수일수록 , 좋은 의미의 편법을 잘 활용한다. 쉽게 복잡해지는 부분, 미래에 변경될 수 있는 부분은 시간을 두고 설계하지만 , 변경 가능성이 작은 부분 등은 시간을 들이지 않고 간단하게 끝내버린다. 


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Polyglot programming

BOOKS 2017. 8. 16. 17:34
  • 프롤로그
    • Boilerplate code(행사코드) : 해결하고자 하는 문제의 해결책과 상관이 없는 코드, Ceremony 라고 앤더슨 하일스버그가 표현. 
    • 모든 언어의 '발전'은 추상수준을 상승시켜서 프로그래머가 작성해야 하는 행사코드의 분량을 줄이는 방향으로 움직인다.    =>Infra쪽에서 같은 방향으로 ?  AWS에서 infra service를 제공하며 개발자에게 Business에 더 집중하라는 것과 같은 맥락인가. 
    • 자바가 전성기를 구가하고 있다고 여기는 사람은 이제 없다. 자바는 더이상 핫하지 않다. 
    • 프로그래머가 어떤 언어에 대해서 얼마나 많이 알고 있는가 하는 것이 아니라 어떤 언어를 얼마나 빠르게 학습할 수 있는가 하는 것이 더 중요하다.  => 그러면 그 언어가 왜 만들어졌으며 특성을 이해하고 사용하는 것도 중요하겠지. 
    • c#과 파이썬을 능숙하게 다룰 수 있다면 그의 폴리글랏 등급은 비로소 '상급' 수준이다. => 이렇게 공부하고 있다. ^^
    • 함수형 언어는 변수가 야기하는 부수 효과를 제거하기 때문에 멀티쓰레드 코드를 작성하는 것이 더 용이하다.                        => 함수형 프로그래밍은 개발자가 병렬처리를 하는 코드를 작성하기보다 실행환경에 병렬처리를 하도록 프로그래밍하므로 

  • 자바
  • 자바를 넘어서    
    • 자바에 비해서 더 동적 언어들은 AOP나 의존성 주입 패턴을 거의 사용하지 않는다. 이것은 자바에서는 매우 중요한 문제를 해결할 때 사용되지만 , 동적언어들은 자바가 프로그래머에게 강제하는 고통을 요구하지 않는다. => 동적언어를 배우자
    • 동적 프로그래밍의 단점은 코드를 작성하는 동안에 컴파일러의 도움을 얻을 수 없다. 실행하는 동안에 더 많은 버그를 만날 수밖에 없음 => 그러므로 TDD 기반의 프로그래밍이 더 요구되는 것 아닐까?  /  
    • 다른 단점은 매서드의 목록이 자동적으로 나타나는 intellisence 기능도 쓸 수없고 리펙토링과 관련한 기능도 거의 사용할 수없다.  루비와 같은 동적 언어를 이용해서 엔터프라이즈 수준의 프로젝트를 진행해본 사람이라면 동적 프로그래밍언어의 한계를 알 것이다. 
    • 동적 프로그래밍 언어가 정적프로그래밍 언어에 비해서 생산성이 높다는 주장은 비교적 규모가 작은 프로젝트에서는 사실일 가능성이 높지만 , 규모가 큰 프로젝트에서는 반드시 사실이라고 말히기 어렵다.

 

  • 람다와 클로저
    • 자신을 둘러싸고 있는 외부의 코드에서 선언한 변수를 마음대로 접근할 수 있는 코드
    • 익명 클래스가 바로 클로저는 아니다. 외부에서 선언한 자유변수가 필요하다. 
    • 익명클래스의 내용 혹은 ActionPerformed 메서드 내부 코드가 Foo()가 실행될 때 곧바로 실행되는 것이 아니라 , 사용자가 버튼을 누를 때 실행. 이벤트 발생 시점에 실행 , 게으른 행동 , Lazy
    • 자바는 외부 변수에 final n = 1 이라고 선언하여 /  n은 변경 가능한 자유변수가 아니다. / 클로저를 제대로 지원하는 C#과 루비는 변경 가능하다. 그러므로 람다를 이용한 간결하고 풍부한 표현이 가능하다. 
    • 람다는 익명클래스보다 더 간단하고 범위가 작은 익명 메서드라고 말할 수 있다. 
    • 람다는 코드조각 혹은 표현을 다른 겍체나 메서드에 전달하기 위한 표현식 /  ( ) -> system.out.printLn("Clicked!)
    • 클로저는 외부에서 정의된 변수를 참조하는 코드조각 혹은 표현을 의미한다. ( ) -> system.out.printLn("Clicked! n = " + n) //n은 외부에서 정의
    • 변경 불가능성에 대한 5가지 규칙 / 멀티쓰레딩 환경에서 동시성 문제를 발생시키지 않고 안전하게 사용
      1. 객체의 상태를 변경시키는 메서드를 제공하지 마라
      2. 클래스가 상속되지 못하도록 final 로 만들어라
      3. 모든 필드를 final로 선언하라
      4. 모든 필드를 private로 선언하라
      5. 변경불가능성을 만족시키지 못하는 컴포넌트에 대한 접근을 통제하라.
    • 상위 수준의 언어가 성취하는 것은 무엇인가?  그것은 비본질적인 복잡성으로부터 프로그램을 자유롭게 만드는 것이다.  쉽게 말하면 프로그래머는 시시콜콜하고 세세한 대상을 반복해서 다루는 대신, 더 크고 개략적인 추상적인 개념을 가지고 주어진 문제를 해결하는데 집중해야 한다는 말이다. 

 

  • 연산자 오버로딩
    • 새로운 언어의 배경이 되는 언어는 행사코드가 범람하게 되면서 생산성이 점점 낮아진다. 새로 탄생하는 언어는 배경이 되는 언어의 추상수준을 한 단계 상승시킨 모습으로 새롭게 담장을 하고 나타나서 새 시대의 출발을 선언한다. 
    • 좋은 프로그래머는 다른 사람이 사용할 수 있는 어휘를 늘려 나간다. 다시 말해서 그들은 자기도 모르는 사이에 언어를 설계하는 것이다. 언어의 설계를 처음부터 시작하는 것은 아니지만 기초가 되는 언어의 프레임 안에서 새로운 언어를 만들어 나간다. 
    • 성장이 가능한 언어를 만드는 것이다. 
    • 자바는 연산사자 오버로딩 기능을 지원하지 않는 유일한 언어

  • 제네릭
    • 제네릭이라는 기능을 정확하게 사용하지 못하거나 남용하는 프로그래머를 보면 사용하지 말라고 권한다. 스타일은 조금 떨어져도 정확한 코드를 작성하는 것이 언제나 우선이다.
    • 어떤 타입 S(Number)와 T(Integer)사이에 상위클래스-하위클래스 관계가 있다고 해서 Collection<S> , Collection <T>라는 서로 다른 타입 사이에서도 똑같은 관계가 자동적으로 성립하지 않는다. 하지만 프로그래밍 언어가 일정한 노력을 기울려서 성립하도록 만들어 줄수 있다. 성립하면 공변을 지원한다고 하는 것이다. 
    • 자바는 배열은 공변이지만 제네릭에서는 공변이 성립하지 않는다. 
      • case 1 . boolean addAll(Colleciton<? extend Number> c)  / extend를 사용해서 트릭사용
      • case 2 . boolean addall(Collection<Number> c)  /  numbers.addAll(integers) comfile Error
    • 반공변 : List<Number>가 기대되는 자리에 list<Integer>를 집어넣을 수 있는 경우 , 다시 말해 List<하위타입>이 기대되는 자리에 List<상위타입>을 집어 넣는 것이다. 
    • C#의 제네릭은 자바의 제네릭에 비해서 실행시간 성능이 좋다는 이점과 , 코드를 더 간결하게 작성할 수 있다는 장점

Public void Add<E>(E fruit)
{
if (fruit.GetType() == typeof(Apple))
Console.Out.WriteLine("I got an apple");
else if (fruit.GetType() == typeof(List<Apple>)) 자바로 작성시 에러 / 아래 코드로 작성
Console.Out.WriteLine("I got a list of apples")

else if (fruit.GetType() == typeof(List<?>))  // 타입 검사 기능을 하지 못함/ 배나 귤을 넣어도 apple을 출력 @.@
Console.Out.WriteLine("I got a list of apples")
}

    • 람다는 C# 1.0 시절에 이미 대리자(delegate) 형태로 , C# 3.0에서는 깔끔한 람다 형태로 지원되어 왔다. 
    • 크로스 커팅 : 어떤 기능이 애플리케이션 전체에 걸처서 고루 작용한다는 뜻 , 예를 들어 로깅 메시지 지원
    • C#과 같은 언어에서 클로저가 변경가능한 mutable 값을 참조하기 때문에 일어나는 골치 아픈 문제.
    • 아래 링크에 자세한 설명
    • https://yuddomack.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%81%B4%EB%A1%9C%EC%A0%80Closure
     List<Action> actions = new List,Action>();
for(int i = 0; i < 10 ; i++)
{
actions.Add( () => Console.WriteLine(i)  );  //  클로저, i라는 자유 변수를 참조
}
for each (Action action in actions) action();

결과는 모두 10을 출력한다.  for 문이 끝난 후에 지역 변수 i는 사라져야 하지만 closure에서는 자유변수 i는 10으로 값을 유지 한다. 

for(int i = 0; i < 10 ; i++)
{
int temp_var = i; // Loop의 내부에 변수를 선언해서 클로저에 넘기면 
actions.Add( () => Console.WriteLine(temp_var)  ); 
}

for each (Action action in actions) action();

 결과는 1,2,3,.....10을 출력한다. for문이 끝난 후에 자유변수 temp_var을 각각 1,2,3...10으로 closure안에 유지되어 있는 것으로 생각된다. 
  • C#
  • 델파이 
    • 델파이와 C#를 만든 사람이 같다. 닉켈스 워스(Nickel's worth) / 닉 라우스 비어트
    • 어떤 표현의 대한 실행 혹은 평가를 미래의 어느 시점으로 연기하는 방식으로 전달하는 것이 바로 Call by Name
    • 이름에 의한 전달은 람다를 통해서 할 수 있는 여러가지 유용한 작업의 하나이다.

  • 속성과 대리자
          Java & C#
public class Person {
private String name;
public String getName() { return name; }
public void setName(String name) { thi.name = name; }
}

person.name 
person.name = "Obama" // 이렇게 쓰고 싶으면 name을 public으로 정의해야 함 => 객체지향 캡슐와를 반하는 Antipattern

-----------------------------------------------------------------------------------------------------------------------------------------------------
           C# 1.0 
public class Person {
private String name ; {
public String Name
get { return name; }
set { name = value; }
}
}

C# 3.0 
public class Person {
public String Name { get ; set ; }
}

person.name = "Obama" 으로 캡슐화를 위반하지 않고 사용할 수 있다. 맞아??? 

책이 이상한 듯 아니면 내가 이해를 못했다.  위와 같이 하면 외부에서 변경이 가능하다. 캡슐화 위반
아래와 같이 private 키워드를 붙여야 캡슐화가 가능하다. 하지만 person.name = "Obama"는 내부에서만 사용가능 

public class PersonA
{
    private String name; 
    public String Name
    {
        get { return name; }
        private set {  name = value; }
    }
}

public class Person
{
     public string Name { get; private set; }
}


  • 일급함수
    • 고계함수 : 어떤 함수에게 함수를 인수로 전달한다고 했을 때, 다른 함수를 인수로 받아들이는 함수 , Higher-order 
ex ) 1,2,3,4,5 를 입력하면101, 102 ~105를 출력하는 함수를 작성

- Java - 명령형의 코드
Collection<Integer> input = Arrary.asList(1,2,3,4,5);
List<Integer> output = new ArryList,Integer>();
for (int n : input) {
output.add(n + 100) ;
}
system.out.printLn(output);

- C#  - 선언적 코드 
var input = Enumarable.Range(1,5);
var output = input.Select(i => i + 100); // Select는 i => i + 100을 받아들이는 고계함수

    • 명령적 접근과 선언적 접근이 갖는 차이는 엄청나다. 만약 위의 예에서 5천만 개의 정수를 처리한다고 하자. 그럼 병렬젹으로 처리하기 알맞다.
      • 명령형으로 작성한 코드에서는 병졀적 처리 과정을 프로그래머 자신이 직접 구현해야 한다.
      • 그러한 동시성 코드를 아무런 버그가 없이 작성하는 것이 어렵고, 멀티코어를 최대한 효율적으로 사용하는 코드를 작성하기도 쉽지 않다. 하지만 이러한 코드가 고계함수를 이용해서 작성되었다면 JVM이나 CLR과 같은 실형환경 자체가 병렬적 처리를 구현하기에 더 용이하다. C#에서는 PLINQ이름으로 구현되어 있다. 
    • 부수효과 
public inf f(int n)
{        return n + 1; }

f 함수를 여러번 call을 해도 언제나 항상 리턴 값은 n + 1로 동일하다.  부수효과가 없다.

public inf g(Person p)
{
p.Age += 1;
return p.Age;
}

g함수를 여러번 call하면 1, 2, 3 함수를 호출할 때마다 값이 1씩 증가한다. 부수요과가 있다. 
        • 함수형 프로그래밍 패러다임은 함수와 값의 등가성이라는 물리학 법칙을 기초로 해서 g와 같은 함수는 토대가 무너진다. 
        • cf) 데이타 베이스 접근, 네트워크 통신, 메모리값 변경, GUI 화면의 출력, 로그 파일 등은   함수형 프로그래밍 관점에서는 부수효과지만 프로그래밍에서 필요하다. 
        • 부수효과가 발생하는 매서드를 작성한 코드는 버그가 숨어서 살아갈 수 있는 음습한 그늘을 제공하기 때문에 나쁘다.
        • 부수효과가 없는 프로그래밍, 변경불가능성(Immutable)을 최대한 활용한 프로그래밍을 가능하게 한다. 
        • 람다표현에서 부수효과를 갖는 코드를 작성하는 사람은 람다를 사용하는 이유를 제대로 이해하지 못한 사람일 가능성

  • 또다른 차이점
    • Try-finally와 try-catch가 거의 10대 1의 비율로 사용되어야 한다. 
    • 예외를 다루는 장소는 하나의 장소로 집중되어야 한다. 프로그램 안에 있는 100갸의 장소에서 가각 저마다의 예외를 다루면서 화면에 에러창을 나타낸다고 생각해봅시다. 만약 에러창을 구성하는 방식을 다르게 만들기로 결정했다면 정말 끔찍하다. 
Public void a() {
try {
b();
} catch (Exeception ex) {
//handle exception
}
}

Public void b() {
try {
c();
} finally {
// clean resource
}
}

Public void c() {
try {
//work
} finally {
// clean resource
}
}
    • 하일스 버그는 대부분의 코드는 finally를 이용해서 스스로를 보호하고, 콜스택의 최상위 부분에서 예외를 잡아서 처리하면 충분하다고 주장한다. 
    • 하지만 고스링은 보수적이고 신중한 곳, 프로그램의 실패를 대단히 심각하게 여기는 곳에서는 많은 곳에서 예외를 발생시켜 소프트웨어의 실패를 최대한 빠르게 다루어야 한다는 주장을 한다. 이것도 맞는 이야기 같다. 

  • LINQ
    • 데이타를 읽는 질의문query을 전보다 선언적인 방식으로 작성하는 것을 가능
    • 서로 다른 도메인의 데이터를 애플리케이션 내부에서 일관성 있는 방식으로 접근할 수 있도록 해주는 것은 상당히 의미가 있다.
    • 마치 프로그래밍 언어와 데이터베이스를 통합시켜주는 성배와 같다. 
    • 타입유추 : 컴파일러가 스스로 타입을 유추할 수 있는 장소에서는 프로그래머가 구태여 타입 정보를 써넣지 않아도 되도록 만듬
      • IEnumerable<int> range = Enumerable.Range(1,2,3,4,5); => var range = Enumerable.Range(1,2,3,4,5);
      • 웨그너 , 변수의 구체적인 타입을 알 필요가 없는 곳이라면 가독성과 상관없이 최대한 var 키워드를 사용하는 편이 낮다.
      • 프로그래밍 언어의 전체적인 방향은 타입유추를 최대한 활용해서 소스코드에 등장하는 타입 정보를 최소화 하는 방향으로
      • C, C++, JAVA, C#과 같은 언어는 정적타이핑 시스템 사용, 루비 , 파이썬, 자바스크립트는 동적 타이핑 시스템을 사용

    • Collection 의 메서드를 람다표현 식으로 구현 후 더하는 일은 C# 확장 메서드를 사용해서 해결 
      • <T> 인터페이스만 있으면 람다를 이요하는 링큐의 메[서드를 모두 마음껏 이용할 수 있다. 

public static void Foo( This IEnumerable<T> source, int n ) 

{ 

Console.Out.Writeline("Foo number = " + n );

 }


IEnumerable<int> list = new List<int>();

list.Foo(3); 

    • Function과 Method 동일한 개념이 아니다. 함수는 ' 일급'으로서 독자적으로 존재하는 코드, 메서드를 객체에 소속된 속성을 의미
    • C#같은 객체지향 언어는 순수한 의미에서의 함수를 가지고 있지 않으며 그들은 모두 객체에 소속된 메서드다. 

  • 스칼라
    • 가디언
      • 가디어 신문사는 스칼라와 플레이를 사용해서 대단히 성공적이 프로젝트를 진행
      • 스칼라 코드는 대단히 안정적인 자바 가상 기계에서 작동하는 자바 바이트코드로 컴파일되고, JVM의 튼튼한 저스트-인-차임 컴파일, 가비지 컬렉션, 그리고 널리 이용되는 전개테크닉을 그대로 활용한다.
      • 스칼라 개발자를 찾으려고 하지 않았다. 그저 뭔가 새로운 것, 자신의 경력에 도움이 되는 새로운 무어을 배우려는 열망이 가득한 열린 마음을 가진 개발자를 찾으려고 했다.
      • '동시성' 프로그래밍 혹은 '병렬' 프로그래밍은 누구도 피할 수 없는 시대적 화두과 되었다. 여기서는 단순히 Lock이나 Synchronized를 둘러싼 API를 향상시키는 정도의 노력으로 해결할 수준이 아니나 새로운 패러다임을 요구
      • 멀티코어, 빅테이터, 분산처리라는 화두는 기존의 객체지향 기법만으로는 해결하기 어려운 새로운 문제에 해당한다. 이 문제는 함수형 프로그래밍이라는 새로운 패러다임의 등장을 요구했다. 
    • 제임스 스트라칸 2009년 7월 6일 월요일
      • 그루비를 개발한 스트라칸은 내가 스칼리를 보았더라면 그루비를 개발하지 않았을 것이다라고 말함
      • 멀티코어 프로세서를 대상으로 하는 프로그래밍이다. 그것은 정적인 타이핑을 사용하는 것이다. 그냥 파이썬, 루비, 그루지 책을 버려라. 자기 몸을 완전히 동적 프로그래밍 전영에 맡기고 있는 사라미 있으면, 다시 생각하기를 바란다. 
    • 트위터
      • 링크드인이 그루비를 이용했다. 트위터가 스칼라 언어를 이용해서 개발되었다.
      • 엉터리 일을 하면서 CPU만 뜨겁게 달구는 일이 없도록 실행 전에 미리컴파일이 되는 언어(정적언어)를 원했다. 스칼라
      • 액터 : 큐 시스템을 이용하는 것과 같다. 
    • 마틴 오더스키
      • 성급한 최적화는 모든 악의 근원이다 . 소프트웨어를 구현할 때 , 사용자가 필요호 하는 기능을 구현하는 데 집중하지 않고 처음부터 소프트웨어 성능을 최적화하기 위해서 서두르는 것은 겨로가적으로 엉터리 코드를 양산할 가능성이 크다는 사실 경고
      • 프로그래머는 설계를 하면서 코드의 얼개를 작성하고 , 필요한 내용을 구현하며 살을 채워가고, 유닛테스트 코드를 통해서 그때그때 논리적 완결성을 증명하고, 필요하면 설계 자체를 수정하고, 그에 따르는 리펙토링을 수행한다. 이러한 사이클을 통해서 반복하면서 완성도가 점진적으로 높아지는 코드를 만든다.  
      • 객체 지향 패러다임을 구성하는 요소가 상속, 폴리모피즘, 캡슐화 
      • 함수형 프로그래밍 패러다임 구성하는 요소는 변경불가능성, 일급함수, 람다와 클로저, 고차함수, 재귀, 게으른 평가, 함수 합성, 모나드. => 코드의 간결함, 추상이다. 
      • 진짜 추상은 프로그래머가 주어진 문제를 해결하기 위해서 '사고를 하는 방식' 자체에 영향을 준다. 
         for (int index = 0; index < 10 ; index++)  => for (Person p : persons) 와 같이 
문법적 추상은 명령형 패러다임이라는 추상의 수준에서 벗어날 것은 아니다.
      • 껍데기 추상 : 인터페이스(구현을 생략한 껍데기) , 람다 , 고계함수 , 전략패턴, 제네릭 등 
      • 커튼 추상 : 언어 자체의 문법이 아니라 라이브러리나 프레임워크를 이요행서 반복된 표현을 하지 않아도 되는 것
        • Java 쓰레드 :  Runnable, Callable interface를 이용해서 구체적인 업무(TASK) 정의한 다음 실행자(Executor)에게 제출, 쓰레드를 생성하고 소멸시키는 지질구레한 일은 집주인이 고용한 실행자들이 우리 눈에 보이지 않는 곳에서 해결. 
      • 지금까지의 멀티쓰레딩 프로그래밍이 '동시성'(Concurrently)을 대상으로 했다면 => Batch 수량이 감소하는 것 동시에 UI에 표현오늘날의 멀티쓰레딩은 '병렬성'(In parallel)을 대상으로 하게 되었다. => 데이타 처리를 병렬로 빠르게처리 
      • 동시성 : 표면적으로는 같은 시간대에 일어나지만 일 사이에서 문맥교환 Context switch가 분주하게 일어나는 것
      • 병렬성 : 사람의 몸이 복제되어 물리적으로 두 사람이 존재. 두 가지 일은 서로에게 영향을 주지 않으면서, 즉 문맥교환을 수행할 필요가 없는 상태에서 문자 그대로 한번에 일어날 수 있는 일
      • 2000년대 중반, CPU는 1, 2개 / 쓰레드를 이용한 동시성 코드를 작성하는 것은 CPU를 공유한다는 것, 문맥교환을 피할수 없음
      • 현재 16, 32 코어의 데스크탑 PC or 분산환경 시스템/  프로그래머가 늘러난 CPU를 모두사용하는  병렬처리 프로그램 개발은 불가능하다. 그러므로 커튼을 치자.  환경이 커튼 안에서 복작성을 다루는 동안 우리는 커튼 빡에서 단순함을 즐기면 된다. 
      • 하지만 개선된 API와 라이브러기를 컴포넌트 사용하는 것으로는 우리가  가진 문제를 모두 해결할 수 없다. 그러므로 커튼(실행환경) 바깥에서 작성하는 코드는 나중에 실행환경(커튼) 내부에서 복잡성을 다룰 사람들이 소비할 수 있는 방식으로 작성될 필요가 있다.  그래서 우리는 어떻게가 생략되고 무엇만이 담긴 선언적인(Declarative) 방식을 사용해야 된다. 
C# TPL - TASK Parallel Library / 선언적 크로그래밍이 같는 수많은 장점의 예
  - 하나의 쓰레드를 사용
from emp in employee
where emp.id > 100
select emp.salary: 
 - 하지만 employee table의 데이타가 100만행이고 16개 중 15개의 CPU가 놀고 있다. 병렬처리를 라는 로직을 구현해야 하지만 
   아래 코드르 간단히 해결할 수 있다. 
     from emp in employee.AsParallel()
where emp.id > 100
select emp.salary; 
    • 트레이트
      • 모나드를 잘 알아두면 도움이 되는 두가지 측면
        • 타입시스템이나 함수합성에 대한 이해가 깊어지기 때문에 객체를 설계하거나 프로그램의 모듈을 구성할 때 확실히 유연하고 확장성이 있는 시스템을 구현할 수 있게 된다.
        • 모나드가 지적인 수전을 검증하는 리트머스처러 통용된다. 
      • 사용하는 언어에 새로운 기능이 추가될 때, 문법적인 측면에서만 접근하는 것은 좋지 않다. 그렇게 하면 그들이 ' 어떤문제'를 해결하기 위해서 고안이 되었는지 그 문제를 해결하는데 '왜' 도움이 되는지 못한 상태에서 암기하게 된다.  => 왜 람다를 쓰는지 항상 궁금했었다. 어떤 장점이 있는지. 이 책에서 알게되었지만. ^^
      • Person 이라는 interface가 있고 그것을 구현하는 클래스가 10개가 있다고 하자. 만약 eat() 이라는 메서드를 추가해야 한다면
        • 구현클래스에 eat() 같은 내용을 구현 => DRY 원리 위반
        • 추상클래스를 구현해서 넣는다고 하자. 하지만 채식주의자를 위한 eat() , 고기를 섭취하는 사람을 위한 eat()을 구현한다면?
        • 여기서 어떤 사람은 어떤 사람은 생선과 계란을 먹는 채식주의, 어떤 사람은 돼지 고기만 먹는다면 ? 
        • 이렇게 까다로운 분류를 인터페이스-추상클래스-하위클래싀 공식에 대입해서 설계하는 것은 어렵고 불안정한 일이다. 
        • 코드의 복작성을 제거해주기 위해 서용되는 객체지향의 상속구조 자체가 오히려 복작성을 증폭시키는 역설이 일어난다.
        • C#이 가진 확장메서드로 이 문제를 쉽게 해결할 수 있다. 하위클래스에 손을 대지 않으면서 인터페이스 안에 구체적인 메서드의 구현 내용을 추가할 수 있다. 자바에서라면 반드시 구현 클래스에서 메서드의 정의와 구현을 해야한다. 
// Person에 확장메서드 추가
Public static void Eat(this Person p) {
Console.Out.WriteLine(" I'm eating...");
}

// 구현 클래스를 수정할 필요가 없다. 야호
Person p = new HungryMan()
p.Eat(); 
        • 하지만 다양한 식성에 맞는 Eat을 구현해야 한다면?? C#의 확장메서드로는 충분하지 않다. 
      //고기를 먹지만 돼지고기는 먹지 않는 IeatAnythingButPort 클래스의 eat()
public override void Eat() {
Console.Out.WriteLine("I eat everything");
Console.Out.WriteLine("Except for port. ");
}
// 채식 주의자지만 계란이나 우유는 먹는 IamVegerarianButCnaEatDiaryFood Class
public override void Eat() {
Console.Out.WriteLine("I eat vegitables only");
Console.Out.WriteLine("With eggs and milk. ");
}
        • 위와 같이 다양한 Eat() 메서드를 모두 Person 인터페이스에 넣을 수 없고, Override 해서 억지로라도 가능하지만 코드가 너무 지저분해진다. 그러므로 하위클래스의 소스코드를 하나씩 열어서 Eat() 메서들 내용을 작성하는 편이 안전. 
        • C#의 확장메서드는 인터페이스를 사후적으로 코드를 주입해야 할 때는 강력한 도움을 주지만 , 인터페이스라는 구조물 자체가 가지고 있는 한계로부터 자유롭지 않다. 
      • C# , JAVA의 인터페이스가 갖는 문제는 어떤 클래스가 그것을 구현하는 순간 그것이 정의하고 있는 API를 받아들여야 한다. 
      • 우리가 원하는 것은 자동자나 , 스마트폰에게 Person 이 가지고 있는 eat() 특정 특질(Trait)를 전달 하는 것이다. 이렇게 어떤 특정한 특질을 주입하는 것을 전문용어로 '섞어 넣기 mix-in' 이라고 한다. 
      • 자바나 C#에서 사용하는 인터레이스라는 구조물이 타입안정성을 보장하기 위해서 사용되는 정적 타입시스템과 관련이 깊은 개념
      • 믹신은 동적프로그래밍 언어에서 애용되는 구조물 . 마틴 오더스키는 스칼라를 설계하면서 믹신과 거의 같은 트레이트를 도입
  • 에필로그

 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

TDD process from Test Driven Development

SOFTWARE ENGINEERING/TDD 2017. 8. 9. 14:44




From Ebook : http://chimera.labs.oreilly.com/books/1234000000754/ch04.html#_recap_the_tdd_process

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Clean coder / Rober c. Martin

BOOKS 2017. 5. 25. 13:33
  1. 추천의 글
    • 법무팀은 우리 IT 팀의 답변은 믿지 않았고 세부사항까지 관리해야 마음이 놓였다. 
    • 그러면서도 무슨 이유에서인지 법무팁은 믿었고 세부사항까지 관리할 생각은 없었다.
    • 법무팀은 어떤 식으로든 프로다운 모습을 보였고 기술팀을 그러지 못했다.
    • 그 날 이후, 전문 기술자로 일하는 긴 세월 동안, 무엇을 바꿔야 프로로 대접받을지 항상 궁금했다.
    • 소프트웨어 프로페셔널리즘에 관한 책
  1. 프로의 마음가짐
    • 프로 프로그래머 - 태도, 원칙 행동이 핵심
    • 테스트를 소홀히 한 이유는 재때 선적했다고 떠벌리고 싶었기 때문이다. 그게 내 체면을 세우는 일이었다. 
      • 고객이나 회사는 뒷전이었다. 관심을 가졌던 건 내 평판뿐이었다. 
    • 해를 끼치지 마라, (기능과 구조 )
    • 제대로 작동하는지 아닌지 확인
      • 간단하다 테스트하고 또 테스트하라 
      • 해결책은 테스트하기 쉽게 코드 작성 
      • 테스트 코드 작성 후 그 테스트를 통과하도록 코드를 작성
    • 구조에 해를 끼치지 마로
      • 전체 구조를 희생하면서까지 기능을 추가하는 일이 헛고
      • 소프트웨어는 변한다. 이가정을 어기고 구조를 유연하게 만들지 못한다면 수익 기반인 경제 모델이 취약
      • 프로가 되고 싶다면 지식을 익혀 큼지막한 덩어리를 만든다음 그 덩어리를 계속 키워야한다.
      • 연습(kata) 
  2. 아니고 말하기
    • 노력한다는 약속은 지금가지는 늑장을 부렸으며 힘을 비축했다고 인정하는 셈이다.
    • 노력하겠다는 약속은 계획을 바꾼다는 약속이다.
    • 훌륭한 코드는 불가능한가
      • 상속 구조가 안 좋은 이유는 극히 일부를 제외하면 has-a 관계가 is-a 관계보다 훨씬 낫기 때문이다.
      • 좋은 코드는 확장 가능해야 한다. 운영하기 좋고, 바꾸기 편해야한다. 
    • 고객은 항상 완료일을 연장한다. 항상 더 많은 기능을 바란다. 항상 나중에 가서야 바꾸고 싶어한다.
    • 고객은 개발자에게 들이는 비용을 절감하고, 이는 훌륭한 코드를 쓸모없게 만든다. 
    • 개발자 입장에서 주의를 기울이지 않으면 시간은 반으로 줄고, 코드는 두 배로 작성하라는 요청/명령/기만을 받게 된다.
    • 제 시간에 일을 완료하기 위해서는 코드가 지저분해도 어쩔 수 없다는 결정을 내리지 말아야 했다. 
  3. 예라고 말하기
    • 수련간의 경험을 통해서 원칙을 깨면 느려질 뿐이라는 사실을 알게 됐다.
    • "예"라고 대답할 수 있는 창으적인 방법을 찾는 데 고심해야한다. 
    • 프로가 "예"라고 대답할 때는 약속을 뜻하는 언어를 사용해서 내뱉은 말에 모호한 부분이 없도록 해야한다.

  4. 코딩
    • 어떤 일에 통달하는 비버은 자신관과 오류를 느끼는 감각이라는 사실을 깨달았다.
    • 준비된 자세
      • 코드는 반드시 동작해야 한다.
      • 코드는 고객이 제시한 문제를 반드시 풀어야 한다.
      • 코드는 기존 시스템에 잘 녹아들어야 한다. SOLID 객체지향 원칙을 따라야 한다.
      • 코드는 다른 프로그래머가 읽기 쉬어야 한다.
    • 디버깅 시간 - 다버깅 시간을 가능한 한 0에 가깝게 줄이는 일을 프로가 짊어진 의무다.
  5. 테스트 주도 개발
    • 단위 테스트는 문서다, 시스템의 가장 낮은 단계의 설계를 알려준다.

  6. 연습
    • 무술과 프로그래밍 두 가지 경우 모두 속도는 연습에 달려 있다.
  7. 인수 테스트
    • 프로그래머와 사업부 사이의 가장 흔한 의사소통 쟁접은 요구사항이다.
    • '완료'라는 모호함. 개발자가 어떤 업무를 완료했다고 말할 떄, 그 의미는 무엇인가?
    • 인수테스트는 자동화 되어야 한다.
    • 인수 테스트는 사업부를 위해 사업부가 작성한다. 
    • 인수 테스트는 사업적 관점에서 시스템이 어떻게 운영되어야 하는지를 구체적으로 표시한 공식 요구사항 문서다. 
    • 단위 테스트는 프로그래머를 위해서 만든다.
    • GUI를 통하는 것보다 실제 API를 통해서 기본 시스템의 기능을 불러오는 테스트를 작성하는 것이다. 이 API는 GUI가 사용하는 API와 같아야 한다.
  8. 테스트 전략
    • TDD는 강력한 원칙이며, 인수테스트는 요구사항을 표현하고 강화하는 가지있는 방법니다.
    • 하지만 이는 전체 테스트 전략의 일부분일 뿐디아. 'QA'는 오류를 찾지 못해야 한다'는 목표를 달정하기 위해서는 개발팀과 QA가 손잡고 단위, 컴포넌트, 통합, 시스템, 탐색 테스트의 계층을 만들어야 한다. 
  9. 시간 관리
    • 오전에는 방해가 되는 일/ 오후에는 중요한 업무
    • 회의
      • 프로는 회의 비용이 비싸다는 사실을 안다.
      • 관리자의 가장 중요한 임무 중 하나는 직원을 회의로부터 보호하는 일이다.
      • 일일 회의 / 어제는 머했다. 오늘은 뭘 할 예정인가, 방해요소는 없다. ( 참석자당 1분)
    • 논쟁/의견 차이
      • 어떤 논쟁이든 5분 안에 해결되지 않으면 논쟁으로는 해결할 수 없다. 논쟁이 길어지는 이유는 양쪽보두 근거가 되는 명뱁한 증거가 없기 때문이다.  => 합의를 보려면 데이타를 가져와야 한다.
      • 데이트는 직접 실험을 하거나, 모의실험 혹은 모델링을 하면된다. 
  10. 추정
    • 프로는 달성할 수 있다는 사실을 알지 못하면 약속하지 않든다.

  11. 압박
    • 코드가 난장판이 되는 말든 고객 시연에 성공하면 영웅이 됐다. 이런 짓을 하면 승진했다.
    • 위기 상황에서도 편하게 느겨지는 규율(ex.Tdd)을 골라라. 그 규율을 항상 따라라. 이 것이 위기상황을 피하는 최선의 방법이다.
    • 어려움에 빠진 사실을 팀 동료와 상사에게 알려야 한다. 깜짝 사고는 피야햐 한다. 깜짝 사고는 압박을 열 배로 늘린다.
  12. 함께 일하기
    • 처음으로 소프트웨어 최적화가 아주 힘들고 최적화 과정은 비직관적
    • 프로그래머 VS 회사
      • 자기 일에 열정적인 것은 좋은 일이다. 하지만 월급을 주는 사람들의 목표를 계속 살피는 것 또한 좋은 일이다.
      • 절대 피해야 할 일은 기술더이메 파 뭍여 정신을 못 차려 주변에서 사업이 무너지고 붙타는 사실을 알아채지 못하는 것이다. 
      • 우리 업무는 사업이 순조롭게 나아가도록 만드는 일이다.
    • 회사의 관습을 따라야 한다. 다른 사람은 정장을 입는데 나는 입지 않았다. 이유는 내가 이기적이고 자아도취에 빠진 멍청이였기 때문
    • 프로는 함께 일힌다. 
    • 프로그래밍은 온전히 다른 사람과 함께 일하는 것에 관한 업무다. 사업부와 함께 일해야 한다. 서로 같이 일해야 한다. 
  13. 팀과 프로젝트
  14. 스승과 제자 그리고 장인 정신
    • 실망 시키지 않은 대학 졸업생 / 대학 입학 전에 혼자서 프로그램을 공부했고 입학 후에도 대학과 상관없이 스스로 지속적으로 공부를 했다.
    • 비관습적인 멘토링
      • 아주 잘 만들어진 메뉴얼
      • 나를 거들떠 보지 않았던 사람들으 보면서 배웠다. 
    • 소프트웨어 견습기간 - 이상적
      • 장인 - 한 가지 이상의 중요 소프트웨어 프로젝트를 주도/ 10년 이상으 경력 , 여러 다른 시스템, 언어 및 운영시스템 작업 , 능숙한 디자이너 건축가, 힘들지이 않고 다른 이들을 위해 코드를 처리. 또한 판독, 연구, 실행 및 가르치기를 통해 기술적 역활을 유지
    • 학교에서는 컴퓨터 프로그래밍 이론을 가르치지만, 장인의 규율, 실태와 장인이 되는 기술은 가르치지 않는다. 
  15. 도구 활용


[프로 소프트웨어 개발자 최소 사항]

1. 디자인 패텬 : 24가지 GOF 패턴을 설명할 수 있고, POSA 패턴을 실무에 적용할 수정

2. SOLID 객체지향 원칙을 알아야 한고, 컴포넌트 개념을 충분히 이해

3. 방법론 : XP, 스트럼, 린, 칸판, 폭포수, 구조적 분석, 구조적 설계 개념을 이해

4. 원칙 : 테스트 주도 개발, 객체지향 설계, 구조적 프로그래밍, 지속적 통항, 짝 프로그래밍을 실천

5. 도구 : UMD, 데이터 흐름도(DFD), Structure chart, Petri Net, 

State transition diagrma dn table, flow chart, decision table을 어떻게 쓰는지



저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Art of Readable code - Ch1 코드는 이해하기 쉬워야 한다.

BOOKS 2017. 4. 6. 16:34

코드는 다른 사람이 그것을 이해하는데 들이는 시간을 최소화하는 방식으로 작성되어야 한다.


1. 분량이 적으면 항상 더 좋은가?


assert((!(bucket = FindBuckcet(key)) || !bucket -> IsOcuppied()); 보다


bucket = FindBucket(key);

if (bucket != NULL) assert(!bucket->IsOccupied());  코드가 이해하기 쉽다.



 주석처리는 '코드를 더하는' 행위지만 코드를 더 발리 이해하게 도와주기도 한다.

// "hash = (65599 * hash ) + c"의 빠른 버젼

hash = (hash << 6) + (hash << 16) - hash + c ; 


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Background worker - Test project with WPF

PROGRAMING/C# 2017. 2. 16. 10:41

Head Frist c# 3rd Edition에 부록에 있는 Background worker 구현 (Progress bar update)

- Do work process

- Cancellation process

- report progress  


1. 쓰레드로 구현하지 않을 경우 , Progress bar가 진행하는 동안 Main process를 접근 불가 (check를 하지 않고 실행)

2. 쓰레드와 Time.Sleep을 구현하는 방법 보다 간단함 




[MainWindow.xml]

<Window x:Class="BackgroundWorkerTest.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:BackgroundWorkerTest"

        mc:Ignorable="d"

        Title="Background Worker Example" Height="150" Width="300">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

            <RowDefinition Height="*"></RowDefinition>

        </Grid.RowDefinitions>


        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="*"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

            <ColumnDefinition Width="*"></ColumnDefinition>

        </Grid.ColumnDefinitions>


        <CheckBox Name="useBackgroundWorkerCheckbox"  Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"></CheckBox>

        <Label Grid.Column="1" Grid.ColumnSpan="2" Content="Use BackgroundWoker" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>

        <Button  Name="goButton" Grid.Row="1" Grid.Column="0" Margin="3,3,3,3" Content="Go!" FontSize="10.667" Click="goButton_Click" IsEnabled="True"></Button>

        <Button  Name="cancelButton" Grid.Row="1" Grid.Column="1" Margin="3,3,3,3" Content="Cancel" FontSize="10.667" Click="cancelButton_Click" IsEnabled="True"  ></Button>

        <ProgressBar Grid.Row="2" Margin="3,3,3,3" Grid.ColumnSpan="3" Name="progressBar1"></ProgressBar>


        


    </Grid>

</Window>


[MainWindow.xaml.cs]

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;


namespace BackgroundWorkerTest

{

    /// <summary>

    /// Interaction logic for MainWindow.xaml

    /// </summary>

    public partial class MainWindow : Window

    {

        private readonly BackgroundWorker backgroundWorker1 = new BackgroundWorker();


        public MainWindow()

        {

            InitializeComponent();

            backgroundWorker1.WorkerSupportsCancellation = true;

            backgroundWorker1.WorkerReportsProgress = true;

            backgroundWorker1.DoWork += backgroundWorker1_DoWork;

            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;

            backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;

        }


        //ui event

        private void goButton_Click(object sender, EventArgs e)

        {

            goButton.IsEnabled = false;


            if (!useBackgroundWorkerCheckbox.IsChecked == true)

            {

                // If we're not using the background worker, just start wasting CPU cycles

                for (int i = 1; i <= 100; i++)

                {

                    WasteCPUCycles();

                    progressBar1.Value = i;

                }

                goButton.IsEnabled = true;

            }

            else {

                // If the form's using the background worker, it enables the Cancel button.

                cancelButton.IsEnabled = true;


                // If we are using the background worker, use its RunWorkerAsync()

                // to tell it to start its work

                backgroundWorker1.RunWorkerAsync(new Guy("Bob", 37, 146));

            }

        }

        /// <summary>

        /// When the user clicks Cancel, call BackgroundWorker.CancelAsync() to send it a cancel message

        /// </summary>

        private void cancelButton_Click(object sender, EventArgs e)

        {

            // If the user clicks Cancel, it calls the BackgroundWorker's CancelAsync()

            // method to give it the message to cancel.

            backgroundWorker1.CancelAsync();

        }


        //background worker function

        /// <summary>

        /// The BackgroundWorker object runs its DoWork event handler in the background

        /// </summary>

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

        {

            // The e.Argument property returns the argument that was passed to RunWorkerAsync()

            Console.WriteLine("Background worker argument: " + (e.Argument ?? "null"));


            // Start wasting CPU cycles

            for (int i = 1; i <= 100; i++)

            {

                WasteCPUCycles();

                // Use the BackgroundWorker.ReportProgress method to report the % complete

                backgroundWorker1.ReportProgress(i);


                // If the BackgroundWorker.CancellationPending property is true, cancel

                if (backgroundWorker1.CancellationPending)

                {

                    Console.WriteLine("Cancelled");

                    break;

                }

            }

        }

        /// <summary>

        /// BackgroundWorker fires its ProgressChanged event when the worker thread reports progress

        /// </summary>

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)

        {

            progressBar1.Value = e.ProgressPercentage;

        }

        /// <summary>

        /// BackgroundWorker fires its RunWorkerCompleted event when its work is done (or cancelled)

        /// </summary>

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

        {

            // When the work is complete, the RunWorkerCompleted event handler 

            // re-enables the Go! button and disables the Cancel button.

            goButton.IsEnabled = true;

            cancelButton.IsEnabled = false;

        }


        //other function

        /// <summary>

        /// Waste CPU cycles causing the program to slow down by doing calculations for 100ms

        /// </summary>

        private void WasteCPUCycles()

        {

            DateTime startTime = DateTime.Now;

            double value = Math.E;

            while (DateTime.Now < startTime.AddMilliseconds(100))

            {

                value /= Math.PI;

                value *= Math.Sqrt(2);

            }

        }

        /// <summary>

        /// Clicking the Go button starts wasting CPU cycles for 10 seconds

        /// </summary>




    }

}


- 아래 프로젝트(Viaual studio 2015에서 작성)

BackgroundWorkerTest.7z

- 실행 파일 

Release.7z


저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

C# Basic 다시 공부

PROGRAMING/C# 2015. 7. 14. 10:29

 공변성 반공변경 대한 자료를 찾다가 발견한 아래 사이트에서 C#을 복습할 있는 기회가 있어 포스팅


http://www.devbb.net/viewforum.php?f=38&sid=0ed08ea5ae039c4a56164f85650622c1




기본 할당과 변수 유효 범위

 

C#은 자동적으로 모든 멤버 변수를 안전한 기본 값 '0' 으로 설정한다.
하지만 메소드내 지역변수는 자동으로 기본 값이 할당되지 않기 때문에, 사용전에 초기화가 필요하다.

Code:

using System;
class DefaultValueTester
{
    public int a;
    public bool b;
    public string s;
    public object o;
    public static int Main()
    {
        //
생성된 객체 v 의 모든 멤버변수는 자동으로 초기값으로 설정된다.
        DefaultValueTester v = new DefaultValueTester();
        //
지역변수는 사용전에 초기화가 필요하다.
        int localInt;
        Console.WriteLine(localInt);  //
오류 !!!
        return 0;
    }
}

 

 

 

값 형식과 참조 형식

 

모든 숫자 데이타 형식(int, float, 등)과 열거형과 구조체를 포괄하는 값 기반형식은 스택에 할당된다.
따라서 값 형식은 정의된 영역 밖에서는 메모리로부터 곧바로 제거 될 수 있다.
하나의 값 형식을 다른 값 형식에 할당하면, 기본적으로 멤버 대 멤버 복사가 이루어진다.

Code:

using System;
class ValRefClass
{
    public static void Main()
    {
        int i = 99;
        int j = i;
        j = 88;
    }
}
결과
i = 99, j = 88;

 

구조체의 경우도 마찬가지다.

Code:

using System;
struct FOO
{
    public int x, y;
}
class ValRefClass
{
    public static void Main()
    {
        FOO f1 = new FOO();
        f1.x = 100;
        f1.y = 100;
        FOO f2 = f1;
        f2.x = 900;
    }
}
결과
f1.x = 100, f1.y = 100
f2.y = 900, f2.y = 100


이와는 정반대로, 참조 형식(클래스)은 가비지 컬렉션의 대상인 힙에 할당된다.
힙에 할당된 참조 형식은 가비지 컬렉션에 의해 제거되기 전까지는 계속 메모리에 남아 있게 된다.

참조 형식의 대입은 멤버의 복사가 아닌 할당된 인스턴스가 생성된 메모리를 복사하게 된다.
C++
의 포인터 끼리의 대입과 같다고 이해하면 된다.

아래의 예제는 위 구조체 예제에서 구조체 대신 클래스를 사용할 때 참조 형식이 되는 예이다.

Code:

using System;
class FOO
{
    public int x, y;
}
class ValRefClass
{
    public static void Main()
    {
        FOO f1 = new FOO();
        f1.x = 100;
        f1.y = 100;
        FOO f2 = f1;
        f2.x = 900;
    }
}
결과
f1.x = 900, f1.y = 100
f2.y = 900, f2.y = 100

시스템 데이터 형식과 C#별칭

모든 내장 C# 데이터 형식은 사실 System 네임스페이스에 정의되어 있는 시스템 형식에 대한 별칭이다.

Attachment:

system_data.JPG


예를 들면 'int' 는 실제 시스템 형식인 System.Int32 의 약칭 표시가 되는 것이다.

Code:

using System;
class Test
{
    public static void Main()
    {
        System.Int32 a = 1000;  // int a = 1000;
와 같음
        System.Int32 b = 1000;  // int b = 1000;
와 같음
        if (a == b)
            Console.WriteLine("Same value!");
    }
}

 

 

 

 

 

 

값 형식과 참조 형식간의 변환 : 박싱(boxing), 언박싱(Unboxing)

 

C# 에는 값 형식과 참조 형식 간의 변환을 간단하게 할 수 있는 메커니즘이 있는데, 이를 박싱(boxing) 이라고 부른다.


값을 박싱한다는 것은 새로운 객체를 힙에 할당하고 새로 할당된 이 인스턴스에 내부 값을 복사하는 것이다. 이때 반환하는 것은 새로 할당된 객체에 대한 참조자이다.

언박싱의 경우에는 반대의 연산이 일어난다. 언박싱은 객체 참조에 들어 있는 값을 이에 상응하는 값 형식으로 변환해 스택에 올려 놓는 과정을 일컫는 용어이다.
여기서 알맞은 데이터 형식으로 언박스하는 것은 상당히 주의를 요하는 작업이며 형식이 틀리다면 InvalidCastException 예외가 발생한다.

Code:

// 값 데이터 형식을 만든다.
short s1 = 25;
//
값을 객체 참조로 박스한다.
object myObj = s1;
//
참조를 이에 상응하는 short 로 언박스(unboxing) 한다.
short s2 = (short)myObj;
try
{
    //
박스에 포함된 형식이 string 이 아니라 short 이다.
    string str = (string)myObj;
}
catch (InvalidCastException e)
{
    Console.WriteLine("OOPS! {0}", e.ToString());
}

 C# 의 'out' 키워드
다음은 C# 의 'out' 키워드를 이용해서 두정수의 합을 반환하도록 하는 함수이다.
C#
의 'out' 키워드는 호출자가 하나의 메소드 호출을 통해서 여러 개의 반환 값을 얻을 필요가 있을때 매우 유용하다.
C++ 에서 변수의 포인터를 함수의 매개변수로 넘겨서 결과를 받아 오는 것과 유사하다.

Code:

using System;
class MainClass
{
    public static void Add(int x, int y, out int ans)
    {
        ans = x + y;
    }
    public static void Main()
    {
        int x = 9, y = 10, z=0;
        Add(x, y, out z);
    }
}
결과
x=9, y=10, z=19;

C# 의 'ref' 키워드

참조 매개변수는 호출된 메소드에서, 호출자의 범위 안에 선언된 데이터 포인터에 대한 연산을 하고 싶은 경우에 필요하다.
출력 매개변수(out 키워드)는 인자로 넘기기 전에 초기화될 필요가 없다. 하지만 참조 매개변수는 인자로 넘어가기 전에 반드시 초기화 되어야 한다. 왜냐하면 이미 존재하는 형식에 대한 참조자를 전달해야 하기 때문이다.

Code:

using System;
class MainClass
{
    public static void UpperCaseThisString(ref string s)
    {
        //
문자열을 대문자로 변경해서 반환한다.
        s = s.ToUpper();
    }
    public static void Main()
    {
        string s = "Can you really have sonic hearing for $19.00?";
        Console.WriteLine("Before: {0} ", s);
        UpperCaseThisString(ref s);
        Console.WriteLine("After: {0} ", s);
    }
}

out : 출력 매개 변수

1. 변수 초기화 필요치 않음 : 출력용 이기 때문에 함수로 전달되기 전 변수값 할당은 무의미 하다

2. 함수내 반드시 변수에 값 할당 : 출력용 이기 때문에 함수내에서 변수 값이 할당 되어야 함.

 

ref : 참조에 의한 전달

1. 변수 초기화 필요 : 일반 매개변수와 같은 의미

2. 함수내 값 설정하지 않아도 됨

 

 

 

 

 

 

 

 

 

C# 의 'params' 키워드

이 키워드를 이용하면 배열과 같은 다양한 종류의 여러 인수를 하나의 매개변수로서 전달 할 수 있다.

Code:

using System;
class MainClass
{
    public static void DisplayArray(string msg, params int[] list)
    {
        Console.WriteLine(msg);
        for (int i = 0; i < list.Length; i++)
            Console.WriteLine(list[i]);
   [/legend] }
    public static void Main()
    {
        int[] arr = new int[3] { 10, 11, 12 };
        DisplayArray("Here is an array of ints", arr);
    }
}

 

C# 의 구조체

C# 의 구조체도 C++ 형식과 크게 다른것이 없으며, C# 구조체를 별칭으로 하는 동일한 이름의 클래스를 가지지 않는다.
C# 의 클래스와의 차이점은 데이터가 스택에 할당되며 구조체의 대입은 참조가 아닌(주소의 공유가 아닌) 값의 복사가 된다.

클래스와 구조체의 차이점

  • 구조체는 값 형식이다.
  • 모든 구조체 형식은 암시적으로 System.ValueType 에서 상속된다.
  • 구조체 형식의 변수에 대입이 이뤄지면 지정되는 값이 복사된다.
  • 구조체의 기본 값은 모든 값 형식 필드를 각 형식의 기본 값으로 설정하고 모든 참조 필드를 null 로 설정한 것이다.
  • 구조체 형식과 객체 간의 변환에는 박싱과 언박싱 연산이 필요하다.
  • this 의 의미가 다르다.
  • 구조체에 대한 인스턴스 필드 선언은 변수 초기화를 포함할 수 없다.
  • 구조체는 매개변수가 없는 인스턴스 생성자를 선언할 수 없다.
  • 구조체는 소멸자를 선언할 수 없다.

 

 

 

 

 

읽기 전용 속성과 쓰기 전용 속성

앞선 예제에서 EmpID 는 읽기/쓰기 속성으로 만들어졌다. 이것을 읽기 전용으로 구성하려면 set 블록을 빼고 만들면 된다.
마찬가지로 쓰기 전용 속성을 만들고 싶으면 get 블록을 빼면 된다.

읽기 전용 필드 만들기

읽기 전용 속성은 읽기 전용 필드와 밀접하게 관련되어 있다. 읽기 전용 필드는 'readonly' 키워드를 이용해 데이터를 보호한다.
읽기 전용 필드는 생성자에서만 할당 가능하며 이 필드에 값을 할당하려고 하면 컴파일 에러가 발생한다.

Code:

public class Employee
{
    //
읽기 전용 필드 (생성자에서 할당)
    public readonly int empID;
    public Employee(int id)
    {
        //
읽기 전용 필드 할당.
        empID = id;
    }
}

class MainClass
{
    public static void Main()
    {
        Employee p = new Employee(10);
        p.empID = 20;  //
읽기 전용 필드이므로 컴파일 에러.
        Console.WriteLine(p.empID);
    }
};

 

 

 

 

 

 

 

 

 

클래스 멤버 버전 관리

 

C# 에는 메소드 재정의에 대해 논리적으로 정반대에 해당하는 기능인 메소드 숨기기(hiding)가 있다.  .NET *.dll 을 구입해서, 여기에 있는 기본 클래스로부터 새 클래스를 파생시키려 한다고 가정해 보자. 이때 여러분이 만들고자 하는 메소드와 호환되지 않는 같은 이름의 메소드가 기본 클래스에 정의되어 있다면 어떻게 해야 할까?
이런 경우, 바로 객체 사용자가 기본 클래스 구현을 유발하지 않도록 'new' 를 사용하면 된다.

Code:

public class MyBase
{
    public virtual void func()
    {
        Console.WriteLine("Base");
    }
}

public class TestClass : MyBase
{
   
// 이전에 구현된 func() 구현을 모두 감추고 TestClass 고유한 기능을 수행한다.
    public
new void func()
    {
        Console.WriteLine("Child");
    }
}

class MainClass
{
    public static void Main()
    {
        MyBase c1 = new MyBase();
        c1.func();
        c1 = new TestClass();
        c1.func();
        TestClass c2 = new TestClass();
        c2.func();
    }
};


Output

Attachment:

class.JPG

같은 방법으로 파생된 형식의 필드(멤버변수)에도 new 키워드를 적용해서 상속의 연결 관계에서 동일한 이름으로 정의된 데이터 형식을 숨길 수도 있다.

C# 의 종결 프로세스

모든 형식에 C# 스타일의 소멸자를 만들고 싶을 수도 있다. 그러나 그렇게 하면 안된다.
무엇보다도, 종결자의 역할이 .NET 객체가 비관리 리소스를 제거할 수 있게 하는 것이라는 점을 잊어서는 안된다.
종결 메소드의 사용을 지양해야 하는 좀 더 실질적인 이유는 종결에 시간이 소요된다는 것이다.

new
연산자를 이용해서 관리 힙에 객체를 하나 위치시킬 때, 런타임은 자동적으로 이 객체가 사용자 지정 Finalize() 메소드를 지원하는지 검사하게 된다.
만약 지원한다면 이 객체는 종결 가능한 것으로 표시되고, 이 객체에 대한 포인터가 종료 대기열(finalization queue)이라는 이름의 내부 대기열에 저장된다.

가비지 컬렉터가 객체를 메모리로부터 해제할 때라고 판단할 때, 가비지 컬렉터는 종료 대기열 목록에 기재되어 있는 모든 항목을 검사하고, 이 객체를 힙으로 부터 finalization reachable table 이라는 이름의 또다른 CLR 관리 구조로 복사한다.
이때 별도의 스레드가 실행되어 다음 번 가비지 컬렉션시 테이블에 있는 각 객체의 Finalize() 메소드를 호출한다.


임시 소멸 메소드 만들기

살펴본 것과 같이, 객체 종료 프로세스에는 시간이 소요된다. 이상적으로는, 객체를 만들 때 종료 가능한(finalizable) 것으로 표시되지 않도록 디자인하는 것이 좋다. 그러나 비관리 리소스를 조작하는 형식에서는 이 비관리 리소스들을 필요한 때에 그리고 예측이 가능하게 해제할 수 있어야 한다. 이를 위해서 C# 소멸자를 이용할 수도 있지만, 좀 더 나은 방법도 있다.

사용자 정의 임시 메소드를 정의해서 시스템의 모든 객체가 이 메소드를 구현하도록 하는 방법이 있다.
이 메소드 이름을 Dispose() 라고 했다면고 하자. 이때 주의할 점은, 객체 사용자가 해당 형식의 사용을 끝낼 때 객체 참조가 범위 밖으로 벗어나기 전에 Dispose() 를 직접 호출해야 한다는 점이다. 

이 방법을 이용하면, 해당 객체에서 종료 대기열에 접근하거나 가비지 컬렉터가 클래스의 종료 로직을 유발하기를 기다릴 필요 없이 비관리 리소스를 얼마든지 제거할 수 있다.
비관리 리소스가 항상 알맞게 제거될 수 있게 하려면, Dispose() 메소드가 예외를 발생시키지 않고 안전하게 여러 번 호출될 수 있도록 구현해야 한다.


iDisposable
인터페이스

명시적 소멸 루틴을 지원하는 모든 객체들에 일관성을 제공할 수 있도록, .NET 클래스 라이브러리에는 Dispose() 라는 이름의 멤버 하나를 갖는 IDisposable 이라는 이름의 인터페이스가 정의되어 있다. (인터페이스 개념에 대해서는 다른장에서 설명될 것이다.)

Code:

public interface IDisposable
{
    public void Dispose();
}


이 방법을 이용하면, 객체 사용자가 얻어왔던 리소스를 가능한 한 빨리 직접 제거하고, 종료 대기열에 들어가서 발생할 오버헤드를 줄일 수 있게 된다. 호출 로직은 간단하다.

Code:

public class Car : IDisposable
{
    public void Dispose()
    {
        //
내부 비관리 리소스 제거
    }
}

public class MainClass
{
    public static int Main()
    {
        Car c1 = new Car();
        c1.Dispose();
        return 0;
    }
    // c1
은 여전히 힙에 있다가 이 지점에서 컬렉트될 것이다.
}



C#
의 "using" 키워드의 또다른 용도

'using'
키워드는 네임스페이스를 지정하는 용도 이외에 자동으로 Dispose() 메소드를 호출하는 용도로도 사용된다.
IDisposable
인터페이스를 지원하는 객체가 using 블록을 빠져 나갈 때 이 객체의 Dispose() 메소드가 자동적으로 반드시 호출된다.
반면, IDisposable 을 구현하지 않은 형식을 using 블록 안에 지정하면, 컴파일시 에러가 발생한다.

Code:

public void SomeMethod()
{
    using (Car c = new Car())
    {
        //
차를 이용한다.
        // using
블록을 나가면 자동적으로 Dispose() 가 호출된다.
    }
}

 

 

 

 

 

 

가비지 컬렉션 최적화가비지 컬레션시에 관리 힙에 있는 모든 객체를 그대로 하나씩 다 검사해서 제거할 대상을 찾지 않는다. 이렇게 하면, 특히 큰 응용프로그램의 경우, 시간이 상당히 많이 걸리게 된다.

이러한 컬렉션 과정의 최적화를 위해 힙에 있는 각 객체에 '세대'가 할당된다. 힙에 오랫동안 있는 객체일수록 더 오래 머물러 있을 가능성이 있는반면, 최근에 힙에 배치된 객체일수록 응용 프로그램에서 빨리 해제될 가능성이 높다는 것이다.

각 객체는 다음의 세대 중 하나에 속하게 된다. (.NET 1.1 버전에서)


  • 0 세대 : 컬렉션 대상 표시가 된 적이 없는 새로 할당된 객체를 식별한다.
  • 1 세대 : 가비지 컬렉션 검색에서 살아남은 객체를 식별한다. (즉, 제거 대상이지만 힙에 충분히 공간이 있어서 아직 제거되지 않은 것을 말한다.)
  • 2 세대 : 두 번 이상의 가비지 컬렉션에서 살아남은 객체를 식별한다.


컬렉션이 일어나면, GC 가 우선 모든 0세대 객체를 표시하고 제거한다. 이 결과 필요한 만큼의 메모리가 확보되어 있으면, 남아 있는 객체들이 다음에 사용 가능한 세대로 표시된다.

만약 모든 0세대 객체가 힙으로부터 제거되었는데도 여전히 메모리가 부족하면, 1세대 객체가 표시되고 제거된다. 그 다음에도 메모리가 부족하면 2세대로 넘어간다.

이렇게 해서, 새로운 객체는 금방 제거되는 반면 오래된 객체는 계속 사용되는 것으로 간주된다. 
한마디로 말해, GC 는 세대를 토대로 해서 힙영역을 빠르게 해제할 수 있다.


System.GC
형식

System.GC
를 이용하면 가비지 컬렉터와 상호작용할 수 있다.

System.GC
형식 주요 멤버 항목


  • Collect() : GC 가 관리 힙에 있는 모든 객체에 대해서 Finalize() 를 호출하게 한다. 원하면 검색할 세대를 지정할 수 있다.
  • GetGeneration() : 현재 객체가 속한 세대를 반환한다.
  • MaxGeteration : 이 속성은 대상 시스템에서 지원하는 가장 큰 세대를 반환한다.
  • ReRegisterForFinalize() : 객체가 다시 finalizable 하게 되도록 한다. 물론 이전에 SuppressFinalize() 에 의해서 종료되지 않도록 표시되었다는 것을 전제로 한다.
  • SuppressFinalize() : 해당 객체의 Finalize() 메소드가 호출되지 않게 한다.
  • GetTotalMemory() : 현재 힙에 있는 모든 객체들에 의해서 사용되고 있는 메모리와 곧 제거될 객체들의 추산된 합(바이트)을 반환한다. 이 메소드에는 Boolean 매개변수가 있는데, 이 매개변수는 이 메소드 호출시 가비지 컬렉션이 발생할지 아닐지를 지정하는 데 이용한다.



종결될 수 있고(finalizable) 소멸될 수 있는(disposable) 형식 만들기

아래 Car 클래스는 IDisposabe 인터페이스와 C# 스타일의 소멸자를 모두 지원한다.
여기에서는, 엔드 유저가 Dispose() 를 직접 호출하기 때문에, 지정된 객체에 대한 소멸자를 호출할 필요가 없다는 것을 시스템에게 알려주기 위해, Dispose() 메소드가 GC.SuppressFinalize() 를 호출하도록 변경했다.

Code:

public class Car : IDisposable
{
    ~Car()
    {
        //
모든 내부 비관리 리소스를 제거한다.
    }
    public void Dispose()
    {
        //
모든 내부 비관리 리소스를 제거한다.
        ...
        //
사용자가 Dispose() 를 호출하면 finalize할 필요가 없다.
        //
그러므로 finalization 을 억제한다.
        GC.SuppressFinalize(this);
    }
}




가비지 컬렉션 강제하기

관리 힙이 가득 차면 '언제든지' 자동적으로 가비지 컬렉션이 유발되지만, 원한다면, 정적 메소드인 GC.Collect() 를 이용해서 런타임이 가비지 컬렉션을 수행하도록 강제할 수 있다. 그러나 관리 힙의 본래 의도는 프로그래머의 직접적인 제어를 벗어나서 관리되는 것이므로, 가능하면 가비지 컬렉션을 강제로 수행하지 않는 것이 좋다.

Code:

// 가비지 컬렉션을 강제하고, 각 객체가 finalize 되기를 기다린다.
GC.Collect();
GC.WaitForPendingFinalizers()l



세대와 프로그래밍 방식으로 상호작용하기 예제

Code:

using System;

public class Car : IDisposable
{
    private string name;
    public Car(string name)
    {
        this.name = name;
    }
    ~Car()
    {
        Console.WriteLine("In destruct for {0}!", name);
    }
    public void Dispose()
    {
        Console.WriteLine("In Dispose() for {0}!", name);
        GC.SuppressFinalize(this);
    }
}

public class MainClass
{
    public static int Main()
    {
        //
이 차들을 관리 힙에 추가한다.
        Car c1, c2, c3, c4;
        c1 = new Car("Car1");
        c2 = new Car("Car2");
        c3 = new Car("Car3");
        c4 = new Car("Car4");

        //
세대를 표시한다.
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c1));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c2));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c3));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c4));

        //
차 몇대를 직접 제거한다.
        c1.Dispose();
        c3.Dispose();

        // 0
세대를 모두 컬렉트한다.
        GC.Collect(0);

        //
세대를 다시 출력한다.
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c1));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c2));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c3));
        Console.WriteLine("C1 is gen {0} ", GC.GetGeneration(c4));

        return 0;
    }
}


Output

Attachment:

dispose.JPG

 

사용자 지정 열거형 만들기 IEnumerable, IEnumerator

사용자 지정 형식인 Car 객체를 모아 놓은 Cars 라는 이름의 클래스를 만들었다고 가정해 보자.
내부의 Car 들을 얻기 위해서는 Cars 를 반복 처리할 때 foreach 구조를 이용하는 것이 편리할 것이다.

Code:

public class Car
{
    private string name;
    public Car(string name)
    { this.name = name; }
    public string CarName 
    { set {name = value; } get { return name; } }
}

public class Cars
{
    private Car[] carArray;
    public Cars()
    {
        carArray = new Car[4];
        carArray[0] = new Car("Car1");
        carArray[1] = new Car("Car2");
        carArray[2] = new Car("Car3");
        carArray[3] = new Car("Car4");
    }
}

public class MainClass
{
    public static void Main(string[] args)
    {
        Cars carLot = new Cars();
        foreach( Car c in carLot )  //
컴파일 오류 !!
        {
            Console.WriteLine("Name: {0} ", c.CarName );
        }
    }
}


그러나 위 코드는, Cars 클래스에 GetEnumerator() 메소드가 구현되지 않았다는 컴파일 에러가 발생할 것이다.
이 메소드는 System.Collections 네임스페이스에 숨어 있는 IEnumerable 인터페이스에 정의되어 있다.

Code:

// foreach 구문을 이용해서 하위 형식을 얻으려면 컨테이너가 반드시 IEnumerable 을 구현해야 한다.
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}


따라서 이 문제를 바로잡기 위해서는 우선 Cars 클래스에 IEnumerable 인터페이스를 추가하고 GetEnumerator() 메소드를 구현해야 한다.
그런데 GetEnumerator() 는 IEnumerator 라는 이름의 또 다른 인터페이스를 반환하게 되어있다.
IEnumerator
는 임의의 객체가 형식들의 내부 컬렉션을 순회하는데 이용할 수 있다.
역시 System.Collections 네임 스페이스에 정의되어 있는 IEnumerator 에는 다음과 같은 세가지 메소드가 정의되어 있다.

Code:

public interface IEnumerator
{
    //
컬렉션의 현재 요소를 가져옵니다.
    object Current { get; }
    //
열거자를 컬렉션의 다음 요소로 이동합니다.
    bool MoveNext();
    //
컬렉션의 첫 번째 요소 앞의 초기 위치에 열거자를 설정합니다.
    void Reset();
}



이제 Cars 클래스는 다음과 같이 수정할 수 있다.

Code:

public class Cars : IEnumerable, IEnumerator
{
    private Car[] carArray;
    int pos = -1;  //
배열의 현재 위치
    public Cars()
    {
        carArray = new Car[4];
        carArray[0] = new Car("Car1");
        carArray[1] = new Car("Car2");
        carArray[2] = new Car("Car3");
        carArray[3] = new Car("Car4");
    }
    // IEnumerator
인터페이스의 메소드 구현
    public bool MoveNext()
    {
        if (pos < carArray.Length - 1)
        {
            pos++;
            return true;
        }
        return false;
    }
    public void Reset() 
    { pos = 0; }
    public object Current 
    { get {return carArray[pos]; } }
    // IEnumerable
인터페이스의 메소드 구현
    public IEnumerator GetEnumerator() 
    { 
         return (IEnumerator)this; 
    }
}


위의 소스코드는 예를 들어 설명하기 위해서 어쩔 수 없이 모두 구현했지만, 이와 같은 IEumerator 인터페이스 구현에는 실제로는 불필요한 부분이 많다. 
배열의 실제 형식인 System.Array 에는 이미 IEnumerator 가 구현되어 있기 대문에, 사실 Car 클래스는 다음과 같이 간략하게 작성될 수 있다.

Code:

public class Cars : IEnumerable // IEnumerator 는 필요하지 않다.
{
    private Car[] carArray;
    public Cars()
    {
        carArray = new Car[4];
        carArray[0] = new Car("Car1");
        carArray[1] = new Car("Car2");
        carArray[2] = new Car("Car3");
        carArray[3] = new Car("Car4");
    }
    // IEnumerable
인터페이스의 메소드 구현
    public IEnumerator GetEnumerator() 
    { 
        //
이제는 내부 배열로 부터 IEnumerator 를 반환한다.
        return carArray.GetEnumerator(); 
    }
}

 

 

복사 가능한 객체 만들기 ICloneable

 

참조 객체의 복사(대입)은 실제 값의 복사가 아닌 단순히 객체의 주소가 복사되는 얕은 복사를 수행한다.
호출자에게 자기 자신의 복사본을 반환할 수 있는 사용자 정의 형식을 만들려면, 표준 ICloneable 인터페이스를 구현하면 된다.

Code:

public interface ICloneable
{
    //
현재 인스턴스의 복사본인 새 개체를 만듭니다.
    object Clone();
}


IConeable
인터페이스를 사용한 예

Code:

public class Point : ICloneable
{
    public int x, y;
    public Point() { }
    public Point(int x, int y) { this.x = x; this.y = y; }
    public override string ToString()
    { return "X: " + x + "Y: " + y; }
    public object Clone()
    { return new Point(this.x, this.y); }
}

public class MainClass
{
    public static void Main()
    {
        Point p1 = new Point(50, 50);
        Point p2 = (Point)p1.Clone();
    }
}


Point
를 위와 같이 구현할 수도 있지만, 좀 더 간단하게 나타낼 수도 있다. Point 형식에 다른 내부 참조 형식에 대한 참조자가 없기 때문에, Clone() 메소드를 다음과 같이 간단하게 할 수도 있다.
( MemberwiseClone()
은 System.Object 에 정의 되어 있는 멤버이다. )

Code:

public object Clone()
{
    // Point
의 각 필드를 멤버 대 멤버 복사.
    return this.MemberwiseClone();
}

 

 

콜벡함수


대부분의 프로그램에서 시스템 내의 객체들은 일반적으로 이벤트, 콜벡 인터페이스와 여타 프로그래밍 구조를 이용해서 '양방향 통신' 에 참여한다.
Windows API
에서는 콜백 함수 또는 줄여서 콜백이라는 이름의 항목을 생성하는 데 C 스타일의 함수 포인터를 이용한다.
프로그래머들은 콜백을 이용해서 하나의 함수가 해당 응용 프로그램에 있는 다른 함수에게 보고(콜벡)하도록 구성할 수 있었다.
포준 C 스타일 함수는 메모리에 있는 주소를 가리키는 것에 지나지 않는다는 데에 문제가 있다.
이상적으로는 콜백에 매개변수의 개수나 형식 그리고 지시된 메소드의 반환 값과 같은 형식 안전 정보가 포함되는 것이 바람직하다.
아쉽게도, 전통적인 콜백 함수에서는 이것이 불가능하기 때문에, 이로 인해 버그나 심각한 충돌 등 여러 런타임 에러가 종종 발생하곤 한다.


델리게이트 Delegate

.NET
에서는 델리게이트를 이용해서 콜벡 기능을 더 안정적이고 더 객체 지향적인 방식으로 수행할 수 있다.
본질적으로, 델리게이트는 해당 응용 프로그램 내에 있는 다른 메소드를 가리키는 객체이다.
.NET Framework
에서는 동기 델리게이트와 비동기 델리게이트를 이용할 수 있다.
구체적으로, 델리게이트에는 세가지 중요한 정보가 포함된다.


  • 델리게이트가 호출하는 메소드의 이름
  • 이 메소드의 인수
  • 이 메소드의 반환 값


*
델리게이트를 설명하는 과정이 다소 복잡해 보이지만, 델리게이트는 함수 포인터를 캡슐화하는 하나의 래퍼 클래스에 지나지 않는다.

 

가장 간단한 델리게이트 예제예제1

주어진 델리게이트의 대상(즉, 호출할 메소드)을 할당하고 싶으면, 해당 메소등의 이름을 델리게이트의 생성자로 전달하면 된다.
이렇게 함으로써, 함수를 직접 호출하는 것처럼 보이는 구문을 이용해서 해당 멤버를 간접적으로 호출할 수 있게 된다.

Code:

using System;
class Program
{
    //
이 메소드는 델리게이트에 의해 호출될 메소드이다.
    public static void PlainPrint(string msg)
    { Console.WriteLine("Msg is : {0} ", msg); }
    //
델리게이트 하나를 정의한다.
    public delegate void AnyMethodTakingAString(string s);
    //
메인함수.
    public static void Main(string[] args)
    {
        //
델리게이트를 만든다.
        AnyMethodTakingAString del;
        del = new AnyMethodTakingAString(PlainPrint);
        //
내부적으로 AnyMethodTakingAString.Invoke() 가 여기에서 호출된다 !!
        del("Hello there...");
        //
델리게이트에 대한 정보를 출력한다.
        Console.WriteLine("I just called : {0} ", del.Method);
    }
}


Output

Attachment:

delegate01.JPG

 

예제 2

델리게이트 객체는 그것이 호출하는 메소드의 실제 이름과는 크게 상관이 없다. 
원한다면 다음과 같이 대상 메소드를 동적으로 변경할 수도 있다.

Code:

using System;
class Program
{
    public static void PlainPrint(string msg)
    { Console.WriteLine("Msg is : {0} ", msg); }
    public static void UpperCasePrint(string msg)
    { Console.WriteLine("Msg is : {0} ", msg.ToUpper()); }


    public delegate void AnyMethodTakingAString(string s);


    public static void Main(string[] args)
    {
        AnyMethodTakingAString del;
        del = new AnyMethodTakingAString(PlainPrint);
        del("Hello there...");
        Console.WriteLine("I just called : {0}\n", del.Method);


        //
델리게이트를 재할당하고 호출한다.
        del = new AnyMethodTakingAString(UpperCasePrint);
        del("Hello there...");
        Console.WriteLine("I just called : {0}\n", del.Method);
    }
}

Output

Attachment:

delegate02.JPG

 

예제3

System.Delegate
기본 클래스에 포함된 호출 리스트에 여러 개의 메소드를 삽입하려면, 오버로드된 += 연산자를 이용하면 된다.

Code:

using System;
class Program
{
    public static void PlainPrint(string msg)
    { 
        Console.WriteLine("Msg is : {0} ", msg); 
    }
    public static void UpperCasePrint(string msg)
    {
        Console.WriteLine("Msg is : {0} ", msg.ToUpper()); 
    }
    public delegate void AnyMethodTakingAString(string s);


    public static void Main(string[] args)
    {
        //
멀티 캐스팅
        AnyMethodTakingAString del;
        del = new AnyMethodTakingAString(PlainPrint);
        del += new AnyMethodTakingAString(UpperCasePrint);
        del("Hello there...");
    }
}


Output

Attachment:

delegate03.JPG

 

 

좀 더 복잡한 델리게이트 예제

현재, 위에서 만든 델리게이트는 논리적으로 관련된 클래스 형식으로부터 분리되어 있다.
이렇게 해도 문제는 없지만, 델리게이트를 클래스 내에서 직접 정의 하는 방법이 좀 더 현명한 방법니다.

Code:

using System;
using System.Collections;

public class Car
{
    private string name;
    private bool isDirty;
    private bool shouldRotate;
    public delegate void CarDelegate(Car c);
    public Car(string name, bool dirty, bool rotate) 
    { 
        this.name = name;
        isDirty = dirty; 
        shouldRotate = rotate; 
    }
    public bool Dirty
    {
        get { return isDirty; }
        set { isDirty = value; }
    }
    public bool Rotate
    {
        get { return shouldRotate; }
        set { shouldRotate = value; }
    }
}

public class Garage
{
    ArrayList theCars = new ArrayList();
    public Garage()
    {
        theCars.Add(new Car("Viper", true, false));
        theCars.Add(new Car("Fred", false, false));
        theCars.Add(new Car("Stan", false, true));
    }
    public void ProcessCar(Car.CarDelegate proc)
    {
        Console.WriteLine("*** Calling: {0} ***", proc.Method.ToString());
        //
인스턴스 메소드를 호출하는가 아니면 정적메소드를 호출하는가 ?
        if (proc.Target != null)
            Console.WriteLine("--> Target: {0}", proc.Target.ToString());
        else
            Console.WriteLine("--> Target is a static method");
        //
메소드를 호출하면서 각 차를 전달한다.
        foreach (Car c in theCars)
            proc(c);
        Console.WriteLine();
    }
}

public class CarApp
{
    //
델리게이트의 대상.
    public static void WashCar(Car c)
    {
        if (c.Dirty)
            Console.WriteLine("Cleaning a car");
        else
            Console.WriteLine("This car is already clean...");
    }
    //
델리게이트의 또다른 대상.
    public static void RotateTires(Car c)
    {
        if (c.Rotate)
            Console.WriteLine("Tires have been rotated");
        else
            Console.WriteLine("Don't need to be rotated...");
    }
    public static int Main(string[] args)
    {
        //
정비 공장을 만든다.
        Garage g = new Garage();
        //
더러운 차를 세차한다.
        g.ProcessCar(new Car.CarDelegate(WashCar));
        //
타이어를 교체한다.
        g.ProcessCar(new Car.CarDelegate(RotateTires));
        return 0;
    }
}

Output

Attachment:

delegate04.JPG

멀티캐스트 델리게이트를 이용하면 여러 델리게이트를 한번에 호출할 수 있다.
멀티캐스트 델리게이트는 여러가지 방법으로 구현할 수 있다.

Code:

public static int Main(string[] args)
{
    //
정비 공장을 만든다.
    Garage g = new Garage();
    //
두 개의 델리게이트를 새로 정의한다.
    Car.CarDelegate wash = new Car.CarDelegate(WashCar);
    Car.CarDelegate rotate = new Car.CarDelegate(RotateTires);
    //
멀티캐스트 델리게이트에 오버로드된 + 연산자를 이용할 수 있다.
    g.ProcessCar(wash + rotate);
    return 0;
}


+
연산자는 정적 Delegate.Combine() 메소드를 호출하는 약어 표시이다.

Code:

// + 연산자는 Combie() 메소드와 동일한 효과를 발휘한다.
g.ProcessCar((Car.CarDelegate)Delegate.Combine(wash + rotate));


이 새 델리게이트를 나중에도 사용하려면 다음과 같이 작성할 수도 있다.

Code:

// 두 개의 델리게이트를 새로 정의한다.
Car.CarDelegate wash = new Car.CarDelegate(WashCar);
Car.CarDelegate rotate = new Car.CarDelegate(RotateTires);
//
이 새로운 델리게이트를 나중에 사용하기 위해서 저장해 둔다.
MulticastDelegate d = wash + rotate;
//
이 새로운 델리게이트를 ProcessCars() 메소드로 보낸다.
g.ProcessCar((Car.CarDelegate)d);


멀티캐스트 델리게이트를 목록에서 항목을 제거하고 싶으면, Remove() 메소드를 호출하면 된다.

Code:

// 이 정적 Remove() 메소드는 Delegate 형식을 반환한다.
Delegate washOnly = MulticastDelegate.Remove(d, rotate);
g.ProcessCars((Car.CarDelegate)washOnly);

 

 

 

 

 

 

 

비동기적 델리게이트

델리게이트 함수 호출을 멀티스레딩으로 메인 스레드와 별도의 스레드에서 실행되게 할 수도 있다.
C#
컴파일러가 'delegate' 키워드를 처리할 때, BeginInvoke() 와 EndInvoke() 라는 이름의 두 메소드가 동적으로 생성되는데 비동기적으로 호출할때 사용된다.

동기 델리게이트의 호출

Code:

using System;
using System.Threading;

public class CarApp
{
    public static void MyPrint(string msg)
    {
        Console.WriteLine("MyPrint() is on thread {0}", Thread.CurrentThread.GetHashCode());
        Thread.Sleep(10000);
        Console.WriteLine("msg : {0}", msg);
    }    
    public delegate void NewDelegate(string msg);
    public static int Main(string[] args)
    {
        Console.WriteLine("Main() is on thread {0}", Thread.CurrentThread.GetHashCode());
        NewDelegate d = new NewDelegate(MyPrint);
        d("Your function is ready !");
        Console.WriteLine("Done invoking delegate");
        return 0;
    }
}


Output

Attachment:

delegate05.JPG

 

 

 

 

메소드를 비동기적으로 호출하기.

Code:

using System;
using System.Threading;

public class CarApp
{
    public static void MyPrint(string msg)
    {
        Console.WriteLine("MyPrint() is on thread {0}", Thread.CurrentThread.GetHashCode());
        Thread.Sleep(10000);
        Console.WriteLine("msg : {0}", msg);
    }    
    public delegate void NewDelegate(string msg);
    public static int Main(string[] args)
    {
        Console.WriteLine("Main() is on thread {0}", Thread.CurrentThread.GetHashCode());
        NewDelegate d = new NewDelegate(MyPrint);
        IAsyncResult itfAR = d.BeginInvoke("Your function is ready !", null, null);
        Console.WriteLine("Done invoking delegate");
        //
다른 작업을 한다...
        d.EndInvoke(itfAR);
        return 0;
    }
}


Output

Attachment:

delegate06.JPG

 

 

 

 

 

 

비동기적 델리게이트로서의 콜벡

Code:

using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

public class CarApp
{
    //
델리게이트 함수 호출이 완료되었을때 호출될 함수.
    public static void MyCallBack(IAsyncResult itfAR)
    {
        Console.WriteLine("DelegateCallBack on thread {0}", Thread.CurrentThread.GetHashCode());
        AsyncResult res = (AsyncResult)itfAR;
        NewDelegate d = (NewDelegate)res.AsyncDelegate;
        d.EndInvoke(itfAR);
    }
    public static void MyPrint(string msg)
    {
        Console.WriteLine("MyPrint() is on thread {0}", Thread.CurrentThread.GetHashCode());
        Thread.Sleep(10000);
        Console.WriteLine("msg : {0}", msg);
    }    
    public delegate void NewDelegate(string msg);
    public static int Main(string[] args)
    {
        Console.WriteLine("Main() is on thread {0}", Thread.CurrentThread.GetHashCode());
        NewDelegate d = new NewDelegate(MyPrint);
        d.BeginInvoke("Your function is ready !", new AsyncCallback(MyCallBack), null);
        Console.WriteLine("Done invoking delegate");
        Console.ReadLine(); //
호출을 마칠때까지 콘솔이 떠 있게 하기 위해.
        return 0;
    }
}


Output

Attachment:

delegate07.JPG

 

 

C# 의 동기화동기화를 하지 않은 소스 예제

Code:

using System;
using System.Threading;

internal class WorkerClass
{
    private int theInt;
    public void DoSomeWork()
    {
        theInt++;
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("theInt: {0}, i: {1}, current thread: {2}",
                theInt, i, Thread.CurrentThread.Name);
            Thread.Sleep(1000);
        }
    }
}

public class App
{
    public static void Main()
    {
        //
단일 작업 객체를 만든다.
        WorkerClass w = new WorkerClass();
        //
세개의 부 스레드를 만들어 각 스레드가 동일한 공유객체를 호출하게 만든다.
        Thread threadA = new Thread(new ThreadStart(w.DoSomeWork));
        threadA.Name = "A";
        Thread threadB = new Thread(new ThreadStart(w.DoSomeWork));
        threadB.Name = "B";
        Thread threadC = new Thread(new ThreadStart(w.DoSomeWork));
        threadC.Name = "C";
        //
하나씩 시작시킨다.
        threadA.Start();
        threadB.Start();
        threadC.Start();
    }
}


Output

Attachment:

thread03.JPG




lock
키워드를 이용한 동기화

'lock'
키워드를 이용하면 코드 블록을 잠가서 현재 스레드가 작업을 완전히 끝낼 때까지 다른 스레드들이 기다리게 만들 수 있다.
'lock'
키워드를 이용하려면 lock 수행문의 범위로 진입하기 위해 스레드가 얻어야 하는 토큰(객체 참조자)을 전달해야 한다.
인스턴스 레벨 메소드를 잠그려면, 현재 형식에 대한 참조자를 전달하기만 하면 된다.

Code:

internal class WorkerClass
{
    private int theInt;
    public void DoSomeWork()
    {
        lock (this)
        {
            theInt++;
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("theInt: {0}, i: {1}, current thread: {2}",
                    theInt, i, Thread.CurrentThread.Name);
                Thread.Sleep(1000);
            }
        }
    }
}


Output

Attachment:

thread04.JPG

 

System.Threading.Monitor 형식을 이용한 동기화

C#
의 lock 수행문은 System.Threading.Monitor 클래스 형식을 이용한 작업을 간소화한 것이다.
Monitor
형식을 이용하면 실행 스레드가 일정 시간 동안 기다리게 하거나(Wait() 메소드를 통해서), 현재 스레드가 완료되었을 때 기다리고 있는 스레드들에게 알려주도록할 수 있다.
내부적으로, 앞의 잠금 로직은 실제로 다음과 같이 처리된다.

Code:

internal class WorkerClass
{
    private int theInt;
    public void DoSomeWork()
    {
        //
모니터에 토큰과 함께 진입한다.
        Monitor.Enter(this);
        try
        {
            theInt++;
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine("theInt: {0}, i: {1}, current thread: {2}",
                    theInt, i, Thread.CurrentThread.Name);
                Thread.Sleep(1000);
            }
        }
        finally
        {
            //
모니터를 나가서 토큰을 해제해야 한다.
            Monitor.Exit(this);
        }
    }
}



 

 

 


System.Threading.Interlocked
형식을 이용한 동기화

System.Threading
네임스페이스는 단일 데이터 포인트에서 원자적으로 연산하는 데 이용할 수 있는 형식을 제공한다.

Interlocked 형식의 멤버

  • Increment() : 값을 1만큼 안전하게 증가시킨다.
  • Decrement() : 값을 1만큼 안전하게 감소시킨다.
  • Exchange() : 두 값을 안전하게 교환한다.
  • CompareExchange() : 두 값이 같은지 안전하게 검사하고, 같으면 하나의 값을 세 번째 값으로 바꾼다.


원자적으로 단일 값을 변경하는 과정은 다중 스레드 환경에서 매우 일반적이다. 따라서 동기화 코드를 lock 을 이용해서 작성하기 보다는 Interlocked 형식을 사용하여 작성하는 것이 좋다.

Code:

int i=0;
lock(this)
{ i++; }

 

Code:

// 변경하고자 하는 값을 참조로 전달한다.
int i=0;
Interlocked.Increment(ref i);

 

Code:

int i=9;
Interlocked.Exchange(ref i, 83);

 

Code:

// i의 값이 현재 83 이면, i를 99로 바꾼다.
Interlocked.CompareExchange(ref i, 83, 99);

 

 

 

 

 

 

 

 

Timer Callback 을 이용한 프로그래밍

 

응용 프로그램에서 일정한 간격을 두고 특정 메소드를 호출해야 하는 경우가 종종 있다. 예를 들어, 도우미 함수를 통해 현재 시간을 상태 바에 표시하는 응용 프로그램이 있을 수 있다. 도 다른 예로, 이메일 메시지를 확인하는 백그라운드 작업을 수행하기 위해서 수시로 도우미 함수를 호출하는 응용 프로그램을 만들 수도 있을 것이다.
이러한 경우, System.Threading.Timer 형식을 TimerCallback 이라는 이름의 관련 델리게이트와 함께 이용할 수 있다.
델리게이트 대상이 사용할 정보를 보내고 싶으면, 생성자의 두번째 매개변수에 있는 null 값을 적당한 정보로 바꾸면 된다.

 

Code:

using System;
using System.Threading;

public class App
{
    static void PrintTime(object state)
    {
        Console.WriteLine("Time is: {0}", DateTime.Now.ToLongTimeString());
    }

    public static void Main()
    {
        TimerCallback timeCB = new TimerCallback(PrintTime);
        Timer t = new Timer(
            timeCB, // TimerCallback
델리게이트 형식.
            null,   //
호출된 메소드로 전달될 정보 (정보가 없으면 null)
            0,      //
시작하기 전에 기다릴 시간.
            1000);  //
호출 사이의 간격
        Console.WriteLine("Hit key yo terminate...");
        Console.ReadLine();
    }
}

 

 

 

 

 

 

 

 

System.Type 클래스

 

System.Type 클래스에는 현재 관찰 중인 형식에 대한 중요한 정보를 추출해 내는데 이용할 수 있는 여러 가지 메소드들이 포함되어 있다.

System.Type 의 멤버

  • IsAbstract / IsArray / IsClass / IsCOMObject / IsEnum / IsInterface / IsPrimitive / IsNestedPublic / IsNestedPrivate / IsSealed / IsValueType
    :
    이 속성들을 이용하면 참조하고 있는 Type 에 대한 여러 가지 기본적인 정보를 알아낼 수 있다. (즉, 추상 메소드인지, 배열인지, 중첩 클래스인지 등)
  • GetConstructors() / GetEvents() / GetFields() / GetInterfaces() / GetMombers() / GetNestedTypes() / GetProperties() 
    :
    이 메소드들을 이용하면 알아내고 싶은 항목들(인터페이스, 메소드, 속성 등)을 나타내는 배열을 얻을 수 있다. 각 메소드들은 관련된 배열을 반환한다
  • FindMembers() : 검색 기준에 기반해서, MemberInfo 형식의 배열을 반환한다.
  • GetType() : 이 정적 메소드는 해당 문자열 이름에 대한 Type 인스턴스를 반환한다.
  • InvokeMember() : 이 메소드를 이용하면 해당 아이템에서 late 바인딩을 이용할 수 있다.




형식 참조자 얻기

1. System.Object
에 정의된 메소드로서 Type 클래스의 인스턴스를 반환하는 GetType() 이라는 메소드를 이용할 수 있다.

Code:

// 유효한 Foo 인스턴스를 이용해서 Type 을 추출한다.
Foo theFoo = new Foo();
Type t = theFoo.GetType();



2. Type
클래스 자체를 이용해서 정적 멤버인 GetType() 을 호출하고 얻어내고자 하는 항목의 이름을 지정할 수 있다.

Code:

// 정적 메소드인 Type.GetType() 을 이용해서 Type 을 가져온다.
Type t = null;
t = Type.GetType("Foo");
//
별도의 어셈블리에 있는 중첩 형식을 가져온다.
t = Type.GetType("MyNamespace.OuterType+NestedType, myOtherAsm");



3. C#
의 typeof() 연산자를 이용해서 Type 의 인스턴스를 얻을 수도 있다.

Code:

// typeof 를 이용해서 Type 을 가져온다.
Type t = typeof(Foo);



 

 

 


Type
클래스 활용 예제

Code:

using System;
using System.Reflection;

namespace TheType
{
    //
두 개의 인터페이스
    public interface IFaceOne
    { void MethodA(); }
    public interface IFaceTwe
    { void MethodB(); }
    // Foo
는 이 두 인터페이스를 지원한다.
    public class Foo : IFaceOne, IFaceTwe
    {
        //
필드
        public int MyIntField;
        public string myStringField;
        //
메소드
        public void myMethod(int p1, string p2) { }
        //
속성
        public int MyProp
        {
            get { return MyIntField; }
            set { MyIntField = value; }
        }
        //
인터페이스
        public void MethodA() { }
        public void MethodB() { }
    }


    public class App
    {
        public static void Main()
        {
            Foo f = new Foo();
            Type t = f.GetType();
            Console.WriteLine("***** Various stats about Foo *****");
            Console.WriteLine("Full name is: {0}", t.FullName);
            Console.WriteLine("Base is: {0}", t.BaseType);
            Console.WriteLine("Is it abstract? {0}", t.IsAbstract);
            Console.WriteLine("Is it a COM object? {0}", t.IsCOMObject);
            Console.WriteLine("Is it sealed? {0}", t.IsSealed);
            Console.WriteLine("Is it a class? {0}", t.IsClass);
            Console.WriteLine("***** Properties of Foo *****");
            PropertyInfo[] pi = t.GetProperties();
            foreach (PropertyInfo prop in pi)
                Console.WriteLine("Prop: {0}", prop.Name);
            Console.WriteLine("***** Methods of Foo *****");
            MethodInfo[] mi = t.GetMethods();
            foreach (MethodInfo m in mi)
                Console.WriteLine("Method: {0}", m.Name);
            Console.WriteLine("***** Fields of Foo *****");
            FieldInfo[] fi = t.GetFields();
            foreach (FieldInfo field in fi)
                Console.WriteLine("Field: {0}", field.Name);
            Console.WriteLine("***** Interfaces of Foo *****");
            Type[] ifaces = t.GetInterfaces();
            foreach (Type i in ifaces)
                Console.WriteLine("Interface: {0}", i.Name);
            Console.WriteLine("**************************");
        }
    }
}


Output

Attachment:

type01.JPG


 

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

MVC4 Could not load type 'System.ServiceModel.Activation.HttpModule'

PROGRAMING/ASP.NET 2014. 11. 25. 13:49

Could not load type 'System.ServiceModel.Activation.HttpModule'


Have you started working on a .NET 4.0 project and received the following error?
Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.Exception Details: System.TypeLoadException: Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly ‘System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

If you have, you probably have installed .Net framework 4.0 on IIS and then enable either a .Net 3.0 or 3.5 WCF feature.  To fix you need to reconfigure ASP.NET by using the following command depending on the version of ASP.NET you have installed.

IIS 32 bit

%SYSTEMROOT%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis /iru

IIS 64 bit

%SYSTEMROOT%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis /iru


출처: http://www.jasonlinham.co.uk/2011/11/could-not-load-type-systemservicemodela.html

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,

Class Web system vs AJAX web system

FUNDAMENT CONCEPT 2014. 2. 21. 09:16

AJAX is a well-known acronym for Asynchronous JavaScript and XML. AJAX is not a single technology, but is a group of interrelated web development techniques used to create asynchronous web applications. With AJAX, web applications can send data to, and retrieve data from, the web server asynchronously without interfering with the display and behavior of the existing page and in this way full page reloads are avoided.

In the diagram below, I present, by using UML diagrams, the Classic Web System Model and the AJAX Web System Model.



Like you can see from the diagrams above in the case of the classic model, for each user request from the User Interface component (from the Browser Client) is send an HTTP request directly to the Web Application (that runs on the Web Server), and the Web Application does some processing and sends back the response as an HTML page (HTTP + CSS) to the browser, and finally the browser renders the entire response.

In the case of AJAX based web applications, when the user requests, the User Interface component sends a JavaScript call to the AJAX Engine component of the browser. This engine is responsible for both rendering the interface the user sees and communicating with the server on the user’s behalf. The AJAX engine allows the user’s interaction with the application to happen asynchronously—independent of the communication with the server. Note that the AJAX Engine sends to the Web Application an HTTP request and receives back as response only the needed data (and not the entire HTML page) in XML format.


refer from : http://www.codeproject.com/Articles/594150/MVC-Basic-Site-Step-4-jqGrid-In

저작자표시 비영리 (새창열림)
블로그 이미지

파란실버라이트

To remember the time when I started learning Silver Light!

,
  • «
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • ···
  • 29
  • »

카테고리

  • Inforamtion Technology (281)
    • DESIGN PATTERN (33)
      • 실용주의 디자인패턴 (29)
    • SOFTWARE ENGINEERING (21)
      • Art Of Readable Code (12)
      • Object Oriented Programming (6)
      • TDD (2)
    • FRAMEWORK (22)
      • Spring.net (2)
      • LightSwitch (20)
    • PROGRAMING (58)
      • C# (20)
      • .NET (6)
      • HTML5 (7)
      • ASP.NET (9)
      • SILVERLIGHT (7)
      • Ruby On Rails (6)
    • PROJECT MANAGEMENT (10)
      • SW Version Management (7)
      • Schedulring Management (1)
    • BOOKS (18)
    • MOBILE APP (1)
      • SENCHA TOUCH (1)
    • SECURITY (5)
    • MES (1)
    • B2B (14)
      • WEBMETHODS (4)
    • ERP (53)
      • SAP/R/3 (51)
    • ABOUT TOOLS (2)
    • FUNDAMENT CONCEPT (21)
    • SOA BPM (22)
    • PORTFOLIO (0)

태그목록

  • 동시성
  • 병렬
  • 프로그래밍

최근에 받은 트랙백

글 보관함

링크

파란실버라이트

블로그 이미지

To remember the time when I started learning Silver Light!

LATEST FROM OUR BLOG

RSS 구독하기

LATEST COMMENTS

BLOG VISITORS

  • Total :
  • Today :
  • Yesterday :

Copyright © 2015 Socialdev. All Rights Reserved.

티스토리툴바