オブジェクト指向はすでに粒度が時代にあっていない

定期的にオブジェクト指向disを書いてしまってるのだけど。

とりあえずオブジェクト指向の話をすると定義が人によって違いすぎるので、改めてここでの定義を書いておくと 、基本的にはOMTの「データ構造と振る舞いが一体となったオブジェクトの集まりとしてソフトウェアを組織化すること」 に従うのですが
「1990年に流行りソフトウェア開発のすべてを飲み込み、いまとなっては人それぞれ定義が違って技術的議論に使えなくなった、主にオブジェクトを基本単位としてプログラムを整理するやりかたを指すマーケティング用語」
という感じです。
ほとんどの場合で人によってオブジェクト指向の指す範囲が違いすぎて、技術的知見の共有には使えなくなっています。でも、いずれの定義にしろオブジェクトを基本単位にするというのは重要ではないかと。
ソフトウェアの組織化の単位としてオブジェクトを使うというのが大事で、データの搬送に構造体代わりのクラス使うくらいでオブジェクト指向っておおげさに言う必要ないと思ってます。

なので、オブジェクト指向いらないと書いたときに「大きいプログラム作らなければそれでいいんでは」みたいなコメントつくけど、「大きいプログラムつくるときにオブジェクトを基本にする必要なくない?オブジェクトを基本にすることほとんどなくない?」となります。
あと、「オブジェクトを使わなくてもオブジェクト指向の考え方は使える」みたいなツッコミが入ることあるけど「オブジェクト使わないならオブジェクト指向って名前で議論する必要なくない?それオブジェクト指向関係なくソフトウェア工学の話では」ってなります。

オブジェクト指向が流行ったときは、分析設計で出てきた要素をコーディングでもそのまま使えるというのが大きな宣伝文句でした。
ソフトウェア部品の再利用をするときに、オブジェクトを単位として販売するというのも見込まれていました。それで販売されたのは結局は画面部品だけだったので、ビジネスロジックを組織をまたがって再利用できるようにするというのを目指したのがEJB(Enterprise JavaBeans)でもありました。でもビジネスロジックを再利用する部品としてEJBが商売になることはありませんでしたね。

結局のところ、ソフトウェアの部品を組織をまたがって再利用する方法としてはWeb APIが主流になっています。
組織内でソフトウェアを管理しやすいように分類するときも、オブジェクトを基本として考えるのではなくて、マイクロサービスとしてサーバごと分離してWeb API経由で結合することが主になっています。
つまり、ソフトウェアの記述をどうまとめるかというレイヤーで管理するのではなく、サービスとして管理するようになっています。
これはオブジェクト指向のあとに現れたSOA(サービス指向アーキテクチャ)が、ようやく形になったとも言えます。ただ、すでにCORBAみたいな分散オブジェクトというのは忘れられていて、オブジェクト指向はベースになっておらずHTTPがベースになりました。
追記:ライブラリとして共有されてるのでは、という指摘をもらっていて、確かにその通りなのだけどうまくこの話の筋に組み込めてない・・・
追記続き:クラスを使ったライブラリはオブジェクト指向なのかというと、またそれは別の話だけど、本筋から外れるので、ここでは「クラスライブラリ=オブジェクト指向」ではない、とだけ書いておきます

オブジェクト指向がなぜソフトウェア部品の共通化通化で使われなかったかというと、ソフトウェアのバージョンアップやメンテナンス、運用といったソフトウェアライフサイクルを管理する視点が欠けていたからだと思います。
そういったライフサイクルまで含めてマイクロサービスとして管理されるようになりました。
サービス管理の細分化を推し進めて、ラムダとかファンクションという単位でサーバレスとして配備するようにもなっています。

そうするともうソフトウェアの記述としてはオブジェクトという単位は大きすぎて、関数という単位で管理すれば十分ということにもなります。

ソフトウェアの記述をまとめるという視点では主にステートレスな関数を分類できれば充分で、データと振る舞いをまとめたオブジェクトというのは大きすぎる、システムを分割して管理しやすくするという視点ではオブジェクトというのはライフサイクルやリソース管理の視点が足りず小さすぎる、ということで、オブジェクト指向の粒度でのソフトウェア管理は出番がなくなっているのではないか、と思います。

