22
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

オンラインモブプロ練習会で学んだ、DDDとC#と日本語プログラミング

Last updated at Posted at 2020-04-08

■ 結論: C# における日本語プログラミングは、特性に注意して『やりすぎなければ』最高にイイ。

まず結論です。
やりすぎないように注意を払う必要がありますが、すごく「イイ」です。

さらに本記事を要約すると、以下のとおりとなります。

□【いいところ】

  1. ドメインエキスパートの用語をそのまま利用できる
  • 直感的に理解できる
  • 思いやニュアンスまで表現できる
  • 『違和感』の炙り出しに優れている
  • 説明変数が『真の意味で説明的』になる

□【わるいところ】

  1. 日本語が一杯並ぶと読めなくなる
  • 日本語変換めんどくさい
  • 大文字小文字がないので、命名規則とぶつかる時がある
  • 日本語と英語が混ざってると脳がバグバグしてくる
  • 日本語ネイティブ以外が混ざり得る環境では使えない(使いにくい)
  • 意外と日本語能力が低い人が多い
  • CIサービスなどが、日本語に対応できない場合がある

□【2020年4月現在の、丁度いいと考えている「日本語具合」(C#)】

対象 言語 備考
ネームスペース 日本語 外部サービスでコンパイルに失敗して回避できないなら英語。
クラス 日本語 ※ "Id" などの一般的な単語は翻訳不要。
メソッド 日本語 省略せず完全情報になるように意識する。
プロパティ 主に日本語 単純なValueObjectの場合など区別の必要性が薄いなら英語。
インスタンス変数 主に日本語 区別の必要がない(ひとつのListしか持たない場合など) は英語でもよい。 日本語にも Prefix に "_" をつける。 例:"_ユーザー名"
ローカル変数 主に日本語 大切な所や説明変数は 日本語。Lambda式の中は自明なら (x => x.Value) のように英語。
引数 主に日本語 クラスを受け取ってその型が自明な場合(Id, Name など)は英語一単語とし、そのほかは日本語とする。 また日本語クラスを受け取る場合は短縮名としてもよい。  primitive を受け取るときは完全情報になるようにする。
ソリューションやプロジェクト内のフォルダ 日本語 -

:warning: アプリケーション全体へ全面的に適用すべきか否かはまだ不明です! (まだ部分適用の経験のみ)


# 以下、本編です。


■ そもそも、オンラインモブプロ練習会 is 何?

DDD について学べる Discord のチャンネル #DDD-Comunity-jp で、
架空の『会議室予約システム』を題材としたモデリング・モブプロのオンライン勉強会を行っています。

はじまりは2019年末、同チャンネルで募集のあったオフラインでのモデリング会に参加したことです。
※ そのときの 記事 はこちらを参照ください。

そこから3ヶ月間、1-2週に1回のペースでモデリングの続きと、そのモデルを使ったモブプロを オンラインで 続けています。
この3ヶ月間のモデリング/モブプロ会について、参加者の皆さん & ガヤ参加頂いた皆さんで振り返りを行いました。

※ 私以外の参加された方々のつぶやきはこちら: Twitter

私自身、皆さんと振り返りをしてものすごく沢山の気付きがありました。
今回の記事では、その中でも現在私が着目している 『日本語プログラミング』 について記事に纏めることにしました。
(何この勉強会、、、マジで無料でいいの?)

参考までに、モブプロのフォーマットは下記のとおりです。
これは現状最高かもしれない。ここについては別記事とします。

  • Google Hangout (画面共有・音声)
  • Discord (チャット)
  • GitHub (Push&Pull 方式によるドライバー交代)

■ 日本語プログラミング is 何?

以前、日本語プログラミングの可能性について 記事 を書きました。
この記事を要約すると、以下のとおりです。

  • DDD ではドメインの言葉を使うのに、なぜプログラムは英語で書くの?
  • 日本語と英語を頭の中で翻訳する際に、脳内リソースを使ってしまっているのでは?
  • 日本語ネイティブなら日本語がいいんじゃないの?

上記のような仮説を立ててから、実際にオンラインモブ会で日本語プログラミングを実践 する機会に恵まれました。
また それを元に実業務に適用した結果 と、オンラインモブ会の振り返り を経て、
学んだことや気がついたことについて書いていきます。


■ 日本語プログラミングのいいところ

【いいこと(1)】ドメインエキスパートの用語をそのまま利用できる

エンジニアの皆さんの多くは、日々、日本語ネイティブのお客さんと仕事をしているのではないかと思います。

DDD においては、その事業や業務について詳しい『ドメインエキスパート』と話をしながら、
彼らの使う専門用語を使って一緒にモデリングを進めていきます。

モデリングの時点ではうまく日本語を使えることも多いでしょう。
しかし、何故かプログラミングになると、(ほぼ)英語を使わなくてはいけません。
そう、いままで私達は 『専門用語を英語に翻訳する』 という必要性に駆られていました。

ドメインエキスパートの使う用語を、本当にエンジニアが英訳してしまっていいのでしょうか?
各種翻訳サービスを使いこなして作られているであろうその英語は、本当に正しい文脈を残せているのでしょうか?

  • 日本語から英語に翻訳してプログラムを書く。
  • 英語から日本語に翻訳して解読する。

このプロセスを繰り返すうちに、失われているコンテキストがあるような気がしてなりません。

日本語でプログラムを書くと、このような悩みが消失します。
これは物凄く大きなメリットと考えています。

※ 仮に軽量DDD だとしても、あるいはDDDでないとしても、そのドメイン領域で使用する専門用語には日本語が多く使われているはずです。


【いいこと(2)】直感的に理解できる

これは文字通りそのままです。
日本語ネイティブの私にとって、英語よりも日本語のほうが理解しやすいです。

翻訳というフェーズを挟むことで流れるような思考に邪魔が入ってしまいます。

慣れている単語であれば止まるのは一瞬で済みますが、頻出でない用語が出てきたとき、
英語のクラス名を見て、えっと・・・このクラスは・・・・・と考えることは、想像以上に脳内のリソースを喰っているという実感があります。

実際に日本語プログラミングを導入してみると、英語を見て一瞬止まるという事象が発生しにくくなり、
フロー状態を維持しやすくなった という実感があります(計測してませんが)。

やはり**「翻訳という行為」は、貴重な限りある脳内リソースを無駄に浪費している** のです。
よほど慣れている単語以外では、日本語を読む際と比較して負荷が掛かっています。

また ドメインの用語は得てして複雑な英語になりやすい、という問題もあります。


###【いいこと(3)】思いやニュアンスまで表現できる
これも日本語ネイティブならではのメリットです。
日本語に込められた思いやニュアンスを感じ取ることができます。

例えば「検索」と「探索」という言葉、英語だとどっちも Search になりがちです。
一方、日本語で「検索」と「探索」と書くと、そこには明確な違いがあります。
言葉に思いを宿すことが可能となるのです。

また一般的には、このような思いやニュアンスを残すにはコメントを使用することが多いと思います。
クラスやメソッドにブロックコメントを書けば、IDE がサポートしてくれることもあります。
しかしこれらの情報は、基本的に 能動的に取りにいく 必要があります。

マウスポインタ当てたり、先頭まで読みに行ったり・・・
何てことない作業ではありますがが、やはり脳内リソースが地味に無駄になっています。

日本語でうまく表現できていれば、場合によってはコメントでの補足が不要になるでしょう。


###【いいこと(4)】『違和感』の炙り出しに優れている

日本語で書かれたクラス群やメソッドを眺めていると、違和感や混乱を覚えることがあります。
これは所謂**『コードの匂い』であり、『エンジニア第6感』であり・・・ つまり、『リファクタ時』**という事になります。

もちろん英語で書かれていても同様の事象は発生します。
しかし実体験として、日本語を使ったほうが違和感が表出しやすい傾向にある ように感じています。

 ・『本当に要素が足りているのか?』
 ・『重複はないか?』
 ・『この名前で正しいのか?』
 ・『この名前にこの責務は合っているのか?』
 ・『概念は正しいか?』

などの内容を考える時、日本語話者にとっては、英語よりも日本語のほうが容易だということは想像いただけると思います。
実際に、英語のときは気が付かなかったのに、名前を日本語に修正した瞬間違和感の塊になった という体験をしました。

並んだ英語ひとつずつ脳内翻訳しながら確認すると、認知的な負荷が非常に高まります。
ワーキングメモリが優れた方なら問題ないのかもしれませんが、
パンピーである私にとっては日本語のほうが概念を頭に留めながら確認することが可能でした。

 
また、理由はわからないけどただただ混乱する・・・ という事態が発生することがあります。
その場合は概念そのものがおかしかったり、責務を与えすぎていたり、引数が多すぎたり・・・というコードの匂いでした。

日本語で分からないなら、そもそも本来何で書いても分からないはずです。
しかし英語だと何故か見過ごすことがあります。
こうした違和感に敏感になれるのが日本語のよいところです。


###【いいこと(5)】説明変数が『真の意味で説明的』になる

説明変数、便利ですよね。私はとても良く利用します。
日本語を使うと、この説明変数がより分かりやすくなります。

例えば、『ユーザーの一覧を、複数の条件で1ステップずつ絞り込んでいく』という例を考えます。

英語だと以下のようなイメージになります。

public List<User> WhereManAndHighSalaryAndHighIQ(List<User> users) {
    var usersOfMan                       = users.Where(x => x.Gender == Gender.Man);
    var usersOfManAndHighSalary          = usersOfMan.Where(x => (x.Salary >= 5000000));
    var usersOfManAndHighSalaryAndHighIQ = usersOfManAndHighSalary .Where(x => (x.IQ > 130));

    return usersOfManAndHighSalaryAndHighIQ .ToList();
}

日本語だと以下のようなイメージになります。

public List<User> 給料が高く頭の良い男性に絞り込む(List<User> ユーザーの一覧) {
    var 男性たち                  = ユーザーの一覧.Where(x => (x.性別 == 性別.));
    var 給料の高い男性たち         = 男性たち.Where(x => (x.給料 >= 5000000));
    var 給料が高く頭の良い男性たち = 給料の高い男性たち.Where(x => (x.IQ > 130));

    return 給料が高く頭の良い男性たち.ToList();
}

「どんなメソッドやねん」 とか「ValueObjectは?」とか「それくらい Where() で繋げよ」とか... 多種多彩なツッコミが入りそうですがあくまでも一例です。

英語を読んでから日本語を読んでいるので不公平ではありますが、日本語のほうが『ぱっと見』で理解しやすいかと思います。
少なくとも、日本語のほうが理解が容易 & 早い場合が存在しそうだ ということはご理解いただけると思います。

特に効果が出やすいと感じているのは、上記の例のように、
複数の絞り込み(Filter, Where) を掛けたり、複数の bool 条件をまとめたりするとき などの、
「長い言葉」や「複雑な概念」、「概念の組み合わせ」にならざるを得ない場合。

つまり 「翻訳が大変な場合」 です。

もっともっと複雑な条件で絞り込みを行いたい場合などのことを考えると、
日本語が得意とする細やかな表現が力を発揮する場面 が一定量存在するはずです。

慣れないと間違いなく違和感がありますが、うまく使えれば日本語、強いです。
(うまく使えれば。)


■ わるいところ

良い事ばかりに言及してきましたが、
実は実践を通じて「日本語イマイチだなぁ」と思った点もたくさんあります。

ここからは、このイマイチなところについて記述していきます。


###【わるいこと(1)】日本語が一杯並ぶと読めなくなる

当初、できる限りすべてを日本語にしようと試みました。
ネームスペース、クラス、メソッド、変数、プロパティ、etc ...

結果、とんでもないモンスター を作りあげる結果となりました:imp:

例えばこんなイメージです。

    class ユーザー
    {
        private ユーザーId ユーザーId { get; }
        private ユーザー名 ユーザー名 { get; }
        private ユーザー権限 ユーザー権限 { get; }
        private 有効無効 有効無効 { get; }

        public ユーザー(ユーザーId ユーザーId, ユーザー名 ユーザー名, ユーザー権限 ユーザー権限, 有効無効 有効無効)
        {
            this.ユーザーId = ユーザーId;
            this.ユーザー名 = ユーザー名;
            this.ユーザー権限 = ユーザー権限;
            this.有効無効 = 有効無効;
        }

        public bool 有効なユーザーか() {
            return 有効無効.Value;
        }
    }

シンプルな例なのに読めない。
もっと複雑になるともうマジで読めない。頭パーーーンッ ってなります。

日本語には 文字がたくさん並んでいると区別を付けにくい という特徴があるように感じています。
英語と違って大文字小文字がないので、「文字の高さ」を使った区別が使いにくくなるからではないか、と私は考えています。

したがって丁度いいレベルまで「日本語の量」を落としたり、「日本語の文字のテンポ」を変えてあげる必要があります。
これは、「たくさんの引数が並ぶ良くない状況に敏感になれる」、という良い点とも言えそうです。

※ あるいは境界づけられたコンテキストの内部なのだから、そもそもユーザーというプレフィックスが要らないと言う匂いかもしれません。
  ここでも先述した日本語の違和感炙り出し力が光ります。


###【わるいこと(2)】日本語変換めんどくさい

これはご想像の通りです。
毎回、日本語/英語を切り替えるのは割と手間 です。

また変換を間違えてしまう、という悲しい事故も起こります。
実際にオンラインモブ会で、『群』と『郡』を間違える というやらかしをしています。

さらに頭の痛い問題として、Intellisense がイマイチ効かない、という点があります。
日本語で『ユーザー』と名前を付けた場合、Intellisense を効かすには 『ユ』と打つ必要があります。
漢字で『住所』と名前が付けられていと、『住』と打たなくてはいけません。

『y』とか『z』とか打ったら候補に挙がってくれると最高に嬉しいのですが・・・

したがって、うまく型が限定されて Intellisense が効きやすいコードになるようを意識しないと、ちょっと面倒です。


###【わるいこと(3)】大文字小文字がないので、命名規則とぶつかる時がある

C# であれば、プロパティは PascalCase、引数は camelCase などのルールがあります。
英語であればこれらを大文字小文字で使い分けるのですが、
日本語においてはそもそも Pascal や camel という概念が存在しえません。

たとえば以下のようなクラス『User』を例にします。

class User {
    private UserId UserId { get; }

    public User(UserId userId) {
        UserId= userId;
    }
}

大文字と小文字で、引数とプロパティを区別する、という割とよくある例です。

上記を何も考えずに日本語にするとこうなります。

class ユーザー {
    private ユーザーId ユーザーId { get; }

    public ユーザー(ユーザーId ユーザーId) {
        this.ユーザーId = ユーザーId;
    }
}

お、おう・・・ って感じですね😇
日本語には大文字小文字という概念がないので、区別が付きにくくなるパターンが存在します。

なんてややこしいんだ。

 
・・・そうか、半角カナを使えばいいのか?

class ユーザー {
    private ユーザーId ユーザーId { get; }

    public ユーザー(ユーザーId ユーザーId) {
        this.ユーザーId = ユーザーId;
    }
}

恐ろしいことに、これコンパイル通るんですよね...:bomb:

※ やらないと思いますが、これはダメな例です。  ・・・いや意外と良いぞ...... :bomb:


###【わるいこと(4)】日本語と英語が混ざってると脳がバグバグしてくる

いつ日本語でいつ英語かが安定しないと脳がバグってきます。
特にヤバいパターンの一例としては、「あるクラスの中に日本語と英語のプロパティが同居している」というものがあります。

public class ユーザー {
    public ユーザーId Id { get; }
    public 所属 所属 { get; }
    public ユーザー名 Name { get; }
    public 作成日 作成日 { get; }
    public 更新日 UpdateDate { get; }
}

// 上記をを使うとこうなる
static void Main() {
    var ユーザー = new ユーザー();
    
    Console.WriteLine(ユーザー.Id);
    Console.WriteLine(ユーザー.所属);
    Console.WriteLine(ユーザー.Name);
    Console.WriteLine(ユーザー.作成日);
    Console.WriteLine(ユーザー.UpdateDate);
}

ちょっと無理やりな例ですが、こんな感じで日本語と英語が混ざり始めると混乱しやすくなります。

書く時も日本語と英語のどっちを使えばよいか分からなくなり、
また読むときも、日本語と英語を交互に眺めているとなぜか脳がバグバグしてきます。

最低限、何らかの指針を立てて回避する必要がありそうです。


###【わるいこと(5)】日本語ネイティブ以外が混ざり得る環境では使えない(使いにくい)

日本語の利点を使おうとしているのですから、
日本語が分からない人や得意でない人がチームに居る場合や、
オフショア開発で海外に出す場合などには利用が難しくなります。

この場合はどうしようもないので、諦めるしかありません。


###【わるいこと(6)】意外と日本語能力が低い人が多い

心苦しいですが、断言します。
「日本語ネイティブだけど、日本語がうまく読み書きできないプログラマ」は一定数存在します。

おそらく大手だろうと中小だろうと関係ないでしょう。
居るんです。マジで?ってなるくらい、日本語が書けない/読めない人たち。

またそもそも日本語の良し悪しをあまり気にしない人も居ます。

ここが日本語プログラミングをするにあたっての最大の難所と言えるかもしれません。
メンバーの日本語力への依存が大きい のです。
油断すると読みにくいプログラムになってしまうので、気がついたら英語のほうがマシだったという事にもなりかねません。

このあたりをどうするべきか、という所は今後の課題としたいと思います。


###【わるいこと(7)】CIサービスなどが、日本語に対応できない場合がある

C# は言語的には Unicode に対応していますので、問題なく日本語を利用可能です。

しかし、外部サービスやツールが日本語に対応できないことがあります。

例えば、CircleCI が提供する 純正の C# のビルド環境(2020年3月ごろ) を使ってビルドしたところ、
namespace が日本語だとエラーになったり、またエラー内容が文字化けしてしまったりと苦戦することになりました。

※ 基本的に、中国語が使えていれば日本語でも問題ないはずなので、この路線で探すと面白いかも。中国のC#エンジニアすごいです。


■【2020年4月現在の、丁度いいと考えている「日本語具合」(C#)】

冒頭の繰り返しとなりますが、
実践を通して学んだことを踏まえ、2020年4月現在で丁度良い塩梅かなと思っている「日本語具合」は以下の通りです。

対象 言語 備考
ネームスペース 日本語 外部サービスでコンパイルに失敗して回避できないなら英語。
クラス 日本語 ※ "Id" などの一般的な単語は翻訳不要。
メソッド 日本語 省略せず完全情報になるように意識する。
プロパティ 主に日本語 単純なValueObjectの場合など区別の必要性が薄いなら英語。
インスタンス変数 主に日本語 区別の必要がない(ひとつのListしか持たない場合など) は英語でもよい。 日本語にも Prefix に "_" をつける。 例:"_ユーザー名"
ローカル変数 主に日本語 大切な所や説明変数は 日本語。Lambda式の中は自明なら (x => x.Value) のように英語。
引数 主に日本語 クラスを受け取ってその型が自明な場合(Id, Name など)は英語一単語とし、そのほかは日本語とする。 また日本語クラスを受け取る場合は短縮名としてもよい。  primitive を受け取るときは完全情報になるようにする。
ソリューションやプロジェクト内のフォルダ 日本語 -

:warning: アプリケーション全体へ全面的に適用すべきか否かはまだ不明です! (まだ部分適用の経験のみ)

  

例は以下の通りです。

namespace ユーザー登録 {

    public class ユーザー {

        private ユーザーId ユーザーId { get; }
        private ユーザー名 _ユーザー名;
        private List<権限種別> _権限の一覧;

        public ユーザー(ユーザーId id, ユーザー名 名前, List<権限種別> 権限の一覧) {
            ユーザーId = id;
            _ユーザー名 = 名前;
            _権限の一覧 = 権限の一覧;
        }
    
        public void ユーザー名を変更する(string 新たなユーザー名) {
            _ユーザー名 = new ユーザー名(新たなユーザー名);
        }
    
        public bool 権限を持っているか(権限種別 権限) {
           return _権限の一覧.Any(x => (x == 権限)); 
        }

        public void 権限を追加する(権限種別 権限) {
            _権限の一覧.Add(権限);
        }
    }


    public class Main {
        public static void Main() {
            var ユーザー = new ユーザー(new ユーザーId(100), // 以下省略...
            
            if (ユーザー.権限を持っているか(権限種別.)) {
                Console.WriteLine("神");
            }
        }
    }
}

上記のようにすることで、

  • 言語仕様またはライブラリ等で用意されているクラスやメソッド
  • 自分で作ったクラスとメソッド

を区別できるようになります。

極限まで DDD に寄せるなら、それがたとえ言語仕様であっても
『自分のドメインやコンテキスト』に属さないものを含めるのはよくない事です。

このような考えに則る場合、一般的にはインターフェース等で実装を隠して扱う ものですが、
私は現在、日本語を導入することで明確に分離可能 なのではないか、と考えています。

言い換えると 「日本語なら自分の持ち物。英語なら他人の持ち物。」 ということです。

おわりに

長々と書いてしまいましたが、私にとっても日本語プログラミングは実験段階になります。
もっと改良の余地があると思いますし、改良していきたいと考えています。

私はこうしているよ、といった例やご指摘等ございましたらぜひご教示いただければと思います!

そして最後に、いつも一緒に勉強会に参加いただいている皆さん、本当にありがとうございました!
サイコーな集まりだと思います!

22
14
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?