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

LeanLanguage2019 リニューアル、こうして不具合は起こった

daponta
August 24, 2019

LeanLanguage2019 リニューアル、こうして不具合は起こった

daponta

August 24, 2019
Tweet

Other Decks in Programming

Transcript

  1. リニューアル、
    こうして不具合は起こった
    LearnLanguage2019
    @da_ponta

    View full-size slide

  2. 4/15に大規模な
    システムリニューアルをしました

    View full-size slide

  3. 前提 リニューアル箇所
    - DB、テーブル構造
    - サーバサイド
    - インフラ
    - アプリ
    - UI
    - フロントエンド
    - 不要な機能の削減
    ⇒ システムすべて

    View full-size slide

  4. 今回はリリース後に発覚した
    不具合事例を紹介します

    View full-size slide

  5. 技術関連の詳細はTechCon2019資料をどうぞ
    https://bit.ly/2Z5lnqn

    View full-size slide

  6. 自己紹介
    井田 祐太 @da_ponta
    所属:株式会社ディー・エヌ・エー
    担当サービスの開発全般を担当
    - Ruby
    - Kubernetes
    - Node.js
    - Android
    ろくろも回します

    View full-size slide

  7. リニューアルの不具合は
    えてしてデータで起こる

    View full-size slide

  8. 時間いっぱいまで紹介していきます
    - リレーション先がないデータ
    - 実はユニークではないカラム
    - nullは許容するが空文字は許容外のデータ
    - レコード化されていなかったデータ
    - ハッシュ化ロジックの継承
    - 大文字と小文字で一致しないメールアドレス
    - 整合性のあってないカウントカラム
    - 移行先のカラムの認識違いによる齟齬
    - リリース直後に壊れるライブラリ
    - SJIS問題
    まだまだあるよ★
    データの更新ができない
    表示に関する不整合
    暗号化・ハッシュ化の闇

    View full-size slide

  9. ① 移行データの更新ができない
    リニューアルにおけるデータにまつわる変更
    - テーブル構造・構成を変えた
    - カラムの方と制約を変えた
    - 一部マスター系のデータは削除ステータスを間引いて移行した
    - バリデーションロジックは強化した

    View full-size slide

  10. ① 移行データの更新ができない
    1-1 リレーション先が存在しない
    例えばコメント削除, 投稿先のtopicは存在しない
    class Comment < ApplicationRecord
    belongs_to :topic, foreign_key: :topic_id
    def remove!
    self.update!(deleted: true)
    end
    end
    > comment.remove!
    ActiveRecord::RecordInvalid: Validation failed: Topic must exist

    View full-size slide

  11. ① 移行データの更新ができない
    1-2 実はユニークではなかったカラム
    認証のメールアドレスは 重複登録できないという前後共通の仕様
    実際に移行してみると同一のアドレスが別々のユーザに登録されている
    ⇒ 結果想定と異なるログイン挙動に

    View full-size slide

  12. ① 移行データの更新ができない
    1-3 nullは許容するが空文字は許容外のデータ
    title未入力はnullであるはずが空文字で登録されているデータが存在する
    class Novel < ApplicationRecord
    validates :title, length: { in: 1..100 }, allow_nil: true
    end
    > novel.title
    => “”
    > novel.validate!
    ActiveRecord::RecordInvalid: Validation failed: Title is too short (minimum is 1 character)

    View full-size slide

  13. ① 移行データの更新ができない
    1-3-2 仕様の長さを超えていることもある
    リニューアル前後ともにタイトルは100m文字まで
    ⇒ 実際には数千文字のレコードは存在する
    ⇒ 「仕様」は信じてはいけない
    class Novel < ApplicationRecord
    validates :title, length: { in: 1..100 }, allow_nil: true
    end

    View full-size slide

  14. ① 移行データの更新ができない
    1-4 そもそもDBにレコードが存在しない
    初期のころHTMLのみで運用されていた機能のデータは移行していなかった
    例えば「運営からのお知らせ」

    View full-size slide

  15. ① 移行データの更新ができない
    なぜ気づかなかったのか?
    - 移行処理の高速化のためにデータ移行時にはバリデーションしていない
    - 太古のデータのみ発生する
    - 太古のデータの状況再現・検知は困難
    ⇒ 手動の検証では検知不可能
    データ移行のチェックうはサンプルではなく網羅的にやりましょう

    View full-size slide

  16. ② 暗号化・ハッシュ化の闇
    2 - 2 ハッシュ化ロジックの継承
    パスワードなどのハッシュ値は復号できないので
    ロジックを引き継がなければならない
    かつ、社内基準に則ったハッシュ化を施す必要がある
    この時点で辛い

    View full-size slide

  17. ログインフォーム

    旧ハッシュ化(弱)

    新ハッシュ化(強)

    旧パスワードと照合
    生パスワード

    新ハッシュ化(強)

    新パスワードレコードを登録

    View full-size slide

  18. ② 暗号化・ハッシュ化の闇
    2 - 1 ハッシュ化ロジックの継承
    特定のキーのときに旧ハッシュ化処理が PerlとRubyで一致しなかった
    ⇒Perlを呼び出すことに
    def self.legacy_hash(password, key)
    script_path = Rails.root.join("script", "perl", "hash.pl").to_s
    stdout, stderr, status = Open3.capture3("perl", script_path, password, key)
    stdout
    end

    View full-size slide

  19. ② 暗号化・ハッシュ化の闇
    2 - 1 大文字と小文字で一致しないメールアドレス
    入力されるアドレス: [email protected]
    移行前に登録されている: [email protected]
    当然ながら暗号化後の結果が異なるため認証は通らない
    ⇒ 全ユーザデータ修正へ
    User.find_each do |users|
    email = decrypt(user.email)
    email.downcase!
    user.update(email: encrypt(email))
    end

    View full-size slide

  20. ③ 表示に関する不整合
    3 - 1 整合性のあってないカウントカラム
    「小説の閲覧数」(以前から存在)と「閲覧した人一覧」(新規)が一致しない※
    だいたいモバゲー時代の名残
    ⇒ カウントデータ修正へ
    ※実際には小説の閲覧ではありません

    View full-size slide

  21. ③ 表示に関する不整合
    3 - 2 移行先のカラムの認識違いによる齟齬
    - レコードの更新日
    - 読者向けの作品最終更新日
    - 作家向けの最終保存日
    これらの元のデータがない・表示される想定の値ではなかった・入れ替わってしまった
    ⇒ 表示側で加工
    バックエンド・フロントエンド間の認識違い

    View full-size slide

  22. ④ ライブラリのバージョンが上がって壊れる
    小説のエディタ機能に Vueのtiptapというライブラリを使用
    → エディタ「ではない」ページのリリース
    → 突如iOSにてエディタが起動せず
    ⇒ 原因:tiptapの依存するライブラリの方でマイナーアップデート
    → バージョンをもどして解決かと思われたが …?
    → 全環境にて起動しなくなる
    ⇒ 原因:特定のエンジニアが生成した package-lock.jsonでnpm installすると壊れる
    バージョンの固定・管理は必須

    View full-size slide

  23. ⑤ SJIS問題
    5-1 URLのパスも変更になっているためリダイレクトする必要があった
    旧:/search?keyword=ファンタジー
    ⇒ /search?keyword=%83t%83%40%83%93%83%5E%83W%81%5B
    新:/novels?keyword=ファンタジー
    ⇒ /novels?keyword=%E3%83%95%E3%82%A1%E3%83%B3%E3%82%BF%E3%82%B8%E3%83%BC
    SJISでエンコードされたURLをリダイレクトしてもシステム側でデコードできない
    ⇒ 対応見送り…

    View full-size slide

  24. まとめ
    - DBまで変えるとまず間違いなく不整合は発生する
    ⇒コア機能については事前に同等のバリデーションをかけるべき
    - 暗号化ハッシュ化ロジックの置き換えには注意
    - 新旧の機能仕様・データ移行の実装・フロントの実装すべての認識のすり合わせは怠らず
    - できることなら全て一度にリニューアルしないことをおすすめします

    View full-size slide

  25. 次はあなたの番かもしれない

    View full-size slide

  26. ありがとうございました
    LearnLanguage2019
    @da_ponta

    View full-size slide