プログラミング

2022/09/10

Javaのモジュールシステムは複雑性をより増している

Java9以降のモジュールシステムについて、探した記事のリンクをメモ。

【参考】
モジュールシステムを学ぶ - Qiita

モジュールグラフが作られる様子を学ぼう - Qiita

Java 9のモジュール機能「Project Jigsaw」の基本を紹介 (1/2):CodeZine(コードジン)

Java 9のモジュール機能「サービス(SPI)」と既存ライブラリの共存 (1/2):CodeZine(コードジン)

Java 9のリリースとこれまでのトレンドを振り返る (1/3):CodeZine(コードジン)

ソフトウェアの複雑性は本質的な性質であって偶有的なものではない: プログラマの思索

(引用開始)
立ちはだかるモジュールシステム
ビルド設定の不備に起因するエラーが増えた

Java 8 以前
「パッケージ...は存在しません」
「シンボルを見つけられません」
java.lang.ClassNotFoundException
java.lang.NoClassDefFoundError
java.lang.NoSuchMethodError

Java 9 以降(上記に加え。。。)
「モジュールが見つかりません: ...」
「パッケージ...は表示不可です」
「パッケージ...はモジュール...で宣言されていますが、エクスポートされていません」
「パッケージ...はモジュール...で宣言されていますが、モジュールfooに読み込まれていません」
「パッケージ...はモジュール...で宣言されていますが、モジュール・グラフにありません」
java.lang.module.FindException
java.lang.IllegalAccessException

(中略)
Java 8 以前のビルドエラーの原因
クラスパスに必要な jar がない
クラスパスに入れている jar のバージョンが間違っている
だいたい、クラスパスの設定を調べれば解決した(要出典)。

Java 9 以降のビルドエラーの原因
設定漏れなどにより、モジュールの解決が正常に完了できなかった
解決されたモジュールグラフが必要な形を満たしていない

モジュールグラフの作られ方を理解していないと、
エラーの原因が特定しづらい(気がする)
(引用終了)

Javaはもはやシンプルなオブジェクト指向言語ではない。
他言語に比較して不足していた機能を次々に取り込んできたために、とても複雑になっていると思う。
モジュールシステムもそうだろう。

以前なら、Mavenで必要なライブラリを管理していたが、それだけでなく、モジュールシステムを使って、どのライブラリを公開するか、必要とするか、という細かい設定ができるようになった。
便利になったように思えるが、これが曲者だ。

以前なら、ビルドパスに必要なライブラリがあるかどうかだけ気にすればよかった。
しかし、モジュールシステムの設定が正しいかどうか、確認する作業まで増えてしまった。

人月の神話」に偶有的な複雑性と本質的な複雑性の話があったが、モジュールシステムは偶有的な複雑性の範疇と思う。
昔のEJB、そしてPOJO、依存性注入などの考え方も、偶有的な複雑性の範囲と思う。

つまり、Javaは本来、コンピュータの内部構造、システムの内部構造を本来は隠蔽して、プログラマがそんな部分を気にせずに業務ロジックの実装に注力できるように整備すればいいのに、そういう部分までプログラマの能力を浪費してしまう部分がある。
とても繊細な積み木をブロックで組み立てている気持ちになる。

ソフトウェアの複雑性は本質的な性質であって偶有的なものではない: プログラマの思索

モジュールシステムについては色々調べているのでまたメモしておく。

| | コメント (0)

2022/09/02

Javaはなぜ関数型言語になろうとしているのか

今のJavaはオブジェクト指向言語である、というよりも、関数型言語になろうとしているように思えた。
ラフなメモ。

【参考】
JavaプログラマのためのIOモナド - kmizuの日記

yasuabe blog: Java8 の Optionalを Haskellの Maybeモナドっぽく使ってみる

Java の語彙で Maybe を説明してみる - ぐるぐる~

JavaでMonadをはじめからていねいに :: Igreque -> Info

モナドについてSwiftで説明してみた - Qiita

モナドとは「メソッド内の副作用の存在を戻り値の型で表現する」ためのデザインパターンです - Qiita

関数型プログラミングなんもわからん。を考えようと言うイベントを開きました。

ラムダ式や関数型インターフェイスは、まあ書けば理解できるが、OptionalクラスやStreamクラスがなぜ必要なのか、正直分かってない。
ネットで漁って、OptionalクラスはMaybeモナド、StreamクラスはListモナドである、という文章を見つけて、そんな難しい構造を持っていたのか、と今頃気づいてる。
StreamのAPIはMapReduceと同じだな、とか。

モナドを支える圏論は大学院のときに代数幾何学の一つの理論として読んだことがあるが、写像を集合とみなして公理系を打ち立てる、ぐらいのイメージしかなくて、プログラミングの観点でモナドがどのように扱われるのか、まだ理解できていない。
今は、モナドとは、メソッドを副作用を持たない関数にした時、戻り値に状態の型のように副作用の型を持たせるとみなして理解している。

