3秒でわかる
同じコードや成果物を、OS やハードウェアの違いを気にせず動かせる性質。実行環境が差を吸収するため、開発機と本番機がそろっていなくても動きます。
もう少し詳しく
どういうものか
書いたプログラムが、Windows でも macOS でも Linux でも同じように動く性質を指します。CPU や OS の違いを、プログラム本体ではなく実行環境の側が吸収することで成り立ちます。
Java の「一度書けばどこでも動く」という考え方が代表例です。コンパイル結果は特定の OS 向けの機械語ではなく、中間形式のバイトコードになり、それを各 OS 向けに用意された JVM が解釈して実行します。Python や JavaScript のインタプリタ、コンテナ、WebAssembly も、位置づけは違えど同じ役割を担います。
ソースコード (1つ)
↓ コンパイル
バイトコード (1つ)
↙ ↓ ↘
JVM(Win) JVM(mac) JVM(Linux)
↓ ↓ ↓
各 OS 上で同じ動作なぜ必要か
OS ごとに別のコードを書くと、保守する対象がそのまま2倍3倍になります。修正を1つ入れるたびに、すべての版へ反映し、すべての環境で試すことになります。
開発と本番で環境が違う現場でも効きます。手元は macOS、本番は Linux という組み合わせは珍しくなく、成果物が環境をまたげることが前提になっています。
具体例
# 手元でコンパイルする (1回だけ)
javac Main.java # Main.class バイトコードができる
# 同じ class ファイルを別 OS へ持っていって実行できる
java Main// パス区切りを直書きせず、環境に<a href="/glossary/decision" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">判断</a>させる
import java.nio.file.Path;
Path p = Path.of("data", "report.csv"); // OS ごとの区切り文字で組まれるつまずきやすいところ
言語が非依存でも、書き方次第で環境に縛られます。パス区切りを \ と直書きする、改行コードを \r\n と決め打ちする、文字コードを指定せずファイルを読む、といった箇所は移した先で壊れます。標準ライブラリの環境非依存な API を使い、文字コードは明示します。
ネイティブライブラリに依存する部分も例外です。特定 OS 向けのバイナリを含むパッケージは、その OS でしか動きません。
コンテナも万能ではありません。Docker イメージは CPU アーキテクチャに紐づくため、Apple Silicon の手元で作った arm64 のイメージは、amd64 のサーバーではそのまま動きません。ビルド時にアーキテクチャを指定する必要があります。
覚え方
差を消しているのではなく、差を引き受ける層を1枚挟んでいる。その層 (JVM、インタプリタ、コンテナランタイム) がどこにあるかを意識すると、動かない理由も追いやすくなります。