Slide 1

Slide 1 text

オブジェクト指向は必要なのか 2024/3/24 Object-Oriented Conference LINEヤフー きしだ なおき

Slide 2

Slide 2 text

2024/03/24 2 自己紹介 ● きしだ なおき ● LINEヤフー ● X(twitter): @kis ● blog: きしだのHatena ● (nowokay.hatenablog.com) ● 「プロになるJava」というJavaの本を書いてます ● WEB+DB PRESS vol.132でオブジェクト指向特集書いてます

Slide 3

Slide 3 text

モチベーション ● プログラム初心者が「まだオブジェクト指向がわからないので」 のような発言をする ● forループが書けるようになるのが先では? ● 「オブジェクト指向」がわかっても、やりたいと思ってること できるようにならんで ● 「オブジェクト指向」が初心者の到達するべき目標になっている ● 「オブジェクト指向」がわかればプログラムが組める? ● プログラムが組めないのは「オブジェクト指向」がわかってない? ● こういう不毛な誤解はなくなるべき ● 初心者に「オブジェクト指向」は不要。かなりあとまわしでいい。

Slide 4

Slide 4 text

モチベーション ● 「オブジェクト指向」はあいまいな意味付けのまま放置されてる ● 現場の技術コミュニケーションで使わないので共通定義が求められて いない ● 「オブジェクト指向」以外の言葉で範囲を狭めて誤解なく表現で きるものについては、その言葉を使うほうがいいのでは? ● 開発作業において「オブジェクト指向」が、「オブジェクト指 向」だけが意味できるものを拾いだして、なぜ使わないのか、ど う使うのか明確にしたほうがいいのでは?

Slide 5

Slide 5 text

簡単な歴史 ● 1960年代: Simulaによる原初の実装 ● 1970年代: アラン・ケイによる命名とコンセプト化 ● 1980年代: C++で一般化 ● カプセル化・継承・ポリモーフィズムという実用的な定義 ● 1990年代: GUIの普及で大流行 ● オブジェクト指向と付ければ売れるので、何でもオブジェクト指向化 ● 2000年代: Web技術の発展により斜陽化 ● 関数型の流行、手法からプロセスへ ● 2010年以降: そして伝説へ ● なんかすごいらしいけど、実際に何を意味するかわからない

Slide 6

Slide 6 text

アラン・ケイのオブジェクト指向 ● プログラミング技術ではないのでは? ● Smalltalkは商用化時にSimula形式のオブジェクト機能を導入 ● 職業プログラマに使いやすくなった ● 「自分の手を離れた」といっている ● エンドユーザーコンピューティングの研究 ● エンドユーザーがコンピュータを使うためのプログラミング ● 定義が断片的 ● 職業プログラマの開発の指針にするのは難しそう ● 実用化には再定義や再構築が必要 ● 結局、その人の手法になる ● ということでout-of-scope

Slide 7

Slide 7 text

代表的なオブジェクト指向手法 ● スリーアミーゴズの手法 ● OMT(オブジェクトモデル化技法) ● ランボー ● オブジェクトモデリング ● OOSE(オブジェクト指向ソフトウェア工学) ● ヤコブソン ● ユースケースによる分析 ● ブーチ法 ● ブーチ ● 開発プロセス ● 他にもコード/ヨードンのOOA/OOD、Shlaer/Mellor法など

Slide 8

Slide 8 text

なぜ多くの手法が現れたのか ● 分析からコードまで同じモデルが使える ● 気難しい継承を扱うために手法が必要 ● クラスと継承を軸にそれぞれ関心ある開発領域をまとめる ● 分析、プロジェクト管理、etc ● オブジェクト指向と名前をつけたら儲かる ● 研究に予算がつく ● 本が売れる ● ソフトウェアが売れる ● ソフトウェア工学が全部オブジェクト指向に ● ソフトウェア工学の名前が浸透しなくなった ● この会も「ソフトウェア工学カンファレンス」が適切(人がこない)