普段の業務系Webシステムで、DBにデータを出し入れするぐらいであれば、関数型言語をわざわざ使って並列処理を効率化するようなシチュエーションなんてない。
ロードバランサ、Webキャッシュみたいに、大量のトランザクションを捌くような処理は、正直フレームワークの中に隠れてしまっていて、普通のプログラマであればそんな低レイヤーは気にしないし、気にしないようなオブジェクト指向なフレームワークを作るべきだと思う。

今のJavaはオブジェクト指向言語だけでなく、関数型言語のAPIも追加されているため、非常に膨大で複雑化してしまっているように思える。

なぜJavaは、わざわざ関数型言語のAPIを取りれたのか?
オブジェクト指向言語のAPIで十分なはずなのに。
Scalaの出現とも絡んでいるのか?

たとえば、Scalaの本を読むと、ScalaのAPIはJavaのAPIと非常によく似ている。
ScalaのOptionはJavaのOptionalと挙動が同じ。
ScalaのFutureはJavaのFutureと挙動が同じ。
Scalaのトレイトは、Javaのインターフェイスがdefaultやstaticで実装メソッドを持つようになったのと同じ。
もちろん、map, flatMapなどはScalaもJavaも挙動が同じ。

つまり、ScalaはJavaとかなり互換性があるように思える。
単にScalaがJVMに乗っていて、JavaAPIを呼び出せる事実以上に、言語の思想としてもJavaがScalaに影響を受けているように思える。

気になるのは、Scalaの書籍は2010年頃に大量に出版されたのに、今はあまり出版されていないこと。
人気も下火になったのかな?

「Javaはなぜ関数型言語になろうとしているのか」については調べてみる。

| | コメント (0)

2022/08/10

Javaのラムダ式の考え方

Javaのラムダ式の考え方について理解できた内容をラフなメモ。
間違っていたら後で直す。

【参考】
Javaにおけるラムダ式とメソッド参照

徹底解説! Javaのラムダ式はどういうもので、どう使えばいいのか!

javaの内部クラスおさらい - Qiita

staticな内部クラス - 技術メモ

【Java】内部クラス(インナークラス)の使い方(static class) | 侍エンジニアブログ

Javaはオブジェクト指向言語ではなく関数型言語だった~「[増補改訂]関数プログラミング実践入門」はお勧めの本だ: プログラマの思索

JavaSilverの感想~Javaはオブジェクト指向と関数型言語の2つの性格を持つ: プログラマの思索

Java8以後は、オブジェクト指向言語ではなく関数型言語とみなした方がいいと感じた。
理由は、ラムダ式のような関数型言語の特徴を取り入れたAPIを多数取り込んでいるからだ。
マルチスレッド、Optional、Stream、IOなどの新しいAPIに触れてみると、ことごとくラムダ式を使って副作用をなくすような処理でいかに書くのか、を目指しているような気がする。

Javaのラムダ式は、RubyやPythonのクロージャみたいなものだと思う。
ただし、Javaのラムダ式では、ローカル変数は実質finalなので更新しようとするとコンパイルエラーになる。
この特徴は、Rubyのブロック、Pythonのクロージャのようなレキシカルスコープとは異なる。

Javaのラムダ式は2つの理解方法がある。

1つ目は、Javaのラムダ式は、内部クラス(Inner class)や匿名クラス(anonymous class)から生まれたものと思えばいい、
ラムダ式のイメージはこんな感じ。

依存しあったクラスが2つある。
→2つのうち1つのクラスを、内部クラスにして1つのソースファイルに統合する。
→static内部クラスにして、内部クラスのインスタンス化を廃止する。
→static内部クラスをメソッド内に取り込んで、ローカルクラスに置き換える。
→メソッド内のローカルクラスを匿名クラスに置き換える。
→匿名クラスをラムダ式に置き換えると出来上がり。

Javaの内部クラス、局所クラス、匿名クラスのような記法は現場であまり使わないから、どこで使うのだろうか、と思っていたが、ラムダ式を生み出すための前段階の仕組みと思えば自然に思える。

徹底解説! Javaのラムダ式はどういうもので、どう使えばいいのか!

2つ目は、「Javaのラムダ式は、関数型インターフェイスを実装したクラスのインスタンスを、簡単に作るための文法」。
つまり、Javaのラムダ式は関数型インフェーエイスを宣言し、実装したクラスからインスタンスを生成する仕組み。

徹底解説! Javaのラムダ式はどういうもので、どう使えばいいのか!

関数型インフェーエイスは、抽象メソッド1個だけを持つのがミソ。
FunctionalInterfaceアノテーションを付けたインターフェイスでは、自動的に関数型インフェーエイスになるが、抽象メソッドを2つ宣言したり、defaultメソッドで実装すると、関数型インフェーエイスではなくコンパイルエラーになる。

