2012년 6월 30일 토요일

JavaScript Web Applications (한빛미디어)




이 책은 자바스크립트 애플리케이션 개발 시 유용한 아키텍쳐 패턴인 MVC 패턴을 소개하고, 이 패턴을 애플리케이션에 적용하는 데 도움을 주는 여러 모듈의 사용 방법 및 테스트를 위한 프레임워크 그리고 HTML5의 파일API, 웹소켓에 대해서 다루고 있습니다.

이제는 웹 애플리케이션이 단순히 서버에서 제공하는 정보를 보여주는 것이 아니라 클라이언트에서 복잡한 연산과 로컬 데이터 생성 및 관리가 필요하게 되었습니다. 곧 네이티브 어플리케이션이 하는 작업을 웹 애플리케이션에서도 수행을 할 수 있게 된것인데, 이는 웹 프로그램도 네이티브 프로그램처럼 복잡해진다는 것을 의미합니다. 따라서 구조화된 개발이 필요하게 되었고, 이 책은 MVC 패턴으로 웹 애플리케이션을 구조화를 할 수 있도록 모델, 컨트롤러, 뷰 컴포넌트에 대해 아주 자세히 설명하고 있습니다. 책 후반부에서는 이 패턴 사용에 필요한 라이브러리인 스파인, 백본, 자바스크립트MVC 라이브러리를 다루고, 간단한 애플리케이션 예제를 통해 라이브러리를 어떻게 활용하는지 설명하고 있습니다. 또한 프로그램이 커져가면서 자연히 의존하는 모듈이 늘어가게 되는데 이러한 의존성을 관리하는 방법을 다루고 있습니다.

이 책의 서두에서 대상독자는 자바스크립트 초보자가 대상이 아니라고 말하고 있지만, 정말 쌩초보(?)가 아니라면 이책을 권하고 싶습니다. 본격적인 개발경험을 하기 전에 이 책을 통해 유용한 자바스크립트 아키텍쳐 패턴인 MVC 패턴에 대해 알고 익힐 수 있다면 실제 개발에 큰 도움이 될 것입니다. 
자바스크립트를 쓸 줄 아는 개발자에서 자바스크립트를 잘! 쓸 수 있는 개발자로 변신하고 싶다면 꼭 이책을 읽기를 바랍니다.

2012년 6월 23일 토요일

About Renderer process


How browser process manages the number of renderer process?

As you may know, chromium has multi process architecture. In this architecture many renderer processes are running. You can see many renderer processes running by ps command(in linux) or task manager(in Windows) When we use chromium browser, many renderer processes are created and destroyed. It lives long or very short depends on the situation.
In this document, I’ll cover two topics. First one is when new renderer process is created. Second is how the number of renderer processes are controlled.

Topic 1. When renderers are created and destroyed?

1. At start time

When user execute chromium, new renderer is created with new tab. If only one tab is opened, one renderer is created. If many tabs are opened, many renderers are created. The number of renderer process depends on installed system memory and --renderer-process-limit option. The number of renderer process will be covered second section.

2.  Type new url to omnibox of opened tab

When user types new url, whether new renderer process is created or not is depends on below two options.
*process-per-site-instance
This is a current default process model. If user don’t add either process-per-site or process-per-tab, this mode is used. When you type new url to current tab, renderer is replaced.
I’m curious about separate visits to the same site on the same tab. Sometime, renderer process is replaced in this case.
In this mode, different tabs have different renderer regardless of its domain.
* process-per-site
If you type url that have different domain to current tab, new renderer is created for current tab. And old renderer is destroyed. Otherwise(typed url that have same domain), existing renderer is used for rendering new url.
  ex1) Current tab is in www.google.com and you type gmail.google.com, current renderer is
           used because two url have same domain(google.com).
  ex2) Current tab is in www.google.co.kr and you type gmail.google.com, current renderer is
          destroyed and new renderer process is launched because two url has different domain.
In this mode,  many tabs that have same domains are grouped in a renderer.
* process-per-tab
When user add this switch value, one renderer process is used before the tab is closed. I found that this mode has some bug when I enabled low-memory-observer.

3. Add new tab

When user clicks new tab button, NTP(New Tab Page) that show most visited pages or installed webapp is created.  Opening many NTP sequentially don’t  create renderer process. When user insert url on the NTP, new renderer is also created if renderer limit is not exceeded. If user types new url or click page snap, new renderer is created and existed renderer is destroyed. This behavior also depends --process-per-tab or --process-per-site.

