Slide 1

Slide 1 text

1 こわくない ソースコードリーディング生活 JJUG CCC 2019 Fall #ccc_c5 Acroquest Technology株式会社 進藤 遼 (@shindo_ryo) Copyright © Acroquest Technology Co., Ltd. All rights reserved.

Slide 2

Slide 2 text

自己紹介 • 進藤 遼 • Acroquest Technology株式会社 • 日本Springユーザ会 スタッフ • Twitter: @shindo_ryo • Spring / JUnit 5 / Microservices • 最近はエンプラ系システムでアーキテクチャ設計やったり Goで分散トレーシングやったり。 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 2

Slide 3

Slide 3 text

Acroquestのミッション・ビジョン Copyright © Acroquest Technology Co., Ltd. All rights reserved. 3 テクノロジストチームとして ビジネスの革新的価値創出に挑戦する ビジョン Acroquestの創り出す技術で 地球を感動で進化させる ミッション

Slide 4

Slide 4 text

おことわり • このセッションでは、僕がOSSのコードを読むときに考えているこ とをお話しします。 • お話ししたことについて「こうやるべきだ!」というわけではなく、 参考程度に聞いていただければ幸いです。 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 4

Slide 5

Slide 5 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 5 Q.

Slide 6

Slide 6 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 6 他人が書いたコード 読んだことがある人?

Slide 7

Slide 7 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 7 OSSライブラリのコード 読んだことがある人?

Slide 8

Slide 8 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 8 Webフレームワークのコード 読んだことがある人? はじめに

Slide 9

Slide 9 text

9 https://github.blog/2018-11-08-100m-repos/ 増え続けるOSSリポジトリ

Slide 10

Slide 10 text

GitHubは優れたコードが 集まる宝石箱

Slide 11

Slide 11 text

いまどきこれらのOSSのコードを 読めないエンジニアがいるんですか?

Slide 12

Slide 12 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 12 はい、僕です

Slide 13

Slide 13 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 13 OSSのソースコードを 読むのはハードルが高い …ホントに?

Slide 14

Slide 14 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 14 OSSのソースコードを 読むのはハードルが高い 高い気がする

Slide 15

Slide 15 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 15 読み方を知れば ソースコードリーディングは こわくない

Slide 16

Slide 16 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 16 一歩ずつ、コードを 読めるようになればいい

Slide 17

Slide 17 text

はじめに • このセッションの対象者 ➢ OSSのソースコードを読んだことが無い ➢ 読んだことはあるがいまいち理解できない • このセッションの目的 ➢ ソースコードを読むことへのハードルを下げる ➢ ソースコードを効率的に学べるようになる Copyright © Acroquest Technology Co., Ltd. All rights reserved. 17

Slide 18

Slide 18 text

アジェンダ • STEP 1: ソースコードを開こう! • STEP 2: ライブラリのコードを読もう! • STEP 3: 構造を読み解こう! • Appendix: ソースコードリーディングは 心がジーンとする Copyright © Acroquest Technology Co., Ltd. All rights reserved. 18

Slide 19

Slide 19 text

STEP 1 ライブラリのコードを読もう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 19

Slide 20

Slide 20 text

STEP 1: ソースコードを開こう! • 例えばこんなコードがあったりする・・・ Copyright © Acroquest Technology Co., Ltd. All rights reserved. 20 if (StringUtils.isEmpty("")) { System.out.println("JJUG CCC 2019 Fall"); } Apache Commons の org.apache.commons.lang3.StringUtils

Slide 21

Slide 21 text

Copyright © Acroquest Technology Co., Ltd. All rights reserved. 21 そもそもコード読むのに 何を使ってますか? 0. はじめに

Slide 22

Slide 22 text

STEP 1: ソースコードを開こう! • ソースコードを読む手段 ① IDE ←オススメ – Eclipse / IntelliJ IDEA / NetBeans … お好きなもので – マウスオーバーで変数や引数の型を確認したり、 Ctrl + 左クリックで型ジャンプができる ② GitHub – ソースコードを取得する必要がないので手軽 – 複数のファイルの行ったり来たりしようとすると、途端に辛くなる (特にパッケージ階層をまたがると辛い) ③ テキストエディタ – 止めはしない。 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 22