では、なぜラムダ式があると便利なのか?
マルチスレッドやStreamAPIでラムダ式を書いていると、処理の宣言と実装を1箇所に書けるのがメリットのように思う。
いちいち、別クラスを宣言して、インスタンスを生成して、メソッドを呼び出すみたいな面倒な処理をたくさん書かなくていい。

ラムダ式を使うと、Factoryクラスは不要になる。
() -> new A()のようなラムダ式を簡単に埋め込めるからだ。

ラムダ式を使うと、Strategyパターンの行数を減らせる。
ポリモルフィズムを使って、それぞれの処理を実装し、インスタンスを生成する部分をラムダ式で1行にまとめられるからだ。

「関数型インターフェイスには1つしか抽象メソッドがないので、戻り値・引数の型と順番を、関数型インターフェイスの型からJavaコンパイラが推測できます。この仕組みを型推論といいます。 」という指摘から、関数型言語の特徴である型推論をJavaでも実現できる。
Haskellと似ているのかな。

実際のエンタープライズJavaの開発現場では、ラムダ式やストリームAPIは禁止されているコーディングルールが多いかもしれない。
でも、Javaに限らず、現代の殆どのプログラミング言語に関数型言語の特徴が盛り込まれているので、今後もチェックしてみる。

残りは、モナドを理解したい。

| | コメント (0)

2022/08/06

Javaはオブジェクト指向言語ではなく関数型言語だった~「[増補改訂]関数プログラミング実践入門」はお勧めの本だ

Oracle Java Gold SE11 を取得するために
徹底攻略Java SE 11 Gold問題集[1Z0-816]対応 徹底攻略シリーズを解いているが、Javaはオブジェクト指向言語ではなく、Javaは関数型言語であった事実に気づき、「[増補改訂]関数プログラミング実践入門 ──簡潔で、正しいコードを書くために」を借りて読んでいる。
Oracle Java Gold SE11 では、ラムダ式とストリームAPIを習得するのがMust要件だが、実は、JavaのOptionalはHaskellのMaybeモナド、JavaのStreamはHaskellのリストモナドに相当する、という文章を読んで、インスピレーションが動いた。
こういうところまで理解しておかないと、たぶんJavaGoldは歯が立たないのだろうと思う。

この本では、Ruby、Python、Java、C++などのソースとHaskellを比較してくれているので、他言語を知っていたら理解しやすくなると思う。
関数型プログラミング言語を習得したい人にとっては、この本はMustだと思う。
まだ全部理解できていないので、これからじっくり読んで消化していく。

| | コメント (0)

2022/07/06

JavaSilverの感想~Javaはオブジェクト指向と関数型言語の2つの性格を持つ

JavaSilverに合格できたので、気づきをメモ。

【参考】
Java SE 11 Programmer I (1Z0-815-JPN) 試験 | Oracle University