Slide 9

Slide 9 text

オブジェクト指向手法統合の夢 ● スリーアミーゴズの3人がラショナル社に集結 ● 乱立していた手法を統合しようとした ● 作業が進まないので記法だけ統一 ● UML 「オブジェクト指向方法論の世界」より

Slide 10

Slide 10 text

オブジェクト指向手法の欠点 ● ウォーターフォールが前提となっている ● 分析→設計→実装 ● 分析と実装で同じ記号が使える部分は実装の前倒しでしかない ● 図によるコーディングでしかない ● アーキテクチャが組み込まれていない ● ネットワーク普及前なので1台で処理する前提になってしまっている ● RDBMSとのインピーダンスミスマッチ ● 複雑なサーバー構成に対応できない ● 現実にはアーキテクチャが決まり実装モデルが決まる ● アプリケーションを一体で構築する

Slide 11

Slide 11 text

手法からプロセスへ ● 各工程ごとの成果物を定義するとウォーターフォールになる ● ウォーターフォールを脱すると各工程での成果物の定義が難しい ● サービス成長にあわせてアーキテクチャの模索も必要になる ● コードの形だけを事前に決めることが難しい ● よいソフトウェアはよいプロセスから生まれる ● CMMの流行 ● ラショナルの統一手法も統一プロセスになった ● コンピューティングリソースを開発プロセスにまわせるように なった ● 継続的インテグレーション ● Gitによる開発プロセス(昔はリポジトリのコピーなんて考えれなかった)

Slide 12

Slide 12 text

オブジェクト指向は継承によるプログラミング ● ストラウストラップ(C++作者) ● 「オブジェクト指向プログラミングは継承を使うプログラミングだ」 ● ランボー(オブジェクト指向モデリング技術) ● 「オブジェクト指向的アプローチに要求される特徴が正確に何か、と いうことに関してはいくつかの議論があるが、それらの議論は普通以 下の4つの面を含んでいる。すなわち、アイデンティティ、分類、多相 性、そして継承である」 ● ブーチ(ブーチ法) ● 「もし言語が継承を直接サポートしないならば、それはオブジェクト 指向とは言えない」

Slide 13

Slide 13 text

オブジェクト指向は継承によるプログラミング ● この定義をおくことで ● オブジェクト指向をどう使うか ● なぜ使われなくなったか ● オブジェクト指向手法とは何だったのか ● などが説明しやすくなる

Slide 14

Slide 14 text

継承ではない条件を考える ● method(obj)をobj.method()と書ければオブジェクト指向 ● 大騒ぎするほどの効果があるか疑問 ● クラスを使えばオブジェクト指向 ● 構造体でよさそう? ● データと関数を一緒に書ければオブジェクト指向 ● 抽象データ型 ● オブジェクトを作ればオブジェクト指向 ● static避けでオブジェクト指向ロンダリングのためのオブジェクト作る ● ソフトウェアをうまく作る工夫はすべてオブジェクト指向 ● ソフトウェア工学のブランディングの失敗・・・

Slide 15

Slide 15 text

抽象データ型 ● データの操作だけを公開することで変更に強く柔軟な型を定義 ● データについてのカプセル化 ● 操作としてデータ操作だけ含む

Slide 16

Slide 16 text

パラダイムは言語ではなく言語機能がもつ ● オブジェクト指向言語、関数型言語という区分けに意味がない ● オブジェクトは関数として扱え、関数はオブジェクトとして扱えるので 混合可能 ● シンタックスシュガーを導入すれば言語機能として持てる ● オブジェクト指向機能、関数型機能をそれぞれの塩梅で持つ ●

Slide 17

Slide 17 text