オブジェクト指向でなぜつくるのか」という本がありますが、「え、いまどきオブジェクト指向でつくらなくない?」っていつも思います。内容的には、もうほとんどはオブジェクト指向関係ないソフトウェア工学の紹介になっていますね。発祥がオブジェクト指向ならオブジェクトが関係なくてもそれはオブジェクト指向だ、みたいな考えの本です。「ソフトウェア工学でなぜつくるのか」って名前変えればいいのだけど、それでは売れないんでしょう。
オブジェクト指向が流行ったときに、オブジェクト指向方法論というのが流行って、いろいろな方法論をつくってそれをベースにコンサルするというのが流行りました。とにかくオブジェクト指向と名前をつけておけばコンサル料が取れるという感じだったのだと思います。
いまでも書籍に「オブジェクト指向」とタイトルにつければ売れるということで、まあ結局、昔も今も、オブジェクト指向は技術用語ではなくマーケティング用語なんでしょうね。

もし「オブジェクト指向」を勉強したいと思ったら、その知りたいことは実際にはソフトウェア工学という分野でまとまっているので、そういったタイトルの本を読むのがいいと思います。

エルディンガーアルコールフリー レモン ~ ノンアルビール飲み比べ

エルディンガーのアルコールフリー、レモン
ビールにレモンの酸味と小麦の甘みがいい感じに混ざっておいしい。 f:id:nowokay:20210920185331p:plain

瓶に「リフレッシュにピッタリな1本です」って書いてあるとおり、食事と一緒に飲むよりは休憩時間に飲むとよさそう。
なので今回はパスタと一緒ではない。

原材料は「小麦麦芽、大麦麦芽、ホップ、酵母」といったエルディンガーに「果糖、レモン果汁、レモンエキス、アセロラ果汁」を混ぜたものになってる。
アルコール度数は0.2%。エルディンガーアルコールフリーが0.4%なので、少し薄まっている。

MARUKUから6本単位で買えます。
大人の味わい エルディンガー アルコールフリー レモン330ml ボトル – MARUKU
1本あたり286円

アマゾンではここから選べるけど在庫切れ

他のノンアルビールについてはこちら。

常陸野ネスト ノン・エール ~ ノンアルビール飲み比べ

常陸野ネストのノンアル
日本の低アルコールビールでいちばんうまい
f:id:nowokay:20210919171339p:plain

おいしい。エールの味がする。
苦めで、ホップの香りもしっかりあって、クラフトビール感があります。
わかりやすく言うと よなよなエールのノンアル版。実際には常陸野ネスト ペールエールのノンアル版というのがいいのだろうけど、伝わりやすさ・・・

ノンアルコールというにはちょっとアルコール高めの0.3%
原材料は麦芽(外国製造)、ホップと炭酸です。


1本あたり240円ですね。

他のノンアルビールについてはこちら。

モレッティゼロ ~ ノンアルビール飲み比べ

イタリアビール、モレッティのノンアル
カートに行くときに早起きしたら @at_tun さんがごほうびにくれた。ありがとう! f:id:nowokay:20210918174325p:plain

0.0%という表記だけど実際には0.05%らしい。 クリーミーで、アロマの匂いがして、ビールでいうとエーデルワイスのような味です。

原材料は水・麦芽・ホップ・アロマ
モレッティビールにはコーンが入っているので、モレッティゼロにもコーンが入ってるかなと思いきや、入ってないようです。

だいたいすぐ品切れになるのだけど、飲み比べセットに入ってるものがありますね。

0.05%がどのくらいのアルコールかというと、グレープフルーツ程度、みかん未満という感じか。
f:id:nowokay:20210918175030p:plain
https://www.jstage.jst.go.jp/article/shokueishi1960/33/6/33_6_619/_pdf

他のノンアルビールについてはこちら。

「写経」の原典

書籍とかのサンプルコードをそのまま入力して勉強することを「写経」というけども、それを言い出したのは角谷さん、というメモ。
写経は言葉ではなく心で理解するのが大事。

恐らく2005年7月ごろではないかと思われる。
この夏は写経が来るね, 地震が来た - 角谷HTML化計画(2005-07-23)

角谷さんのブログでの初出も7/15だけど、babieさんのコメントを見るとこの時期にまわりで語ってたことを推しはかることができる。
『カンフーハッスル コレクターズ・エディション』, 『ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道』 - 角谷HTML化計画(2005-07-15)

このころ角谷さんはPofEAA読書会などたくさんの勉強会を主催していたので、そこで広めていたんじゃないだろうか。そもそも「勉強会」という言葉も定着させてないか?

t_wadaの「以前の現場に通いながら」という話はここで語られてる。
第 43 回 和田卓人 さんの巻 | オブジェクトの広場

