Software Development

Tom Curley's Opening Keynote at ONA Conference

We are shifting from an old “telegraph” model of pushing news to our subscribers through proprietary pipelines to a database model, where our customers can retrieve what they want, when they want it, over the network.

Our content is being formatted and databased to facilitate this new on-demand access, and, most important, we’re realigning our human resources to cover the kinds of stories people want to read and watch. We’re equipping our bureaus worldwide with flashcams. We’re adding domestic video to our content portfolio. We’ve established regional editing desks around the world to drive content from conceptualization to consumption.

Politics and breaking news remain a core strength — as we have demonstrated once again in the election, as well as in Iraq where we spend millions to cover the war and keep our journalists at the front safe. And we also have increased our coverage of financial news, entertainment and news for young audiences.

And we’re trying to harness the right technologies — search and RSS in particular — to plot a strategy for moving AP content where it needs to go in the new, free-flowing world of Web 2.0.

Tom Curley’s Opening Keynote at the ONA Conference (via 태우’s log)

Tom Curley's Opening Keynote at ONA Conference 더 읽기"

조엘 온 소프트웨어

조엘 온 소프트웨어조엘 온 소프트웨어 by Joel Spolsky

지인에게 생일 선물을 주느라 ‘조엘 온 소프트웨어’를 사면서 내 것도 함께 두권을 샀다. 원래 생일 선물 같은 걸 챙기는 타입은 아니지만, 내 생일 때 받아먹은 터라.

‘조엘 온 소프트웨어’는 이미 구독하고 있었을 뿐만 아니라, 몇몇 글들은 이미 읽어본 터여서 대충 넘어가면서 토요일 하루만에 읽을 수 있었다. 전체적인 내용은 기본적인 소프트웨어 엔지니어링의 주장에 충실하면서 Mythical Man-MonthPeopleware에 준하는 내용이었다. 물론, 그런 것과는 별로 관련없는 업계의 동향에 관한 내용과 전략에 관한 내용도 있긴 했다. 다른 점이라면 좀 더 재미있고 친근하게 설명한달까. 마치 누군가의 블로그를 보는 것처럼. (당연하다!) 칭찬할만 점은 어느 하나의 기술이나 의견에 치우치지 않고 균형잡힌 시각을 보여준다는 것이다. 어느 정도 권위가 있는 엔지니어들의 글을 보면 항상 느낄 수 있는 것이기도 하다.

번역은 – 그동안의 IT 관련 서적들의 번역 품질에 비해 – 매우 훌륭했다. 하지만, 역시 조엘의 유머를 우리말로 옮겨놓으니 재미가 떨어지는 것이 사실이었다. 역자주에서도 꼼꼼히 원작의 오류를 정정하거나 독자들이 모를만한 사실들을 언급해두고 있었던 점은 칭찬하고 싶다.

좀 마음에 안드는 점은 역자의 블로그 내용이나 번역 경험담을 중간중간에 넣어놓은 것이었다. 블로그 내용 같은 경우에는 원작의 내용과 관련된 내용이었는데, 조엘이 기술한 것 이상의 내용은 없었기 때문에 무의미한 것이었고, 번역 경험담은 역자 후기 정도에나 들어갈 내용이지, 중간중간에 들어가서 주의를 산만하게 만들만한 가치를 가진 것은 아니라고 생각한다. 분명히, 훌륭한 역자는 원작의 난해한 부분을 설명해주거나 새로운 방식으로 해석해줌으로써 원작과 다른 새로운 가치를 만들어낸다. 하지만, 조엘온소프트웨어 번역판에 삽입된 역자의 글들은 그럴만한 가치는 없었다고 생각한다.

Update 2005/09/09: 역자의 블로그 내용과 번역 경험담에 대한 의견 추가.

조엘 온 소프트웨어 더 읽기"

fread/ifstream::read/mmap performance comparison

