カテゴリー「システムエンジニアリング」の9件の記事

2012/04/28

OracleのJOINも遅い

でMySQLのJOINでparse時間が極端に長くなる例を上げましたが、同様の症状がOracle 11g R2でも発生しました。

 

MySQLのところで挙げた例では比較的JOINが長かったですが(定説としてはJOINは6回くらいまでに抑えた方が良いらしいですが、それから比べると大したことは無いですが)、今回は単純な2表のINNER JOINで発生しました。特徴として挙げられることと言えば、やや結合条件が多いのと、group byに指定した項目が多いくらいでしょうか。

 

先日参加してきたQCon Tokyo 2012でAmazon Web Servicesがプッシュされていたこともあり、せっかくなのでAmazon EC2上にOTN開発者ライセンスのEnterprise Editionをインストールして検証しようとしたのですが、再現しませんでした…

後から調べたところによると、どうやらバージョン12.2.0.3.0でしか発生しないようで、12.2.0.2.0や、私がインストールしたPSRの無い無償版(12.2.0.1.0)ではちゃんと短時間で返ってきます。

今回はプロダクトを変更する訳にもいかず(普通そうだと思いますが)、色々と試した結果、NO_QUERY_TRANSFORMATIONヒント句を付けることで、そこそこの時間に短縮されました(200秒以上が3秒程度)。

[追記]本事象が発生した時間は、AWRレポートの項目”Parse CPU to Parse Elapsed”パーセンテージがかなり低い(20-30%台)ということが共通する事項としてありました。

 

しかし、Oracleのサポート受けられる状況であればもう少し詳しく分かったのかもしれませんが、今回のところはこのような形で逃げました。

2011/05/05

[読書]プログラマが知るべき97のこと その1 『19:誰にとっての「利便性」か』

 

本書プログラマが知るべき97のことを読み進めているといくつか過去の経験から言いたいことが出てきたので、これはメモ取りながら読んだ方が良いな、と思っていたのですが、そんな環境で本を読む時間がほとんどないことに気付きました(普段読書するのは吊革につかまりながら、なのです)。

また、途中まで書いたメモを読み返すと、結構背景補足を行わないといけないことに気付き、これは私がこの本のようにエッセイを書くのと変わらないな、と挫折しました。

そんなわけで「その1」と銘打ってはいますが(いつもの通り)続編があるかどうかは分かりません…

ちなみに、本書に収録されているエッセイは、CC-by-3.0-USによってライセンスされているそうで、オライリーのサイトで原文を閲覧できます(日本語版では日本の方が書かれた10本のエッセイが追加収録されていますので、本書の全てのエッセイが、というはけではないです)。日本語訳については一部のようですがWikisourceで読めます

 

本章『誰にとっての「利便性」か』では、作る側の利便性よりも使う側の利便性を考えてAPIを設計しましょう、という内容が書かれています。詳細は他の方がすでに書かれていますのでそちらを参照するのが良いでしょう。

そして、以下のような具体例が挙がっています。

たとえば、 walk(true) というようなコードを書かされるよりは、単に run と書ける方が間違いなく使いやすいでしょう。walkとrunは本質的には同じ動作で、ただスピードが違うだけとみなすこともできるのですが、言葉が2つある方が使う側にとっては便利なのです。

私は、著者の主張『作る側の利便性よりも使う側の利便性を考えてAPIを設計しましょう』というのには賛成ですが、walkとrunの例には賛同できません。ただスピードが違うだけなのであれば、ただスピードが違うだけなのだと使用者に伝えるべきで、それを最も明示できる方法の一つがメソッドシグニチャによる表明だと考えます。

今回の例ではwalkとrunの2種しか登場ませんが、これより種類が多い、あるいは種類が多くなる可能性があることを考えてみましょう。おそらく日本の列車種別のように特急、準急、快速ってあるけど結局どれが速いの?ということになるでしょうし、動く(walk/run)以外のAPIも同じように並んでいるとメソッド名を見ただけでは判断がつかなくなると思います。これは使う側の利便性も低下していることになるでしょう。

