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

インターフェースのラッパーを作る際の落とし穴 / Go Conference mini 2023

mazrean
November 30, 2023

インターフェースのラッパーを作る際の落とし穴 / Go Conference mini 2023

外部ライブラリで提供されているインターフェイスをラップする際にembedded fieldが使われます。
しかし、このようにして作られたラッパーでは型アサーションの結果が変化することがあります(例: https://go.dev/play/p/slMbwUjpiHn)。
Go言語ではライブラリの後方互換性を維持するために型アサーションを使用して機能拡張を行うことがあります。
このため、型アサーション結果の変化は予期しない挙動の原因となります。
例えば、HTTPサーバーなどで利用されるインターフェースのhttp.ResponseWriterではhttp.Flusherを実装している場合のみバッファリングされたデータのフラッシュが可能になります。
このため、型アサーション結果の変化により、フラッシュの挙動に依存したServer Sent Events実装が機能しなくなるなどの危険性があります。
本セッションでは、ラップ前の実装メソッドを基に動的にラッパー構造体を構成することでこの問題を解決する手法と、それを容易に行えるようにする自作ツールiwrapperの紹介をします。

mazrean

November 30, 2023
Tweet

More Decks by mazrean

Other Decks in Programming

Transcript

  1. インターフェースのラッパーを
    作る際の落とし⽳
    Go Conference mini 2023
    @mazrean

    View full-size slide

  2. mazrean
    2
    n東工大 修士1年
    ltraP所属
    nツール作るのが趣味
    lISUCON13でツール作って負けた…
    https://trap.jp/post/2046/

    View full-size slide

  3. Q. http.ResponseWriterで
    レスポンスサイズを計測するには?
    3

    View full-size slide

  4. A. embeddingを使う
    nResponseWriterにサイズを取り出す機能はない
    → ラップが必要
    nインターフェースのメソッドを全て引き継ぐ
    → 同じ挙動に!
    4

    View full-size slide

  5. 本当に?

    View full-size slide

  6. 型アサーションの挙動が変わる
    6
    nインターフェースに含まれないメソッドは消える
    nこのようなメソッドは多くある
    l後方互換性を保って拡張できるため
    lex) http.Flusher, http.Hijacker, etc

    View full-size slide

  7. 例) Server Sent Events
    7
    ラップすると型アサーションに失敗する
    → うまく動かなくなる!

    View full-size slide

  8. 解決策
    8
    オプショナルなメソッドも実装しましょう

    View full-size slide

  9. とはならない

    View full-size slide

  10. Flusherがない場合
    11
    nFlusherがなかった場合、panic
    nライブラリの場合、問題
    l過去バージョンでも使われることがあるため

    View full-size slide

  11. 解決策: 動的に構造体構築
    12
    nラップ前にhttp.Flusherが実装されているか確認
    n結果に応じてもう一段ラップ

    View full-size slide

  12. 解決策: 動的に構造体構築
    13
    nラップ前にhttp.Flusherが実装されているか確認
    n結果に応じてもう一段ラップ

    View full-size slide

  13. いいえ、まだです

    View full-size slide

  14. ケースは2!個
    16
    n他にも考慮すべきインターフェースは色々
    lhttp.Hijacker,etc(計4個)
    l(database/sql/driver).Connに至っては8個
    n各インターフェースで実装有無判定
    → 2!ケース
    自動化しよう!

    View full-size slide

  15. ツール作った!
    17
    リポジトリ: https://github.com/mazrean/iwrapper
    動的な構造体構築をする関数を自動生成する

    View full-size slide

  16. 今度こそ完!
    注: 本当です

    View full-size slide