예전에 comp.lang.c++.moderated에서 iostream performance가 fread를 사용하는 것에 비해서 나쁘다라는 글을 읽고 해당 테스트 케이스를 사용하여 실제로 테스트해 보았다. 테스트 케이스는 일정 크기의 파일 내에서 특정 레코드를 찾아내는 코드로, 읽기 오퍼레이션에 대한 성능 테스트에 가깝다.

결론은 fread와 ifstream::read는 별 차이가 없고, mmap은 엄청나게 빠르다는 것이다. gcc 버전에 따라 약간의 우위를 보이는 것이 흥미롭다.

fread/ifstream::read/mmap performance comparison 더 읽기"

Language Oriented Programming

Language Oriented Programming: The Next Programming Paradigm by Sergey Dmitriev

Part 1에서는 Language Oriented Programming (이하 LOP)이란 paradigm이 어떻게 나오게 되었는가를 설명하고 있다. 지난 번에 소개했던 Martin Fowler의 글과 내용은 거의 중복된다.

To achieve this independence, I need the freedom to create, reuse, and modify languages and environments. For this freedom to be practical, it needs to be easy to archive.

OOP나 DSL과 같은 높은 레벨의 abstraction을 제공하는 것은 생산성 향상에 있어서 중요한 의미를 가질 것이라는 것까지는 누구나 공감할 수 있는 내용일 것이지만, 그냥 지나치기 어려운 대목은 아무래도 DSL을 쉽게 만들 수 있도록 함으로써 그러한 이익을 극대화할 수 있다는 논리일 것이다. 물론, LOP의 성공 여부는 그것이 얼마나 쉬워질 수 있느냐하는 문제일 것이다. 얼마나 쉬워질 수 있는가에 대한 설득력 있는 논리가 부족한 것이 약간 아쉽다.

Part 2에서는 JetBrains의 Meta Programming System (이하, MPS)에서 어떻게 Language Oriented Programming을 구현했는가에 대해서 설명하고 있다. 즉, DSL을 쉽게 만드는 것이 중요하다는 것을 강조하는 것이 Part 1이라면 어떻게 쉽게 만들 수 있도록 할 것인가를 보여주는 것이 Part 2의 내용이다. MPS는 현재 JetBrains가 개발한 상용 Java IDE인 IntelliJ IDEA의 플러그인으로 구현되어있다. MPS는 Early Access Program을 통해서 개발중인 제품이 공개되고 있기 때문에 튜터리얼 (스크린샷 포함)을 약간 따라가보았다. DSL을 설계하기 위해서는 기본적으로 Structure Language, Editor Language, Transformation Language/Template을 사용하여 DSL을 표현해야하는데, 이러한 과정이 GUI를 통해서 이루어지는 것이 상당히 흥미로웠다.

The ideas underlying LOP and MPS are not new, and have actually been around for more than 20 years. The term Language Oriented Programming itself has been around for at least 10 years. What is new is that these ideas have silently saturated the software development community, and their time has finally come.

결론 부분에서 얘기하는 것과 같이 현재에 주목을 받고 있는 여러가지 기술들은 대부분 옛날에 만들어진 개념으로부터 출발하고 있다. 하지만, 그것이 주목을 받는데에는 거기에 근접한 기술들이 충분히 성숙해야할 뿐만 아니라 그 기술을 사용하는 사람들로부터 유효한 기술이라는 공감대를 형성하는 것이 필요하다. LOP가 과연 그들이 얘기하는 것처럼 OOP를 대체하는 시대를 뛰어넘는 기술일까? 지켜볼만한 가치는 있는 것 같다.

Language Oriented Programming 더 읽기"

The Design of C++0x

The Design of C++0x는 Bjarne Stroustrup이 CUJ 2005년 5월호에 기고한 글이다. C++0x 디자인의 기본적인 정책에 대해 설명하고 있다.

먼저 C++0x에서의 언어 디자인에 관해서는 최대한 호환성을 고려할 것이지만, 충분한 이익을 얻을 수 있는 부문이라면 호환성에 있어서의 작은 희생도 감수하겠다고 얘기하고 있다.

C++0x will be almost 100-percent compatible with the existing Standard C++. … We aim for compatibility but realize that there may be cases where a large advantage is worth paying for by small incompatibilities.

