いさぽん部屋(isapon.com)

ゲーム系プログラマによる特に方針のないブログ。技術系とカレー、ラーメンネタ多めだったはずが、最近はダイエットネタ多め。

プログラミングのコツはいろいろなOSやコンパイラを使うこと

だと思います。終わり。

と、それじゃあまりにもそっけないので。 今回のプログラミングというのは広義の意味でのプログラミング。スクリプト言語なども含みます。 コンパイラに関してもかなーり広義……というか、少し解釈を曲げて、「人間が書いたプログラムを機械がわかるように翻訳して実行するもの」としています。なので、本来は別物ですが、仮想マシンやインタプリタなども含めていると思ってください。

結構いろいろなプログラムの案件もこなしてきましたが、その中で感じたことはサーバー系では「ステージングと本番はOSやアプリケーションのバージョンを合わせる」というのはごくごく当たり前なことなのですが、逆に「ステージングと本番以外は異なるOSやアプリケーションのバージョンを使え」ということです。 特に(広義の意味で)プログラム言語やそれに付随するライブラリは、「この機能のサポートが必須」などのよほどの縛りがない限りはある程度バージョンを変えて開発したほうが後々のトラブルを回避しやすくなると思います。サーバーを使わないものにしても、出来ればサポートするOSを種類を変えて用意しておくと良いです。

言語は仕様が変わる

プログラム言語やライブラリはバージョンアップするといくつかの機能が使えなくなったり、場合によっては書式そのものが変わったりすることがあります。これは意図的な仕様変更の時もあれば、バージョンによって「本来は意図しない実装によりたまたま動いちゃった」という状態の時もあります。前者はサーバープログラミングをしている人は何度か体験したことがあると思います。C++を使っていれば、C++11になった際にも大きな仕様変更がありましたし、PHPやPythonだと、何年かに1回くらいやってくるような印象ですね。また、後者は気が付いてないけど実は経験してる方も多いと思いますが、コンパイラをアップデートしたらエラーがなくなった(エラーが出た)!とかね。

これって結構気を付けてプログラムを書いていても、気が付かないうちにひっかかっていたりするもんです。それに、仕様変更なども実はそこそこ頻繁にあるので、全部リアルタイムに追うのは結構至難の業です。それこそ、特定の1言語しか使えません!使いません!というのならまだしも、プロとして複数のプログラム言語を使っているとそうも言ってられません。

こういった事態をなるべく効率よく回避するためにお勧めしたいのが、複数のコンパイラと使うこと。

例えばC++。VisualC++とclang++を使うとか(もちろんg++などでもOKです)。どちらのOSも警告をすべて表示するようにしても、意外にも出ない警告というのがあるんです。例えばfloatからintへの代入なんかはclang++では警告になりませんが、VCでは警告扱いです。この辺りはたぶんコンパイラベンダーのポリシーによるところも大きいと思います。

他にもPHPなどでは、5.2, 5.4, 5.6 あたりを併用してみると、細かい書式の違いがあるのですが、書式の違いがあるところ、つまりは仕様変更を行ったところというのはコンパイラの仕様を考える際に何かしら問題の出やすかったところなど、できれば使用を控えておいたほうが良い部分というのが大半です。異なるバージョンを使うことで、そうした部分を自然と回避しやすい体質が作られます。

とはいえ、どの言語でもそうですがあまり古いバージョンでも動くようにと考えていると、いつまでも新機能が使えずモダンな書き方ができなくなるのでそこはそれぞれの判断にお任せします。個人としては2年くらい前のバージョンくらいまでサポートしておくと無難な感じがします。

OSが違うと「お作法」が違う

Windowsとそれ以外のOSでの分かりやすい違いとしては「ディレクトリセパレータとして扱う記号が違う」ということです。Windowsならバックスラッシュ(¥マーク)で非Windowsならスラッシュ(/)です。正直言えばWindowsも/でいいやん!(ちなみにWindowsは/でも動いてくれます)と思いますが。 その他にも、fork()が使えないとか、ンポラリディレクトリの位置が異なるとか。結構違いがあります。

それにWindowsだけではなく、例えば Linux でもディストリビューションによっても違いがあったり、Linux と FreeBSD でも結構異なります。FreeBSD のユーザーランドを使っている部分も多い MacOSX でもやっぱり違いは多いものです。

WindowsとUnixっぽいOSは結構違いがあれども、PHPやPythonならそのお作法を守っていれば同じように動作します。逆に言えばUnixっぽいOSからWindowsに移行したときに何か不具合が出るなら、環境依存になっている非推奨なコードが混じっていると思っても良いと思います。C++にしても、もちろん限度はありますが、main()関数をスタートしたCUIベースのものであれば、ソースレベルでは互換性があります。例えば、


#include <stdio.h>
#include <stdlib.h>

int main(int, char**)
{
  printf("Hello, World!\n");
  return 0;
}

なんてプログラム(実用性があるかは別にして)はどちらでも意図通りに同じ動きをします。規模が大きなプログラムだとしても、stdioやstdlibをメインに使っている限り、本来はほぼほぼ同じプログラムが動くはずです(実際ほとんどの部分で動きます)。それでもOSが違うと動かない部分があるとすれば、何かしら環境に依存するコードが含まれているのだと疑ってみると新しい発見があると思います。

アップグレードが怖くない

こうしたOSやコンパイラ間で互換性を保つことで得られる一番のメリットはセキュリティホール対策などでOSをアップグレードしないとならないとなったときの恐怖心がかなり抑えられるということです。どのOSや言語も作ってる人は馬鹿じゃない(というか、むしろ頭の出来はかな~り良いほう)ので大きく互換性を崩すことはないのですが、もともと2つくらいのバージョンをまたいで動かしていれば、その延長上でだいたいすんなり動きます。仮に問題が出ても、警告が多少出る程度など、被害をかなり小さなものに抑えることができます。コードを資産として使いまわすことを考えると、これは大きなメリットです。

最後に

別に異なるOSやコンパイラを使うと問題が全て解決するわけではないのですが、運用のことを考えるとかなりの部分で楽ができるようになります。何より、知らぬ間に環境依存になっていた非推奨のコードを見直すきっかけになるので、結果的にはスキルアップにつながりますので、ぜひ試してみてください。 とりあえず最初はビックリするぐらい警告が出ると思いますが、むしろそれを楽しんでみましょう。