Javaメモ目次(Hishidama's Java Memo)

Java新機能メモ(Hishidama's Java up-to-date)

【1】僕はJavaは好きだ。
Javaを習得した後、オブジェクト指向設計やUML、RUPを知りたくなって、開発プロセスの奥深さを学ぶことができた。
オブジェクト指向の考え方を学ぶならJavaはお勧めだと思う。

一方、Java SE11で書いてみると、Javaはオブジェクト指向言語というよりも関数型言語になろうとしている気がする。
実際、ラムダ式やvar、型推論などは関数型言語の特徴をJavaに取り入れている。
Javaに新しくストリームAPIとは何だろう?と思っていたら、何のことはない、MapReduceのAPIに過ぎない。
つまり、関数型言語の特徴を取り入れて並列処理を意識しているわけだ。

そんなことを思うと、Javaはオブジェクト指向言語と関数型言語の2つの性格を持つように進化したのだろうと思う。

以前のJavaから追加された主な文法、機能をメモしておく。
・ module-info.java (exports パッケージ, requires モジュール)
・ javaコマンドのソースファイルモードで直接実行
・ jmod, jdeps
・ アノテーション
・ ラムダ式
・ インターフェースのdefaultメソッド、privateメソッド
・ var型
・ try-with-resources 構文
・ オートボクシング
・ ジェネリクス
・ 可変長引数
・ 共変戻り値によるオーバーライド
・ ストリームAPI=MapReduce用API
・拡張for文

Javaで気づいたことをメモしておく。

【2】Javaのvarについて

varを使えば、わざわざ変数の型宣言はしなくていい。
ただし、型が判定できるような初期値でなくてはいけない。

Java varメモ(Hishidama's Java var Memo)

しかし、varを取り入れることで、今までのJavaの文法や考え方が複雑化していると思う。
たとえば、Javaにはジェネリクスがある。
さらに、ダイアモンド演算子によって、ジェネリクスの型宣言を短く書けるようになった。

ダイアモンド演算子は右辺の型引数を省略(推論)するが、varは左辺の型を推論するから、両方を組み合わせるとややこしくなる。

変数の定義方法の変遷 Java varメモ(Hishidama's Java var Memo)

(引用開始)
ダイアモンド演算子は、右辺の型引数を省略(推論)するものである。
一方、varは左辺の型を省略(推論)するものなので、ダイアモンド演算子とは相性が悪い。
つまり「var map = new HashMap<>();」と書いたら、変数が何の型なのか分からない^^;
(実際に書くと、HashMapと推論される)
(引用終了)

【3】自動ボクシング

プリミティブ型とラッパークラスを同一視して代入できるようになった。
自動ボクシングのおかげで、プリミティブ型はオブジェクトっぽく考えられるかな。

自動ボクシング Java型メモ(Hishidama's Java type Memo)

しかし、オーバーライドする時に、int[]という配列はObject型とみなす場合がある時は正直迷った。

【4】拡張for文

RubyやPythonのようなfor文を書くことができる。
ループ処理の文法は、while→for文→拡張for文→List.forEach()へと進化しているが、過去の文法が残っているのでややこしく感じてしまう。

for each(拡張for文) Java文メモ(Hishidama's Java Statement Memo)

【5】Javaは実行時のインスタンスのメソッドが呼ばれる

Rubyと違って、Javaは実行時のインスタンスのメソッドが呼ばれる。
C++のvirtualメソッドと同じ。

つまり、Javaでは、クラスやインスタンスは、型に強く紐づく。
型は、フライパンのタイヤキの型に例えられる。

実行時のインスタンスのクラスが重要 裏Javaメモ(Hishidama's Java Memo)

この性質を使えば、ポリモルフィズムによって、実行時に動的にインスタンスを切り替えて、同一のメソッドで処理を入れ替えられる。

【6】同一クラス内の同一変数名、同一ローカル変数

(引用開始)
変数名やメソッド名に同じ名前を使える箇所がある。同じ名前が使えない箇所もある。
(引用終了)

重複する名前、同一クラス内の同一変数名、同一ローカル変数 裏Javaメモ(Hishidama's Java Memo)

メソッド内で、フィールドと引数が同じ変数名の場合、thisを使っていないとローカル変数とみなされる。
Eclipseでは、変数名が色付けされるのでフィールドなのか、ローカル変数なのか、区別できるが、エディタ上では判別できない。
普通は、潜在バグになるので、こういう紛らわしい変数名を付けないと思う。

【7】アクセス制御

Javaのアクセス制御は普通の考え方でいい。
注意点は、public/protected/privateのような修飾子がない場合は、同一パッケージ内でしか呼び出しできないこと。

アクセス制御 Javaクラス定義メモ(Hishidama's Java Class define Memo)

下記のような変な書き方もできるが、普通はしないだろう。

スーパークラスを呼ぶだけのオーバーライド 裏Javaメモ(Hishidama's Java Memo)

【8】ラムダ式は無名内部クラス(匿名クラス)を短く記述できる記法

Javaのラムダ式は、Rubyのクロージャを知っていればすぐに理解できるだろう。
一方、Javaの観点では、ラムダ式は無名の内部クラスで冗長に書き換えられる。

Javaラムダ式メモ(Hishidama's Java8 Lambda Expression Memo)

ラムダ式の注意点は、「ラムダ式内部で外側の変数を使う場合は、その変数はfinalもしくは実質的finalでなければならない。」
つまり、「ラムダ式の外側で定義されている変数を、ラムダ式内部から参照することが出来る」が、書き換えは不可。
コンパイルエラーになる。
RubyやPythonのレキシカルスコープとは異なる。

【9】リソース付きtry文

Javaでも、例外をキャッチしたらリソースClose→finallyが簡便に書けるようになった。
Rubyのbegin~rescue~ensureと似てる。

リソース付きtry文 Java文メモ(Hishidama's Java Statement Memo)

リソース付きtry文が無い頃は、finallyの中でさらに、try~catchをわざわざ書いていた。
Release It! 本番用ソフトウェア製品の設計とデプロイのためににも、それを書かなかった場合の本番障害の事例が書かれていた。

| | コメント (0)

2022/06/20

Javaのenum型はシングルトンクラスみたいだ

Javaの最新版に触れてみたら、enum型にコンストラクタやメソッドを持たせることができると分かった。
ちょっとびっくりした。

(2) よしけーさんはTwitterを使っています: 「enum にメソッド持たせるのは effective Java あたりを読まないと気がつけない気がする。。 #ドメインモデルパターンに挑戦する苦労ばなし」 / Twitter

(2) akipiiさんはTwitterを使っています: 「Effective Javaにenumのパターンが確かに書いてあった。enumでメソッドを定義する発想がなかった。後で読む」 / Twitter

あなたの知らないJava enumの使い方 - SEチャンネル

Effective Java 第3版 第6章enumとアノテーション - Qiita

Effective Java 3rd [Chapter 6] - enum とアノテーション - Little by little and bit by bit - マイペースにこつこつと

【Effective Java】項目30:int 定数の代わりに enum を使用する - The King's Museum

Effective Java 第3版 「ほぼ全章」を「読みやすい日本語」で説明してみました。 - Qiita

ドメイン駆動設計に関する勉強会で、Javaのenumにメソッドを持たせられるというツイートを見た。
Effective Java 第3版 | Joshua Bloch, 柴田 芳樹」を読んでみたら、たしかにenumに1章を割いて、詳しく説明されていた。

個人的印象としては、JavaのEnum型はシングルトンクラスみたいだ。
グローバル変数の出し入れに使える感じ。
使い道としては、業務システムのシステムコントロール定数を持たせたい時だろうか。

Javaから離れていたので、最新版のAPIや文法がかなり変わっているのに気づいた。
Javaはオブジェクト指向言語だというぐらいのイメージしかなかったが、RubyやPython、JavaScriptなどの良い面をJavaも取り入れようとしている印象を受ける。
Javaにラムダ式ぐらいを取り入れるのはまだよいが、ストリームAPIは何かやりすぎな感じもした。
気づいたことはまた書く。



| | コメント (0)

2022/05/26

「コーディングを支える技術」は良い本だ

コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)」を読んで、良い本と思った。
ラフなメモ書き。
プログラミング初心者の適当な感想。

【参考】
コーディングを支える技術――成り立ちから学ぶプログラミング作法:書籍案内|技術評論社

「コーディングを支える技術」著者公式ページ
「コーディングを支える技術」著者公式ページ 補足記事

【1】Javaで開発経験をした後、RubyやPythonを覚えた今、「コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)」を読むと、ああそういうことか、と気づくことがある。

【2】IF文の裏ではGOTO文が動いている、という内容を読んで、VBのことを思い出した。
VBでは、例外処理などのAPIが貧弱なので、割とGOTO文がよく出てくるので、VBは好きでなかった。
たぶん、APIが貧弱な古いプログラミング言語ほど、GOTO文が幅を利かせている。
その分、何でもできるが、とても読みづらく保守しづらい。

コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)」の一節に、大学でC言語を初めて習った人が、「while文があればfor文はいらないのでは?」と思ったらしいと書かれていた。
僕も似たような感覚を抱いていた時があった。
JavaでもRubyでも、なぜ、while文、do-while文、for文、拡張for文など、似たようなループ処理の文法があるのか?と不思議に思っていた。

理由は単純で、当初はIF文みたいにwhile文を使っていたが、カウンタ変数のスコープがブロック外にあるので使いにくいから。
だから、while文からfor文の記法により、カウンタ変数のスコープはブロック内に収まった。
さらに、拡張for文により、カウンタ変数そのものも不要になった。
さらに、ListのforEachメソッド、Rubyのブロックのように、for文はクロージャとして吸収される。
つまり、プログラミングの文法もどんどん進化しているわけだ。

【3】変数のスコープの説明では、Perlで静的・動的スコープをプログラムで説明してくれている。
Perlを初めて書いていた時、なぜlocalやmyを変数に付ける必要があるのか、分からなかった時を思い出した。

Pythonでは、わざわざglobal/nonlocalで変数のスコープを制御できるようにしてくれている。
この文法を見た時、Perlみたいだな、と思ったことを思い出した。

Rubyなら、def~endのブロックとクロージャのブロックで、変数のスコープが異なるように使い分けている。
この文法は最初は理解しづらかったが、このおかげで、Rubyはメタプログラミングでやり放題ができるわけだ。

【4】オブジェクトとクラスでは、JavaとRubyでは考え方が全く違う。
親子で継承関係にあるクラスがあった時、インスタンス変数、インスタンスメソッド、クラス変数、クラスメソッドの挙動がJavaとRubyで異なる。
Javaでは、インスタンス変数、クラス変数、インスタンスメソッド、クラスメソッドは、親子クラスそれぞれで保持する。
ただし、親クラスの変数に、子クラスのオブジェクトを代入した場合、インスタンスメソッドは、子クラスのメソッドを利用する。
つまり、Javaでは、親クラスの変数の振る舞いは、ポリモーフィズムで動的に処理が変わるように見せかけられる。

一方、Rubyでは、親子間でインスタンス変数が共通として扱われる。
親クラスが定義したインスタンス変数と同じ名前のインスタンス変数を子クラスで使うと、親クラスのインスタンス変数は子クラスで上書きされる。
この書き方に慣れると、「クラス(型)は仕様である」を時々忘れてしまう。

資格取得に40代後半からチャレンジ JavaとRubyを比較(注意しておくことその1)

資格取得に40代後半からチャレンジ JavaとRubyを比較(注意しておくことその2)

資格取得に40代後半からチャレンジ JavaとRubyを比較(注意しておくことその3)

資格取得に40代後半からチャレンジ JavaとRubyを比較(注意しておくことその4)

Javaでは「クラス(型)は仕様である」が、Rubyではメッセージを渡したオブジェクトに全てを委ねる。
Rubyはまさにダック・タイピングなので、例えばdesktop.printが変数なのか、メソッドなのかも動かしてみないと分からない。

【5】多重継承のデメリットをどう解決するか?も、Java、Ruby、Pythonなどで全く違う。
Javaは多重継承を禁止するが、インターフェイスを導入して解決しようとした。
Javaでは、継承の代わりに委譲を進めるが、さらに委譲の参照をソースにハードコードするのではなく、依存性の注入により、設定ファイルを使って動的に変更できるような手法が多くなった。
JavaのフレームワークではDIが多いから、設定ファイルにXMLを用いることが多く、その分、プログラムを書くよりもXMLを書いている時が多くてあまり楽しくなくなる。

Rubyは、多重継承の問題を「どの順番で継承関係を検索するか」という問題に置き換えた。
Rubyでは継承関係は、Objectを頂点とするツリー構造だから、継承ツリーをメソッド検索することで解決しようとする。
include, prepend, refinementsはそういう使い道だろう。
また、Rubyでは、どうしても多重継承したい時は、モジュールでMix-inを使う。

Pythonでは多重継承できる、と聞いていてまだ理解できていなかったが、「コーディングを支える技術 ~成り立ちから学ぶプログラミング作法 (WEB+DB PRESS plus)」によれば、C3線形化のアルゴリズムで継承関係の検索を決めることで解決しているわけだ。

[Python入門]多重継承:Python入門(1/2 ページ) - @IT

Pythonのメソッド解決順序(MRO) - 情報系大学院生の勉強メモ

【6】それから、並行処理のプログラミングの章も非常に分かりやすい。
Windows3.1やMacOS9は強調マルチタスクで、プリエンプティブマルチタスクではなかった、という一節を読んだ時、昔のPowerbookがMacOS9だった時を思い出した。

並行処理の問題点は、競合状態が起きること。
競合状態は3つある。
1つ目は、2つの処理が変数を共有している。
2つ目は、少なくとも1つの処理がその変数を上書きする。
3つ目は、一方の処理が一段落付く前に、もう一方の処理が割り込む可能性がある。

1つ目の対策は、結局スレッドを使っているので、変数を共有しない方向で解決していない。
アクターモデルのように、メッセージを送ることで解決しようとしている。
Erlangがその例だろう。

2つ目の対策は、メモリを共有しても書き換えないようにする方針もある。
全ての変数はImmutableにすればいい。
Haskellなどの関数型言語がそうだろう。

3つ目の対策は、協調的なスレッドを使う。
たとえば、Rubyのファイバー、Cのコルーチン、Pythonのジェネレータ。

あるいは、ロック、ミューテックス、セマフォ、モニタのような機構を使う。
Javaなら、synchronizedブロックで囲むだけでいい。

【7】自分は「プログラミングのできない山羊」出身なので、プログラミングを経験してやっとこういう本の内容が分かってきたという気がしている。
ソフトウェア開発は、数学や物理、経済学、財務会計、心理学などと違って、やっぱり独特の考え方がいると思う。
自分の中で言語化できていない部分は気づいたらブログで残しておく。

「プログラミングのできる羊とできない山羊を区別する方法」の記事のリンク: プログラマの思索

「60%の人間はプログラミングの素質がない」記事のリンク: プログラマの思索

プログラミングしてる時はでっかいピタゴラ装置を作ってるみたいな感じ: プログラマの思索

プログラミングは「ブロックを組み合わせる」感覚に似ている: プログラマの思索

| | コメント (0)

2022/01/09

「RubyやRailsは終わった」という記事のリンク

「RubyやRailsは終わった」という記事があったが本当なのか?
見つけた記事だけをリンクしておく。
自分が後で読むためのメモ書き。

【参考】
“Rubyは死んだ”のか? まつもとゆきひろ氏が語る「プログラミング言語サバイバル」とRubyの未来 - Part1 - ログミーTech

Ruby2系はチームの幸福度を最大化できなかった - Qiita

「Railsは終わった」と言われる理由 - Qiita

Rubyは死んだというが。流行り廃りに拘らず、便利なものは活用すればいいのに - Qiita

Rubyは果たして死んだのか | 日経クロステック(xTECH)

Rubyは終わった?将来性と今後の展望をまとめてみた│エンジニアハック

将来性のないプログラミング言語5選として「Ruby」が挙がり話題に | スラド IT

個人的にはRubyは好きだ。
メタプログラミングRuby 第2版」を読んで、色々動かして、やっとダックタイピングの意味が分かった。
やはりRubyはJavaとは違う。
Rubyは究極のオブジェクト指向言語なのかもしれない。

また、Rubyというコミュニティも素晴らしいと思う。

なぜソフトウエア後進国の日本でRubyは成功したのか?~ソフトウェアの成功の秘訣はコミュニティ、そしてコンウェイの法則にある: プログラマの思索

一方、RubyはPerlのシンタックスを受け継ぐ部分があるせいか、初心者には読みにくい記法がある。
慣れないと使いこなせない部分もある。

「Rubyのしくみ」を読んだ後のRubyの感想: プログラマの思索

Ruby技術者認定試験の感想: プログラマの思索

Ruby初心者が間違いそうなこと: プログラマの思索

メタプログラミングRubyの感想: プログラマの思索

Rubyのブロック、Proc、lambdaのメモ: プログラマの思索

RedmineやRubyについては今後も追いかけていく。


| | コメント (0)

プログラミングしてる時はでっかいピタゴラ装置を作ってるみたいな感じ

「プログラミングしてる時はでっかいピタゴラ装置を作ってるみたいな感じ」というツイートを見つけたすごく共感した。

【参考】
Rui UeyamaさんはTwitterを使っています 「少数派の意見かもしれないけど、プログラミングしてるときはでっかいピタゴラ装置を作ってるみたいな感じで、数学が関係ある感じがあんまりしない。」 / Twitter

結城浩さんはTwitterを使っています 「@rui314 デバッグしてるときと証明読んでるときはなんか似てる。素直に読みつつ穴探ししてるみたいな感覚。」 / Twitter

英語勉強中さんはTwitterを使っています 「@rui314 めちゃくちゃわかります。僕は書いてるとき数学のことなんか考えてないです」 / Twitter

akipiiさんはTwitterを使っています 「プログラミングはこの感覚に近いな」 / Twitter

プログラミングは「ブロックを組み合わせる」感覚に似ている: プログラマの思索

「プログラミングのできる羊とできない山羊を区別する方法」の記事のリンク: プログラマの思索

「60%の人間はプログラミングの素質がない」記事のリンク: プログラマの思索

プログラマに必要なスキル: プログラマの思索

プログラムを書いている時、数学の知識を使っているかと言われるとそうではない気がする。
むしろ、APIやFWのライブラリをまずは頭に叩き込んでおき、自分が実装したい目標に対して、それらAPIをどうやって組み合わせて意図通りに動かすか、に注力している。
ちょうど、ブロックで巨大な積み木を組み立てている感じに似ている。

だから、「プログラミングしてるときはでっかいピタゴラ装置を作ってるみたいな感じ」にはとても共感するし賛同する。

たとえば、RDBでSQLをデータ抽出したり、機械学習や深層学習のライブラリを使って母集団を推定したり、マーケットを予測したり、Web上の通信を暗号化したりする時、数学の理論はAPIやライブラリの中に隠れてしまっている。
それらライブラリを呼び出すだけで、高尚な理論を使えるのは素敵だが、だからと言って、プログラミングが楽になっているわけではないと思う。

一方、やりたいことを実現するには、PythonやRDB、Webサーバー、Dockerなどの開発環境を揃えて、Githubで構成管理し、CIツールでビルド&デプロイできるようにして、Jupyter を動かせるようにしたり、IntelliJなどの開発環境を構築したり、とプログラミングの前準備がすごく多い。
普通の初心者はこの部分で挫折するのだろうと思う。

僕自身、新しい環境を揃えてプログラミングスタイルを覚える時は割と苦痛に感じる時もあった。
Ruby on Railsもそうだし、AWSでの環境構築、GNS3でのCiscoルータ&スイッチの環境構築の時もそうだ。
Python+Anacondaはまだマシだった。
プログラミングは奥が深い。

| | コメント (0)

2021/07/23

値オブジェクトの設計がオブジェクト指向モデリングの最初の登山口

先日7/14に開催された「アジャイル開発におけるモデリング活用実践セミナー」のオンライン動画を見ていて、興味深かった。
羽生田さん、増田さん、原田さん達の会話が面白かった。
気になった発言をラフなメモ。
自分の感想も混じっていて、全くロジカルでない。

【参考】
「アジャイル開発におけるモデリング活用実践セミナー」(2021.07.14開催) - UMTP 特定非営利活動法人UMLモデリング推進協議会

ドメイン駆動設計が好きで、ベンチャー企業のWebサービスの開発で使っている

最近は、基幹系システムのリプレースでドメイン駆動設計を使いたい、という話も多く来ている
すごく難しいけど、やりがいもあるし面白い

オブジェクト指向モデリングのワークショップでモデルを書こうとすると、みんな、フレームワークが前提でモデルを書いてしまう
ドメインの外側ばかり話している
肝心のドメインをプログラミングしようとすると、意外に誰も書けない
まずは値オブジェクトから始めよう
みんな、値オブジェクトでプログラミングできない
増田さんのオブジェクト指向モデリング本「現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法」は、値オブジェクトから書こうとしているのでお勧め

intやStringのデータ型だけではトランザクションスクリプトみたいに書いてしまう
値オブジェクトが大事
オブジェクト指向では、Immutableな値オブジェクトから始まる
関数的プログラミングとも相性がいい
ドメインに特化してプログラムを書こうとすると、必ず値オブジェクトから始まる
値オブジェクトの設計がオブジェクト指向モデリングの最初の登山口

エンティティを重視するとデータモデリングになってしまう
手続き型プログラミングで、でかいエンティティを書いて、長いトランザクションスクリプトを書くと失敗する
書いていて怖い
データモデリングとオブジェクト指向モデリングは違うと考えた方がいい

エリック・エヴァンスのDDD本「エリック・エヴァンスのドメイン駆動設計」に出てくる例では、OODBを使っていた
昔はデータのストアはOODBでいい、という感じだった
OODBでは性能が出ないので廃れた

業務の複雑さに関するデータのモデリングは、データモデリングの方が一日の長がある

1990年代にモデリングが盛んだったのに、現代ではモデリングが廃れたのは、モデリングが伝承されなかったからではない
むしろ、現代的な課題に対して、長年知られていたモデリング手法のこの部分は今も使えるが、この部分は今は使えない、という交通整理された本がほしいね

2010年代にピアソン本が絶版されたので古いオブジェクト指向モデリング本が手に入らなくなり、エリック・エヴァンスのDDD本「エリック・エヴァンスのドメイン駆動設計」だけが唯一残った
そのために、オブジェクト指向モデリングの歴史に断絶がある

メソッドは3個まで
それができない人は、クラス化、カプセル化が分かってない
入出力処理は手続き型になりやすい

顧客との対話では、UMLを普通に使う
ただし、アクティビティ図、コンテキスト図、データフロー図を使う場合が多い
システム要件に落とす時は、UMLをガンガン使う

要件定義でモックを作るときはHTMLを使う
最近はいい感じですぐにモックデザインが作れる
実データを画面で見せた方が早い

プロダクトオーナーとの対話では、RDRA2.0を使って話する時が多い
システム設計では、UMLを使っている
図を書くのが目的ではなく、会話や意思決定のために使っている

DDDのエンティティはミュータブル?イミュータブル?
Webならイミュータブルが普通でしょ
setter, getterと無関係なモデルにしている
イミュータブルが普通
エンティティに状態は持たせない
void実行でなく、新しい状態のオブジェクト、エンティティを別で返す
Webならイミュータブルが普通
エンティティの状態をSetして変更すると、バグが出そう
イミュータブルだからFreezeしているのでCloneする必要もない

アジャイル開発プロセスとモデリング作業の事例は?

モデリングでも、概念モデルのレベルでプログラミングを書く
合わせてDFDやER図を書く
事業分野の可視化はシステムで書きにくいので、シナリオ、バリューチェーンを書く
バリューチェーンで、どこのプロセスに差別化要素があるか、強みがあるか、を分析する
ビジネスを理解するモデリングとシステムとして動かすプロトタイプの2つを行き来している

増田さんのドメインモデルのサンプルが分かりやすい
パッケージ図でクラス図を分割して、HTMLで一覧にしている
さらに、ユースケースのシナリオからパッケージ図、クラス図まで一気通貫でHTMLにしている
軽量で明快なモデリング
ビジネスモデルとDFD・ER図をつなぎつつ、パッケージ図・クラス図で方にしてHTMLで見せている
増田さんのクラス図は値オブジェクトが中心
取引日、貸し出しも全てクラスになっている
増田さんにとって、モデル駆動とはドキュメント駆動のイメージ
ソースコードとモデルを行き来していて、モデルが自然にドキュメントになっている

Scrumで開発する時に、ユーザーストーリーマッピングを使う場合が多い
このメソッドを実装する時、このメソッドはこの要件から来ていて、この要件はユーザーストーリーマッピングのこの部分に対応する、と辿れる

【感想】
エリック・エヴァンスのドメイン駆動設計現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法を読むと、ドメインのソースコードが値オブジェクトになっている場合が多い。
その理由は、ドメインをプログラミングに注力しているから、と見ると分かりやすい気はする。
オブジェクト指向でプログラムを書くと、状態を持たせるエンティティが頻出して、バグが出やすい箇所はたいていその部分であり、デバッグしないと追跡できない場合が多いのを思い出した。

| | コメント (0)

より以前の記事一覧