Slide 23

Slide 23 text

STEP 1: ソースコードを開こう! • ソースコードを取得する方法 ① Maven or Gradleで *-sources.jar をDL – IDEだとクリックだけで簡単にダウンロードできる – 使っているバージョンと正確に一致したソースコードを確認できる – 自分が書いたコードからライブラリのコードに直接ジャンプできる ② git clone – ソースコードだけでなく、READMEやテストコードも取れる – 大きなリポジトリは大体git cloneで取ってきてます – 別バージョンのソースコードを取ってこないように注意 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 23

Slide 24

Slide 24 text

STEP 1: ソースコードを開こう! • 再掲 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 24 if (StringUtils.isEmpty("")) { System.out.println("JJUG CCC 2019 Fall"); } Apache Commons の org.apache.commons.lang3.StringUtils

Slide 25

Slide 25 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 25 Q. このメソッドの中身は どうなっているでしょうか?

Slide 26

Slide 26 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 26 public static boolean isEmpty(final CharSequence cs) { return cs == null || cs.length() == 0; } A.

Slide 27

Slide 27 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 27 public static boolean isEmpty(final CharSequence cs) { return cs == null || cs.length() == 0; } 引数のcsがnull またはcsの長さが0

Slide 28

Slide 28 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 28 こんな簡単なコードから始めるの? って思いました?

Slide 29

Slide 29 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 29 ここから始めます

Slide 30

Slide 30 text

STEP 1: ソースコードを開こう! • ライブラリのソースコードを読むことはハードル高くない ➢ 大部分のコードは、1行1行は難しいこと書いてない ➢ Javaの文法と基本的なAPIを抑えていれば、Apache Commons 程度であれば大体読める ➢ きちんとしたライブラリであればJavadocに仕様はちゃんと 書いてある Copyright © Acroquest Technology Co., Ltd. All rights reserved. 30

Slide 31

Slide 31 text

STEP 1: ソースコードを開こう! • なぜソースコードリーディングを難しく感じるのか • 多重知能理論 • 言語的知能 • 論理数学的知能 • 音楽的知能 • 身体運動的知能 • 空間的知能 • 対人的知能 • 内省的知能 • 博物的知能 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 31 http://www.nichinoken.co.jp/np5/nnk/multiple_intelligences/mi/mi.html

Slide 32

Slide 32 text

STEP 1: ソースコードを開こう! • ソースコードリーディングは知識・論理・読解の複合スキル • 知識 ・・・ CS、Web、API、etc… • 論理 ・・・ ロジック、アルゴリズムの理解 • 読解 ・・・ 文法の適用、 文脈を理解して適度に必要のない情報を無視する (英語力も?) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 32 知識 論理 読解 ソースコード リーディング

Slide 33

Slide 33 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 33 ソースコードリーディング = スキル

Slide 34

Slide 34 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 34 スキルはトレーニングによって身に付く

Slide 35

Slide 35 text

STEP 1: ソースコードを開こう! • トレーニングの成果は負荷(質)と量によって決まる • 簡単なコードだけを大量に読んでも負荷がかからない • 難しすぎるコードも、全く理解できなければ負荷にならない Copyright © Acroquest Technology Co., Ltd. All rights reserved. 35

Slide 36

Slide 36 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 36 最初は誰でもつまづく

Slide 37

Slide 37 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 37 知らなかったことを知る 読めなかったものが読めるようになる

Slide 38

Slide 38 text

STEP 1: ソースコードを開こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 38 それが成長

Slide 39

Slide 39 text

STEP 2 ライブラリのコードを読もう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 39

Slide 40

Slide 40 text