関数型インタフェースまとめ

Javaには関数型インタフェースがたくさん用意されてるのだけど、なにがあってなにがないのかとかわかりにくいのでまとめている。

ここの最後にまとめていたのだけど、検索しづらいので独立させた
https://nowokay.hatenablog.com/entry/20130824/1377300917

しかし見れたもんじゃないな・・・
下のほうに再掲

第一引数 第二引数 void int long double boolean object R (T=U=R)
    Runnable IntSupplier LongSupplier DoubleSupplier BooleanSupplier Supplier  
int   IntConsumer IntUnaryOperator IntToLongFunction IntToDoubleFunction IntPredicate IntFunction  
int int   IntBinaryOperator          
long   LongConsumer LongToIntFunction LongUnaryOperator LongToDoubleFunction LongPredicate LongFunction  
long long     LongBinaryOperator        
double   DoubleConsumer DoubleToIntFunction DoubleToLongFunction DoubleUnaryOperator DoublePredicate DoubleFunction  
double double       DoubleBinaryOperator      
ObjectT   Consumer ToIntFunction ToLongFunction ToDoubleFunction Predicate Function UnaryOperator
ObjectT ObjectU BiConsumer ToIntBiFunction ToLongBiFunciton ToDoubleBiFunction BiPredicate BiFunction BinaryOperator
ObjectT int ObjIntConsumer            
ObjectT long ObjLongConsumer            
ObjectT double ObjDoubleConsumer            




























第一引数 第二引数 void int long double boolean object R (T=U=R)
    Runnable IntSupplier LongSupplier DoubleSupplier BooleanSupplier Supplier  
int   IntConsumer IntUnaryOperator IntToLongFunction IntToDoubleFunction IntPredicate IntFunction  
int int   IntBinaryOperator          
long   LongConsumer LongToIntFunction LongUnaryOperator LongToDoubleFunction LongPredicate LongFunction  
long long     LongBinaryOperator        
double   DoubleConsumer DoubleToIntFunction DoubleToLongFunction DoubleUnaryOperator DoublePredicate DoubleFunction  
double double       DoubleBinaryOperator      
ObjectT   Consumer ToIntFunction ToLongFunction ToDoubleFunction Predicate Function UnaryOperator
ObjectT ObjectU BiConsumer ToIntBiFunction ToLongBiFunciton ToDoubleBiFunction BiPredicate BiFunction BinaryOperator
ObjectT int ObjIntConsumer            
ObjectT long ObjLongConsumer            
ObjectT double ObjDoubleConsumer            

20年前にPHPでJavaカスタムタグのようなものを実装していた

2001年くらいにPHPJavaカスタムタグのようなものを実装したのを発掘したので放流。

PHPでJavaのカスタムタグっぽいものを実装した2001年 · GitHub

メーリングリストでやりとりをしてたときに
「できらぁ!PHPJavaカスタムタグの実装できらぁ!」
「え、PHPJavaカスタムタグを?」
ってなって、一晩でがーっと作った記憶。
自分だけしか使わない前提で、%var%で変数が埋め込まれる程度のものを作ったのだけど、1年くらい実プロジェクトで使っていた。
600行くらいでコンパクト。
当時は元気があったんだな。

PHP4の時代で、テンプレートエンジンもなかったというかPHP自体がテンプレートエンジンというイメージで まだテンプレートエンジン需要も あまりなかったんじゃないかと。
SynfonyやZend Frameworkもまだ出ていなかった。

こんな感じのテンプレートを書く。

<php:switch condition="%user_type%">
    <php:case value="2">
        <h1>提案書一覧</h1>
    </php:case>
</php:switch>
<pg:exec result="rtn">
    <pg:title field="youki_type_cd">
        <b><pg:result field="youki_type_nm">種類</pg:result></b><br>
        <ul>
    </pg:title>
    <pg:aif href="teian.php?teian=" field="teian_cd"><pg:result field="teian_nm">提案書名</pg:result></pg:aif><br>
    <pg:total field="youki_type_cd">
        </ul>
    </pg:total>
</pg:exec>

そうするとこんなPHPが生成されて、あとはそのままこれを実行する。
そういう動きもJSPのカスタムタグと同じ。
勢いで書いたわりにはよくできてるな。