4. OOM Handler (chromeos)

When browser process receive oom event from kernel’s low-mem notifier, browser process choose least recently used tab’s renderer process. And that renderer is discarded.

Topic 2. How many renderers are created?


As I mentioned earlier, you can see many renderers. The number of tabs is not equals the number of renderer process. In this topic, I’ll explain what determines the number of renderer process

1.  --renderer-process-limit=N

Browser process only creates renderer process up to N. When new tab is created, RenderProcessHost checks whether this switch is used.

2. --single-process

Browser process don’t create renderer process if this is on.

3. Installed system memory

If above switches are not used, max number of renderer process is calculated based on installed system memory not available memory.
You can see the formula that calculates the max number of renderer process in the RenderProcessHost::GetMaxRendererProcessCount().

4. The number of Extension service process

If there is a room to create another renderer process, chromium considers running extension service. Browser process don’t create renderer if extension service process number is bigger than max number of render process * 0.3.
Refer to ChromeContentBrowserClient::ShouldTryToUseExistingProcessHost().

5. Click the link

When user clicks url link with target attribute ‘_blank’, new tab is created for that link. But, browser process don’t create new renderer process and share its parent’s renderer process. When I click many links from same webpage, only one renderer is used for all created tabs.

2012년 5월 30일 수요일

읽기 좋은 코드가 좋은 코드다 (한빛미디어)



"읽기 쉬운 100줄의 코드는 읽기 어려운 50줄의 코드에 비해서 훨씬 낫다"

회사의 프로젝트를 수행하면서 직접 개발을 하는 경우가 많지만, 이에 못지않게 이미 개발된 소스코드를 분석하는 일도 많다.
남의 소스코드를 분석하다보면 잘 이해가 되는 소스가 있는 반면, 여러번 봐야하고, 심지어 필기를 해가며 분석을 해가야 이해가 되는 소스가 있다. 함수가 어떤 동작을 수행하는지 알기 위해 코드 한줄 한줄을 다 읽어야 이 함수가 무슨 일을 하는 지 알수 있다면 이 코드의 분석은 정말 끔찍하고 피하고 싶은 일이 될것이다.
이 책을 읽고 난 뒤, "이 코드는 이 부분 때문에 가독성이 참 떨어지네" 라고 잡아낼 수 있는 감이 생긴 것 같다. 물론 직접 코딩을 할 때도 많은 도움이 될 것이다.

이 책은 얇다. 삽화, 소스코드, 글 들이 잘 배치가 되어있어서 지루하지않고 재미있게 읽을 수 있고, 250페이지 정도여서 짧은 시간에 읽을 수 있는 분량이다.
저자들은 예제를 통해서 이 코드는 왜 나쁜지, 어떻게 하면 읽기 좋은 코드가 되는지를 설명하고 있다. 저자들이 직접 개발했던 코드들, 오픈소스 코드들(크로미움 프로젝트 등)에서 어떠한 부분이 읽기 좋지 않았고, 어떻게 개선이 되서 읽기 좋은 코드가 되었는지 잘 설명을 해주고 있다. 설명을 위해 만든 코드가 아닌, 문제가 있었던 코드들을 찾아서 사용하고 있어서 그런지 예제들이 참 좋았던 것 같다.

이 책은 총 네 파트로 구성 되어있다.
첫번째 파트 (표면적 수준에서의 개선) - 파트 이름대로 표면적 수준에서의 개선할 수 있는 내용들을 설명하고 있다. 변수명, 함수명, 주석등을 통해 코드를 접했을 때 바로 보이는 부분들을 다루고 있다.
두번째 파트 (루프와 논리를 단순화하기) - 조건문, 루프 (do/while, goto)를 분석하기 쉽게 구성하는 방법, 큰 논리를 단순한 작은 논리로 단순화하여, 읽는 사람이 쉽게 소화할 수 있는 방법을 제시하고 있다.
세번째 파트 (코드 재작성하기) - 큰 흐름과 관계없는 작은 문제들로 쪼갠다음 분리하고, 작업은 한번에 하나씩이라는 원리를 토대로 작업을 재정리하는 방법을 다루고 있다.
네번째 파트 (선택된 주제들) - 이 파트에서는 테스트 코드의 가독성에 대해 다루고, 분/시간 카운터 설계 및 구현과정을 진행하면서 어떻게 가독성을 높여가는지 보여주고 있다.