STEP 2: ライブラリのコードを読もう! • コードを読む上で大事なこと 1. 目的、目標を設定する (重要) ➢ これがないと読むべきところ、読み飛ばして良いところの区別がつかない 2. 深く掘り下げすぎない ➢ 記憶はスタック構造。詳細を見すぎると全体像を見失う 3. クラスの使い方を把握する ➢ Hello worldで良いので、どんな機能か、呼び出し元はどう書くかを調べる 4. 名前に注意する ➢ クラス名・変数名・メソッド名の意味を理解することで仕様を理解する Copyright © Acroquest Technology Co., Ltd. All rights reserved. 40

Slide 41

Slide 41 text

STEP 2: ライブラリのコードを読もう! • Commons DBUtils • 軽量なRDBアクセスライブラリ • 生JDBCドライバを使ったコードに比べて 簡潔に記述することができる • QueryRunnerクラスのquery(), insert(), update() といった メソッドを呼び出し、ResultSetHandlerインタフェース(とその実装クラ ス)を使って結果を特定の型にマッピングする。 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 41

Slide 42

Slide 42 text

STEP 2: ライブラリのコードを読もう! • 読むのは以下のコード Copyright © Acroquest Technology Co., Ltd. All rights reserved. 42 DataSource ds = … QueryRunner queryRunner = new QueryRunner(ds); List result = queryRunner.query( "SELECT * FROM users;", new BeanListHandler<>(User.class)); RDBへの接続を作るファクトリ。 大抵の場合コネクションプール。 usersテーブルからデータを取得して、 各レコードをUser型に変換したリスト を作成する。

Slide 43

Slide 43 text

STEP 2: ライブラリのコードを読もう! • 目標を設定する ✓ QueryRunnerがJDBCとどう連携しているかを理解する ✓ コネクションをいつ取得して、いつクローズしているかを確認する ✓ usersテーブルの”first_name“をUserクラスの”firstName”に マッピングできるかどうかを調べる Copyright © Acroquest Technology Co., Ltd. All rights reserved. 43 これを目標にして ソースコードの読解を進める

Slide 44

Slide 44 text

STEP 2: ライブラリのコードを読もう! • QueryRunner#query() Copyright © Acroquest Technology Co., Ltd. All rights reserved. 44

Slide 45

Slide 45 text

STEP 2: ライブラリのコードを読もう! • QueryRunner#query() Copyright © Acroquest Technology Co., Ltd. All rights reserved. 45 引数のnullチェック 例外処理 これらは一旦無視

Slide 46

Slide 46 text

STEP 2: ライブラリのコードを読もう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 46 _人人人人_ > 無視 <  ̄Y^Y^Y^ ̄

Slide 47

Slide 47 text

STEP 2: ライブラリのコードを読もう! • コードは読み飛ばしていい • 最初から細かいところまで全部読んで、記憶のスタックを使い果たす くらいなら、目標と関係ないところは読み飛ばしたほうがマシ • コードリーディングは、コードの意図や構造を理解する営み。 一字一句音読するものではない。 • 「全部読め」派も特に否定はしないです Copyright © Acroquest Technology Co., Ltd. All rights reserved. 47

Slide 48

Slide 48 text

STEP 2: ライブラリのコードを読もう! • QueryRunner#query() Copyright © Acroquest Technology Co., Ltd. All rights reserved. 48 この部分を集中 して読む

Slide 49

Slide 49 text

STEP 2: ライブラリのコードを読もう! • QueryRunner#query() Copyright © Acroquest Technology Co., Ltd. All rights reserved. 49 stmt = this.prepareStatement(conn, sql); this.fillStatement(stmt, params); rs = this.wrap(stmt.executeQuery()); result = rsh.handle(rs); PreparedStatementの作成 SQSにクエリパラメータをセット クエリを実行 型 ResultSetを 型の変数に変換

Slide 50

Slide 50 text

STEP 2: ライブラリのコードを読もう! • 一旦図に整理 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 50

Slide 51

Slide 51 text