この例で、私が採ると思われる策は、速さをenumの引数で表すことです。つまり move(Speed speed) のような形になります(Speedがenum)。

  • runとwalkという文字列で表したいのであれば、そのようにSpeedを定義すれば良い。
  • 速さの種類が増えてもインタフェースの互換性は失われない。また、前述の列車種別のような例でもenumの定義順から速さの順番は推測できる。
  • Javaではenumでストラテジパターンも実現可能であり、設計に幅ができる。

(JavaのEnum詳細については書籍Effective Java 第2版 「項目30 int定数の代わりにenumを使用する」を参照してみてください。)

…もしかすると、著者と私で想定している背景が異なっているため、上のような結論の差異が出ているのかもしれません。実際に設計する際には「あの本に載っていたから」を理由にするのではなく、前提条件がその本と一致しているか、自分の問題にも適用するのが最適なのか、などといったことも考慮する必要がある、というのを覚えておくべきでしょう。

 

最後に。本書は「(比較的著名な)プログラマ97人がが考えている、知っておくべきこと集」であって、「プログラマが知るべきことのうちBEST97」ではないことに留意しましょう。もし今年SEになったばかりの人に何か良い本は無いかと尋ねられた場合、おそらく私が本書を勧めることは無いと思います。本書が悪書である、と言いたいわけではなく、新人SEが本書より先に読むべきものは他に沢山ある、ということです(個人的には、本書はファンブックに分類されるものだと考えます)。

(補足: 便宜上プログラマ97人と書きましたが、実際には1人の方が複数のエッセイを書かれていますので正確には73人です(前述したとおり日本語版では+8名)。)

2011/05/03

QCon Tokyo 2011 #qcontokyo に参加した

 

4月12日(火)に開催されたQCon Tokyo 2011に参加してきましたのでその感想などを。文中の敬称は畏れ多いですが「さん」で統一してます。

 

10:00 – 12:00 基調講演

基調講演はEric Evansさんと伊藤直也さんが行われたのですが、当日の朝、比較的大きい地震があり電車が止まってしまいましたのでほとんど参加できませんでした…特に私の一番の目当てであったEric Evansさんのお話が全く聞けなかったのは痛かったです。

伊藤直也さんのお話もほとんど聞けず。基調講演で記憶に残っているのは『グリーのサービスでは既にAndroid利用者数がiPhone利用者を超えている』という1点だけです。なんとなくそういったサービスを利用している人はAndroid?iOS?なにそれ?みたいな人が大半で、そういう人はAndroid端末よりiPhoneを選ぶだろうと考えていたので意外でした。

 

13:00 – 13:50 クラウドのデータアーキテクチャ―設計の原則 萩原 正義 さん(日本マイクロソフト株式会社)

クラウド(型)アーキテクチャを採用する上で最適化にはどういった考慮が必要になるか、というお話で、具体的にはMapReduceでの例、Columnar(カラム指向データベース())での例を説明されていました。Columnarの考え方は普通にRDBでも適用できるんじゃないかな、と思っていたところ、『RDBMSのオプティマイザをあまり舐めない方が良い 』みたいなこともお話しされていたので、そんな私の考えも「何を今さら」という感じなのでしょう。

他には、半導体レベル(FPGA、と説明されてたかな?この辺明るくないので聞き間違っているかも)での最適化の試みもある、というようなことに少し触れられていました。いわゆる業務SEでもそっち系の知識が求められる時代が来るのでしょうか、空恐ろしい…しかし、ある業務に最適化されたハードウェアと”クラウド”って相反するところがあるような。そこまでの最適化ではなく、MapReduceとかHadoopとか、そういったミドルウェア的プロダクトレベルの最適化になるんでしょうかね。

他の方のtweetでは本セッションは基本的な事項に留まっていた、というような意見もありましたが、ぶっちゃけ私ははてなのRDB vs KVS煽り合いホットエントリみたいなところで得た知識しかなかったので、MapReduceって何をするプロダクトなのか、というところから学べたので有意義でした。

 

14:05 – 14:55 品質検査技術のトレンド -レビューと測定・欠陥工学を中心に- 細川 宣啓 さん(日本アイ・ビー・エム株式会社)

申し訳ないことに当日まで細川さんのお名前を存じていなかったのですが、参加してみてびっくり、個人的に超大穴セッションでした。