소프트웨어 엔지니어라는 직업을 가지고도 변수 명, 변수 선언 위치 등에 대해 고민하고 구현을 했었던 적이 과연있었나 싶고, 부끄럽기까지하다. 이 책의 내용들을 통째로 머릿속에 집어넣고 다니고 싶다. 코드를 작성하는 사람이 아닌 코드를 읽는 사람의 입장에서 구현을 하라는 말을 명심한다면 읽기 좋은 코드를 작성할 수 있을 것이다.

자신의 코드를 남에게 보이기 부끄러웠다면, 당장 이 책을 사서 보길 바란다.

2012년 5월 16일 수요일

Chromium - Notification Service

Overview

Notification Service provides notification delivery mechanism from producer to observer in the same thread. This class is created and used in browser process’s sub threads.
Refer to src/content/browser/browser_process_sub_thread.cc






Components

a. NotificationService
It handles notification delivery and manages observer list.
This service provides method that can add or remove notification for observer.
Also, Notify method is provided for notification provider.
To get the NotificationService object, content::NotificationService::current() is used.
It could be used in that thread only. It means calling content::NotifcationService::current()
returns different object in UI thread and IO thread.

b. Notification Observer:
This component is responsible for registration its preferred notification type to
NotificationService.
For receiving notification, Observer must implement NotificationObserver class.

c. Notification Provider:
It is a notification producer. This component sends notification to NotificationService.


How To Register Notification to NotificationService

a. Add Notification
For registration, NotificationRegistrar class is used instead of using NotificationService
directly. It is a helper class for registering notification and ensures that all registered
notifications are unregistered when the class is destroyed.
Refer to src/content/public/browser/notification_registrar.h

b. Implement Notification Handler
For implementing handler, Observer should implement NotificationObserver class as a base
class. It has only one function, observe(). When registered notification is occured,
NotificationService calls this function.
Refer to src/content/public/browser/notification_observer.h


How to Notify to NotificationService

NotificationService provides Notify() for synchronous notify mechanism. Notification provider should deliver notification type, source that originates this notification and details that contains additional information to NotificationService via Notify().
Refer to src/content/browser/notification_service_impl.cc 

2012년 5월 8일 화요일

Chromium Bug - 82276 (3)

이제 FindBarController가 마우스 클릭 이벤트를 구독하도록 하고, 이벤트 핸들러를 구현해보자.

이전 포스트에서 언급했듯이 Find Bar의 life cycle은 FindBarController 의 Show()/EndFindSession() 에서 시작되고 종료된다.

Show() 함수에서 다음과 같이 마우스 클릭 이벤트를 등록했다.


registrar_ (content::NotificationRegistrar) 의 Add() 를 이용해서 Noti를 받고싶은 원하는 notification type을 등록한다.
Add()의 첫번째 파라미터로 NotificationObserver를 구현한 객체를 전달하는데,
Notificaiton Service (NotificationServiceImpl) 에게 이 Noti가 발생했을때, 이 객체의 Observe()를 호출하라는 의미이다.
두번째 파라미터는 Noti의 이름이고, 세번째 파라미터는 받고싶은 Noti의 Source를 설정하는 부분이다.
Noti의 Source란 이 Noti를 생성하는 부분인데, 두번째 파라미터의 Noti를 Observer 가 특정 객체로부터 생성된 것만 받거나 모든 객체에서 생성되것을 받을 수 있다.
다음과 깉이 설정하면 WebContents의 객체에서 Noti만 받을 수 있다.
content::Source(tab_contents_->web_contents())
위 그림에서 처럼 AllSources() 로 설정하면, 모든 객체에서 생성되는 INPUT_EVENT_ACK Noti를 받을 수 있다.


다음은 Observe() 함수에 추가한 부분이다.



Observe() 함수의 파라미터를 통해 type, source, details를 받을 수 있다.
details는 이 Noti가 전달해주는 추가 데이터이다. INPUT_EVENT_ACK의 경우 인풋 이벤트의 종류이다.
여기서는 Mouse Up 이벤트만 관심있으므로 datails 를 통해 인풋 이벤트중 원하는 이벤트를 선택할 수 있다.

마지막으로 이벤트 등록을 삭제하는 부분이다.


삭제도 물론 NotificationService 로부터 이루어지므로 registrar_의 Remove() 를 통해 이루어지고, 파라미터는 Add() 와 같다.


이것으로 Find Refresh 에 필요한 이벤트 등록이 완료됐다.
다음 포스트에서는 어떻게 Refresh를 할지 고민해보자.