ぶうううん's Cafe

どうにかこうにか。備忘録に近い。

fetchとaxios

 フロントエンドからバックエンドAPIにアクセスする方法はいくつか存在する。今回はReactに限った話ではないが、代表的な手法であるfetchとaxiosについてまとめておく。

共通な部分

  • 非同期通信を可能にする。
  • Ajaxの実装である。
  • Promiseを返却する。

fetch

メリット・デメリット

  • コードが長くなりがち。
  • レスポンスが HTTP 404 や 500 を返す HTTP エラーステータスの場合でも拒否されない。拒否されるのは、ネットワーク障害の場合や何かがリクエストの完了を妨げた場合のみ。
    • fetch() が成功したかどうかを正確に判定するには、プロミスが解決された後でResponse.ok プロパティが true になっているかを確認する。

その他

  • javascriptの標準API
  • fetchは init オプションで資格情報を設定しない限り、オリジンをまたぐクッキーを送信しない。
  • Fetch Requestは受け取るリソースからの指示ではなく、CSPの connect-src ディレクティブによって制御される。
  • 認証情報付きRequestを送るようにするには、credentials: 'include' を init オブジェクトに追加して fetch() メソッドに渡す。

axios

メリット・デメリット

  • npmなどでinstallとimportが必要。
  • 各種http request methodに対応したメソッドが存在する。

まとめ

  • 個人的にはfetchよりはaxiosが直感的だと思う。
  • axiosをimportできる場合は使ったほうが楽。

References

Reactの仮想DOMについて調べてみた。

仮想DOM(VDOM)とは

 メモリ上に保持された仮想なUIが、ReactDOMなどのライブラリによって実際のDOMと同期されるプログラミング上の概念である。仮想DOMの場合、実際のDOMはメモリ上に保持された仮想なUIとの差分を基に更新が行われる(差分検出処理)。
 仮想DOMがあることにより、宣言的APIが可能になる。仮想DOMは特定の技術ではない。私がこれまで持っていた仮想DOMのイメージは、「メモリ上に保持された仮想なUI(DOM)そのもの」であったが、これは少し間違いである。

差分検出処理について

 DOMツリーの差分検出において、全てのDOMの比較を行ってしまっては必然的に計算量が膨大となる。そこで、Reactは次の2つの仮定に基づき、O(n)程度のアルゴリズムでの差分検出を行っている。

  1. 異なる型の2要素は異なるDOMツリーを生成する。
  2. 開発者はkeyプロパティを与えることで、異なるレンダー間でどの子要素が変化しない可能性があるのかについてヒントを出すことができる。

 上記の仮定に合致しない場合、パフォーマンスの低下につながる。(ほとんどの場合合致するので、心配する必要はない。)

  1. よく似た出力を行う2つのコンポーネントの型を入れ替えている場合、同じ型にしたほうが良い。(現実的にこれが問題になったことはないらしい。)
  2. 不安定なkey(例えば乱数を用いたkey)はコンポーネントインスタンスとDOMノードを不必要に再生成させる。

References

Remote Containersを導入してVSCodeでのコンテナ開発を快適にする。

VSCodeでのコンテナ開発を快適にする

VSCode拡張機能のRemote Containersを導入。Remote Containersを導入するとVSCodeからDockerのコンテナに接続ができ、VSCodeを用いたコンテナ開発が行い易くなる。

https://code.visualstudio.com/assets/docs/remote/containers/architecture-containers.png

https://code.visualstudio.com/assets/docs/remote/containers/architecture-containers.png より

.devcontainer/とは

VSCodeでRemote Containerを利用してDockerfileかdocker-compose.ymlが存在するディレクトリを開くと、自動的に作成されるディレクトリである。.devcontainer/の中にはdevcontainer.jsonとdocker-compose.ymlが作成される。devcontainer.jsonの"dockerComposeFile"を設定することで、自動的に作成されるdocker-compose.ymlは利用せずとも良い。

導入後の注意点

  • 一度.devcontainer/が作成されたコンテナはDocker DesktopのDashboardから起動できないことがある。
  • FileNotFoundErrorが原因だが、見当たらない'./docker-compose.devcontainer.containerFeatures-{timestamp}.yml'を利用した覚えはない。
  • devcontainer.jsonにfeaturesの設定を追記しても、Dashboardからは起動ができなかった。

References

RESTful APIについて

RESTful APIの前提知識を盛大に勘違いしていたので、戒めとして書いておきます。

