プリプロセッサでダイエットプログラム（iアプリサイズへの対処法）

現在の携帯端末は、スマホのiPhoneとandroidが主流ですが、各々のアプリのサイズの上限って知っていますか？
2020年8月現在で、iOSアプリは4GB、androidアプリは100MBです。

こう見ると随分と差がありますね・・・
androidは大容量のゲームは、後からデータをダウンロードさせる方式にしているのかな。
ヒープは詳しく書いているところがありませんが、端末が数GBのメモリを持っているので、そこまで大きく困ることはないでしょう。

でも今回話題にしたいのは、スマホ誕生前に主力として活躍していたフューチャーフォン（＝ガラケー）で、かつドコモのiアプリの話です。

初期のドコモのiアプリの開発方法が、涙ぐましい努力の結晶だったことを紹介したいと思います。

# ドコモのiアプリのサイズ

時は遡って、ガラケーの時代。
ガラケーのアプリ界を引っ張ったのは、ドコモのiアプリだと認識していますが、当時のサイズ上限はどうだったかというと・・・・

以下は最初期に出された、DoJa-1.0プロファイル上のアプリの情報です。

|機種|アプリサイズ（KB）|ヒープ容量(KB)|
|:-----------------|:-----------------|:-----------------|
|FOMA N2001|10|96|
|FOMA N2002|10|560|
|FOMA P2101V|30|1100|
|FOMA D2101V|10|128|
|FOMA P2002|10|560|
|FOMA SH2101V|30|1024|
|FOMA T2101V|30|1105|

公式ページ
https://www.nttdocomo.co.jp/service/developer/make/content/spec/iappli/#notice05

アプリサイズは10KB、ヒープ容量が96KBが最小でした。
ネイティブヒープなるものが別にいて、端末側のメモリも少し使えたっぽいですが、純粋なJava部分ではこの容量。

アプリサイズは、コードからコンパイルしたバイトコードや、画像などのリソースも含めたJarファイルです。
これを10KB（10240バイト）に抑えていたわけ。

あまり意識しかことないかもしれないので、どのくらいのもんなのか確認してみます。
ただ、iアプリの開発環境を構築するのは難しい事情があるので、2020年8月現在のandroidのアプリサイズで比較します。

- Jota+(Text Editor)　7.7MB
- ストップウォッチタイマー　8.84MB

比較的機能が少なそうなアプリを選んだつもりですが、MB単位は当たり前ですね。
モノも時代も異なるので一概に比較はできませんが、10KB以内に収まるとは想像できません。

# 初期のアプリの開発コード
iアプリのサイズが極めて厳しいことは分かったけど、じゃあどうやって作っていたのよ、と疑問になります。
削る要素はプログラムしかない。

プログラム削ったら機能が不足するので、やりたいことできないと言われると確かにそうですが、一つだけ機能を減らさずにサイズを減らす方法があります。
それは変数名やクラス名、メソッド名を小さくすることです。

コードはかなり適当な感じで書きますが、例えばこんな感じ。


```java:変更前
public class MainFrame {
 
    private static final String TITLE = "サンプルアプリ";
    private static final String ERROR_MESSAGE = "エラーが発生しました";
 
    public void showFrame() {
        try {
            // 何らかの処理
        } catch (Exception e) {
            showMessage(ERROR_MESSAGE);
        }        
    }
 
    public void showMessage(String message) {
        // メッセージ表示処理
    }
}
```
 
```java:変更後
public class F {
 
    private static final String A = "サンプルアプリ";
    private static final String B = "エラーが発生しました";
 
    public void s() {
        try {
            // 何らかの処理
        } catch (Exception e) {
            m(B);
        }
    }
 
    public void m(String s) {
        // メッセージ表示処理
    }
}
```

変数名やメソッド名の文字数を減らしていけば、コンパイルされるclassファイルに書かれる文字数が減るのでサイズ減少が期待できます。
とにかく省エネのプログラムですね。

この程度の大きさのプログラムであれば、これでも読めないことはありませんが、組めば組むほど可読性が悪くなるのは目に見えています。
この問題をどうやってクリアしたのでしょうか？

# プリプロセッサ＋Javaという邪道

先人は知恵を絞った結果、Java言語では使用しないあるものを使用することにしました。
C系の言語でよく使用するプリプロセッサです。

具体的には以下のようなコードを書きます。

```c++:プリプロセッサ使用版のコード
#define _MainFrame     F
#define _TITLE         A
#define _ERROR_MESSAGE B
#define _showFrame     s
#define _showMessage   m
  
public class _MainFrame {

    private static final String _TITLE = "サンプルアプリ";
    private static final String _ERROR_MESSAGE = "エラーが発生しました";

    public void _showFrame() {
        try {
            // 何らかの処理
        } catch (Exception e) {
            _showMessage(_ERROR_MESSAGE);
        }
    }

    public void _showMessage(String s) {
        // メッセージ表示処理
    }
}
```

下記の構文は"_MainFrame"という文字を"F"という文字に変換することを意味しています。

```c++:
#define _MainFrame     F
```

この部分はJavaの構文ではないので、当然Javaコンパイラではコンパイルできず。
なので、プリプロセッサに通します。
そうすると、以下のコードが出来上がり。

```java
public class F {
  
    private final String A = "サンプルアプリ";
    private final String B = "エラーが発生しました";
  
    public void s() {
        try {
            // 何らかの処理
        } catch (Exception e) {
            m(B);
        }
    }
  
    public void m(String s) {
        // メッセージ表示処理
    }
}
```

これでコンパイルすることができるので、あとは普通にビルドするだけですね。

このようにマクロ併用のコードに対し、プリプロセッサ→Javaコンパイラと2段階に分けて通すことで、可読性を上げつつサイズを減少させることができます。
IDEは使えないので、それは大変だったと思いますが。

# 最後に

今回の記事は、10年近く前に別サイトで見たプリプロセッサ併用の工夫を元に書いています。
そのサイトは既に存在しませんが、こんな工夫がされていたことを残したくて書いてみました。