以前会社に所属していたとき、その会社から品質管理専任としてプロジェクトに来られる方は、はソフトウェア開発スキルが低く、かといってプロジェクトマネジメントもできない方ばかりでした(ああ、これが大企業病の一症状なんだなあ、と思ったものです)。

そういった方たちの持っている品質管理スキルは結局開発者が持っているスキルのサブセットでしかなく、提案された方法も、既により効率的なやり方でやっていたり、手間を複雑にしてるだけだったり、開発者から見て安心・信頼できるとは言い難かったです。

細川さんは、レビュアが的確な指摘を行うために必要なものは経験だ、とおっしゃっていました。ではその経験はいつ得られるのかというと、現状では実際に自分で開発したとき、だけなのではないかと思います。自分が失敗し、それをどうリカバリしたり、あるいは本来どうすべきだったのか考えることでしか得られるようになっていない、ということです。そして、品質管理という立場では、自身が行ってきたことと発生した問題の因果関係が明確になりにくいため、開発者ほど真剣に失敗に取り組んでいない(つまり、開発者ほど大した経験が得られていない)ように感じます。

資料p.22以降にもある通り、細川さんは、品質管理の専門家となるための体系だった知識が未発達であり、この問題の対応策として、バグを世界規模で収集し類型化できるようなデータベースの構築に取り組んでいるとおっしゃっていました。私も、このような分野がシステム開発の一分野として発達すれば、前述したような品質管理者のスキル不足が解消され、専門家としてプロジェクトの中で活躍できるのではないかと考えます。

セッション内容の本筋からは逸れますが、ソフトウェアはバージョンが上がる度(つまり機能が増える度)に品質は下がる、とおっしゃっていました。また、後述Twitter社のEvan Weaverさんは、Twitter社で働いている時間のうち半分はコードを削減するのに費やしてきた、と語っていらっしゃいました。ソフトウェアを成長させていくには、過去のコードに対しても大きな労力が実際には必要であるということです。にもかかわらず、典型的な請負型契約ではそういったことは行えない、といった問題についても、品質管理分野が発達すれば解消されるのかな、と考えたりもしました。

 

15:10 – 16:00 サービスのスケーラビリティと無停止のためのインメモリ技術 杉 達也 さん(日本オラクル株式会社)

Oracle社が買収する前の、Tangosol社時代のCoherenceを少し触った経験があるので、回顧目的で参加しました。私の目的は達成されたわけなんですけれども、技術セッションというよりOracle社のCoherenceプリセールス活動的な色が非常に濃かったので、他の聴衆の皆さんが満足されたのかは非常に疑問が残りました。

前述した萩原さんクラウドアーキテクチャに関するお話を聞いているときに感じていたのですが、Coherenceも自分の欲しいデータがローカルに無い(正確には、有るとは限らない)点やKeyの性質でValueを分散させる点などが似通っているのではないでしょうか。従って、KVSの考え方が応用できたり、また、最適化の際にはKVS的な考慮が必要だったりすると思っています。せっかく世間でクラウドが流行っているのだからそういう点からアプローチすれば良いのに、と感じました(繰り返しになりますが、KVSちゃんと知ったの当日が初めてなので誤解しているかもしれませんが)。

そういえばJavaSpacesという仕様があって、その実装プロダクトであるGigaspacesと比較されることがしばしばありましたし、詳しくは知らないのですがGemstoneやTerracottaといった同等のプロダクトもあるようです。本セッションではJavaEEとの親和性の高さを強調していらっしゃったので、そういった機能でCoherenceと他社プロダクトを差別化する、ということなんでしょうかね。

 

16:15 – 17:05 Performance Engineering at Twitter Evan Weaver さん(Twitter社)

PDFになってしまったセッション資料を見ると色々とはみ出してて不恰好に見えますね…実際の資料は、PDFの最後のページ(28ページ目)が最初に映され、説明が進む度にシームレスに各項目がズームインされる、といった形で、超カッケー感じでした。Preziで作成されたものらしく、こちらのサイトで見られる作品で、どんなものだったかイメージがつかめるかと思います。

