Slide 1

Slide 1 text

位置情報の新しいイノベーションへ Facade Patternで磨く、 コードの可読性と分解力 中森 紳介

Slide 2

Slide 2 text

©Project PLATEAU / MLIT Japan 中森 紳介 自己紹介 NAKAMORI Shinsuke 2024年2月 MIERUNE入社        神奈川在住で普段はフルリモート勤務 普段のお仕事:QGISプラグイン開発など BBQ参加歴:#10のみ(今日が2回目) (代打系)GISエンジニア

Slide 3

Slide 3 text

© 地理院地図 全国最新写真(シームレス) 普段からコードを書いている人🙋

Slide 4

Slide 4 text

© 地理院地図 全国最新写真(シームレス) 普段からコードの可読性を 意識している人🙋

Slide 5

Slide 5 text

© 地理院地図 全国最新写真(シームレス) 「コードの可読性」って なんですか?

Slide 6

Slide 6 text

©Project PLATEAU / MLIT Japan 諸説あるかもしれませんが コードの可読性とは コードの可読性 = どれだけ読みやすいか

Slide 7

Slide 7 text

©Project PLATEAU / MLIT Japan 諸説あるかもしれませんが コードの可読性とは コードの可読性 = どれだけ読みやすいか コードの可読性 = どれだけ処理内容を追いやすいか

Slide 8

Slide 8 text

©Project PLATEAU / MLIT Japan フードデリバリーで商品を届ける一連のフローについて考える フードデリバリーの例で考えてみる

Slide 9

Slide 9 text

©Project PLATEAU / MLIT Japan class Delivery: def 商品を届ける(self, 注文先: レストラン, 商品リスト: list, 目的地: str): お店の住所 = 注文先.お店の場所を確認する() 配達員リスト = [配達員A, 配達員B, 配達員C] 最短時間 = float("inf") for 対象者 in 配達員リスト: 現在地 = 対象者.現在地() 所要時間 = お店までの到達時間(現在地, お店の住所) if 所要時間 < 最短時間: 配達する人 = 対象者 最短時間 = 所要時間 所要時間 = 注文先.所要時間を確認する(商品リスト) レジ袋 = 注文先.商品を作る(商品リスト) 経路 = 配達する人.配達経路を確認する(目的地) 完了報告 = 配達する人.商品を運ぶ(レジ袋, 経路) if 完了報告: print("商品をお届けしました") return True else: print("商品の配達に失敗しました") return False

Slide 10

Slide 10 text

©Project PLATEAU / MLIT Japan class Delivery: def 商品を届ける(self, 注文先: レストラン, 商品リスト: list, 目的地: str): お店の住所 = 注文先.お店の場所を確認する() 配達員リスト = [配達員A, 配達員B, 配達員C] 最短時間 = float("inf") for 対象者 in 配達員リスト: 現在地 = 対象者.現在地() 所要時間 = お店までの到達時間(現在地, お店の住所) if 所要時間 < 最短時間: 配達する人 = 対象者 最短時間 = 所要時間 所要時間 = 注文先.所要時間を確認する(商品リスト) レジ袋 = 注文先.商品を作る(商品リスト) 経路 = 配達する人.配達経路を確認する(目的地) 完了報告 = 配達する人.商品を運ぶ(レジ袋, 経路) if 完了報告: print("商品をお届けしました") return True else: print("商品の配達に失敗しました") return False 具体的な処理内容と 関数化された処理が混在していて 処理全体のフローが ぱっと見で把握しにくい

Slide 11

Slide 11 text

©Project PLATEAU / MLIT Japan class DeliveryFacadePattern: def 商品を届ける(self, 注文先: レストラン, 商品リスト: list, 目的地: str): アプリ = Application() お店の住所 = 注文先.お店の場所を確認する() 配達する人: 配達員 = アプリ.近くの配達員を検索する(お店の住所) 所要時間 = 注文先.所要時間を確認する(商品リスト) アプリ.所要時間を表示する(所要時間) レジ袋 = 注文先.商品を作る(商品リスト) 経路 = 配達する人.配達経路を確認する(目的地) 完了報告 = 配達する人.商品を運ぶ(レジ袋, 経路) アプリ.利用者に報告する(完了報告)