그리고, C++의 강점은 일반성(generality)라고 얘기하고 있고, 이러한 장점을 강화하는 방향으로 갈 것이라고 얘기하고 있다.

C++’s emphasis on general features (notably classes) has been its main strength, and often its lack of specialized features (such as “properties” and threads0 has been seen as its main weakness. … Nevertheless, we must keep the focus on general features aimed at efficient abstraction; the huge diversity of the C++ community requires that. … The obvious areas where C++ could be improved for greater generality is through better support for generic programming and more flexible initialization/construction mechanisms. Is is also obvious that some support for concurrency is needed as many forms of concurrent, parallel, and distributed programming are becoming common.

프로그래머가 프로그래밍 언어를 대하는 태도에 관한 짤막한 의견.

You don’t want to become a language expert-you want to be (or become) an expert in your own field and know just enough of some programming language to get your work done.

type safety는 compiler optimization 등의 이점을 얻기 위한 중요한 C++의 특성임을 강조하고 있다. 언어의 변경을 위해서 완벽한 type safety를 얻기는 힘들지만, 표준 라이브러리를 통해서 이를 강화하겠다고 얘기하고 있다.

C++0x will not be able to close all the loopholes in the C++ type system, but it will not introduce new holes and it will provide ways of avoiding inherently unsafe facilities-primarily through the Standard Library providing (compile-time or run-time) type-safe alternatives.

C++의 중요한 원칙 중의 하나인 zero-overhead principle을 재확인하고 있다.

That is, the zero-overhead principle: “what you don’t use, you don’t pay for” and “what you use can be implemented without overhead compared with hand coding” is still the bedrock of C++.

라이브러리의 중요성.

A language cannot support everything, but conceivably, a large set of libraries could. … Library extensions will be preferred to language extensions.

표준 결정 과정에서 벤더들에 대한 고려(예를 들어 구현의 용이성)도 중요한 요소임을 강조하고 있다.

The development of C++0x must be timely and to gain acceptance from vendors, new language features must be easier to implement that the most difficult C++98 features. … we dislike dialects. … My suggestion is for programmers to avoid nonstandard features whenever possible.

C++ Programming Language를 읽어보신 분이라면, C++0x 또한 C++의 기본 철학에서 크게 벗어나지는 않는다는 것을 알 수 있을 것이다. 특히 눈에 띄는 점은 라이브러리에 대한 강조.

Whereas we’ll be cautious and skeptical about language extensions, we’ll be aggressive and opportunistic when in comes to new library-especially for libraries that extend the range of portable support for systems programming.

The Design of C++0x 더 읽기"

Static Typing Where Possible, Dynamic Typing When Needed

PDC 05에서 C# 3.0에 대한 발표가 예정되어있는 가운데, 흥미로운 paper가 있더군요. C# 3.0에는 type inference, contract, lazy evaluation이 들어갈지도 모를 일입니다.

Static typing is a powerful tool to help programmers express their assumptions about the problem they are trying to solve and allows them to write more concise and correct code. Dealing with uncertain assumptions, dynamism and (unexpected) change is becoming increasingly important in a loosely couple distributed world. Instead of hammering on the differences between dynamically and statically typed languages, we should instead strive for a peaceful integration of static and dynamic aspect in the same language. Static typing where possible, dynamic typing when needed!

Static Typing Where Possible, Dynamic Typing When Needed (pdf)

Dynamic Typing in C#

Static Typing Where Possible, Dynamic Typing When Needed 더 읽기"

time-to-market pressure in software development

Slashdot 글한 comment에서 인용.

It is rather amazing that there appears to be a consensus among industry experts that there has not been any improvement in code quality over the past 30 years or so despite the development of a vast number of new tools and languages. It is true that the size and scope of the average application has grown by leaps and bounds. But most likely, the primary contributing factor to these kind of quality problems is the prevalent time-to-market pressure in the software industry which is typically coupled with severe underestimation of time and resources required for projects.

time-to-market pressure in software development 더 읽기"

Refactoring traditional web application with MVC pattern (Part 2)

Adding functionality

Part 1에서는 Subscription을 등록하는 기능만을 구현했지만, Subscription을 삭제하고, 등록된 Subscription과 그 리스트를 보여주는 기능을 추가해보자.

case-when 절에 각각의 리퀘스트에 해당하는 처리 루틴을 추가하고, Subscription 클래스의 메서드를 호출하도록 구현한다.

Adding functionality (controller routines)

Subscription 클래스는 다음과 같이 구현할 수 있다.

Adding functionality (Subscription class)

Seperating View and Controller

Subscription 리스트를 보여주는 부분을 구현해보자.

code fragment that shows subscription list

문제는 Subscription 리스트를 보여주는 html code는 request 변수들을 처리하고 Subscription 클래스를 다루는 code 보다 자주 바뀔 가능성이 있다는 것이다. 물론, 이런 작은 예제를 구현할 때는 그렇지 않다. 웹 어플리케이션이 커질 수록 html code의 복잡도도 커지고, 그런 code를 다루는 것은 프로그래머가 아닌 디자이너의 역할로 넘어가는 경향이 있다. 따라서, 웹 어플리케이션의 규모가 커지면 View와 Controller의 구분이 불가피해지는 것이다. Subscription List를 보여주는 부분을 SubscriptionListView 클래스로 분리해보자.

code fragment that shows subscription list

Controller에서 직접 HTML을 rendering하는 코드를 SubscriptionListView를 사용하도록 변경해준다.

code fragment that shows subscription list

Refactoring traditional web application with MVC pattern (Part 2) 더 읽기"

부동소수점 수의 비교

얼마전에 재민군이 질문했던 내용인데, 태준형의 도움으로 해결했던 문제입니다.

Question

먼저 다음과 같은 코드가 있습니다.

#include 
int main()
{
int i = 10;
double val = i*12.34;
if(val == i * 12.34){
printf("Equaln");
} else {
printf("Not Equaln");
}
}

결과는 무엇일까요?

물론 답은 이 프로그램을 컴파일하고 실행하는 환경에 따라 다르다입니다. 즉, 어셈블리 코드를 생성하는 컴파일러와 이 코드를 실행하는 아키텍쳐에 따라 다를 것이라고 예상할 수 있습니다. 그런데, 신기한 것은 같은 아키텍쳐(Pentium 3)와 같은 컴파일러(gcc 3.4)를 사용하더라도 OS에 따라(Linux와 FreeBSD) 다른 결과가 나온다는 것입니다. 자세히 얘기하면, Linux에서는 “Not Equal”이 출력되고, FreeBSD에서는 “Equal”이 출력됩니다. 어째서 그럴까요?

Answer

설마, 어셈블리 코드가 다르게 나오는 걸까요? OS가 달라서 그럴지도, 컴파일러 설정이 달라서 그럴지도 모르지 않습니까? 아니면 컴파일러 버그? 그런데, 그렇지 않습니다. 부동소수점 연산과 비교를 수행하는 부분의 코드는 다음과 같이 똑같습니다.

movl    $10, -4(%ebp)
fildl   -4(%ebp)
fldl    .LC0
fmulp   %st, %st(1)
fstpl   -16(%ebp)
fildl   -4(%ebp)
fldl    .LC0
fmulp   %st, %st(1)
fldl    -16(%ebp)
fxch    %st(1)
fucompp
fnstsw  %ax
andb    $69, %ah
cmpb    $64, %ah
je  .L3
jmp .L2

간단히 설명하면, 10과 12.34를 FPU stack에 넣고 곱셈을 수행한 후, (FPU stack에 들어있는) 결과를 다시 메모리에 저장합니다. 두번째 연산을 위해 역시 10과 12.34를 FPU stack에 넣고 곱셈을 수행한 후, 메모리에 저장했던 결과도 다시 FPU stack에 불러들여, 두 값의 비교를 수행하는 코드입니다.

두 값의 차이는 곱셈의 결과가 메모리로 잠시 다녀왔는가의 여부 뿐이죠. OS에 따른 결과의 차이도 바로 여기서 발생합니다.

The difference between Linux and FreeBSD is that in Linux, the FPU is operated by default in “extended precision” mode, where 80-bit internal registers are used for floating point numbers. In FreeBSD, the default is to use “double precision” mode, where 64-bit precision is retained.

Excerpt from Resolution of Differences Between X86 Linux/glibc Floating-Point to Integer Conversion Behavior Relative to Other Platforms

즉, 387 내에서 부동소수점 수는 80bit의 정밀도를 가질 수 있는데, 메모리 상에서는 IEEE 754대로 64bit의 정밀도를 가지므로 일종의 rounding error가 일어난다는 거죠. 그리고 FreeBSD에서는 80bit 정밀도 기능을 OS 수준에서 꺼버리지만 Linux는 그렇지 않기 때문에 차이가 나는 것이구요.

More Fun?

참고로, 제 amd64 머신에서는 “Equal”이 출력되고 다음과 같은 코드를 생성합니다.

movl    $10, -4(%rbp)
cvtsi2sd    -4(%rbp), %xmm1
movlpd  .LC0(%rip), %xmm0
mulsd   %xmm1, %xmm0
movsd   %xmm0, -16(%rbp)
cvtsi2sd    -4(%rbp), %xmm1
movlpd  .LC0(%rip), %xmm0
mulsd   %xmm0, %xmm1
movlpd  -16(%rbp), %xmm0
ucomisd %xmm0, %xmm1
jp  .L5
je  .L3

즉, SSE instruction을 사용하죠. gcc는 x86-64 (aka. amd64) 아키텍쳐에서는 기본적으로 SSE를 사용한다고 합니다.

sse Use scalar floating point instructions present in the SSE
instruction set. This instruction set is supported by Pentium3
and newer chips, in the AMD line by Athlon-4, Athlon-xp and
Athlon-mp chips. The earlier version of SSE instruction set
supports only single precision arithmetics, thus the double and
extended precision arithmetics is still done using 387. Later
version, present only in Pentium4 and the future AMD x86-64
chips supports double precision arithmetics too.
For i387 you need to use -march=cpu-type, -msse or -msse2
switches to enable SSE extensions and make this option effec-
tive. For x86-64 compiler, these extensions are enabled by
default.
The resulting code should be considerably faster in the major-
ity of cases and avoid the numerical instability problems of
387 code
, but may break some existing code that expects tempo-
raries to be 80bit.
This is the default choice for the x86-64 compiler.

Pentium 4이상의 머신에서 다음과 같이 컴파일 하면 역시 “Equal”이 출력되는 것을 확인할 수 있습니다. (Pentium 3에서도 컴파일은 되지만, Illegal Instruction 예외가 발생합니다.)

gcc -msse -msse2 -mfpmath=sse test_double.c

Conclusion

문제의 원인은 x86 FPU가 80bit extension을 사용하고 있고, FreeBSD에서는 이 기능을 꺼버리고 Linux는 그대로 두는 것에 있습니다.

어떻게 보면, x86의 FPU가 사용하는 80bit extension이 표준(IEEE754)을 잘 지키지 않은 것이 문제라거나 Linux가 문제의 소지가 있는 CPU 기능을 켜놓은 것이 문제라고 볼 수도 있습니다. 하지만, 모두들 아시다시피 부동소수점 수의 비교 연산은 보장받기 어려운 것이므로, 이런 간단한 비교 연산의 정확도를 버리고 연산의 정밀도를 택한 trade-off는 정당하다고도 생각됩니다.

결국, 부동소수점 수의 비교 연산은 아무리 간단하더라도 rounding error와 같은 문제를 무시해서는 안된다는 것이죠.

위에서 인용했던 글에서 읽어보라고 하고 있는 David Goldberg의 What Every Computer Scientist Should Know About Floating-Point Arithmetic를 읽어볼 생각입니다.

부동소수점 수의 비교 더 읽기"