사 놓은지는 꽤 되었지만 최근에서야 정독하게 된 전공서적입니다.



.Net Framework 속 깊은 부분에 대해서 심도있게 정리한 책으로 가볍게 접근하면 어려운 책입니다. 하지만 닷넷 Framework 의 속 깊은 부분에 대해 이해하기에는 많은 도움이 될 것 같습니다.


닷넷 환경에서 개발하시는 분들이라면 시간내어 살펴보시면 좋을 듯 싶네요.



목차

들어가며

1장. 성능 측정과 도구
- 측정 대상 선택
- 평균 VS. 백분위
- 측정 도구
- 요약

2장. 가비지 수집
- 기본 동작
- 구성 옵션
- 할당 비율 감소
- 가장 중요한 규칙
- 개체 수명 줄이기
- 트리의 깊이 줄이기
- 개체들 간의 참조 줄이기
- 고정 피하기
- 종료자 피하기
- 큰 개체 할당 피하기
- 버퍼 복사 피하기
- 수명이 긴 풀과 큰 개체
- 큰 개체 힙 조각화 줄이기
- 전체 GC 수행을 강제하는 환경
- 필요에 따라 대형 개체 힙 조각 모음
- 수집 발생 전에 수집 알림 받기
- 캐시를 위한 약한 참조 사용
- GC 성능 측정과 조사
- 요약

3장. JIT 컴파일
- JIT 컴파일의 이점
- JIT 컴파일의 비용
- JIT 컴파일의 최적화
- JIT와 시작 시간 줄이기
- 프로파일링으로 JITing 최적화
- NCEN 사용 시기
- JIT가 경쟁력이 없을 때
- 측정
- 요약

4장. 비동기 프로그래밍
- Tasks 사용
- 병렬 루프
- 차단 피하기
- I/O 차단을 피하기 위한 Tasks 사용
- Async와 Await
- 프로그램 구조에 관한 고찰
- 올바른 타이머 사용
- 바람직한 시작 스레드 풀 크기
- 스레드를 중단하지 않는다
- 스레드 우선순위를 변경하지 않는다
- 스레드 동기화와 잠금
- 측정
- 요약

5장. 일반 코딩 및 클래스 설계
- 클래스와 구조체
- 구조체에 대한 Equals 및 GetHashCode 오버라이드
- 가상 메서드 및 봉인 클래스
- 인터페이스 디스패치
- 박싱 피하기
- For와 Foreach
- 캐스팅
- 플랫폼 호출(P/Invoke)
- 대리자
- 예외
- Dynamic
- 코드 생성
- 전처리
- 측정
- 요약

6장. .NET 프레임워크 사용
- 호출하는 모든 API를 이해하자
- 동일한 작업을 하는 여러 API
- 컬렉션
- 문자열
- 정상적인 상황에서 예외 발생 API 회피하기
- 대형 개체 힙에서 할당한 API 회피하기
- 느슨한 초기화 사용
- 열거의 높은 비용
- 추적 시간
- 정규 표현식
- LINQ
- 파일 읽기
- HTTP 설정 및 네트워크 통신 최적화
- 리플렉션
- 측정
- 요약

7장. 성능 카운터
- 존재하는 카운터 사용
- 사용자 정의 카운터 생성
- 요약

8장. EWT 이벤트
- 이벤트 정의
- PerfView에서 사용자 정의 이벤트 사용
- 사용자 정의 ETW 이벤트 수신자 생성
- EventSource 데이터 상세 구하기
- 사용자 정의 PerfView 분석 확장
- 요약

9장. Windows Phone
- 도구
- 가비지 수집 및 메모리
- JIT
- 비동기 프로그래밍과 메모리 모델
- 기타 고려 사항
- 요약

10장. 코드 안정성
- OS와 API와 하드웨어 기본 이해하기
- 코드의 특정 영역에서 API 사용 제한하기
- 중앙 집중화 및 성능에 민감한 추상화와 어려운 코드
- 비관리 또는 안전하지 않은 코드 격리
- 입증 전까지 성능에 대한 코드 무결성 유지
- 요약