Slide 12

Slide 12 text

©Project PLATEAU / MLIT Japan class DeliveryFacadePattern: def 商品を届ける(self, 注文先: レストラン, 商品リスト: list, 目的地: str): アプリ = Application() お店の住所 = 注文先.お店の場所を確認する() 配達する人: 配達員 = アプリ.近くの配達員を検索する(お店の住所) 所要時間 = 注文先.所要時間を確認する(商品リスト) アプリ.所要時間を表示する(所要時間) レジ袋 = 注文先.商品を作る(商品リスト) 経路 = 配達する人.配達経路を確認する(目的地) 完了報告 = 配達する人.商品を運ぶ(レジ袋, 経路) アプリ.利用者に報告する(完了報告) 具体的な処理内容は 1行も書いてないが、 処理全体のフローが理解できる

Slide 13

Slide 13 text

©Project PLATEAU / MLIT Japan コンピュータソフトウェアのデザインパターンの一つ Facade Pattern 参照:https://ja.wikipedia.org/wiki/Facade_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3 Facadeクラス ● 複雑な実装を持たない ● 基本、処理を投げるだけ 複数のサブシステム ● 具体的な実装を持つ

Slide 14

Slide 14 text

©Project PLATEAU / MLIT Japan コンピュータソフトウェアのデザインパターンの一つ Facade Pattern 参照:https://ja.wikipedia.org/wiki/Facade_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3 Facadeクラス ● 複雑な実装を持たない ● 基本、処理を投げるだけ 複数のサブシステム ● 具体的な実装を持つ どう分けるのが 適切なの?

Slide 15

Slide 15 text

©Project PLATEAU / MLIT Japan 単一責任の原則が一般的(なはず 単一責任の原則について調べると以下のような記述を見かける ●クラスは変更理由が一つだけであるべき ●クラスの目的は一つだけで、それが変わった場合のみ変更される ●1つのクラスは1つだけの責任を持たなければならない

Slide 16

Slide 16 text

©Project PLATEAU / MLIT Japan いやいや、その「単一」が分からんのじゃ 「配達員」は単一なの?それとも「配達する」が単一なの? 配達員のクラスで まとめていいの? 「配達する」って クラスを作るの? 細かすぎない? まあシステムの 大きさとかに寄るよね そこはセンスの 問題かな

Slide 17

Slide 17 text

©Project PLATEAU / MLIT Japan 「単一」の迷路に迷い込んでしまったら 私はセンスがないので、以下の手順をよく踏みます 1)とにかく思いついた「単一」っぽいものをバラバラに列挙する 2)同程度の粒度のものをグルーピングする 3)構造化して並べ直す 4)抜け漏れがないか、チェックする 5)具体的な処理を必要とする一つ上の粒度を「単一」と考えてみる 6)しっくりこなければ、粒度を一段変更してみる

Slide 18

Slide 18 text

© 地理院地図 全国最新写真(シームレス) 試しにやってみる

Slide 19

Slide 19 text

©Project PLATEAU / MLIT Japan 思いついたやつをバラバラに列挙する 商品代を算出する お代を受け取る 近くの配達員を探す 商品を袋に詰める 調理する 調理時間を確認する お店の場所を確認する 現在地を取得する 配達する 利用者に報告する 所要時間を表示する レストラン 配達員

Slide 20

Slide 20 text

©Project PLATEAU / MLIT Japan 同程度のものをグルーピング レストラン 配達員 お店の場所を確認する 調理時間を確認する 調理する 近くの配達員を探す 所要時間を表示する 利用者に報告する 商品を袋に詰める 現在地を取得する 配達経路を確認する 配達する 商品を渡す お代を受け取る 商品代を算出する 粒度:大 粒度:小