STEP 2: ライブラリのコードを読もう! • BeanListHandler Copyright © Acroquest Technology Co., Ltd. All rights reserved. 51 public class BeanListHandler implements ResultSetHandler> { private final Class extends T> type; private final RowProcessor convert; public BeanListHandler(Class extends T> type) { this(type, ArrayHandler.ROW_PROCESSOR); } @Override public List handle(ResultSet rs) throws SQLException { return this.convert.toBeanList(rs, type); } Bean変換は convert が行っ ている。 convertの中身は BasicRowProcessor

Slide 52

Slide 52 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor Copyright © Acroquest Technology Co., Ltd. All rights reserved. 52 public List toBeanList(ResultSet rs, Class extends T> type) throws SQLException { List results = new ArrayList(); if (!rs.next()) { return results; } PropertyDescriptor[] props = this.propertyDescriptors(type); ResultSetMetaData rsmd = rs.getMetaData(); int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); do { results.add(this.createBean(rs, type, props, columnToProperty)); } while (rs.next()); return results; } BasicRowProcessorのtoBeanList(rs, type)は BeanProcessorに処理を移譲するだけ PropertyDescriptorはBeanの プロパティをgetter/setter経由 でアクセスするためのクラス

Slide 53

Slide 53 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor Copyright © Acroquest Technology Co., Ltd. All rights reserved. 53 public List toBeanList(ResultSet rs, Class extends T> type) throws SQLException { List results = new ArrayList(); if (!rs.next()) { return results; } PropertyDescriptor[] props = this.propertyDescriptors(type); ResultSetMetaData rsmd = rs.getMetaData(); int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); do { results.add(this.createBean(rs, type, props, columnToProperty)); } while (rs.next()); return results; } BasicBeanProcessorのtoBeanList(rs, type)は BeanProcessorに処理を移譲するだけ 結果セットのカラム名を取得する ここが怪しい

Slide 54

Slide 54 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor#mapColumnsToProperties(…) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 54 やっていることはResultSetの各 カラムの値が、Beanのどの PropertyDescriptorに格納され るかの対応づけ

Slide 55

Slide 55 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor#mapColumnsToProperties(…) ➢ JavaDocも読んで見る ◆ 戻り値の配列 (int配列) の位置はカラム番号を表します。各位置に 格納されてる値は、そのカラム名に対応したBeanプロパティの PropertyDescriptor[]の位置を表します。カラムに対応するBean プロパティが存在しない場合は、その位置には PROPERTY_NOT_FOUND (-1) がセットされます。 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 55 戻り値のint配列に値がセットされているところを見れば、 対応付けの方法がわかりそう

Slide 56

Slide 56 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor#mapColumnsToProperties(…) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 56 カラム名を取得して

Slide 57

Slide 57 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor#mapColumnsToProperties(…) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 57 columnToPropertyOverridesにcolumnNameに 対応したpropertyNameがあれば取得して、 なければcolumnNameをpropertyNameに使って HashMap デフォルトでは空

Slide 58

Slide 58 text

STEP 2: ライブラリのコードを読もう! • BeanProcessor#mapColumnsToProperties(…) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 58 PropertyDescriptor配列をぐるぐる回して、 プロパティ名が一致するものを探す (大文字小文字の違いは無視)

Slide 59

Slide 59 text

STEP 2: ライブラリのコードを読もう! • 結論 ➢ 元のコードでは、“first_name”を”firstName”にマッピングしてくれな い。 ➢ BeanProcessorのcolumnToPropertyOverrides で”first_name”と”firstName”の対応を指定すれば マッピングできそう。 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 59 Commons DBUtils完全にマスターした

Slide 60

Slide 60 text

STEP 3 構造を読み解こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 60

Slide 61

Slide 61 text

STEP 3: 構造を読み解こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 61 Webフレームワークのソースコード、 読みたくなりません? 読みたいですよね?

Slide 62

Slide 62 text

STEP 3: 構造を読み解こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 62 でもJavaのWebフレームワークって 大体10KL以上で読むの辛いし 多機能すぎるし・・・

Slide 63

Slide 63 text

STEP 3: 構造を読み解こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 63 そこで ですよ