11장. 성능을 고민하는 팀 꾸리기
- 중요한 성능 영역 이해
- 효과적인 테스트
- 성능 인프라 및 자동화
- 숫자만을 신뢰하자
- 효과적인 코드 리뷰
- 교육
- 요약













모바일 서비스를 하기 위해서는 서버 또는 외부에서 정해진 스케쥴에 의해 푸시를 발송하는 경우가 빈번합니다. 요즘은 클라우드 서비스를 비롯하여 Facebook 에서도 약간의 비용을 받고 푸시 발송 솔루션을 제공하는데요.. 굳이 외부 솔루션을 사용하지 않고 직접 Push 서비스를 구축할 수 있는 오픈 라이브러리를 소개합니다. 간단한 사용으로 푸시의 모든 기능을 손쉽게 구축할 수 있는 매력적인 솔루션입니다.



1. APNS 발송 처리 부분
// Configuration (NOTE: .pfx can also be used here)
var config = new ApnsConfiguration (ApnsConfiguration.ApnsServerEnvironment.Sandbox, 
    "push-cert.p12", "push-cert-pwd");

// Create a new broker
var apnsBroker = new ApnsServiceBroker (config);

// Wire up events
apnsBroker.OnNotificationFailed += (notification, aggregateEx) => {

    aggregateEx.Handle (ex => {

        // See what kind of exception it was to further diagnose
        if (ex is ApnsNotificationException) {
            var notificationException = (ApnsNotificationException)ex;

            // Deal with the failed notification
            var apnsNotification = notificationException.Notification;
            var statusCode = notificationException.ErrorStatusCode;

            Console.WriteLine ($"Apple Notification Failed: ID={apnsNotification.Identifier}, Code={statusCode}");

        } else {
            // Inner exception might hold more useful information like an ApnsConnectionException           
            Console.WriteLine ($"Apple Notification Failed for some unknown reason : {ex.InnerException}");
        }

        // Mark it as handled
        return true;
    });
};

apnsBroker.OnNotificationSucceeded += (notification) => {
    Console.WriteLine ("Apple Notification Sent!");
};

// Start the broker
apnsBroker.Start ();

foreach (var deviceToken in MY_DEVICE_TOKENS) {
    // Queue a notification to send
    apnsBroker.QueueNotification (new ApnsNotification {
        DeviceToken = deviceToken,
        Payload = JObject.Parse ("{\"aps\":{\"badge\":7}}")
    });
}

// Stop the broker, wait for it to finish   
// This isn't done after every message, but after you're
// done with the broker
apnsBroker.Stop ();



APNS 발송 처리시 더 이상 유효하지 않은 단말의 토큰을 Feedback 서비스를 통해 삭제하는 작업을 별도로 진행해 줘야만 합니다.

2. APNS Feedback 처리
var config = new ApnsConfiguration (
    ApnsConfiguration.ApnsServerEnvironment.Sandbox, 
    Settings.Instance.ApnsCertificateFile, 
    Settings.Instance.ApnsCertificatePassword);

var fbs = new FeedbackService (config);
fbs.FeedbackReceived += (string deviceToken, DateTime timestamp) => {
    // Remove the deviceToken from your database
    // timestamp is the time the token was reported as expired
};
fbs.Check ();



GCM 의 경우 발송 처리시에 유효하지 않은 단말이라는 결과를 전달 해 줌으로 한 번의 작업으로 깔끔하게 마무리 할 수 있습니다.

3. GCM Push 처리

// Configuration
var config = new GcmConfiguration ("GCM-SENDER-ID", "AUTH-TOKEN", null);

// Create a new broker
var gcmBroker = new GcmServiceBroker (config);

