久々にSQLを直接書きました。とうのは、最近はORマッパーを使うことが多くて、直接SQLを書くことがめっきりなくなっていたからです。しかし今回は既存のコードに手を加える作業をするという状況で、既存のコードがORマッパーなど使用していないコードだったものですから、SQLを直接書くことになりました。
別にDBの専門家ではないので、パフォーマンスのチューニング方法などはあまり詳しくありません。もちろん速度は考慮して書きますが、それは基本的な部分であって、高度なチューニング(例えばDBMSの種類ごとの最適化やストレージエンジンごとの違いの考慮など)はできません。
とは言うものの、そこまで高度なチューニングが求められる場面は、Webアプリケーションにおいて少ないですし、今後も少なくなっていくように思います。基本的な原則(例えば、不要なレコードは取得しない=WHERE句でなるべく絞り込む、など)に則っていればよいと思います。以前はSQLの方で最適化しなければならなかったようなパターンも、DBMS自身の進化によって高速化している例もありますし。
Web開発者としては、そもそもSQLをチューニングしなければならないようなDB構成を避けるという方向性の方がよいような気もします(既存のシステムだとそうも行きませんが、そこはDBの専門家の出番でしょう)。
ということで、Web開発者の自分としては、SQLについては今後も基本的な原則は学んでいこうと思いますが、DBMSの種類ごとの最適化やストレージエンジンごとの違いの考慮といった事項は、DBの専門家にまかせておこうと思っています。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
2014年7月18日金曜日
2014年7月17日木曜日
システム構築に必要な「統一性のセンス」
エンジニアとしてITシステムの構築を生業とするにあたっては様々な能力を必要とされますが、中でも重要な能力だと思っているのが「統一性のセンス」ですね。
これは、直接ユーザの目に触れるユーザインターフェース(UI)についても言えることですし、直接ユーザの目に触れないプログラミングやデータベース構造といったものについても当てはまることです。
例えばUIについては、ボタンの配置の方向や順番や色、アイコンの形、語彙表現など様々な要素について統一性を持たせることが、使いやすさに大きく影響します。
プログラミングについても、変数名・クラス名・メソッド名などの命名規則、論理的構造のパターンなどに統一性を持たせることで、バグの低減やメンテナンス性の向上を図ることができます。
システム構築には美的センスが求められる、と言う場合、その多くは「統一性のセンス」を意味しているのです。なぜなら、統一性のあるUIやソースコードは美しいものだからです。芸術作品では「混沌のセンス」も美的センスとしてアリなのでしょうが、システム構築にはありえないですからね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
これは、直接ユーザの目に触れるユーザインターフェース(UI)についても言えることですし、直接ユーザの目に触れないプログラミングやデータベース構造といったものについても当てはまることです。
例えばUIについては、ボタンの配置の方向や順番や色、アイコンの形、語彙表現など様々な要素について統一性を持たせることが、使いやすさに大きく影響します。
プログラミングについても、変数名・クラス名・メソッド名などの命名規則、論理的構造のパターンなどに統一性を持たせることで、バグの低減やメンテナンス性の向上を図ることができます。
システム構築には美的センスが求められる、と言う場合、その多くは「統一性のセンス」を意味しているのです。なぜなら、統一性のあるUIやソースコードは美しいものだからです。芸術作品では「混沌のセンス」も美的センスとしてアリなのでしょうが、システム構築にはありえないですからね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
2014年7月16日水曜日
他人のソースコードを読む際には推理能力も要る
昨日、プログラミングの際には考え方と目的も記録を残せと書いたんですが、自分はそうするよう気をつけていても、実際に仕事で扱う既存のソースコードにおいて、考え方と目的をコメントや公開サイトや付属ドキュメント等に書いていてくれているのかというと、まあ残念ながら書いてくれていない場合も多いわけですよ。
そういう時は仕方ありませんから、まるで推理小説の名探偵よろしく推理するしかありません。例えば変数やメソッドの名前も人によって微妙に用法が異なったりするので、ソースコード全体の傾向から、その名前が意味する所を推し量ったりとか。静的にソースコードを解析するだけでは分からない時は、デバッグツールを使って実際の動きを見ながら、コードの意味を分析したり、わざとエラーを起こさせてみたり。Javascirptの時なんかはよくやる手段です。
その意味では推理能力も必要ですね。つくづくプログラミングってのは思考を駆使すると思うんですよ。だから楽しいんですけどね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
そういう時は仕方ありませんから、まるで推理小説の名探偵よろしく推理するしかありません。例えば変数やメソッドの名前も人によって微妙に用法が異なったりするので、ソースコード全体の傾向から、その名前が意味する所を推し量ったりとか。静的にソースコードを解析するだけでは分からない時は、デバッグツールを使って実際の動きを見ながら、コードの意味を分析したり、わざとエラーを起こさせてみたり。Javascirptの時なんかはよくやる手段です。
その意味では推理能力も必要ですね。つくづくプログラミングってのは思考を駆使すると思うんですよ。だから楽しいんですけどね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
2014年7月15日火曜日
プログラムを書いたら考え方と目的も記録を残すこと
プログラミングをする過程で、他人の書いたソースコードを読んでいて本当に強く思うんですけど、その実装方法に至る経緯や考え方や目的が分からないと非常に解読に苦労します。
単なる処理の動きだけならソースコードを読めば分かります。でも、例えばどういう時に使うクラスやメソッドなのかとか、以前別の方法で実装したけれど何らかのトラブルがあって直したとか、そういう情報がないときちんと理解出来ないんですよね。
だからソースコードに考え方と目的を、コメントとして残しておくか、あるいはRedmineなどのタスク管理システムを使っているならチケットに書いておくとか、何らかの方法で記録しておくべきだと思います。場合により使い分けるといいと思いますね。
これは将来そのソースコードを読む他人のためでもあり、そして後から修正をすることになった時の自分のためでもあります。忘れるものですからね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
単なる処理の動きだけならソースコードを読めば分かります。でも、例えばどういう時に使うクラスやメソッドなのかとか、以前別の方法で実装したけれど何らかのトラブルがあって直したとか、そういう情報がないときちんと理解出来ないんですよね。
だからソースコードに考え方と目的を、コメントとして残しておくか、あるいはRedmineなどのタスク管理システムを使っているならチケットに書いておくとか、何らかの方法で記録しておくべきだと思います。場合により使い分けるといいと思いますね。
これは将来そのソースコードを読む他人のためでもあり、そして後から修正をすることになった時の自分のためでもあります。忘れるものですからね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
2014年7月13日日曜日
gitのpush前にmerge --squashとpullとrebaseを
gitでどうブランチを切ってコミット・プッシュするかの運用方法については様々な意見というか流派(?)があるように思います。僕自身も複数人数のチームで開発を実際に行う中で、こうしたらいいんじゃないかって思っている方法を書いてみようと思います。
まず開発のタスク管理にはredmineを使っている、という背景があります。gitの共有リポジトリはredmineと連携させていて、共有リポジトリにプッシュしたコミットのメッセージにチケット番号を記載しておくと、自動的にredmineのチケットからリポジトリビューアにリンクされるようになっています。そのような背景から、チケットごとにコミットを1つにまとめています。
さらに、共有リポジトリへプッシュする際は、自分の名前が付けられたブランチにプッシュすることにしています。(masterへのマージはmasterブランチ管理者以外は行わない。)例えば僕はkasaiという名前のブランチを作成して、そこへ自分が担当するチケットを解決するコミットを行い、それを共有リポジトリへプッシュします。
masterブランチ管理者は、共有リポジトリへプッシュされた他の担当者のブランチをローカルリポジトリへプルしてmasterへのマージを行い、改めて共有リポジトリへプッシュします。(つまり、共有リポジトリのmasterへのプッシュを行えるのはmasterブランチ管理者だけです。)
この辺までは結構よくある運用方法でしょうね。ここまで全体的な流れの話を書きましたが、次に、各担当者が個人的に行う運用方法についてです。
僕の場合、ローカルリポジトリにはローカル用ブランチを作って作業しています。ローカル用ブランチは自分のためだけのブランチで、一度行った変更を後のコミットで元に戻したり、試行錯誤の汚い履歴が混在していて、そのまま共有リポジトリにプッシュするなんて考えられない代物です。ちなみに僕はローカル用ブランチには local/yy.mm.dd という名前を付けています(yy.mm.ddは作成時の日付、1日に複数作成した場合はyy.mm.dd-2などとする)。
とういことで、ローカル用ブランチで試行錯誤して、完成したら提出用ブランチ(前述した例ではkasai)にまとめて取り込むという方法を採っています。その際にはmerge --squashを使います。
なお、提出用ブランチにmerge --squashされた後のローカル用ブランチは消してもいいのですが、バックアップの意味もあるし、コードが動かなくなった際に履歴が残っていると原因究明にも役立ったり、元に戻したりできるので残しておくことにしています。
では、提出用ブランチをこのままpushすればいいかというと、ちょっと考えるべき問題があります。pushする前に、共有リポジトリのmasterに、自分が元にした時点から変更がいくつも加わっている場合、コミット内容がmasterと競合しないにもかかわらず、仕様変更によりコードが動かなくなってしまう可能性があります。例えば、他人の担当範囲で定義されていた関数やメソッドを呼び出してコードを書いたが、自分がローカルで作業している間に、その関数やメソッドの挙動を変えるコミットがmasterに既にマージされていた、といった場合です。(この問題に関してはGitユーザマニュアルの「マージコミットの分割が1本線の履歴の分割よりも困難となる理由」の解説が分かりやすいです。)
だから、push直前に、最新のmasterを改めてpullで取得し、その最新のmasterにこれからpushしようとする変更を統合した状態で動作することを確認しておきたいんですね。そのためにrebaseを行ます。つまりpush直前に、自分のブランチをpullで取得した最新のmaster上にrebaseするのです。
こうすることで、上記のようにmaster側に知らないうちに仕様変更が加わっていて、競合が発生しないにもかかわらずコードが動かなくなる、という事態に陥る危険性を(ゼロではないにしても)かなり減らすことができます。また、もしそのような事態になったとしても、rebaseしておくことで原因の究明はぐっとやりやすくなります(当然ながら、これはpush前のコミットだからrebaseしてもいいのであって、たとえ提出用ブランチでも、一旦pushした後のコミットは決してrebaseしてはいけません)。
まとめると、こういう流れになります。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
まず開発のタスク管理にはredmineを使っている、という背景があります。gitの共有リポジトリはredmineと連携させていて、共有リポジトリにプッシュしたコミットのメッセージにチケット番号を記載しておくと、自動的にredmineのチケットからリポジトリビューアにリンクされるようになっています。そのような背景から、チケットごとにコミットを1つにまとめています。
さらに、共有リポジトリへプッシュする際は、自分の名前が付けられたブランチにプッシュすることにしています。(masterへのマージはmasterブランチ管理者以外は行わない。)例えば僕はkasaiという名前のブランチを作成して、そこへ自分が担当するチケットを解決するコミットを行い、それを共有リポジトリへプッシュします。
masterブランチ管理者は、共有リポジトリへプッシュされた他の担当者のブランチをローカルリポジトリへプルしてmasterへのマージを行い、改めて共有リポジトリへプッシュします。(つまり、共有リポジトリのmasterへのプッシュを行えるのはmasterブランチ管理者だけです。)
この辺までは結構よくある運用方法でしょうね。ここまで全体的な流れの話を書きましたが、次に、各担当者が個人的に行う運用方法についてです。
僕の場合、ローカルリポジトリにはローカル用ブランチを作って作業しています。ローカル用ブランチは自分のためだけのブランチで、一度行った変更を後のコミットで元に戻したり、試行錯誤の汚い履歴が混在していて、そのまま共有リポジトリにプッシュするなんて考えられない代物です。ちなみに僕はローカル用ブランチには local/yy.mm.dd という名前を付けています(yy.mm.ddは作成時の日付、1日に複数作成した場合はyy.mm.dd-2などとする)。
とういことで、ローカル用ブランチで試行錯誤して、完成したら提出用ブランチ(前述した例ではkasai)にまとめて取り込むという方法を採っています。その際にはmerge --squashを使います。
なお、提出用ブランチにmerge --squashされた後のローカル用ブランチは消してもいいのですが、バックアップの意味もあるし、コードが動かなくなった際に履歴が残っていると原因究明にも役立ったり、元に戻したりできるので残しておくことにしています。
では、提出用ブランチをこのままpushすればいいかというと、ちょっと考えるべき問題があります。pushする前に、共有リポジトリのmasterに、自分が元にした時点から変更がいくつも加わっている場合、コミット内容がmasterと競合しないにもかかわらず、仕様変更によりコードが動かなくなってしまう可能性があります。例えば、他人の担当範囲で定義されていた関数やメソッドを呼び出してコードを書いたが、自分がローカルで作業している間に、その関数やメソッドの挙動を変えるコミットがmasterに既にマージされていた、といった場合です。(この問題に関してはGitユーザマニュアルの「マージコミットの分割が1本線の履歴の分割よりも困難となる理由」の解説が分かりやすいです。)
だから、push直前に、最新のmasterを改めてpullで取得し、その最新のmasterにこれからpushしようとする変更を統合した状態で動作することを確認しておきたいんですね。そのためにrebaseを行ます。つまりpush直前に、自分のブランチをpullで取得した最新のmaster上にrebaseするのです。
こうすることで、上記のようにmaster側に知らないうちに仕様変更が加わっていて、競合が発生しないにもかかわらずコードが動かなくなる、という事態に陥る危険性を(ゼロではないにしても)かなり減らすことができます。また、もしそのような事態になったとしても、rebaseしておくことで原因の究明はぐっとやりやすくなります(当然ながら、これはpush前のコミットだからrebaseしてもいいのであって、たとえ提出用ブランチでも、一旦pushした後のコミットは決してrebaseしてはいけません)。
まとめると、こういう流れになります。
- ローカル用ブランチを作成し開発を行う。コミットは適宜好きなように行う。
- 提出用ブランチにてmerge --squash でローカル用ブランチの変更をまとめて取り込む。まとめる単位はredmineのチケット単位とする。
- masterブランチにてpullで共有リポジトリの最新の状態を取り込む。
- 提出用ブランチにてrebaseで変更を最新のmaster上に移し替える。
- rebaseされた提出用ブランチにて共有リポジトリへpushする。
- (masterブランチ管理者のみ) 各担当者の提出用ブランチブランチをpullし、ローカルでmasterへのマージを行い、共有リポジトリへpushする。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
2014年7月11日金曜日
オープンソース時代こそ「コメント力」を
オープンソースとしてソースコードが公開されているソフトウェアを仕事で使ってたりするんですが、その際にソースコードを読み込んで目的に合わせてコードを追加したり改造したりするんですよね。で、何が一番大変かって言うと、そのソースコードを書いた作者の"意図を読み取ること"です。
プログラムの動作自体はソースコードそのものを読めば分かります。ただ、この変数をここで加算して、この関数に引数として渡して・・・といったプログラミング言語の処理自体は分かっても、そのソースコードが"何を目的に書かれているのか"が分からなければ意味がありません。
結局、ある一部分の動作がどういう意味を持つのかを知るために、関連するソースコードがを読み漁り、相当広い範囲を調べてようやく分かったりします。ただ、そこまで時間がかかるのには理由がありまして、ソースコードに"コードの目的・意図を記述した"コメントがほとんど無い場合にそうなるのです。
前にも書きましたが、ソースコードを読めば分かるってのは嘘ですからね。プログラムの機械的動作は確かに分かりますが、コードの目的や意図まで読み取るのは簡単ではありません。もちろんソースコードの関連する部分を含め広い範囲を読めば見えてくるのですが、しかしそれもどうなんでしょうか。
やはり、オープンソース時代であるからこそ、ソースコードを読む人に対する配慮は大切だと思うし、だからこそ、コードの目的や意図を分かりやすく記述できる「コメント力」が大切だと思うんですよね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
プログラムの動作自体はソースコードそのものを読めば分かります。ただ、この変数をここで加算して、この関数に引数として渡して・・・といったプログラミング言語の処理自体は分かっても、そのソースコードが"何を目的に書かれているのか"が分からなければ意味がありません。
結局、ある一部分の動作がどういう意味を持つのかを知るために、関連するソースコードがを読み漁り、相当広い範囲を調べてようやく分かったりします。ただ、そこまで時間がかかるのには理由がありまして、ソースコードに"コードの目的・意図を記述した"コメントがほとんど無い場合にそうなるのです。
前にも書きましたが、ソースコードを読めば分かるってのは嘘ですからね。プログラムの機械的動作は確かに分かりますが、コードの目的や意図まで読み取るのは簡単ではありません。もちろんソースコードの関連する部分を含め広い範囲を読めば見えてくるのですが、しかしそれもどうなんでしょうか。
やはり、オープンソース時代であるからこそ、ソースコードを読む人に対する配慮は大切だと思うし、だからこそ、コードの目的や意図を分かりやすく記述できる「コメント力」が大切だと思うんですよね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
2014年7月10日木曜日
プログラミング言語のバイリンガル以上を
現在僕が関わっているプロジェクトは1つはRuby、もう1つがPHPをメインの言語として採用しています。自分自身の経験としても、PHPとRubyは得意とする言語なので両方とも言語を使うこと自体に苦労はありません。その他にもJavascriptは両方のプロジェクトで多用していますし、補助的にPythonも少しだけ使っています。あとは汎用言語ではありませんがシェルスクリプトも駆使します。HTML・CSSの知識は言うまでもありません。
実際プロジェクトの開発を進めてて思うんですが、2つ以上の得意な汎用言語を持っておくと色々メリットが有るんですよね。別にRubyとPHPじゃなくてPythonでもC#でもJavaでもPerlでも何でもいいんですけどね。とにかく2つあれば、色々比較ができるわけで、両方の言語を実際に使って開発した体験・経験を比べることによって言語の特徴が体感覚として分かるわけですよ。
例えば片方の言語で慣れたやり方を、もう一方の言語で実装しようとした時にすんなり行かないことがあったら、そこで言語の強みと弱みが分かります。また、そこでもう一方の言語で実装するときの最適解を考えますから、これも力になります。
それに、複数の言語での実装を知っていると、より汎用的なロジックを考えられるようになります。特定の言語に依存したロジックではく、別の言語でも問題なく実装できるようなロジックを考える傾向がつきます。その方がバグも出にくく、品質の工場にも寄与すると考えられますね。
ともあれ、プログラミング言語はバイリンガルになっておくと色々得をします。もちろん2つに留まらず、3つ4つと大いに越したことはありませんが、まずは2つを目指すとよいでしょうね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
実際プロジェクトの開発を進めてて思うんですが、2つ以上の得意な汎用言語を持っておくと色々メリットが有るんですよね。別にRubyとPHPじゃなくてPythonでもC#でもJavaでもPerlでも何でもいいんですけどね。とにかく2つあれば、色々比較ができるわけで、両方の言語を実際に使って開発した体験・経験を比べることによって言語の特徴が体感覚として分かるわけですよ。
例えば片方の言語で慣れたやり方を、もう一方の言語で実装しようとした時にすんなり行かないことがあったら、そこで言語の強みと弱みが分かります。また、そこでもう一方の言語で実装するときの最適解を考えますから、これも力になります。
それに、複数の言語での実装を知っていると、より汎用的なロジックを考えられるようになります。特定の言語に依存したロジックではく、別の言語でも問題なく実装できるようなロジックを考える傾向がつきます。その方がバグも出にくく、品質の工場にも寄与すると考えられますね。
ともあれ、プログラミング言語はバイリンガルになっておくと色々得をします。もちろん2つに留まらず、3つ4つと大いに越したことはありませんが、まずは2つを目指すとよいでしょうね。
※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。
登録:
投稿 (Atom)