Slide 64

Slide 64 text

STEP 3: 構造を読み解こう! • Javalin • シンプル・軽量なWebフレームワーク • Jettyを内包しており、single jarで動作する • WebSocket, バリデーション、Server-Sent Eventsなど 基本的な機能は一通りそろっている • JavaだけでなくKotlinも混ざっているけどキニシナイ! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 64

Slide 65

Slide 65 text

STEP 3: 構造を読み解こう! • Java Servlet (Jakarta Servlet) • JavaでWebアプリケーションをつくるための仕様 (と作成されたプログラム) • HttpServletクラスを継承し、doGet/doPost/doPut/… メソッドに HTTPリクエストを受け付けた際の処理を書く • Servletを動作させるにはサーブレットコンテナ(Tomcat, Jetty, etc…)が必要 • Jetty • サーブレットコンテナの一種 • Tomcatに比べてサイズが小さく起動が早い Copyright © Acroquest Technology Co., Ltd. All rights reserved. 65

Slide 66

Slide 66 text

STEP 3: 構造を読み解こう! • コードを読む上で大事なこと (再掲) 1. 目的、目標を設定する ➢ これがないと読むべきところ、読み飛ばして良いところの区別がつかない 2. 深く掘り下げすぎない ➢ 記憶はスタック構造。詳細を見すぎると全体像を見失う 3. クラスの使い方を把握する ➢ Hello worldで良いので、どんな機能か、呼び出し元はどう書くかを調べる 4. 名前に注意する ➢ クラス名・変数名・メソッド名の意味を理解することで仕様を理解する Copyright © Acroquest Technology Co., Ltd. All rights reserved. 66

Slide 67

Slide 67 text

STEP 3: 構造を読み解こう! • コードを読む上で大事なこと② 1. 型を強く意識する ➢ 各クラス・インタフェースの役割を把握することで、クラス間の関係が 非常に理解しやすくなる 2. メモする ➢ 大きなコードを読むときに現在位置を把握しておく 3. ドキュメント、Javadocをよく読む ➢ 仕様だけでなく実装の解説も書いてあったりする Copyright © Acroquest Technology Co., Ltd. All rights reserved. 67

Slide 68

Slide 68 text

STEP 3: 構造を読み解こう! • JavalinでシンプルなWebアプリケーション Copyright © Acroquest Technology Co., Ltd. All rights reserved. 68 Javalin.create() .get("/hello", ctx -> ctx.result("Hello, World!")) .start(); たった3行でWebアプリケーションの 起動ができる

Slide 69

Slide 69 text

STEP 3: 構造を読み解こう! • まずはJavadocを読む Copyright © Acroquest Technology Co., Ltd. All rights reserved. 69 Javalin.create() .get("/hello", ctx -> ctx.result("Hello, World!")) .start(); Javalinインスタンスの生成 /hello にハンドラを登録 サーバーの起動

Slide 70

Slide 70 text

STEP 3: 構造を読み解こう! • 上から順に読み進めていく Copyright © Acroquest Technology Co., Ltd. All rights reserved. 70 Javalin.create() .get("/hello", ctx -> ctx.result("Hello, World!")) .start(); まずは全体像の理解から進める。 ※各メソッドで深追いしすぎないように注意

Slide 71

Slide 71 text

STEP 3: 構造を読み解こう! • Javalin#create() Copyright © Acroquest Technology Co., Ltd. All rights reserved. 71 public static Javalin create() { return create(JavalinConfig.noopConfig); } public static Javalin create(Consumer config) { Javalin app = new Javalin(); JavalinConfig.applyUserConfig(app, app.config, config); if (app.config.logIfServerNotStarted) { Util.logIfServerNotStarted(app.server); } return app; }

Slide 72

Slide 72 text

STEP 3: 構造を読み解こう! • Javalin コンストラクタ Copyright © Acroquest Technology Co., Ltd. All rights reserved. 72 protected JavalinServer server; protected JavalinWsServlet wsServlet; protected JavalinServlet servlet = new JavalinServlet(config); protected Javalin() { this.server = new JavalinServer(config); this.wsServlet = new JavalinWsServlet(config); } サーバーっぽい何か Servletっぽい何か WebSocketっぽいので一旦無視

