Upgrade to Pro — share decks privately, control downloads, hide ads and more …

20241128_NEWT‐Tech-Talk_nakano

reiwa-travel
November 29, 2024
82

 20241128_NEWT‐Tech-Talk_nakano

reiwa-travel

November 29, 2024
Tweet

Transcript

  1. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 2
 Backend Engineer 中野

    紘典 ⾃⼰紹介 Background 2021年にヤフー株式会社(現LINEヤフー株式会社)に新卒⼊社。 社内オブジェクトストレージの開発/運⽤業務を担当。 2024年1⽉より令和トラベルにバックエンドエンジニアとして⼊社。 海外旅⾏アプリ「NEWT」のAPI開発と社内の業務⾃動化基盤の開発 に従事。 Tech • TypeScript(令和トラベルに転職〜) • Go(前職で使ってました) Like • バスケ🏀 • サウナ🧖 • 旅⾏✈
  2. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 Agenda 3
 • 今までのDBドキュメントの運⽤⽅法と課題

    • 今回導⼊したDBドキュメント⾃動⽣成 • どのように移⾏したか • 導⼊した結果と今後
  3. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 DBドキュメントがなぜ令和トラベルで必要なのか? 5
 DBをエンジニア以外の社内の様々な関係者が利⽤するから 例)

    マーケティングチームの分析メンバーが予約状況可視化のダッシュボード作成 DBのテーブル定義やテーブルの関係をエンジニア以外も理解できる必要がある ツアーの⽬的地集計したいけど ⽬的地のカラムどれだ。。。 😇
  4. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 Schema Spyを使⽤してDB情報を可視化 6
 Schema

    Spyとは? DBからエンティティ関係図を含む HTML ドキュメントを⽣成するツール エンティティ関係図 カラムの情報 SchemaSpyを使⽤してエンジニア以外のメンバーにもDBの情報を公開 → エンジニア以外のメンバーもテーブル定義やテーブルの関係を理解可能
  5. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 エンジニア DBのドキュメントを反映する負担が増加 😇 7


    エンジニア以外のメンバー ドキュメントあるのでDBを理解しやすい👏 エンジニアから⾒たら課題が。。。
  6. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 SchemaSpyへのドキュメントの反映⽅法 8
 1. 説明を記載したマークダウンファイル(mdファイル)を記述

    2. mdファイルからXMLファイルに変換し、SchmaSpyへ反映するScriptを実行 (SchemaSpyのメタ情報の記載に則したXMLファイルを記載する必要がある) # sample サンプルの説明 ## id idの説明 ## column1 column1の説明 ドキュメント(md) <schemaMeta xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schemaspy.org/xsd/6/schemame ta.xsd"> <tables> <table name="sample" comment="sampleの説明"> <column name="id"comment= "idの説明"/> <column name="column1" comment= "column1の説明"/> </table> </tables> </schemaMeta> SchemaSpyのメタ情報の記載に則したXMLファイル
  7. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 従来の⽅法の課題 9
 ソースコードとテーブル定義ドキュメントが別ファイルとして管理 import

    {BaseEntity, Column, Entity, PrimaryGeneratedColumn} from "typeorm"; @Entity() export class Sample extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() column1: number; } ソースコード # sample サンプルの説明 ## id idの説明 ## column1 column1の説明 ドキュメント(md)
  8. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 従来の⽅法の課題 10
 レビューお願いします テーブル定義のmd記載してください

    👍 すいません、記載します🙏 ドキュメント(md)がソースコードと離れていることからドキュメントを作成し忘れる 👉 レビューの⼯数が増える 👉 そもそもレビュワーも気づかずドキュメントが作成されないケースも... レビュワー
  9. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 課題を解決するために必要なこと 11
 1. コメントとソースファイルを⼀箇所にまとめる🔥

    → コメントを書きやすい状態にすることでエンジニアの負荷を減らす 2. エンジニアにコメントを追加することのメリットを作る🔥 → エンジニアがコメントにメリットを感じればコメントを書くはず
  10. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 今回導⼊した⽅法 👉ソースファイルにJSDoc  でコメントを記載 13


    👉TypeScript Compiler APIを 使っ  てソースファイルから JSDocを抽出し、XMLファイルを 作成 今まで これから マークダウンでコメント 定義のファイルを作成 マークダウンファイルから XMLファイルを作成 コメントの記載方法 SchemaSpyへの反映⽅法
  11. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 JSDocとは? 14
 /** *

    Represents a book. */ function Book(title) { } • ドキュメント化されるコードの直前に配置 • /** で始める JSのソースコードに注釈を追加するために使われるマークアップ⾔語 JSDocのルール
  12. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 TypeScript Compiler APIとは? TSのコードをプログラムで解析‧操作できるようにするためのAPI

    ソースコードを変換したASTを元に解析処理が可能 let message = "Hello"; console.log(message); ソースコード SyntaxList: let message = "Hello";console.log(message); FirstStatement: let message = "Hello"; VariableDeclarationList: let message = "Hello" LetKeyword: let SyntaxList: message = "Hello" VariableDeclaration: message = "Hello" Identifier: message FirstAssignment: = StringLiteral: "Hello" SemicolonToken: ; ExpressionStatement: console.log(message); CallExpression: console.log(message) PropertyAccessExpression: console.log Identifier: console DotToken: . Identifier: log OpenParenToken: ( SyntaxList: message Identifier: message CloseParenToken: ) SemicolonToken: ; EndOfFileToken: AST 変換 16

  13. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 TypeScript Compiler APIを使⽤した背景 ソースファイルを解析してJSDocを抽出するコードをTypeScript

    Compiler APIなら簡単に実装可能 JSDocだけでなく@Entityなどの情報もAPIを通して取得できるので ソースファイルの特定も容易にできた 17
 import {BaseEntity, Column, Entity, PrimaryGeneratedColumn} from "typeorm"; /** * サンプルエンティティの説明 */ @Entity() export class Sample extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() column1: number; } 変換 SyntaxList: …. ImportDeclaration: ClassDeclaration: … JSDocComment: /** * サンプルエンティティの説明 */ ….
  14. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 移⾏前〜 ⽣成AIで軽く試す 19
 TypeScript

    Compiler API は知見が全くなかったので 簡単なJSDocを記載したサンプルで生成AIを使って試してみた 👉TypeScript Compiler APIの使い方と簡単に実現できるか調べるため TypeScript Compiler API を使えば、以下が簡単に実装できると分かった💪 1. @Entityデコレータの検出   👉 ソースファイルの特定が可能だから 2. JSDocを検出&値を取得すること   👉 ソースファイルからコメントを抽出することが可能だから
  15. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 どのように移⾏するか 20
 フェーズ1 mdファイルから該当するソー

    スファイルにJSDoc コメントを転記する フェーズ2 JSDocからSchemaSpyの メタデータの形式に則した XMLファイルを作成する
  16. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 どのように移⾏するか 21
 フェーズ1 マークダウンのドキュメン

    トファイルから該当する ソースファイルにJSDoc コメントを転記する フェーズ2 JSDocからSchemaSpyの メタデータの形式に則した XMLファイルを作成する
  17. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 マークダウンファイルからJSDocへの変換 - 全体図 22


    JSDocコメントの⽣成 TypeScriptファイルへJSDocを適⽤ mdファイルの検出 とパース
  18. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 マークダウンファイルからJSDocへの変換 - マークダウンファイルの検出とパース処理 23


    # sample サンプルの説明 ## id idの説明 ## column1 column1の説明 mdファイル 各⾏は特定のパターンに基づいて処理 • # で始まる⾏はテーブル定義として認識され、直後の⾏はそのテーブルの説明⽂として保存 • ## で始まる⾏はカラム定義として認識同様に、直後の⾏はそのカラムの説明⽂として保存
  19. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 マークダウンファイルからJSDocへの変換 - JSDocコメントの⽣成 24


    { title: "sample", content: ["サンプルの説明"], subSections: [ { title: "id", content: ["idの説明"] }, { title: "column1", content: ["column1の説明"] } ] } { // テーブル用のJSDoc classJSDoc: "/**\n * サンプルの説明\n */", // カラム用のJSDoc columnJSDocs: { id: "/**\n * idの説明\n */", column1: "/**\n * column1の説明\n */" } } mdのパース処理で作成した中間データをJSDocコメントに変換 • メインセクションの説明⽂をテーブルの説明としてJSDocコメントに変換 • サブセクションの説明⽂を各カラムの説明として形式のJSDocコメントに変換し、キー名と紐付け mdのパース処理で作成した中間データ JSDocに変換した中間データ
  20. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 マークダウンファイルからJSDocへの変換 - TypeScriptファイルへJSDocを適⽤ 25


    /** * サンプルの説明 */ @Entity() export class Sample extends BaseEntity { /** * idの説明 */ @PrimaryGeneratedColumn() id: number; /** * column1の説明 */ @Column() column1: number; TypeScript Compiler APIを使⽤し以下ロジックでJSDocをソースファイルに追加 • @Entityがあるクラスの場合 その上にテーブルの説明を追加 • @PrimaryGeneratedColumn、@Columnの場合、カラムの説明を追加
  21. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 どのように移⾏するか 26
 フェーズ1 マークダウンのドキュメント

    ファイルから該当するEnソー スファイルにJSDoc コメントを転記する フェーズ2 JSDocからSchemaSpyの メタデータの形式に則した XMLファイルを作成する
  22. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 JSDocからSchemaSpyのXMLファイル変換 - ファイル検索 28


    DB名に基づいて解析対象のTSファイルを特定 • コマンドライン引数からDB名を取得し、そのDBに対応するモジュールディレクトリを決定 // 対象ファイルリスト const entityFiles = [ "src/modules/sample1/sample1. entity.ts", "src/modules/sample2/sample2. entity.ts" ]
  23. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 JSDocからSchemaSpyのXMLファイル変換 - エンティティ解析 29


    /** * sampleの説明 */ @Entity() export class Sample extends BaseEntity { /** * idの説明 */ @PrimaryGeneratedColumn() id: number; /** * column1の説明 */ @Column() column1: number; // EntityInfo構造体 const entityInfo = { name: "sample", description: "sampleの説明", properties: [ { name: "id", type: "number", description: "idの説明" }, { name: "column1", type: "number", description: "column1の説明" } ] } 解析するtsファイル 解析後作成された中間データ
  24. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 JSDocからSchemaSpyのXMLファイル変換 - ドキュメント⽣成 30


    // EntityInfo構造体 const entityInfo = { name: "sample", description: "sampleの説明", properties: [ { name: "id", type: "number", description: "idの説明" }, { name: "column1", type: "number", description: "column1の説明" } ] } <schemaMeta xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schemaspy.org/xsd/6/schemame ta.xsd"> <tables> <table name="sample" comment="サンプルの説明"> <column name="id"comment= "idの説明"/> <column name="column1" comment= "column1の説明"/> </table> </tables> </schemaMeta> XMLファイル 抽出したエンティティ情報をSchemaSpy形式のXMLファイルに変換 SchemaSpy互換のXMLファイルとして出⼒することで、DBドキュメントが⾃動⽣成
  25. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 導⼊した結果 32
 mdファイル(全64ファイル)に記載されていたテーブル定義を全てJSDocのコメントに変換できた🎉 •

    JSDocでコメントをつけたことでホバー機能で詳細を確認可能 👉 ソースファイルとコメントが一箇所になった 👉 JSDocがつくことでエンジニアにもコメントを書くメリットが生まれた
  26. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 @Field(() => Boolean, {

    description: `column1の説明`, }) /**   column1の説明 */ @Column({ type: "boolean", default: false }) column1: boolean; 苦労した点 33
 コメント追加が意図しない箇所にされてしまう 本来は@Fieldの上に配置したい。。。😇 現在チームで規定されている型と異なるパターンが存在 例)@Columnデコレータの上に別のデコレータ ソースファイルの書き方が統一されている 👉解析処理の観点でも大事 問題点 原因
  27. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 今後の課題 34
 マークダウンのコメント定義にないテーブル、またはカラムはいまだに JSDocもなく、SchemaSpyのコメントとしても反映できていない

    • GithubActionsでPR時にEntityファイルにJSDocの記載があるか チェックする機能を導⼊ • モジュールごとにコメントの記載率を可視化 ⽬指せ、JSDoc記載率100%🔥
  28. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 今回の学びと今後の展望 35
 今回の実装でTypeScript Compiler

    APIを使用すれば、ts ファイルを解析処理が容易にできることがわかった ライブラリの変更やアップデートで多くファイルの表記を変更す る場合などに応用できそうなのでやってみたい🔥 今回の学び 今後の展望
  29. CONFIDENTIAL
 © 2023 Reiwa Travel, Inc.
 まとめ 36
 SchemaSpyを使⽤してエンジニア以外のメンバーにもDBの情報を公開していた ソースコードとテーブル定義ドキュメントが別ファイルとして管理しているため、

    反映作業がエンジニアの負担になっていた • コメント定義⽤のmdファイルを作成 →ソースファイルにJSDocでコメントを追加 • ソースファイルをTypeScript Compiler APIで解析し、XMLファイルを作成 ソースファイルにJSDocでコメントを書けるようになることで エンジニアがコメントを反映する負担が減るだけでなく、書くメリットが⽣まれた 問題 実装 結果