« さきゅばす/coroid用ffmpegビルドpatch更新 | トップページ | [読書]彼女と二人で「C」体験!にあえてツッコむ »

2010/09/20

[読書]どの口が東証システム(arrowhead)開発を指して正攻法だとのたまうのか『システム改革の正攻法』

「システム改革の正攻法」という東証の次世代株式売買システム「arrowhead」を立ち読みして、少し違和感を感じたので購入してみました。

パラパラとめくってみて、うーん、他の人はどんな感想なんだろう、と検索してみたところ、小飼弾さんの書評

なにしろこちらにはソースコードの一部まで乗っているのだ。

という記述を見つけました。おおそんなものが書いてあったのか、と該当箇所を読んでみたところ、全く腑に落ちなかったのでまとめてみました。「第12章 スピード1000倍増の秘密 - 世界最速システムの全貌」 の 「マイクロ秒を惜しみ処理時間を削る」という節です。

p.132 図12-3に対応がまとめてありましたのでここから引用します。

tse01 

  • 設計段階で、業務ロジックを基に実行ステップ数を算出し、そこから処理時間を試算。目標時間を超えるものはステップ数削減のためにロジックや記述を見直す

○。ありだとは思いますが、この節のタイトル「マイクロ秒を惜しみ処理時間を削る」とはちょっとレベル感が違うような気はします。まあ正攻法ということで。

 

  • アプリケーション内で複数のエラー検定(チェック)処理を行う場合、当てはまる確率の高い順に記述
  • 業務処理やデータの特性に合わせた検索方法を採用

◎。これは、今回の発注者(東証)側の体制への取り組みを考えると、非常に効果的に機能したと想像します。

 

  • 呼び出し順序が決まっているいくつかのソフト部品を一つに集約、関数の呼び出し回数を削減

×。関数のインライン化、ということでしょうが、一般的には正攻法ではなくバッドノウハウです。

アンチパターンでは肥満児(The Blob)という名前が付けられています(ただしこのパターンはOOD/Pに対して適用されるもので、本システムに対しては正確な名付けではありません)。また、リファクタリングのモチベーションとなる不吉な匂いの「長すぎるメソッド」にも分類されます。

正攻法としては、関数インライン化はコンパイラに任せることです(C99ではinlineキーワードが標準化されました)。

また、強引にインライン化した際のデメリットとしては、キャッシュメモリが有効に機能しなくなる、スラッシングが発生する、といったことが挙げられます。

「ソフト部品を一つに集約」という表現が曖昧で、もしかするとダイナミックリンクをスタティックリンクに変更する、LTO(Link-Time Optimization)が効かないコンパイラへの対応(コンパイラ事情には疎いのですが、gccでは比較的最近取り入れられたそうです)、といった内容にもとれますが、いずれにせよ保守性とのトレードオフになりますので諸手を挙げて正攻法とは呼べません(どちらかというとバッドノウハウに分類されます)。

 

  • 複数のスレッドによるデータの共有を禁止(データを持ちまわりたい場合は、引数による受け渡しを利用)

×。速度向上につながる理由も分かりませんし、カッコ前後の文章のつながりも分かりません。一般的にはデータは共有した方がパフォーマンスは向上します。引数による受け渡しを行ったからといって共有が禁止できるわけではありません。スレッド間でデータを共有しない一般的な理由は、パフォーマンスに拠るものではなく並行処理におけるアクセス競合を防ぐためです。

 

  • データ操作時の関数は「memxxx」を利用(「strxxx」関数は使わない)

○。strcpy_sを使わずにmemcpyを使用する、memmoveを使わずにmemcpyを使う、といった方針であれば、パフォーマンスとセキュリティリスクのトレードオフで前者を選択したのだな、ということが明確なのですが(ただしそれが正攻法であるかどうかは別問題です)。