オブジェクトと関数の関係 ● オブジェクトと関数は可換 ● 属性をもたずメソッドが一つのオブジェクトは関数として扱える ● Javaのラムダ式 ● 名前を与えて要素を返す関数はオブジェクトとして扱える Function myObj(int a, int b) { return name -> switch(name) { case "a" -> a; case "b" -> b; case "mul" -> a * b; case "add" -> a + b; default -> throw new RuntimeException(); }; } class MyFunc() { int apply(int a, int b) { return a + b; } }

Slide 18

Slide 18 text

デザインパターンで関数的処理の実装 ● デザインパターンは言語に足りない機能を補完する ● 人間がパターンを覚えて手で書かないといけないのは何かが負けている ● 多くのパターンが言語機能の導入で不要になっている ● 高階関数の利用パターンをクラスと継承で再現したものが多い ● ex テンプレートメソッド

Slide 19

Slide 19 text

テンプレートメソッド ● ポリモーフィズムの基本 abstract class Base { abstract void before(); abstract void after(); void proc() { before(); println("はろー"); after(); } } class School extends Base { @Override void before() { println("起立"); } @Override void after() { println("着席"); } }

Slide 20

Slide 20 text

高階関数による実装 ● 高階関数だとすっきり書ける void proc(Runnable before, Runnable after) { before.run(); println("はろー"); after.run(); } proc(() -> println("起立"), () -> println("着席")); ※ Runnableは引数戻り値なしの関数を表すのに使われる

Slide 21

Slide 21 text

差分プログラミング ● 似たような処理のうち異なる部分を抜き出す ● 通常の関数やメソッドでは共通部分を抜き出す

Slide 22

Slide 22 text

ポリモーフィズムは事前評価での条件分岐 ● 条件をどのように集約するか ● 次のcartの合計処理を考える ● PackedとBulkで計算処理が違う sealed interface Type { /** 量り売り */ record Bulk(int price, int unit) implements Type {} /** パッケージ */ record Packed(int price) implements Type {} } record Item(Type type, int amount) {} var cart = List.of( new Item(new Packed(300), 3), new Item(new Bulk(250, 100), 230));

Slide 23

Slide 23 text

switchで条件分岐 ● switchで条件分岐 var cart = List.of( new Item(new Packed(300), 3), new Item(new Bulk(250, 100), 230)); int total = cart.stream() .mapToInt(item -> switch(item) { case Item(Packed(int price), int amount) -> price * amount; case Item(Bulk(int price, int unit), int amount) -> price * amount / unit; }).sum();

Slide 24

Slide 24 text

継承で条件分岐 ● 継承を使うとスッキリかけるように見える ● Typeが増えても計算部分を変更しなくていい sealed interface Type { int calc(int amount); /** 量り売り */ record Bulk(int price, int unit) implements Type { int calc(int amount) { return price * amount / unit; } } /** パッケージ */ record Packed(int price) implements Type { int calc(int amount) { return price * amount; } } } var cart = List.of( new Item(new Packed(300), 3), new Item(new Bulk(250, 100), 230)); int total = cart.stream() .mapToInt(item ->  item.type().calc(item.amount())) .sum();

Slide 25

Slide 25 text

継承を使うときの問題 ● 処理を追うために複数のクラスを見る必要がある ● 条件がTypeではないときにきれいに書けなくなる ● 時間帯とか ● Typeの中で条件分岐が必要になる ● 把握していないTypeがあると困ることがある ● 業務処理では処理が一箇所にまとまってるほうがいい

Slide 26

Slide 26 text

オブジェクト指向は状態管理技術 ● 状態管理を共通化する ● 例 ● I/O ● List abstract class IO { boolean opened; void open() { if (opened) return; openImpl(); opened = true; } void close() { if (!opened) error; closeImpl(); opened = false; } abstract void openImpl(); abstract void closeImpl(); } class MyIO extends IO { @Override void openImpl() { println("開いた!"); } @Override void closeImpl() { println("閉じた!"); } }

Slide 27

Slide 27 text