Slide 73

Slide 73 text

STEP 3: 構造を読み解こう! • 上から順に読み進めていく Copyright © Acroquest Technology Co., Ltd. All rights reserved. 73 Javalin.create() .get("/hello", ctx -> ctx.result("Hello, World!")) .start();

Slide 74

Slide 74 text

STEP 3: 構造を読み解こう! • Javalin#get(…) Copyright © Acroquest Technology Co., Ltd. All rights reserved. 74 public Javalin get(@NotNull String path, @NotNull Handler handler) { return addHandler(HandlerType.GET, path, handler); } public Javalin addHandler(@NotNull HandlerType handlerType, @NotNull String path, @NotNull Handler handler, @NotNull Set roles) { servlet.addHandler(handlerType, path, handler, roles); eventManager.fireHandlerAddedEvent( new HandlerMetaInfo(handlerType, Util.prefixContextPath(servlet.getConfig().contextPath, path), handler, roles)); return this; } ラムダ式はHandler型のインスタンスになる JavalinServlet#addHandlerに移譲 イベントハンドラに発火 とりあえず無視

Slide 75

Slide 75 text

STEP 3: 構造を読み解こう! • 上から順に読み進めていく Copyright © Acroquest Technology Co., Ltd. All rights reserved. 75 Javalin.create() .get("/hello", ctx -> ctx.result("Hello, World!")) .start();

Slide 76

Slide 76 text

STEP 3: 構造を読み解こう! • Javalin#start() Copyright © Acroquest Technology Co., Ltd. All rights reserved. 76 server.start(servlet, wsServlet); これ以外は とりあえず無視

Slide 77

Slide 77 text

STEP 3: 構造を読み解こう! • メモで整理 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 77

Slide 78

Slide 78 text

STEP 3: 構造を読み解こう! • もう一段深く読み込む ✓ JavalinServlet#addHandler(…)を呼び出したあと、 ハンドラはどんなデータ構造で保持されている? ✓ HTTPリクエストが来たとき、ハンドラはどうやって呼び出されている? Copyright © Acroquest Technology Co., Ltd. All rights reserved. 78

Slide 79

Slide 79 text

STEP 3: 構造を読み解こう! • もう一段深く読み込む ✓ JavalinServlet#addHandler(…)を呼び出したあと、 ハンドラはどんなデータ構造で保持されている? ✓ HTTPリクエストが来たとき、ハンドラはどうやって呼び出されている? Copyright © Acroquest Technology Co., Ltd. All rights reserved. 79

Slide 80

Slide 80 text

STEP 3: 構造を読み解こう! Copyright © Acroquest Technology Co., Ltd. All rights reserved. 80 ※ちなみにここからKotlinのコードが 混ざり始めます 僕も文法ちゃんと覚えてないからヘーキヘーキ

Slide 81

Slide 81 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 81 fun addHandler(handlerType: HandlerType, path: String, handler: Handler, roles: Set) { val shouldWrap = handlerType.isHttpMethod() && !roles.contains(CoreRoles.NO_WRAP) val protectedHandler = if (shouldWrap) Handler { ctx -> config.inner.accessManager.manage(handler, ctx, roles) } else handler matcher.add(HandlerEntry(handlerType, path, protectedHandler, handler)) } 1, 2行目はアクセス制御 PathMatcher HandlerEntryはpathとhandler をセットにしたクラス

Slide 82

Slide 82 text

STEP 3: 構造を読み解こう! • PathMatcher.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 82 fun add(entry: HandlerEntry) { if (entry.type.isHttpMethod() && handlerEntries[entry.type]!!.find { it.type == entry.type && it.path == entry.path } != null) { throw IllegalArgumentException("Handler with type='${entry.type}’ and path='${entry.path}' already exists.") } handlerEntries[entry.type]!!.add(entry) } 同じパスに対して複数の ハンドラが登録されたら 例外を投げる private val handlerEntries = HandlerType.values().associateTo( EnumMap>(HandlerType::class.java)) { it to arrayListOf() }