要するに文字列を文字列として扱わず固定長バイナリとして扱う、ということなのですが、この対応を行うことの問題点としては

    • 有効バイト以降(‘\0’以降)も意識する必要がある。本システム方針に沿って言えば、本来不要な部分の初期化、代入コストが発生する。
    • 文字列を文字列として扱っている部分との境界(例えば周辺システムとのインタフェース)でも上記を意識する必要がある。
    • 本来未初期化部分であるべきところを正しそうな値に置き換えてしまうことで、動的検査(例えばPurifyPlus)の能力を弱めてしまう。

といったことが挙げられ、個人的には△としたいです。しかし、現実のパフォーマンス差を見ると…という点で○です(私もこういう対応を行うことはありますし…)。

 

  • フラグ(1バイトデータ)の比較には、「memcmp」関数を使わずに直接データを比較
  • 1バイト以外のデータの比較には「memcmp」関数を使う

×。意味不明ですが、おそらくchar flg;char str[10];の場合の差異を言いたいのでしょう。しかしmemcmpがとる引数はvoid*型なのでそもそもchar型変数を引数にとることはできません。char*型変数が指す1バイトのデータ比較であれば、==を使おうがmemcmpを使おうがパフォーマンスは変わりません。

ところで、この記述を正確に読み取ると、intみたいな組み込み型変数もmemcmpを使うようになりますが(通常intは4バイト)、さすがにそんなことはやっていないでしょうね。

 

  • データ項目一つひとつを初期化するのでなく、初期値をセットした変数を一度にコピー(図12-5参照)

後述します。

 

  • 関数の引数にはポインタを使う、繰り返し処理内で無駄な記述をしない、冗長なチェック処理をなくす、無駄なログ出力を止める

○。当たり前と言えば当たり前なのですが、「正攻法」という観点なので。ただし繰り返し処理の中で変数宣言を行うな、といった最適化でどうとでもなるようなものだったら笑います。

ちなみに、私が担当したシステムでは、ログの重要度に応じて非同期で出力するか同期で出力するか切り替える、といったようなことも実装しました。JavaだとLog4jのAppenderで簡単に実現できみたいなんですけどね。

 

後回しにした構造体について。

 tse02

この図からわかることを列挙します。

  • 初期値の代入にはBGAA_Memcpyという関数が使われていますが、以下では文中の説明よりmemcpy相当として考えています。引数からみても、memcpyより高速なことを行っているようには見えないです。
  • コメントのついていない Filter_m[n] はアラインメント調整用のパディングメンバでしょう。OSがLinuxn=5のものがあるということは、64bitなんでしょうかね。
  • アラインメントが決め打ちです。
  • sizeof(int)などが決め打ちです。
  • 初期値をchar配列で定義しており、サイズは構造体に合わせています。

これだけでも個人的には×をつけたいところですが、移植性に関しては考慮する必要が無いという判断なのでしょうし(longを使わずにlong longを使っているところを見るとあまり吹っ切れていないようにも見えますが)、保守性について重視していないこともこれまでの対応で明らかなので、ひとまず置いておきます。

構造体の初期化、というと通常は代入を使うわけですが、それよりもmemcpyの方が高速だ、という判断でmemcpyを使用しているのですから、双方比較してみれば妥当性は確認できます。