RESTとは

  • アーキテクチャ上の成約の集合である。
  • RESTで情報をやり取りする際はHTTP上で、以下の形式で送受信を行う。
  • RESTfulでは、以下の内容を満たす必要がある。
    • クライアント、サーバ、リソースからなるクライアント/サーバアーキテクチャである。
    • ステートレスなクライアント/サーバ通信。セッション状態に関する情報はサーバではなくクライアントが保持する。HTTPはステートレスなのでRESTfulと相性が良い。
    • キャッシュ可能なデータである。
    • 以下の要件を満たす、コンポーネント間で統一されたインタフェースである。
      • 要求されるリソースは識別可能であり、クライアントに返却される表現とは切り離されている。
      • クライアントが受け取る表現には操作に十分な情報が含まれており、クライアントはその表現を用いてリソースを操作可能である。
      • サーバからのレスポンスには、クライアントがレスポンスを処理するために必要十分な情報が含まれている。
      • ハイパーテキスト/ハイパーメディアが利用可能である。
    • 要求された情報の取得に関係するWAFやロードバランサなどのサーバを、クライアントからは参照できないようにする階層化システムである。
    • 実行可能コードを要求されたときに、サーバからクライアントにコードを送信するコードオンデマンド機能が利用できる。(これに関しては任意である)

私の勘違いと正しいAPIエンドポイント設計

  • APIエンドポイントについて、HTTPリクエストメソッドそれぞれに対応して、1つ1つエンドポイントを作成するものだと思っていた。つまり、HTTP GETリクエストに対応するAPIエンドポイント、HTTP POSTリクエストに対応するAPIエンドポイントといった形で分けて作成し、以下のように HTTPリクエストメソッドとAPIエンドポイントは1対1で対応するものだと思っていた。
    • https://hogehoge.com/users_get
    • https://hogehoge.com/users_create
    • ...
  • APIエンドポイントはCRUD単位などでまとめて作成するものであり、応答するAPIエンドポイントをHTTPリクエストメソッドごとにそれぞれ分けて作成すべきではない。
  • サーバが処理すべき内容はHTTPリクエストメソッドで判別すべきである。
  • 本来は次のように、 HTTPリクエストメソッドとAPIエンドポイントの関係は多対1である。
    • https://hogehoge.com/users
    • https://hogehoge.com/users/012345...

References

パスパラメータ・クエリストリング・リクエストボディの使い分け

フロントからバックに値を渡すときの手段

 フロントエンドからバックエンドに値を渡すとき、以下のような方法が存在する。

  • パスパラメータ

  • クエリストリング

  • リクエストボディ

本記事ではこれら3つの説明とその使い分けについて記述する。


パスパラメータ

 パスパラメータでは次のようにURIのパス指定で値を渡す。{...}の部分がパスパラメータである。
https://hogehoge.com/category/{category_name}/...

次の例はcategory_nameとしてfoodsかdrinksを指定している。

https://hogehoge.com/category/foods/...
https://hogehoge.com/category/drinks/...

パスパラメータは表示のベースとなるWebページそのものを指定することに使われる。上記の例であれば、foodsカテゴリ・drinksカテゴリなど、商品検索のベースとなるカテゴリを指定できる。


クエリストリング

 クエリストリングではURIの後方で?name=といった形で指定する。次の例は検索ワードとしてラーメンを指定する例である。
https://hogehoge.com/category/foods/?word=ラーメン

 また、クエリストリングは次のように連続して記述ができ、複数渡すことができる。 https://hogehoge.com/category/foods/?word=ラーメン&order=desc

クエリストリングはWebページのオプションを指定する場合に使われる。上記の例であれば、foodsカテゴリのWebページにてラーメンを検索し、検索結果を降順で表示する。


リクエストボディ

 リクエストボディではHTTP Requestのボディ内でパラメータを指定する。指定する際にはJSON形式などを用いる。次の例は、商品レビューを追加する例である。

POST /hoge/ HTTP/1.1
Host: hogehoge.com
Connection: keep-alive
...

{
  "review_id": 12345,
  "title": "おすすめ"
  "detail: "この商品は..."
}

リクエストボディは複雑なパラメータを渡すことができる。そのため、新規に内容を作成する場合や、既存の内容を更新する場合などに使われる。


まとめ

  • フロントエンドからバックエンドに値を渡す代表的手法として、パスパラメータ・クエリストリング・リクエストボディが存在する。
  • 表示のベースとなるWebページを指定するにはパスパラメータを使用する。
  • Webページでオプションを指定する際にはクエリストリングを使用する。GETメソッドがこれにあたる。
  • 内容の作成や更新を行う際はリクエストボディを使用する。POST、PUT、PATCHメソッドがこれにあたる。

References

RSpecについて調べてみた。

RSpecとは

  • テストフレームワークの1つ。
  • rspec-railsRails用。
  • Gemでインストールできる。
  • specによって、テストの対象がそれぞれ違う。
  • 統合テスト用にsystem specとrequest specがある。

github.com


Unitテスト

