プログラマーの雑レポート

脳死で読めるコードを書きたい

Swagger(rswag)を導入した話

勤めている会社にAPIドキュメントがなく、バックエンドはPostmanとかでAPI通信確認してたんだけど、クライアントも容易に確認できた方がいいよねっていうことで、Swagger(OpenAPI)を導入したので、そのお話。(具体的な導入手順は省くよ)

本題

方法としては、主に4つあるかなと考えていて、結果的に4を採用することにした。

  1. yamlを直接書く
  2. controllerに書く
  3. RSpecから自動で生成する(rspec-openapi)
  4. RSpecから自動で生成する(rswag)

1 yamlを直接書く

導入は容易なんだけど、一から手書きするのはしんどいなと言うことで、これは最終手段かなと思っていた。

2 controllerに書く

具体的には、 swagger_blocks gemとかで、そもそも最終更新が数年前なので、微妙だなぁと思ったのと、既存システムのcontrollerを書き換えるのは、結構大変そうだな。と言うことでやめた。

GitHub - fotinakis/swagger-blocks: Define and serve live-updating Swagger JSON for Ruby apps.

3 RSpecから自動で生成する(rspec-openapi)

既存specでも自動でyamlを生成できるやつで、これは運用もしやすそうだなと思ったんだけど、既存specのカバレッジ(どのくらい網羅できてるか)によってドキュメントの質が大きく変わってしまうのと、ちょっと挙動が特殊だったりするので、やめた。

挙動については、↓あたり

RailsでOpenAPI(Swagger)を生成したくてrspec-openapiにPRを立てた話 - スタディスト Tech Blog

でも、結構導入している企業多いなという印象なのでこれでも良さそうとは思ってた。

4 RSpecから自動で生成する(rswag)

GitHub - rswag/rswag: Seamlessly adds a Swagger to Rails-based API's

RSpecから自動生成できるという点では3と同じだけど、これは特殊な書き方をしないといけなくて、そのspecのみが生成対象となる。

これは専用の書き方に書き換えたspecのみが生成対象となるため、正しくドキュメント化したいAPIを少しずつ対応することができるので導入しやすいと思った。

ただ、ちょっと書き方に癖があるので、慣れるまでは実装工数がかかりそうだなと思ったんだけど、実際には既にあるspecをコピってきて、ちょっと書き換える。とかでいけるのでそこまでの問題ではなかった。

今後の課題として、レスポンススキーマの生成はどうにかしたいなと思ってる。

components も便利なんだけど、それすら書くのが面倒だし、実際のスキーマと異なる可能性があるので、実際のAPIレスポンスクラスを基に、rswagのレスポンススキーマが生成できるように変換する処理みたいなのを入れたいと思ってる。

おわり

最初から導入することが決まっているなら、2とかもありだと思うけど、後入れなら、3,4かなと思ってる。

正直自分は、Postmanで使っていたのでそこまで恩恵ないかもなんだけど、これで全体の開発スピードが上がったら嬉しいですね!

連続投稿5日目!yoshi!

参考になった記事

scrapbox.io

初めてのクソゲーができました

これを見ながらクソゲーができました。

感想

たのしいけど、むずい!

初めてC# 触ったけど個人的にはそこまで癖強めとは感じなかった。

クライアントはバックエンドと違って状態管理みたいなのしなきゃ行けないから難しい。

あと、実装時のUnity上で操作するのとスクリプトファイルを書くのとで二つあるので、むずい。なんか新鮮だったけど。

スクリプト作って、アタッチしてーみたいな。

何もしていないのに、なんか新規差分とか出ているのがちょっと気持ち悪い。。(自分だけ?。 gitignoreすべきところしていないとかかも)

終わりに

ほぼパクリで作ったけど、結構楽しかったので、ブラッシュアップしたり、新しいゲームとかも挑戦してみたいなと思います!

途中死んでるけど、ボスも一応作った

API レスポンスサイズが大きい時の対策(JSON)

実装していたAPIのレスポンスサイズが大きい時、考えていた対策案のメモ

1. 不要なデータを返していないか。

まずは、不要なデータを返していないか、見直す。

モデルの全カラムとか無駄に渡しちゃっていないか、既存処理を脳死で複製していないか。とか

2. ネスト(階層)を浅くする

そこまで効果があるのかは謎。

ただ、利便性は下がりそう。

3. ページネーション