一番時間が割かれたのはは、こちらにあるTwitter社の記事についてのことでした。Matz' Ruby ImplementationやRuby Enterprize Edition(RubyにEnterprize Editionなんてものがあるのも本セッションに参加して初めて知りましたが、サイトを見るとGC改良に力を入れているようです)では満足のいくGCパフォーマンスが得られず、自社で改良することにした(Project Kiji)ところ、良い結果が得られた、ということでした。JVMで採用されているような世代別GCを実装したそうです。

セッションの初めの方ではjemalloctcmallocについても触れられていました。が、ちょうど話されていることを直接英語で聞き取れないか奮闘していたため(無駄な努力でしたが)内容分かりません…マルチスレッド環境下ではjemallocの方がパフォーマンスが良い、ということだった、かも。

TwitterサービスはRubyからJVM言語(JavaやScala)に移行している部分もありますが、JVMも大きなオブジェクトのGC管理においては満足のいくパフォーマンス管理が得られていないようです。また、今からTwitterを構築するとしたらどんな言語を使いますか、という質問に対してはJRubyも回答に入っていたことから、Rubyの言語仕様(や言語仕様の決まり方)自体に問題があると考えているわけではないのかな、と思いました。

 

17:20 – 18:10 ドメイン駆動設計においてレガシーシステムを扱うための戦略 Eric Evans さん

残念ながら途中までしか参加できませんでした…dddcommunity.orgのEscaping Legacy while Avoiding Strategic Trapsというエントリに見覚えのある図が出ていましたので、これと似た内容だったのかもしれません。

途中まで参加した内容と、上記リンク先のビデオ(英語は聞き取れないのでスライドからの想像ですが)から想像するに、書籍エリック・エヴァンスのドメイン駆動設計の第4部「戦略的設計」を中心にお話しされたのではないかと思っています。この部分は翌日開催されたDDDチュートリアルの後半でも、寸劇を採り入れるなど時間をかけて解説されていましたのでこの部分重要!ってことなんでしょうね。

 

そんなわけで始めも終わりも中途半端になってしまいましたが、その辺は他の方のblogで補完を、ということで、検索してヒットしたblogのリンクを載せてみました(実際にはもっと多くの方が感想を書かれていると思いますが、私が検索できた範囲で…)。

 

最後に。『QCon Tokyo 2011 にご来場いただいた方の中から希望者全員に「日経コンピュータ」(通常 19,800円)もしくは、「日経SYSTEMS」(通常13,800円)の年間購読を無料でプレゼントいたします。』というのがあったのですが、申し込み用紙出すのをすっかり忘れていました…

2011/02/27

[書籍]DDD日本語版『エリック・エヴァンスのドメイン駆動設計』の発売日が決定した

でも、夏になる前にぐらいに出るーぐらいに思っていただけると幸いです。 RT @kohsei: はい、今のところ、3月に刊行予定のようです! RT @afukui: DDD日本語版は来年出ます。と @kohsei さんが言ってたような。 #devlove #devlove1218
3:36 PM Dec 21st, 2010 TweetDeckから

というtweetをたまたま見つけて心待ちにしていたのですが、『エリック・エヴァンスのドメイン駆動設計』という名前で発売されるようです。2011年4月8日(amazonでは9日になってますね)、5,460円。

原著のタイトルはDomain-Driven Design: Tackling Complexity in the Heart of Software、愛称はDDDです。今の時点ではこの名前で検索かけた方が多くの情報を得られるかと思います。

ドメイン駆動型設計は、上流設計作業内容の見える化だ!!本書は、有益なソフトウェアのドメインモデルを構築するためのテクニック、ノウハウ、パターンを満載した設計ガイドブックです。たとえば、金融・証券系システムなら入出金、流通系システムなら集配、amazonなどネット通販系システムなら買い物かごなど、開発対象領域のシステム毎に必要となる機能やそれらを実現する設計パターンが抽出でき、これにより、従来は分析・設計のひと言でくくられていた作業工程の不透明部分が開発対象領域毎に明確に定義できます。本書は、これらの知見を網羅し、利用するためのポイントをまとめ、現場で分析・設計をする開発技術者必見の1冊となっています。

 

本書の要約のようなものがDomain-Driven Design Quicklyとして日本語版も無料で公開されています(要メンバー登録)。こちらで本書のイメージが掴めるのではないでしょうか。

 