// Wire up events
gcmBroker.OnNotificationFailed += (notification, aggregateEx) => {

    aggregateEx.Handle (ex => {

        // See what kind of exception it was to further diagnose
        if (ex is GcmNotificationException) {
            var notificationException = (GcmNotificationException)ex;

            // Deal with the failed notification
            var gcmNotification = notificationException.Notification;
            var description = notificationException.Description;

            Console.WriteLine ($"GCM Notification Failed: ID={gcmNotification.MessageId}, Desc={description}");
        } else if (ex is GcmMulticastResultException) {
            var multicastException = (GcmMulticastResultException)ex;

            foreach (var succeededNotification in multicastException.Succeeded) {
                Console.WriteLine ($"GCM Notification Failed: ID={succeededNotification.MessageId}");
            }

            foreach (var failedKvp in multicastException.Failed) {
                var n = failedKvp.Key;
                var e = failedKvp.Value;

                Console.WriteLine ($"GCM Notification Failed: ID={n.MessageId}, Desc={e.Description}");
            }

        } else if (ex is DeviceSubscriptionExpiredException) {
            var expiredException = (DeviceSubscriptionExpiredException)ex;

            var oldId = expiredException.OldSubscriptionId;
            var newId = expiredException.NewSubscriptionId;

            Console.WriteLine ($"Device RegistrationId Expired: {oldId}");

            if (!string.IsNullOrWhitespace (newId)) {
                // If this value isn't null, our subscription changed and we should update our database
                Console.WriteLine ($"Device RegistrationId Changed To: {newId}");
            }
        } else if (ex is RetryAfterException) {
            var retryException = (RetryAfterException)ex;
            // If you get rate limited, you should stop sending messages until after the RetryAfterUtc date
            Console.WriteLine ($"GCM Rate Limited, don't send more until after {retryException.RetryAfterUtc}");
        } else {
            Console.WriteLine ("GCM Notification Failed for some unknown reason");
        }

        // Mark it as handled
        return true;
    });
};

gcmBroker.OnNotificationSucceeded += (notification) => {
    Console.WriteLine ("GCM Notification Sent!");
};

// Start the broker
gcmBroker.Start ();

foreach (var regId in MY_REGISTRATION_IDS) {
    // Queue a notification to send
    gcmBroker.QueueNotification (new GcmNotification {
        RegistrationIds = new List { 
            regId
        },
        Data = JObject.Parse ("{ \"somekey\" : \"somevalue\" }")
    });
}

// Stop the broker, wait for it to finish   
// This isn't done after every message, but after you're
// done with the broker
gcmBroker.Stop ();
공식 다운로드는 이 곳에서 하시면 됩니다. https://github.com/Redth/PushSharp

'IT 이야기 > Code' 카테고리의 다른 글

고성능 .NET코드 프로그래밍 <책소개>  (0) 2016.11.08
Open source vs Commercial software - 1부  (0) 2015.05.27

 지난 개발 이력을 잠시 생각해 보면..

처음 직장 생활에선 C(Turbo C) 언어부터 시작해서 Delphi (Borland 제품) 을 사용하다가 .Net (VS2003 부터) 으로 넘어 왔었고..  이제는 Java 개발 쪽으로 이동하고 있습니다.

 

Turbo C(Borland), Delphi, Visual Studio .Net 이 세가지 언어와 툴은 이것만 있으면 모든 개발을 할 수 있을 정도로 완벽한 개발 환경을 제공합니다. (물론 뛰어난 기능을 갖은 상용 Library 들은 많이 있구요. ^^ )

그러다가 자바쪽으로 넘어와서 개발을 하려 하니..

 

자바 개발을 위해서 어느 것 하나만 있으면 된다는 믿음은 없어졌습니다.

말 그대로 Open source 진영이라 불러도 좋을 만큼 많은 휼륭한 기능들을 GNU License 로 포장을 하고 무료로 제공하다 보니 이러 저러한 Open source 들을 갖다 쓰지 않고서는 위의 상용 개발환경을 따라 갈 수가 없습니다.

 