Slide 83

Slide 83 text

STEP 3: 構造を読み解こう! • handlerEntriesのデータ構造 handlerEntries: GET: [{path: ”/hello”, handler: …}, {path: “/bye”, handler: …}], POST: [{path: “/echo”, handler: …}], PUT: … … Copyright © Acroquest Technology Co., Ltd. All rights reserved. 83 HTTPメソッド + αがkey Listがvalue

Slide 84

Slide 84 text

STEP 3: 構造を読み解こう! • もう一段深く読み込む ✓ JavalinServlet#addHandler(…)を呼び出したあと、 ハンドラはどんなデータ構造で保持されている? ➢ ハンドラのリストが、HandlerTypeをキーとしたMapの Valueに格納されている ✓ HTTPリクエストが来たとき、ハンドラはどうやって呼び出されている? Copyright © Acroquest Technology Co., Ltd. All rights reserved. 84

Slide 85

Slide 85 text

STEP 3: 構造を読み解こう! • もう一段深く読み込む ✓ JavalinServlet#addHandler(…)を呼び出したあと、 ハンドラはどんなデータ構造で保持されている? ➢ ハンドラのリストが、HandlerTypeをキーとしたMapの Valueに格納されている ✓ HTTPリクエストが来たとき、ハンドラはどうやって呼び出されている? Copyright © Acroquest Technology Co., Ltd. All rights reserved. 85

Slide 86

Slide 86 text

STEP 3: 構造を読み解こう! • JavalinServer.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 86 httpHandlerという変数名に注目して この部分を集中して読む

Slide 87

Slide 87 text