model spec

  • モデルをテストする。RailsにおいてはActive Recordをテストする?。
  • 以下のようなものをテストする。
  • 最低限、以下のようなテストを含める。
    • 有効な属性で初期化された場合は、モデルの状態が有効(valid)になっていること。
    • バリデーションを失敗させるデータであれば、モデルの状態が有効になっていないこと。
    • クラスメソッドとインスタンスメソッドが期待通りに動作すること。
  • 以下のようなベストプラクティスがある。
    • 期待する結果をまとめて記述(describe)している。
    • example( it で始まる1行)一つにつき、結果を一つだけ期待している。こうすれば、exampleが失敗したときに問題が起きたバリデーションを特定できる。
    • どのexampleも明示的である。itのあとに続く説明用の文字列は必須ではないが、省略してしまうとspecが読みにくくなる。
    • 各exampleの説明は動詞で始まっている。

controller spec


request spec

  • request specは統合テストの軽量なラッパーである。
  • JSONを返却するだけのAPIなど、リッチなUIを必要としないものが対象のテストならばsystem specではなくこっち。
  • 以下のことができる。
    • 単一のリクエストを指定する。
    • 複数のコントローラー間で複数の要求を指定する。
    • 複数のセッションにわたって複数のリクエストを指定する。

system spec

  • system specはRails独自のシステムテストのラッパーである。
  • E2Eテストの1つ。
  • Viewを含めてテストしたいならばrequest specではなくこっち。
  • 実際のブラウザもしくはヘッドレスブラウザでテストを実行できる。
  • 内部でCapybaraを利用する。CapybaraはDSLとドライバを提供するテストサポート用ライブラリである。
    • DSL経由でのTest::UnitやRSpecの利用を可能にする。
    • ドライバを通してWebKitSeleniumの利用を可能にする。

TDDとBDDの関係

TDD

TDDは以下の順序で進む。
1. プロダクトコードを書く前にテストコードを書き、それが失敗することを確認する (レッド)。
2. テストに成功するようにプロダクトコードを書く (グリーン)。
3. プログラムの振る舞いを変えないように、プロダクトコードの重複などを整理する (リファクタリング)。
4. (最初に戻る)。

重要なのは、テストが失敗するまでプロダクトコードを書いてはいけないということ。レッドの段階で、プロダクトコードに関係なくテストコードが常に通らないということを確認する。これはつまり、テストコードが確実であることを担保することを意味する。

BDD

  • BDD (Behaviour Domain Development)
  • BDDはTDDの派生と言える。
  • BDDはUI駆動テストに広く使われている。
  • 実行可能なサンプル(example)・・・テストメソッド(テストケース)のこと。
  • 振舞(behaviour)・・・テストクラス(テストケースの集まり)のこと。
  • エクスペクテーション(expectation)・・・アサート(コードの検証)のこと。

Factorybot

  • Rspec標準で使える"fixture"に代わり、テストデータの準備をサポートするライブラリ。
  • "factory_bot_rails"はRails向けの拡張版Factorybot。

自動テストで目指すべき状態

  • 前提として、正常系と異常系それぞれの利用ケースが明確に定義されている必要がある。
  • 自動テストでまず目指すべき状態は、想定される正常系の利用ケースが通ることを網羅することである。
  • もちろん異常系の利用ケースもきちんと弾く必要はある。
  • 自動テストでは可能な限り有効なテストケースを網羅し、テストに必要な時間を削減する。
  • 手動テストは必要に応じて使用するべきである。

References

ありがとうべーちゃん

最近のべーちゃん

 今朝起きると、我が家で一番長く飼っている熱帯魚のべーちゃんが亡くなっていました。べーちゃんは夏前ぐらいから腹水の症状が出ておりました。薬浴もしてみたのですが効果がなく、べーちゃん自体は元気に動き回っていました。ただ、8月後半くらいから動かずじっとしている時間が徐々に増えてきており、最近はおやすみリーフの上で休んでいることがほとんどでした。今週に入って急激に体調が悪くなっているように見え、薬浴は体力も消耗しますし希望は薄いですがグリーンFゴールドで薬浴させておりました。それでも息をするのがやっとという感じでした。

癒やしのべーちゃん

 べーちゃんは昨年の8月10日から飼い始めたベタのスーパーデルタテールです。熱帯魚屋で売られていた時から売り場の他のベタよりも大きく、額に傷っぽいものがあったので売れ残っていたのかもしれません。約1年と1月を我が家で過ごしてくれました。ヒレを優雅に広げてひらひらと泳ぐ姿は、新型コロナウィルスの影響で家族と会えなくなった私を何度も癒やしてくれました。私が水槽に近づくと餌が欲しいと動き回るような愛嬌のある子でもありました。いままでありがとうべーちゃん。