<?//switch
if (!isset($__phptag_switch_1)) $__phptag_switch_1 = new SwitchTag;
$__phptag_switch_1->parenttag = null;
ob_start();
?><?=$user_type?><?$__phptag_switch_1->attr["condition"] = ob_get_contents();
ob_end_clean();
if ($__phptag_switch_1->doStartTag() == TAG_BODY_INCLUDE){
ob_start();
?>
    <?//case
if (!isset($__phptag_case_2)) $__phptag_case_2 = new CaseTag;
$__phptag_case_2->parenttag = &$__phptag_switch_1;
$__phptag_case_2->attr["value"] = "2";
if ($__phptag_case_2->doStartTag() == TAG_BODY_INCLUDE){
ob_start();
?>
        <h1>提案書一覧</h1>
    <?
$page_content = ob_get_contents();
ob_end_clean();
echo $page_content;
}
$__phptag_case_2->doEndTag();
?>
<?
$page_content = ob_get_contents();
ob_end_clean();
echo $page_content;
}
$__phptag_switch_1->doEndTag();
?>
<?//exec
if (!isset($__phptag_exec_3)) $__phptag_exec_3 = new PgExecTag;
$__phptag_exec_3->parenttag = null;
$__phptag_exec_3->attr["result"] = "rtn";
if ($__phptag_exec_3->doStartTag() == TAG_BODY_INCLUDE){
$__phptag_exec_3->doInitBody();
while(true){
if ($__phptag_exec_3->doBeginBody() == TAG_SKIP_BODY) break;
ob_start();
?>
    <?//title
if (!isset($__phptag_title_4)) $__phptag_title_4 = new PgResultTitleTag;
$__phptag_title_4->parenttag = &$__phptag_exec_3;
$__phptag_title_4->attr["field"] = "youki_type_cd";
if ($__phptag_title_4->doStartTag() == TAG_BODY_INCLUDE){
ob_start();
?>
        <b><?//result
if (!isset($__phptag_result_5)) $__phptag_result_5 = new PgResultTag;
$__phptag_result_5->parenttag = &$__phptag_title_4;
$__phptag_result_5->attr["field"] = "youki_type_nm";
if ($__phptag_result_5->doStartTag() == TAG_BODY_INCLUDE){
ob_start();
?>種類<?
$page_content = ob_get_contents();
ob_end_clean();
echo $page_content;
}
$__phptag_result_5->doEndTag();
?></b><br>
        <ul>
    <?
$page_content = ob_get_contents();
ob_end_clean();
echo $page_content;
}
$__phptag_title_4->doEndTag();
?>
    <?//aif
if (!isset($__phptag_aif_6)) $__phptag_aif_6 = new PgResultIfLinkTag;
$__phptag_aif_6->parenttag = &$__phptag_exec_3;
$__phptag_aif_6->attr["href"] = "teian.php?teian=";
$__phptag_aif_6->attr["field"] = "teian_cd";
if ($__phptag_aif_6->doStartTag() == TAG_BODY_INCLUDE){
ob_start();
?><?//result
if (!isset($__phptag_result_7)) $__phptag_result_7 = new PgResultTag;
$__phptag_result_7->parenttag = &$__phptag_aif_6;
$__phptag_result_7->attr["field"] = "teian_nm";
if ($__phptag_result_7->doStartTag() == TAG_BODY_INCLUDE){
ob_start();
?>提案書名<?
$page_content = ob_get_contents();
ob_end_clean();
echo $page_content;
}
$__phptag_result_7->doEndTag();
?><?
$page_content = ob_get_contents();
ob_end_clean();
echo $page_content;
}
$__phptag_aif_6->doEndTag();
?><br>
    <?//total
if (!isset($__phptag_total_8)) $__phptag_total_8 = new PgResultTotalTag;
$__phptag_total_8->parenttag = &$__phptag_exec_3;
$__phptag_total_8->attr["field"] = "type_cd";
if ($__phptag_total_8->doStartTag() == TAG_BODY_INCLUDE){
$__phptag_total_8->doInitBody();
while(true){
if ($__phptag_total_8->doBeginBody() == TAG_SKIP_BODY) break;
ob_start();
?>
        </ul>
    <?
$page_content = ob_get_contents();
ob_end_clean();
if ($__phptag_total_8->doAfterBody($page_content) != TAG_BODY_AGAIN) break;
}
}
$__phptag_total_8->doEndTag();
?>
<?
$page_content = ob_get_contents();
ob_end_clean();
if ($__phptag_exec_3->doAfterBody($page_content) != TAG_BODY_AGAIN) break;
}
}
$__phptag_exec_3->doEndTag();
?>