STEP 3: 構造を読み解こう! • JavalinServer.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 87 ServletContextHandlerはServletHandlerや SessionHandlerなどを集約したJettyのクラス ServletContextHandlerの匿名クラス “/*” で全てのパスに対して、 JavalinServletを登録している

Slide 88

Slide 88 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 88 class JavalinServlet(val config: JavalinConfig) : HttpServlet() { JavalinServlet は HttpServletを 継承したクラス

Slide 89

Slide 89 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 89 HttpServlet#service メソッドのJavadoc 「public で定義された service メソッド経由で標準 HTTP リクエスト を受け取り、それらをこのクラスで定義された doXXX メソッドに ディスパッチします。」

Slide 90

Slide 90 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 90 fun tryBeforeAndEndpointHandlers() = tryWithExceptionMapper { (中略) matcher.findEntries(type, requestUri).firstOrNull()?.let { entry -> entry.handler.handle( ContextUtil.update(ctx, entry, requestUri)) return@tryWithExceptionMapper // return after first match } serviceメソッドから抜粋

Slide 91

Slide 91 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 91 fun tryBeforeAndEndpointHandlers() = tryWithExceptionMapper { (中略) matcher.findEntries(type, requestUri).firstOrNull()?.let { entry -> entry.handler.handle( ContextUtil.update(ctx, entry, requestUri)) return@tryWithExceptionMapper // return after first match } PathMatcher handlerEntriesを保持

Slide 92

Slide 92 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 92 fun tryBeforeAndEndpointHandlers() = tryWithExceptionMapper { (中略) matcher.findEntries(type, requestUri).firstOrNull()?.let { entry -> entry.handler.handle( ContextUtil.update(ctx, entry, requestUri)) return@tryWithExceptionMapper // return after first match } Type (HTTPメソッド) とURLにマッチ するHandlerEntryを探索 fun findEntries(handlerType: HandlerType, requestUri: String) = handlerEntries[handlerType]!!.filter { he -> match(he, requestUri) } 線形に探索している

Slide 93

Slide 93 text

STEP 3: 構造を読み解こう! • JavalinServlet.kt Copyright © Acroquest Technology Co., Ltd. All rights reserved. 93 fun tryBeforeAndEndpointHandlers() = tryWithExceptionMapper { (中略) matcher.findEntries(type, requestUri).firstOrNull()?.let { entry -> entry.handler.handle( ContextUtil.update(ctx, entry, requestUri)) return@tryWithExceptionMapper // return after first match } Handlerの実行

Slide 94

Slide 94 text

STEP 3: 構造を読み解こう! • クラス・メソッドの関係を図に書いてみる Copyright © Acroquest Technology Co., Ltd. All rights reserved. 94

Slide 95

Slide 95 text

STEP 3: 構造を読み解こう! • HTTPリクエストを受け付ける流れ Copyright © Acroquest Technology Co., Ltd. All rights reserved. 95 JavalinServlet が全てのリクエストを受け付けて Handlerに処理を振り分けている

Slide 96

Slide 96 text

STEP 3: 構造を読み解こう! • もう一段深く読み込む ✓ JavalinServlet#addHandler(…)を呼び出したあと、 ハンドラはどんなデータ構造で保持されている? ➢ ハンドラのリストが、HandlerTypeをキーとしたMapの Valueに格納されている ✓ HTTPリクエストが来たとき、ハンドラはどうやって呼び出されている? ➢ JavalinServletが全てのリクエストを受け付けて、パスに応じて 各Handlerに処理を振り分けている Copyright © Acroquest Technology Co., Ltd. All rights reserved. 96

Slide 97

Slide 97 text

STEP 3: 構造を読み解こう! • まとめ ➢ 浅く広く読んでから、少しずつ深いところまで読み進める ➢ ときどき図に書いて整理すると構造を理解しやすい ➢ 目標と関係ないコードを読み飛ばすの大事 Copyright © Acroquest Technology Co., Ltd. All rights reserved. 97 Javalin完全に(以下略)

Slide 98

Slide 98 text

余談 • Sourcetrail • Coati Softwareが開発する コードエクスプローラ • 数日前にオープンソース化された • クラスの依存関係、 呼び出し階層などを グラフィカルに表示できる • これを使うとコード読むのが捗るかも? Copyright © Acroquest Technology Co., Ltd. All rights reserved. 98 https://www.sourcetrail.com/

Slide 99

Slide 99 text

APPENDIX ソースコードリーディングは 心がジーンとする Copyright © Acroquest Technology Co., Ltd. All rights reserved. 99

Slide 100

Slide 100 text

ソースコードリーディングは心がジーンとする Copyright © Acroquest Technology Co., Ltd. All rights reserved. 100 僕のトロが言ってました 「にゃるほど、ソースコードリーディングは 心がジーンとする!」

Slide 101

Slide 101 text

ソースコードリーディングは心がジーンとする • 良いコードとは? ✓ 読みやすい ✓ 適切に抽象化されている ✓ 責務が明確 ✓ Javadoc、コメントが過不足ない ⇒ 良いコードを読むことは、これらのサンプルを知ること Copyright © Acroquest Technology Co., Ltd. All rights reserved. 101

Slide 102

Slide 102 text

ソースコードリーディングは心がジーンとする Copyright © Acroquest Technology Co., Ltd. All rights reserved. 102 コードをたくさん読むことで 良いコードの審美眼を鍛える

Slide 103

Slide 103 text

ソースコードリーディングは心がジーンとする Copyright © Acroquest Technology Co., Ltd. All rights reserved. 103 良いコードを書くには 良いコードを読むことが早道

Slide 104

Slide 104 text

まとめ • ソースコードリーディングはこわくない • ソースコードリーディング力はトレーニングで身に付く • 良いコードを読むことでコードの審美眼を鍛える • Commons DBUtils完全にマスターした • Javalin完全にマスターした Copyright © Acroquest Technology Co., Ltd. All rights reserved. 104

Slide 105

Slide 105 text

良いソースコードリーディング生活を! Evolve the Earth with Emotion of Technology Copyright © Acroquest Technology Co., Ltd. All rights reserved. 105