状態管理はモジュール境界に現れる ● 状態管理はモジュールの端点に現れる ● 例: DOM、HTTP、DB接続では状態管理が必要 ● 中間の処理はステートレス GUI ロジック データ ストア ユーザー アプリケーション DOM HTTP DB接続

Slide 28

Slide 28 text

端点にオブジェクト指向を使う ● DBConnectionを継承してMySQLConnectionやOracleConnection を実装するとオブジェクト指向がハマる ● ただし、MySQLConnectionやOracleConnectionは世界にひとつだけあ ればいい ● ブラウザがGUIの状態管理をすればGUIフレームワークは ステートレスにできる ● 構造化されたGUI定義とイベントハンドラ ● ブラウザの実装にはオブジェクト指向がハマるけど技術的には世界に ひとつあればいい(社会的には複数あったほうがいい)

Slide 29

Slide 29 text

部分型はオブジェクト指向か? ● 確かに部分型は継承の重要な機能 ● オブジェクト指向は部分型以外の型機能に触れていない ● 関数型 ● 総称型(ジェネリクス) ● 部分型にも種類がある ● 継承の部分型は明示的に基底型を指定する ● 公称型 ● 継承=公称型+属性拡張 ● 指定した要素を持っていれば部分型とみなすやりかたもある ● 構造的部分型 ● ダックタイピング

Slide 30

Slide 30 text

部分型はオブジェクト指向か ● 公称型はオブジェクト指向と呼んでもいいかもしれないけど 型理論の一部とみなすほうが豊かな議論が可能 ● 公称型という仕組み自体はオブジェクト指向から独立できる(ハズ) ● 初心者は公称型のコンセプトだけわかってれば当面Javaつかえる(ハズ) ● interfaceの実装は必ずしもオブジェクト指向とは考えれない ● 代数的データ型の直和型の実現と考えれる ● 例: Type型はBulk型かPacked型かどちらかになる sealed interface Type { /** 量り売り */ record Bulk(int price, int unit) implements Type {} /** パッケージ */ record Packed(int price) implements Type {} }

Slide 31

Slide 31 text

オブジェクト指向をどう使うか ● クラスのデータ性とモジュール性を認識する ● アプリケーションはレイヤー化する ● アプリケーションの端点にオブジェクト指向を使う

Slide 32

Slide 32 text

クラスのデータ性とモジュール性 ● クラスにはデータ型としての性質とモジュールとしての性質 ● データ型としてのクラス ● インスタンスが複数つくられる ● モジュールとしてのクラス ● シングルトンであることが多い ● サブシステムになる ● 処理のあつまり class Name { String first; String last; Name(String first, String last) { this.first = first; this.last = last; } String toString() { return first + " " + last; } } @RestController class Greeting { @GetMapping("/hello") String hello() { return "hello"; } @GetMapping("/myname") Name myName() { return new Name("Naoki", "Kishida"); } }

Slide 33

Slide 33 text

純粋データ型を考える ● 純粋関数 ● 副作用をもたない ● 同じ引数を与えると同じ戻り値が返る ● 純粋データ型(造語) ● データ型の外に副作用をもたない ● 同じ属性を持つデータのメソッドに同じ引数を与えると同じ戻り値が 返る

Slide 34

Slide 34 text

アプリケーションをレイヤー化する ● モジュールとデータの分離 ● アプリケーション処理はステートレス ● モジュールは関数の集まり ● 関数を分割するときはレイヤーに ● 無限ループの回避 ● レイヤー上をデータが流れる ● データ指向プログラミング

Slide 35

Slide 35 text

まとめ ● オブジェクト指向は継承を使うプログラミングであり状態管理 ● 継承以外はオブジェクト指向以外の言葉が使える ● 用語のブレがないので技術コミュニケーションしやすい ● アプリケーションではオブジェクト指向の出番はほとんどない ● 端点で状態管理をすれば中間はステートレス=関数的 ● フレームワークやミドルウェアでは必要 ● オブジェクト指向を勉強してフレームワークやミドルウェアを作ろう