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

後方互換の保ち方 / How to Maintain Compatibility

後方互換の保ち方 / How to Maintain Compatibility

松江Ruby会議09 セッション#4

Katsuya Hidaka

June 30, 2018
Tweet

More Decks by Katsuya Hidaka

Other Decks in Programming

Transcript

  1. 後⽅互換の保ち⽅
    松江Ruby会議09

    View Slide

  2. ⽇⾼ 克也
    @hidakatsuya
    Misoca松江オフィス勤務
    サーバサイド⽅⾯(主にRuby)

    Thinreports 開発者

    View Slide

  3. Thinreports
    • Ruby向けのPDF⽣成ツール
    • OSS
    • Thinreports Editor
    - レイアウトを作成するデスクトップアプリ
    • Thinreports Generator for Ruby
    - レイアウトからPDFを作る gem

    View Slide

  4. hello_world.tlf
    require 'thinreports'
    report = Thinreports::Report.new layout: ‘hello_world.tlf'
    report.start_new_page do |page|
    page.item(:world).value = 'World'
    end
    report.generate filename: ‘hello_world.pdf’
    PDF

    View Slide

  5. History
    • 2010年 0.6.0 プレビュー版リリース
    • 2011年 0.7.0 最初の安定版
    • 2012年 Fukuoka Ruby Award 2012 で⼤賞受賞
    • 2015年 0.8.0 リリース
    • 2015年 Thinreports for PHP がリリース
    • 2016年 0.9.0 リリース
    - レイアウトファイル (*.tlf) の仕様を⼤幅に変更
    • 2017年 0.10.0 リリース

    View Slide

  6. For PHP, Java, Go
    • https://github.com/thinreports-php/thinreports-php
    • https://bitbucket.org/symfo/thinreports-java
    • https://github.com/naofum/thinreports-java
    • https://github.com/renatosuero/thinreports-go

    View Slide

  7. 0.8 to 0.9
    • レイアウトファイル (*.tlf) の内部構造を⼤幅に変更
    • 互換性を壊す変更
    • このときにどう対応したか
    • 以降、古い仕様を 0.8 ver、新しい仕様を 0.9 ver と呼称

    View Slide

  8. 0.8 ver tlf
    1: {
    2: "version": "0.8.2",
    3: "config": {
    4: "title": "Report Title",
    5: "page": {
    6: "paper-type": "A4",
    7: "orientation": "landscape",
    8: "margin-top": 0.0,
    9: "margin-bottom": 0.0,
    10: "margin-left": 0.0,
    11: "margin-right": 0.0,
    12: }
    13: },
    14: "svg": "class=\"canvas\">id=\"rect_id\" x=\"100.0\" y=\"100.0\"
    width=\"200\" height=\"200\"/>...
    g>"
    15: }

    View Slide

  9. Ploblems for 0.8 ver
    • 変更箇所の Diff が全くわからない
    • Editor の実装に強く依存していて、仕様変更が困難
    • 構造や属性の仕様がわかり⾟いし、扱いにくい
    - サードパーティにも広がらない

    View Slide

  10. 0.9 version
    • すべてをJSONで表現
    • Editor の依存を排除
    • Diff も⼀⽬瞭然
    • ⼈間が読める
    • その後の開発が断然や
    りやすくなった
    {
    "version": "0.10.0",
    "items": [
    {
    "type": "text",
    "display": true,
    "x": 210.6,
    "y": 55,
    "width": 174,
    "height": 48,
    "style": {
    "font-family": ["IPAGothic"],
    "font-size": 24,
    "color": "#000000",
    "text-align": "center",
    "vertical-align": "middle",
    "font-style": []
    },
    "texts": ["ݟੵॻ"]
    },
    {
    "id": "recipient_name",
    "type": "text-block",
    "display": true,
    :

    View Slide

  11. ⽅針: 後⽅互換を保つ
    • 0.8 ver の tlf は Generator v0.9 でもそのまま利⽤できる
    • 0.8 ver の tlf は Editor v0.9 でも編集でき保存できる
    - 保存すると 0.9 ver の tlf になる

    View Slide

  12. Generator v0.9
    • 0.9 ver の tlf で PDF ⽣成できるように書き換える
    • tlf が 0.8 ver の場合は 0.9 ver に変換してから扱う
    - 0.8 ver to 0.9 ver にコンバートするクラスを追加

    View Slide

  13. Thinreports::Layout::

    LegacySchema
    1: def initialize(legacy_schema)
    2: @legacy_schema = legacy_schema
    3: :
    4: end
    5:
    6: def upgrade
    7: config = legacy_schema['config']
    8: page_config = config[‘page']
    9:
    10: {
    11: 'version' => legacy_schema['version'],
    12: 'title' => legacy_schema['config']['title'],
    13: 'report' => {
    14: 'paper-type' => page_config['paper-type'],
    15: 'width' => page_config['width'].to_f,
    16: 'height' => page_config['height'].to_f,
    17: :
    18: },
    19: 'items' => item_schemas
    20: }
    21: end

    22:
    23: private
    24: :

    View Slide

  14. Thinreports::Layout::Format
    1: def self.build(filename)
    2: schema = JSON.parse(read_file(filename))
    3: version = Layout::Version.new(schema['version'])
    4:
    5: unless version.compatible?
    6: raise Errors::IncompatibleLayoutFormat.new(
    7: filename, schema['version'],
    8: Layout::Version.compatible_rules.join(' and ')
    9: )
    10: end
    11:
    12: if version.legacy?
    13: warn ‘[DEPRECATION] ...’
    14: schema = Layout::LegacySchema.new(schema).upgrade
    15: end
    16:
    17: new schema #=> Thinreports::Layout::Format
    18: end

    View Slide

  15. Design
    • 0.8 ver に関する知識と責務を集約
    • 0.8 ver の tlf に関するコードを排除
    - 条件分岐は最⼩限にしたい
    • 考えることを増やさない
    - 以降の実装がやりやすい
    • テスト書きやすい

    View Slide

  16. thinreports-cli gem
    • Editor 0.9 で⼀個ずつ開いて保存して変換→⾟いとの声
    • 0.8 ver の tlf を 0.9 ver に変換できるコマンドを作った
    $ thinreports upgrade /path/to/0.8.tlf /path/to/0.9.tlf

    View Slide

  17. Reuse
    1: module Thinreports
    2: module Cli
    3: module Commands
    4: class Upgrade
    5: def initialize(source_path, destination_path)
    6: @source_path = Pathname.new(source_path)
    7: @destination_path = Pathname.new(destination_path)
    8: end
    9:
    10: def call
    11: source_schema = load_source_schema
    12: destination_path.write(upgrade_schema(source_schema), encoding: 'UTF-8')
    13: end
    14:
    15: private
    16:
    17: attr_reader :source_path, :destination_path
    18:
    19: def upgrade_schema(source_schema)
    20: upgraded_schema = Thinreports::Layout::LegacySchema.new(source_schema).upgrade
    21: JSON.pretty_generate(upgraded_schema)
    22: end
    23: :

    View Slide

  18. Future of Thinreports
    • Custom Font (WIP)
    - 任意のフォントが使えるようになる
    - だいたいできてる
    - https://github.com/thinreports/thinreports/issues/5
    • Section Report (WIP)
    - 新しいレポート形式
    - より柔軟に動的なレイアウトが作れるようになる
    - https://github.com/thinreports/thinreports/issues/7

    View Slide

  19. end

    View Slide