1ページあたりのデータ件数を減らす。

4. 圧縮する

それでも、大きい場合は、圧縮かな

終わり

毎日投稿頑張ってみようかなということで、小ネタでも投稿していこうかと思います。

【お題】本は控えめに言って最高

ざっくりジャンルごとにスクショしてみた。

お題「我が家の本棚」

プログラミング/IT

人生/投資

「DIE WITH ZERO」と「限りある時間の使い方」はおすすめ

仕事/働き方

デンマーク人…はおすすめ

英語学習

おわり

ほかにも読んだ本はあるけど、メルカリとかでかなり売っちゃったから、意外と少なかった。

本は本当に素晴らしいものだと思う。

今後もどんどん読んでいきたい!

のと、お気に入りの本をどんどん増やしていきたい(収集癖)

Goって何がいいの?

Gopher(ゴーファー)くんっていうらしいよ

先日こんなツイートをしたんだけど、型を型を書く事になったとしてどんなメリットがGoにはあるの?とふと疑問に思ったので、調べてみる事に。

1. 処理速度が速い

プログラミングの実行には、「インタプリタ」と「コンパイル(ラ?)」の2種類があって、インタプリタ(Ruby, Pythonなど)は、コード1行ずつ翻訳→実行をするのに対し、コンパイル(Java, Go)は、全て翻訳してから実行する。という違いがあって、

なので、コンパイル方式のほうが効率がよくて、速いというわけらしい。

そう考えるとRubyってめっちゃ非効率の人みたいじゃん。。

2. 統一性のあるコードになりやすい

Goは、型指定やシンプルな構文であるため、開発者の癖のあるコードが生まれにくいよう。

これは良さそうだね。そこそこ人数がいるチームとかであれば、なおさら。

正直触ってみないとどこまで統一性があるかわからないけど、確かにRubyは癖が出やすいのかもしれないから、良さそうだね

3. エラーに気づきやすい

型を書くからね。

ただ、型を書く手間を考えると個人的には、メリットとしては弱いと思っている。(動的なRubyでもそこまで困ってない)

終わり

メリットを考えると、大規模サービス・チーム人数が多い・高速なやりとりを必要とするサービスとかだとGo(コンバイル言語)は向いてそう。

ただ、Ruby(Rails)のサービスを形にする速度はやはりピカイチな気がするので、MVP(必要最低限の機能を備えリリース)して、ユーザの反応見て運用していけそうであれば、Goとかにリプレイス(移行)していく。という流れが良さそう。

後もう一つのメリット忘れてた。

マスコットキャラクターがいるということ

ルビーちゃんとか作って

参考

GoとRubyの言語特性を理解して構築した“いいとこどり“アーキテクチャとは? - Findy Engineer Lab 【RubyとGoの将来性・平均年収・求人数を徹底比較】学ぶべきなのはどっち?|未経験からWebエンジニアへ RUNTEQ BLOG

(Rails)これはハマるよ find_by_sql

複雑なクエリを書きたい時、 SQLを直書きできる find_by_sqlメソッドを使うのだが、配列の引数を渡すケースがあったときに、その配列が空だと正常にデータを取得できなくなるよう。

例えば、こんな感じで、1みたいに配列に値があればうまく動作するのだが、2のように空だとうまくいかないっぽい。

# 1.
arg_user_ids = [1,2,3]
# 2. 
arg_user_ids = []

 query = (
      <<~SQL
        SELECT users.*
        FROM users
        INNER JOIN posts ON posts.user_id = users.id
        WHERE posts.user_id NOT IN (:exclude_post_user_ids)
      SQL
    )
    User.find_by_sql([query, { exclude_post_user_ids: arg_user_ids }])

だから、微妙なんだけど、分岐させてクエリを変える必要があるみたい?(別案知ってたら教えてほしい)

arg_user_ids = []

if arg_user_ids.blank?
 query = (
      <<~SQL
        SELECT users.*
        FROM users
        INNER JOIN posts ON posts.user_id = users.id
        -- ここ削除
      SQL
    )
else
 query = (
      <<~SQL
        SELECT users.*
        FROM users
        INNER JOIN posts ON posts.user_id = users.id
        WHERE posts.user_id NOT IN (:exclude_user_ids)
      SQL
    )
end

    User.find_by_sql([query, { exclude_post_user_ids: arg_user_ids }])

せめて、エラーか警告かほしいところ。。ではある。