今回使用したコードは以下になります。構造体は図12-5の上半分を用いています。また、コンパイル環境はUbuntu10.04 32bit gcc-4.4.3になります。結果は-O3で最適化しています。

   1: #include <stdio.h>
   2: #include <stdlib.h>
   3: #include <string.h>
   4:  
   5: typedef struct {
   6:     char IssueKey[16];
   7:     char SecExKbn[1];
   8:     char MktKbn[2];
   9:     char IssueCd[12];
  10:     char IssueKbn[4];
  11:     char Filter_1[5];
  12:     long long Irate;
  13:     long long RepP;
  14:     char YldRstrn[1];
  15: } LAA01_t;
  16:  
  17: const static LAA01_t init_value = {
  18:     {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
  19:     {0x20},
  20:     {0x20,0x20},
  21:     {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
  22:     {0x20,0x20,0x20,0x20},
  23:     {0x20,0x20,0x20,0x20,0x20},
  24:     0,
  25:     0,
  26:     {0x20}
  27: };
  28:  
  29: const static char init_value_char[sizeof(LAA01_t)] ={
  30:     0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  31:     0x20,
  32:     0x20,0x20,
  33:     0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
  34:     0x20,0x20,0x20,0x20,
  35:     0x20,0x20,0x20,0x20,0x20,
  36:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  37:     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  38:     0x20
  39: };
  40:  
  41:  
  42:  
  43: void assign_operator(LAA01_t *t1, const LAA01_t *t2){
  44:     *t1=*t2;
  45: }
  46:  
  47: void assign_memcpy(LAA01_t *t1, const LAA01_t *t2){
  48:     memcpy(t1,t2,sizeof(LAA01_t));
  49: }
  50:  
  51: void assign_memcpy_char(LAA01_t *t1, const char *c){
  52:     memcpy(t1,c,sizeof(LAA01_t));
  53: }
  54:  
  55:  
  56: int main(int argc, char** argv) {
  57:     LAA01_t t1, t2, t3;
  58:  
  59:     assign_operator(&t1,&init_value);
  60:     assign_memcpy_char(&t2,init_value_char);
  61:     assign_memcpy(&t3,&init_value);
  62:  
  63:     printf("%s[end]\n",t1.IssueKey);
  64:     printf("%s[end]\n",t2.IssueKey);
  65:     printf("%s[end]\n",t3.IssueKey);
  66:     return (EXIT_SUCCESS);
  67: }
  68:  

上記コードの説明を簡単に行います。

  • 初期値としてinit_valueという構造体を定義しています。
  • 東証のコード相当の初期値はchar配列のinit_value_charです。
  • assign_memcpy_charはmemcpy関数でchar配列から値をコピーする関数です。東証のコード相当です。
  • assign_operatorは代入演算子で代入する関数です。
  • assign_memcpyはmemcpy関数で構造体から値をコピーする関数です。参考として作成してみました。

つまり、assign_memcpy_char関数とassign_operatorの差が、memcpyを利用して初期値を設定することのメリットになります。上記コードをコンパイル後、objdump -dコマンドでアセンブラコードを表示し、比較しました。

アセンブラについての知識は全く無いに等しいので検証できるか不安でしたが、杞憂に終わりました。以下がそれぞれの関数の部分についてのコードになります。

   1: 080484e0 <;assign_memcpy_char>:
   2:  80484e0:    55                       push   %ebp
   3:  80484e1:    89 e5                    mov    %esp,%ebp
   4:  80484e3:    8b 55 0c                 mov    0xc(%ebp),%edx
   5:  80484e6:    8b 45 08                 mov    0x8(%ebp),%eax
   6:  80484e9:    8b 0a                    mov    (%edx),%ecx
   7:  80484eb:    89 08                    mov    %ecx,(%eax)
   8:  80484ed:    8b 4a 04                 mov    0x4(%edx),%ecx
   9:  80484f0:    89 48 04                 mov    %ecx,0x4(%eax)
  10:  80484f3:    8b 4a 08                 mov    0x8(%edx),%ecx
  11:  80484f6:    89 48 08                 mov    %ecx,0x8(%eax)
  12:  80484f9:    8b 4a 0c                 mov    0xc(%edx),%ecx
  13:  80484fc:    89 48 0c                 mov    %ecx,0xc(%eax)
  14:  80484ff:    8b 4a 10                 mov    0x10(%edx),%ecx
  15:  8048502:    89 48 10                 mov    %ecx,0x10(%eax)
  16:  8048505:    8b 4a 14                 mov    0x14(%edx),%ecx
  17:  8048508:    89 48 14                 mov    %ecx,0x14(%eax)
  18:  804850b:    8b 4a 18                 mov    0x18(%edx),%ecx
  19:  804850e:    89 48 18                 mov    %ecx,0x18(%eax)
  20:  8048511:    8b 4a 1c                 mov    0x1c(%edx),%ecx
  21:  8048514:    89 48 1c                 mov    %ecx,0x1c(%eax)
  22:  8048517:    8b 4a 20                 mov    0x20(%edx),%ecx
  23:  804851a:    89 48 20                 mov    %ecx,0x20(%eax)
  24:  804851d:    8b 4a 24                 mov    0x24(%edx),%ecx
  25:  8048520:    89 48 24                 mov    %ecx,0x24(%eax)
  26:  8048523:    8b 4a 28                 mov    0x28(%edx),%ecx
  27:  8048526:    89 48 28                 mov    %ecx,0x28(%eax)
  28:  8048529:    8b 4a 2c                 mov    0x2c(%edx),%ecx
  29:  804852c:    89 48 2c                 mov    %ecx,0x2c(%eax)
  30:  804852f:    8b 4a 30                 mov    0x30(%edx),%ecx
  31:  8048532:    89 48 30                 mov    %ecx,0x30(%eax)
  32:  8048535:    8b 4a 34                 mov    0x34(%edx),%ecx
  33:  8048538:    89 48 34                 mov    %ecx,0x34(%eax)
  34:  804853b:    8b 52 38                 mov    0x38(%edx),%edx
  35:  804853e:    89 50 38                 mov    %edx,0x38(%eax)
  36:  8048541:    5d                       pop    %ebp
  37:  8048542:    c3                       ret    
  38:  8048543:    8d b6 00 00 00 00        lea    0x0(%esi),%esi
  39:  8048549:    8d bc 27 00 00 00 00     lea    0x0(%edi,%eiz,1),%edi
   1: 08048470 <;assign_operator>:
   2:  8048470:    55                       push   %ebp
   3:  8048471:    89 e5                    mov    %esp,%ebp
   4:  8048473:    8b 55 0c                 mov    0xc(%ebp),%edx
   5:  8048476:    8b 45 08                 mov    0x8(%ebp),%eax
   6:  8048479:    8b 0a                    mov    (%edx),%ecx
   7:  804847b:    89 08                    mov    %ecx,(%eax)
   8:  804847d:    8b 4a 04                 mov    0x4(%edx),%ecx
   9:  8048480:    89 48 04                 mov    %ecx,0x4(%eax)
  10:  8048483:    8b 4a 08                 mov    0x8(%edx),%ecx
  11:  8048486:    89 48 08                 mov    %ecx,0x8(%eax)
  12:  8048489:    8b 4a 0c                 mov    0xc(%edx),%ecx
  13:  804848c:    89 48 0c                 mov    %ecx,0xc(%eax)
  14:  804848f:    8b 4a 10                 mov    0x10(%edx),%ecx
  15:  8048492:    89 48 10                 mov    %ecx,0x10(%eax)
  16:  8048495:    8b 4a 14                 mov    0x14(%edx),%ecx
  17:  8048498:    89 48 14                 mov    %ecx,0x14(%eax)
  18:  804849b:    8b 4a 18                 mov    0x18(%edx),%ecx
  19:  804849e:    89 48 18                 mov    %ecx,0x18(%eax)
  20:  80484a1:    8b 4a 1c                 mov    0x1c(%edx),%ecx
  21:  80484a4:    89 48 1c                 mov    %ecx,0x1c(%eax)
  22:  80484a7:    8b 4a 20                 mov    0x20(%edx),%ecx
  23:  80484aa:    89 48 20                 mov    %ecx,0x20(%eax)
  24:  80484ad:    8b 4a 24                 mov    0x24(%edx),%ecx
  25:  80484b0:    89 48 24                 mov    %ecx,0x24(%eax)
  26:  80484b3:    8b 4a 28                 mov    0x28(%edx),%ecx
  27:  80484b6:    89 48 28                 mov    %ecx,0x28(%eax)
  28:  80484b9:    8b 4a 2c                 mov    0x2c(%edx),%ecx
  29:  80484bc:    89 48 2c                 mov    %ecx,0x2c(%eax)
  30:  80484bf:    8b 4a 30                 mov    0x30(%edx),%ecx
  31:  80484c2:    89 48 30                 mov    %ecx,0x30(%eax)
  32:  80484c5:    8b 4a 34                 mov    0x34(%edx),%ecx
  33:  80484c8:    89 48 34                 mov    %ecx,0x34(%eax)
  34:  80484cb:    8b 52 38                 mov    0x38(%edx),%edx
  35:  80484ce:    89 50 38                 mov    %edx,0x38(%eax)
  36:  80484d1:    5d                       pop    %ebp
  37:  80484d2:    c3                       ret    
  38:  80484d3:    8d b6 00 00 00 00        lea    0x0(%esi),%esi
  39:  80484d9:    8d bc 27 00 00 00 00     lea    0x0(%edi,%eiz,1),%edi
   1: 08048550 <;assign_memcpy>:
   2:  8048550:    55                       push   %ebp
   3:  8048551:    89 e5                    mov    %esp,%ebp
   4:  8048553:    8b 55 0c                 mov    0xc(%ebp),%edx
   5:  8048556:    8b 45 08                 mov    0x8(%ebp),%eax
   6:  8048559:    8b 0a                    mov    (%edx),%ecx
   7:  804855b:    89 08                    mov    %ecx,(%eax)
   8:  804855d:    8b 4a 04                 mov    0x4(%edx),%ecx
   9:  8048560:    89 48 04                 mov    %ecx,0x4(%eax)
  10:  8048563:    8b 4a 08                 mov    0x8(%edx),%ecx
  11:  8048566:    89 48 08                 mov    %ecx,0x8(%eax)
  12:  8048569:    8b 4a 0c                 mov    0xc(%edx),%ecx
  13:  804856c:    89 48 0c                 mov    %ecx,0xc(%eax)
  14:  804856f:    8b 4a 10                 mov    0x10(%edx),%ecx
  15:  8048572:    89 48 10                 mov    %ecx,0x10(%eax)
  16:  8048575:    8b 4a 14                 mov    0x14(%edx),%ecx
  17:  8048578:    89 48 14                 mov    %ecx,0x14(%eax)
  18:  804857b:    8b 4a 18                 mov    0x18(%edx),%ecx
  19:  804857e:    89 48 18                 mov    %ecx,0x18(%eax)
  20:  8048581:    8b 4a 1c                 mov    0x1c(%edx),%ecx
  21:  8048584:    89 48 1c                 mov    %ecx,0x1c(%eax)
  22:  8048587:    8b 4a 20                 mov    0x20(%edx),%ecx
  23:  804858a:    89 48 20                 mov    %ecx,0x20(%eax)
  24:  804858d:    8b 4a 24                 mov    0x24(%edx),%ecx
  25:  8048590:    89 48 24                 mov    %ecx,0x24(%eax)
  26:  8048593:    8b 4a 28                 mov    0x28(%edx),%ecx
  27:  8048596:    89 48 28                 mov    %ecx,0x28(%eax)
  28:  8048599:    8b 4a 2c                 mov    0x2c(%edx),%ecx
  29:  804859c:    89 48 2c                 mov    %ecx,0x2c(%eax)
  30:  804859f:    8b 4a 30                 mov    0x30(%edx),%ecx
  31:  80485a2:    89 48 30                 mov    %ecx,0x30(%eax)
  32:  80485a5:    8b 4a 34                 mov    0x34(%edx),%ecx
  33:  80485a8:    89 48 34                 mov    %ecx,0x34(%eax)
  34:  80485ab:    8b 52 38                 mov    0x38(%edx),%edx
  35:  80485ae:    89 50 38                 mov    %edx,0x38(%eax)
  36:  80485b1:    5d                       pop    %ebp
  37:  80485b2:    c3                       ret    
  38:  80485b3:    8d b6 00 00 00 00        lea    0x0(%esi),%esi
  39:  80485b9:    8d bc 27 00 00 00 00     lea    0x0(%edi,%eiz,1),%edi

全て同一です。ちなみに最適化しない場合は、memcpyを利用するとインライン化されず関数コールが増える分、memcpyを利用する方がコスト増です。

今回はソースコードを書いて試してみましたが、そもそも、なぜコンパイラは最適な代入処理を行ってくれない、という考えに至るのでしょうか。

上記のような対応を行った結果、保守性、移植性を低下させたにも関わらず、パフォーマンスには全く寄与しない(どころか低下させる可能性がある)ものになっています。評価としては二重×どころでは済みません。

 

これまで示してきた内容より、この書籍が言うところの「正攻法」とは、バッドノウハウを駆使してでもarrowheadの第一優先目標である速度向上を叶える、というものです。しかし一般的にはそれを正攻法とは呼びません。

以上、小飼さんの書評がきっかけということもあり、久しぶりにこちらを意識して書いてみました。

 

最後に。本書の中で鈴木義伯東証CIOが「技術者冥利に尽きる」とおっしゃっていらっしゃることについて。

このような巨大システム構築プロジェクトを予定通り(で良いんでしたっけ?当初は2009年秋だったような気もしますがこれは忘れます)完遂できた、情報システムの最高責任者であるCIOのプロジェクトマネジメント能力は並大抵のものではないと思われます。正直、私は2010年1月4日にarrowheadが稼働できるとは思っていませんでした。

しかし、私が同じような立場に立ったとするならば、目標を達成するために上で述べてきたような(仮に全て速度向上に繋がるとしても)泥臭い対応を行わなければならなかったことや、21世紀にもなってこのような保守性の低いシステムを見続けなければならないだろう若いSEのことを考えると、「技術者冥利に尽きる」などとは決して言うことはできないでしょう。万が一そのような言葉を吐かなければならない状況が予想されるのであれば、ここで記載したような対応をオープンにはしないでしょう。

この「技術者」についての価値観の違いが、冒頭に記載した違和感の正体かな、と考えます。

というか冒頭で示した小飼さんの書評、

全く奇をてらったことがない。まさに正攻法。愚直といってもいい。

自身で示した箇所の内容もちゃんと読んでませんよね…?

 

プログラミング的な部分以外にも言いたいことは出てきそうな予感がしますが、それはまた気が向けば。

« さきゅばす/coroid用ffmpegビルドpatch更新 | トップページ | [読書]彼女と二人で「C」体験!にあえてツッコむ »

コメント

この記事へのコメントは終了しました。

トラックバック

» [読書]彼女と二人で「C」体験にあえてツッコむ [雪羽の発火後忘失]
彼女と二人で「C」体験! (MF文庫 J い 2-7) 石川ユウヤ ストーリー上の小道具なわけで、無粋かとも思いましたので淡々と。前エントリからの流れということで… 出てくるソースはこれだけです。 1: #includeempirex.h 2: class CHeavyInfantry : public CHoplite 3: { 4: public: 5: int ReflectAnyStrik... [続きを読む]

» [読書]約定率が低いことは良いことか『システム改革の正攻法』 [雪羽の発火後忘失]
システム改革の「正攻法」 大和田 尚孝 正確には、システムの性能が上がったことを外部の人に示す指標として約定率の低下を用いるのは適切なんだろうか、という疑問です。 本書『システム改革の正攻法』の冒頭で、東証新システムarrowhead導入の効果について、以下のように記述されています。 arrowheadの導入効果は、早くもデータに表れている。代表例が東証の株式市場における「約定率」の変化だ(図1-... [続きを読む]

« さきゅばす/coroid用ffmpegビルドpatch更新 | トップページ | [読書]彼女と二人で「C」体験!にあえてツッコむ »

other sites

  • follow us in feedly
  • github
  • stackoverflow

ソフトウェアエンジニアとして影響を受けた書籍

  • Christain Bauer: HIBERNATE イン アクション

    Christain Bauer: HIBERNATE イン アクション
    理論と実践が双方とも素晴らしい製品であるHibernate。本書はそのプロダクトを書名に冠していますが、Hibernateを使うつもりがなく、ORマッピングの解説書として読むにしても十分な良書です。Second EditionとしてJava Persistence With Hibernateという書籍も出版されていますが、残念ながら現在のところ 和訳はされていません。-インアクションは2.xの、Java Persistence-は3.1の頃のものなので、最新版とはちょっと違うところもあることに注意。 (★★★★★)

  • アンドリュー・S・タネンバウム: 分散システム 原理とパラダイム 第2版

    アンドリュー・S・タネンバウム: 分散システム 原理とパラダイム 第2版
    クライアント/サーバシステムを構築する上で必要となる知識が総論されてます。Web技術者も、フレームワーク部分を開発するのであれば必読。 (★★★★★)

  • Joel Spolsky∥著: ジョエル・オン・ソフトウェア

    Joel Spolsky∥著: ジョエル・オン・ソフトウェア
    前述の書籍「ソフトウエア開発プロフェッショナル」をより砕いたもの、という感じでしょうか。 前書きではプログラマでなくSE向けの本のように書かれているが、プログラマが読んでも面白い本であると思われます。 SEになった新人(あるいはそういう会社に入る/入りたての人)にとっては、これからどういったことが仕事を遂行していく上で起こりえるのか、どのように考えて行なっていけばいいのか決定する助けになると思います。 元は″Joel on Software″というブログの記事で、web上でも一部日本語で読めます。 http://japanese.joelonsoftware.com/ (★★★)

  • ドナルド・C・ゴース,ジェラルド・M・ワインバーグ: ライト、ついてますか

    ドナルド・C・ゴース,ジェラルド・M・ワインバーグ: ライト、ついてますか
    問題解決(一昔前のの流行語で言うところの『ソリューション』)能力は、システムエンジニアのスキルとして備えるべきもののうちのひとつです。しかし、これは難しい。学校で出されるテストと違い、唯一の、(問題提出者が想定している)解を求めるだけが「問題解決」では無いからです。そもそも、何が問題なのか、それは本当に問題なのか、それは本当に解決すべき問題なのか、その問題解決方法は正しいのか、などを解決しなければ、「その解は正しいのか」に辿りつくことができません。この本の最も良いところのひとつは、本があまり厚くないこと。すぐに読めるし、何回も読み返す気になるでしょう。 (★★★★★)

  • スティーブ・マコネル: ソフトウエア開発プロフェッショナル

    スティーブ・マコネル: ソフトウエア開発プロフェッショナル
    コードコンプリートで有名なスティーブマコネルの著書。新人SEに読んで欲しい。個人として業界の中でどうあるべきか、組織としてどうあるべきか、SEのプロ意識とは?SEの心構え概論、といったところでしょうか。また、業界における資格の重要性についても説かれています。この業界では資格が特に軽んじられる傾向がありますが、この傾向はどんな弊害をもたらすのか、将来的にこの業界は資格に対してどのような姿勢で臨んでいくべきなのか。日経BP社では(他の出版社もだが)最近、似たような類いのあまり面白くない書籍が乱出版されていますが、この本は別格だと思うので安心して購入して欲しいと思います。 (★★★★★)

無料ブログはココログ