さらに、Qcon Tokyo 2011セッションスピーカとして著者のEric Evans氏が来日され、翌日には来日記念チュートリアルなんかも開催されるようです(参加費ちょっと高いですが)。

QCon Tokyo 2011の開催日が本書発売直後の4月12日(火)なので、読んで予習しとけよーってことでしょう。

 

ちなみに本書、翔泳社のオンラインショップで予約するとTシャツがもらえるそうですよ…!

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のことを考えると、「技術者冥利に尽きる」などとは決して言うことはできないでしょう。万が一そのような言葉を吐かなければならない状況が予想されるのであれば、ここで記載したような対応をオープンにはしないでしょう。

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

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

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

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

 

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

2009/11/29

静的型付けの何が良いか

以前、「動的型付け言語はやはり使用できない」というタイトルでエントリを書いたのだが、「Scalaスケーラブルプログラミング[コンセプト&コーディング] (Programming in Scala)」という本に言いたかったことが書かれていたので紹介する。

 

p.34 1.3.4 静的な型付け(簡潔性、柔軟性、検証可能性、安全性、ドキュメント性):

静的な型システムは、ある種のランタイムエラーが存在しないことを証明できる。たとえば、真偽値が整数に加算されていない、非公開変数がクラス外からアクセスされていない、関数が適切な数の引数に対して適用されている、文字列の集合に追加されているのは文字列だけである、といったことを保証できるのである。
しかし、今日の静的型システムでは、その他の種類のエラーは検出されない。たとえば、終了しない関数、配列の境界を越えたアクセス、0による除算などは検出されない。[中略]そのため、静的型システムは、一部の人々からはあまり役に立たないものだと軽視されている。さらに、静的型システムは単純なエラーを検出できるだけだが、「単体テストならもっと広い範囲のエラーを検出できるのだから、わざわざ静的型システムを使う必要はない」とまで言う人々もいる。

上記の意見は、前エントリのブルース・エッケルの意見と同じ方向だろう。これに対して、以下の反論が続く。

確かに、静的型システムは単体テストの代わりになるわけではないが、プログラムの性質を確認するために普通なら必要だった単体テストの数を減らしてくれる。さらに、単体テストは静的型付けの代わりにはならない。Edsger  Dijkstra(エドガー・ダイクストラ)が言ったように、テストが証明できるのはエラーの存在であって、エラーの不在ではない。静的型付けが与えてくれる保証は単純なものかもしれないが、どれだけテストをしたとしても得られない本物の保証なのである。

 

ダックタイピングという言葉がある。動的型付けにおいて、ダック(と思われるもの)を用いたとき、テストは

  • それがダックであることを確認する(鳴かせてみる)
  • 鳴き声が妥当であることを確認する

の2種類が必要になる。一方、静的型付けにおいては、それがダックであることは確実なので(保証されているので)、

  • 鳴き声が妥当であることを確認する

の1種類で済む。

テストコードを書く場合、もしかすると両者は同じ1つのテストケースで実行可能かもしれない。が、コードレビューを行う場合(実際にプログラムを実行できない場合)では、かなりの負荷になると思う。

2007/07/11

この仕事には、プログラミングがかなり好きでなければ乗り越えられないシーンが含まれています。

株式会社カプコン:“MT Framework”ゲームエンジンプログラマ募集のサイトより。

久しぶりに身震いした言葉。仕事関係でこういうことがあるときは、大体今の仕事に不満がある時期である。

考えてみれば、今の職場にプログラミングが自分より好きであるような人間がいないのでは。

イメージとして、ゲーム作成は、業務システムとは異なりテストフェーズの重要性を正しく理解できている、というのがある(最近のゲーム機はネットワークアップデートが可能になっているからか、旧世代機より間抜けなバグが多くなっているようにも思えるが)。少なくともこの点においては、見習うべきであるなあ、と思う。少なくともプログラミングを行う人間とテストを実施する人間を分けない限りは、品質を高く保つことは不可能ではないか。

テスト対象が、業務システムと比べて、人の興味を引きやすいという違いもあるのだろうか。

2006/01/28

建築も見えにくい

