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

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

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

    • Thinreports Generator for Ruby - レイアウトからPDFを作る gem
  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
  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 リリース
  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
  7. 0.8 to 0.9 • レイアウトファイル (*.tlf) の内部構造を⼤幅に変更 • 互換性を壊す変更 •

    このときにどう対応したか • 以降、古い仕様を 0.8 ver、新しい仕様を 0.9 ver と呼称
  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": "<svg><g class=\"canvas\"><rect x- id=\"rect_id\" x=\"100.0\" y=\"100.0\" width=\"200\" height=\"200\"/>...</ g></svg>" 15: }
  9. Ploblems for 0.8 ver • 変更箇所の Diff が全くわからない • Editor

    の実装に強く依存していて、仕様変更が困難 • 構造や属性の仕様がわかり⾟いし、扱いにくい - サードパーティにも広がらない
  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, :
  11. ⽅針: 後⽅互換を保つ • 0.8 ver の tlf は Generator v0.9

    でもそのまま利⽤できる • 0.8 ver の tlf は Editor v0.9 でも編集でき保存できる - 保存すると 0.9 ver の tlf になる
  12. Generator v0.9 • 0.9 ver の tlf で PDF ⽣成できるように書き換える

    • tlf が 0.8 ver の場合は 0.9 ver に変換してから扱う - 0.8 ver to 0.9 ver にコンバートするクラスを追加
  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: :
  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
  15. Design • 0.8 ver に関する知識と責務を集約 • 0.8 ver の tlf

    に関するコードを排除 - 条件分岐は最⼩限にしたい • 考えることを増やさない - 以降の実装がやりやすい • テスト書きやすい
  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
  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: :
  18. Future of Thinreports • Custom Font (WIP) - 任意のフォントが使えるようになる -

    だいたいできてる - https://github.com/thinreports/thinreports/issues/5 • Section Report (WIP) - 新しいレポート形式 - より柔軟に動的なレイアウトが作れるようになる - https://github.com/thinreports/thinreports/issues/7
  19. end