그러다 보니 자연스럽게 오픈 소스 하나 둘씩 갖다 쓰게 됩니다.

이런 상황속에서 자바 개발자 vs 비자바 개발자(또는 MS 개발자) 구도로 편 가르기를 하더니 서로 우리 것이 더 낫니 어쩌니 소모성 논쟁을 많이 합니다.

물론 한 사람의 개발자로서 이런 논쟁을 지켜 보고 있으면 재미 있긴 합니다.

 

어쨌든 재미 있는 논쟁 거리를 하나 찾은 김에..

제가 겪어 본 환경 중에서 양쪽의 특징에 대해 한 번씩 정리해 보면 어떨까 싶어 비교 해 봅니다.

(물론 제가 아는 지식이 전부는 아니기에 혹시라도 잘 못 된 부분이 있으면 언제든 글 남겨 주세요. 시비는 사양이구요. ㅋ)

 

자 그 많은 비교 대상중에 요즘 이슈가 되고 있는 기능 중 하나인 Entity Mapping 기능에 대해 정리 해 봅니다.

 

Entity Mapping 이라 함은..

데이타 관점의 개발을 지향하는 방법 중 하나로서 DB 스키마 정보를 프로그램 개발 환경으로 좀 더 깊숙히 가져와서 데이타 위주의 효율적인 개발을 할 수 있도록 지원하는 환경이라고 말하고 싶습니다.

아무래도 DB 개발 따로 하고 비지니스 개발 따로 해서 두 가지를 조합하다보면 여기 저기서 문제가 될 만한 부분이 많으니 데이타 모델에 대해서는 간결하고 핵심적인 부분들을 추려서 프로그램 영역으로 가져온 후 통합 개발을 한다면 개발적인 부분에서는 생상선 향상을 가져 올 수 있다는 것이죠.

 

예를 들자면 기존에는 SP를 만들고 그 결과(Result set)을 특정 클래스로 구현해서 필요한 정보만 가져온 후 일련의 비지니스를 처리하는 방식이었다면..

Entity Mapping 방식은 SP가 됐든 Native Query 문이 됐든 DB에서 리턴하는 모든 결과셋을 해당 테이블의 Result set class 로 전달 받는 구조입니다.

어찌보면 큰 틀의 개념은 별 차이가 없어 보이기는 하지만 ..

결과셋을 재이용하는 측면에서 보면 공통된 테이블에 대해서 여러 가지 다른 결과셋을 가져오는 쿼리문이 존재할 경우에 재사용성이 증가할 수 있겠죠.

 

여기서 주목할 점은 과거엔 비지니스 위주의 개발을 했다면..  이제부턴 데이타 관점의 개발을 한다는 부분입니다.

 

사실 많은 개발 요소 중 System Core Library 모듈들을 제외하곤 데이타가 로직의 중심이니 맞는 말이겠죠 ?

 

자.. 그럼 자바 환경과 MS 환경에선 어떤 이름으로 제품이 나왔는지 보겠습니다.

 

Entity Framework (MS) : myBatis (Java)

 

참고 자료는 아래와 같습니다.

EF : http://msdn.microsoft.com/en-us/data/bb399567

iBatis : http://code.google.com/p/mybatis/

 

두 제품을 히스토리를 간단히 정리해 보자면 ..

MS 에서는 .Net Framework 3.5 부터 LinQ 라는 이름의 ORM Mapping 기능과 동적 쿼리를 생성해 주는 강력한 기능을 제공하고 있었고 자바 진영에서는 Hibernate 라는 프로덕트로 역시 동일한 기능을 제공하고 있었습니다.

양 쪽 모두 휼륭한 기능을 갖고 있었고 생산성 향상이라는 놀라운 효과를 갖고 오긴 했지만..

문제는 동적 쿼리 문을 생성하다보니 DB(Database) 입장에서는 최고의 성능을 내도록 하기 위해서는 DBA 가 아닌 개발자의 목을 졸라야만 하는 한계를 가져 오게 됩니다.