建築とソフトウェアの比較がされるとき、大きな違いとして、建築は見えにくくソフトウェアは見えにくい、というものが挙げられていた。
しかし、耐震偽装の問題では必ずしも建築(物)が見えているわけではない(容易に見えるところだけを以ってして検証が出来るわけではない)ということが分かった。

しかし、法が整備されていたり、法の強化が議論されたり、一般の関心が高さを見るにつけ、ソフトウェア開発の環境は遅れているのだなあ、と感じる。
昨年末からの、東証を始めとする証券システム問題と見比べれば、差は明らかである。

2005/11/12

Visual Studio .NET

私が所属するプロジェクトでは、VC6を用いてクライアントアプリを開発している。
しかし、
http://support.microsoft.com/default.aspx?scid=fh;JA;lifeDevToolFam
にある通り、VC6の製品サポートはすでに終了している。

このことが直接の原因というわけではないが、ついに.NETアプリケーションを、プロジェクトでも開発していくことになりそうだ。

前回のJava開発の際に、品質管理の立場から色々と開発プロセスを策定し、また、このプロセスに従うために必要なツールなどを決定した。
今回.NET開発においても、基本的にはこれに従うことにしたいと考えている。

しかし、使用するツールについては全く調査しておらず、そもそも誰が調査・決定するのかもまだ決まっていない。必要性も今の段階で認識している人がいるのか不明である。
(ちなみに私はこの.NET開発についてはアサインされていない)

今日少しWebを巡回してみたところ、VisualStudio 2005 Team Systemというバージョンではかなり目的のことが達成できるようである。
しかし、用いるVisual Studioのバージョンはおそらく既に決まっており、それはこのVSTSではないはずである。


その他、この開発を進めるにあたって障害になりそうだと思うこと。
  1. ツール購入の問題
    Java開発においては開発ツール(Eclipseから始まり、プロファイラやFindBugsなど)がお金をかけずに揃えられた。これに対し、.NET 開発では同等のツールがあるかどうかを調査する時間が必要であり、また、あったとしても無料で使用できるのかどうか。お金がかかるとなると自社で購入する のかそれとも客の金で買うのかなど、私の権限で決められない。
  2. ツール導入の問題
    PCに新しいツールをインストールしようと思うと許可をもらわなければならず、手続きが滞りがち。滞ると開発が遅れることになるのだが、そういったリスク は今のところ誰も考慮していない。(そもそもエンドユーザPCと開発用PCの運用ポリシーが同じというところでも、開発上大きな問題になるのだが、自社の ポリシーではないのであまり強くはいえない)

今回の件は、品質管理担当に任命しておきながら、私の知らないところで話が進んでいるので、口は出しても手は最後まで出さないようにするのが賢明か。

学生時代は、システム開発会社だと高価なツールが既に使用可能か購入が容易で、MSDN会員にも当然入ったりして、潤沢な開発環境が揃っているとおもって いたのだが、学生時代と比較できないほど求められる要求が高度であるにもかかわらず、開発環境はプアなままである(むしろ学生の頃の方が自分で勝手にフ リーツールを導入できたりして便利だった)というのはつらいことである。
高価なツールを購入しても使いこなせる開発者が少ない、という開発者自身の問題もあることにも驚きではあるが。(使いこなせないと、金を出す方も次から躊躇するのは当然。)



新しいVisual Studioの機能を理解するのに、システム・テクノロジー・アイ社主催のVisualStudio 2005/SQL Server2005 Quick Learningはそれなりに役に立った。

JUnit相当のものはNUnitというものがあり、使用方法、チュートリアルはWeb上に豊富にあるため導入は容易であると思われる。

静的コード分析はFxCopというものがあるらしい。VSTSでは使用可能のようだが、他のバージョンやエディションで使用可能なのかは不明。(gotdotnetのサイトからダウンロードできるようだが)

テストカバレッジやプロファイリングについては、VSTSでは標準機能としてあるようだが、他のバージョン、エディションでは代替機能が用意できるのか不明。

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社では(他の出版社もだが)最近、似たような類いのあまり面白くない書籍が乱出版されていますが、この本は別格だと思うので安心して購入して欲しいと思います。 (★★★★★)

無料ブログはココログ