Slide 21

Slide 21 text

©Project PLATEAU / MLIT Japan 構造化して並べ直す システム レストラン 配達員 お店の場所を確認する 調理時間を確認する 調理する 商品を袋に詰める 商品代を算出する 現在地を取得する 配達経路を確認する 配達する 商品を渡す お代を受け取る 近くの配達員を探す 所要時間を表示する 利用者に報告する

Slide 22

Slide 22 text

©Project PLATEAU / MLIT Japan 抜け漏れがないか確認する システム レストラン 配達員 お店の場所を確認する 調理時間を確認する 調理する 商品を袋に詰める 商品代を算出する 現在地を取得する 配達経路を確認する 配達する 商品を渡す お代を受け取る 近くの配達員を探す 所要時間を表示する 利用者に報告する システムから伸びる 対象の粒度が あってないな 処理内容を グルーピング できないかな?

Slide 23

Slide 23 text

©Project PLATEAU / MLIT Japan 抜け漏れがないか確認する システム レストラン 配達員 アプリケーション データ登録 実務 お店の場所を確認する 商品代を算出する 調理時間を確認する 調理する 商品を袋に詰める 待機状態 配達 会計処理 表示 処理 現在地を取得する 配達経路を確認する 配達する 商品を渡す お代を受け取る 所要時間を表示する 利用者に報告する 近くの配達員を探す

Slide 24

Slide 24 text

©Project PLATEAU / MLIT Japan 具体的な処理を書く一段上を単一とする システム レストラン 配達員 アプリケーション データ登録 実務 お店の場所を確認する 商品代を算出する 調理時間を確認する 調理する 商品を袋に詰める 待機状態 配達 会計処理 表示 処理 現在地を取得する 配達経路を確認する 配達する 商品を渡す お代を受け取る 所要時間を表示する 利用者に報告する 近くの配達員を探す

Slide 25

Slide 25 text

©Project PLATEAU / MLIT Japan Facade Patternで呼び出すクラスの粒度を検討するには、システム全 体を適切に分解して、構造化する能力が必要(だと思っている これが「分解力」である(決めつけ

Slide 26

Slide 26 text

©Project PLATEAU / MLIT Japan 「分解力」が発揮できる場面の例 ●フォルダ整理 ●資料作成 ●要因分析 などなど 実はコーディング以外でも使えます

Slide 27

Slide 27 text

©Project PLATEAU / MLIT Japan 物事の「分解力」を磨いて、業務全体の可読性を上げていこう ということで クラス設計の粒度が揃う データを探しやすくなる 読みやすい構成に

Slide 28

Slide 28 text

©Project PLATEAU / MLIT Japan (余談)なお、個人的には 今回の例なら、配達員やレストランのFacadeクラスを用意する方が好き システムFacade アプリFacade 配達員Facade レストランFacade 配達モジュール 会計モジュール

Slide 29

Slide 29 text

©Project PLATEAU / MLIT Japan 洗い出した項目を構造化するのが、とても楽になる オススメしたいもの①:XMind 一旦、端に置いておくこともできる ドラッグ&ドロップで 簡単に構造を組み替えることができる

Slide 30

Slide 30 text

©Project PLATEAU / MLIT Japan 「分解力」高めるなら、キーボードも適切な粒度に分解せねば オススメしたいもの②:分割キーボード キーボード 右手用キーボード 左手用キーボード Q W E Y U I … … ↑先週手に入れたやつ

Slide 31

Slide 31 text

© 地理院地図 全国最新写真(シームレス) ●Facade Patternでフローを見やすくしよう ●呼び出すサブシステムは、適切な粒度にしよう ●求められる能力は、物事の分解と構造化 ●「分割キーボードはいいぞ」 まとめ