한 마디로 DBA들은 문제의 쿼리를 어떤 놈이 만드는지 모르게되고 개발자들은 혼자만의 세상을 꾸며 놓고 인수인계란 절차를 남겨 놓고 떠나게 됩니다.

 

 이러한 문제점이 비단 한국내의 문제점만은 아닌 듯 싶네요.

어쨌든 양쪽 진영에도 동일한 문제점에 대해 이슈가 되는 일이 많아졌고 이런 틈 속에서 iBatis 라는 오픈 소스가 대안으로 주목을 받기 시작합니다.

iBatis 는 동적으로 쿼리를 생성하지는 않지만 DB Result Set 에 대해서는 클래스로 맵핑할 수 있는 기능을 제공하고 쉬운 환경 설정 및 간단한 코드만으로 쉽게 개발 할 수 있는 환경을 제시합니다. 한 마디로 휼륭합니다.

그러다 최근에는 apache 진영과 이별을 했는지 myBatis 란 이름으로 바꾸면서 많은 부분 네임스페이스에서도 아파치가 사라졌습니다.

하지만 여전히 최고입니다.

 

 myBatis가 인기를 끌기 시작하면서 MS 진영에서는 .Net F/W 4.0을 Release 하게됩니다.

Entity Framework 이란 먼가 거창한 이름을 갖고 대대적인 홍보를 하게 됩니다. 이름 짓는것만 봐도 MS 답다는 느낌을 개인적으로 받습니다만.. ;;

 

아직 EF( Entity Framework) 으로 개발을 해 보지는 않아서 구체적인 기능에 대해서 논하긴 어렵지만 후발 주자로 나선 라이브러리인만큼 기존 myBatis 에서 제공하던 기능 외에도 많은 편리한 기능을 제시하지 않을까 싶습니다.

 

간단히 MS 홈페이지에 소개하는 소주제 내용을 살펴보면 아래와 같습니다.

 

  •  Giving Life to Models : 데이타 관점의 모델링
  •  Mapping Objects to Data  : ORM Mapping
  •  Accessing and Changing Entity Data  : Entity 통한 CRUD
  •  Data Providers 
  •  Entity Data Model Tools : Entity Generator
  • (우측의 글은 제가 이해한 내용에 대한 의미 부여입니다.)

     

     

    먼가 대단한게 있어 보이는데요..

    그렇다면 아키텍쳐 그림은 어떨까요 ?

     

     

    myBatis

     

     

    Entity Framework

     

     

     

    위 2가지 모델에 대해 System layer 를 구분해 정리해 보면 이런 것 같습니다.

     

     Layer

     MS

    myBatis 

    Role

     비지니스 프로그램

     Object Service

     Object

     비지니스 영역

     Entity

     Entity Data Provider

    (Mapping)

     Mapper

     Entity - Class mapping

     Data Provider

     ADO.Net

     JDBC

     DB 접속자 역활

     

    어떤가요 ?

    이름만 다를뿐 동일하지 않나요 ? ㅋㅋㅋ

    누가 먼저 만들었는지는 모르겠지만.. 소송을 걸어도 될 만한 구성인것 같습니다.

     

    EF를 사용해 봤으면 좀 더 유익한 분석을 할 수 있었을테지만 MS 툴이 엄청난 고가인지라 회사에 라이센스가 없습니다.

    트라이얼 버젼을 설치해서 해 볼까도 생각이 들지만..

    귀차니즘으로 인해 스킵합니다.

     

    어찌됐든 양쪽 진영이 Data Driven Architecture 를 좀 저 자연스럽게 지원할 수 있는 환경을 제시한다는 점에서는 매우 고무적입니다. 이를 통해서 MVC 모델로 개발하기도 쉬워지고 굳이 방법론에 대해 잘 몰라도 그냥 쓰다보면 방법론을 적용할 수 있다는 것이 매우 흥미로운 것 같습니다.

    + Recent posts