車を例に考えるユニットテスト

さあ、車を作ることを想像してみてください。

まず、必要な部品を考えてみます。

  • エンジン
  • 車体
  • シャーシ
  • シャフト
  • タイヤ
  • などなど

はじめに、これらの部品の一つ一つを製造します。

そして、これらの部品を組み立てると、車が完成しました。

では、完成した車にのってドライブに行こうと、車に乗り込んでエンジンキーを回しました。

しかし、なにも起こりません。そう、エンジンが点かないのです。

さて、エンジンが点かない原因はどこにあるでしょうか。

車に使ったいずれかの部品が故障しているのか、もしくは、それぞれの部品を組み合わせた相性が悪かったのか。

組み立てる前に一つ一つの部品に不具合がないか確認をしてから組み立てておけば、少なくとも部品の故障ではないことが判明していました。

しかし、すでに組み立ててしまった後なので、原因の究明が困難になってしまいました。

車の製造に失敗してしまいました。

次から失敗しないために、まずは部品毎に検査を行い、不具合がなければ、部品を組み立てるようにします。

このように部品(モジュールやコンポーネント、プログラムではクラスやメソッドといった小さな単位)毎に行う検査(テスト)を単体テストユニットテスト)といいます。

ということで、次は部品毎に検査することを想像してみてください。

ここでは、タイヤの検査をします。

タイヤの検査をするためには、タイヤを回す機構(エンジンやシャフト等)が必要になります。

しかし、部品単位で検査したいので、ほかの部品と組み合わせて検査するのはNGです。

そこで、検査のためにタイヤを回す機構をモーターを使って作りました。

そのモーターによって、タイヤを回し検査を行います。

このようにある部品(モジュール)をテストするために必要なほかの部品(モジュール)を、検査(テスト)用のものに置き換えて検査(テスト)を行います。
プログラムでは、このようなテストに利用するモジュールの代わりをモックやスタブと呼びます。

ここでは、モックやスタブについての説明は割愛します。

また、部品を組み立てたあとの検査(テスト)のことを、プログラムにおいては結合テストとよび、各モジュールを組み合わせた時の動作をテストします。

※私は車の製造に携わったことはありません。

docker-compose down が遅い

f:id:utouto97:20210706233740j:plain

TL;DR CMD ["command", "param1", "param2"]の形式で記述する
execコマンドを使う

Dockerコンテナの終了が遅い

docker-compose downdocker stopしたときに、Dockerコンテナの終了が遅いことがあります。
(数秒の時間がかかることがあります。)
しかも、docker-compose ps で確認してみると、xxxxx exited with code 137となっており、SIGKILLにより終了しています。
docker-compose down が遅いと、作業にも支障がでますので、原因と解決策を調べてみました。

原因

docker stopでは、PID=1 のプロセスに対して SIGTERMが送信されます。
このことが主な原因となっています。

Dockerfileに記述するCMDは、コンテナ起動時に実行するコマンドを指定することができます。
この指定方法はいくつかありますが、

  1. CMD ["command", "param1", "param2"]
  2. CMD "command param1 param2"

のどちらかが多いのではないでしょうか。

このうち前者のCMD ["command", "param1", "param2"]は、execにより実行されています。
execコマンドでは、新規プロセスを生成して処理するのではなく、今のプロセスで処理します。
そのため、実行元のPIDを保持したまま処理が行われます。
CMD ["command", "param1", "param2"]の記述では、このexecコマンドによって実行されていることにより、PID=1として実行されていて、PID=1に対するSIGTERMを受け取ることができます。

一方で、後者のCMD "command param1 param2"は、sh -cにより実行されます。
sh -cで実行する場合は、新規プロセスが生成され、そのプロセスで実行されるため、PIDも実行元とは異なります。
そうなると、PID=1に対してSIGTERMが送られても、CMD "command param1 param2"により実行されているプロセスにはSIGTERMが送られません。

つまり、docker stopではPID=1のプロセスに対して、SIGTERMが送信されることが重要となっていて、それを踏まえてDockerfileやエントリーポイントを指定することで解決することができます。

解決策

原因はdocker stopではPID=1のプロセスに対して、SIGTERMが送信されるが、異なるPIDで実行してしまっていることでした。

そのため、解決するにはPID=1で実行すればよいということになります。

そこで、DockerfileにCMDを記述するときは、配列形式で記述するとよいです。

`CMD ["command", "param1", "param2"]`

また、エントリーポイントを指定していて、その中で複数コマンドを実行している場合もあると思います。
その場合は、コマンドの実行にexecコマンドを使うことで、PID=1として実行することができ、docker stopによって送信されるSIGTERMによる終了ができるようになります。

まとめ

CMD ["command", "param1", "param2"]の形式で記述する
execコマンドを使う

参考
docker stop | Docker Documentation
Dockerfile reference | Docker Documentation

Dockerコンテナをずっと起動しておく

f:id:utouto97:20210725220655j:plain

TL;DR
docker runでは-itオプションをつける
docker-composeではyamltty: truestdin_open: trueを書く

処理が終わるとDockerコンテナは終了

通常、dockerコンテナは起動したらそのまま終了してしまいます。
DockerfileにCMDを指定することで、コマンドを実行させることができますが、その指定されたコマンドが終了すると、やはりdockerコンテナは終了してしまいます。

しかし、dockerコンテナを起動したままにしておきたいときもあると思います。
例えば、コンテナ内に入ってコマンドを打ち込みたいとき、等があります。

そのようなときに、dockerコンテナを起動したままにしておく方法をまとめます。

Dockerコンテナを起動したままにするにはitオプション

Dockerコンテナを起動するとき、docker run コマンドを使用します。

$ docker run -d python:3.7 

このとき、-it オプションをつけると、コンテナは終了せずに、維持されます。
(もともとついてる-dオプションと合わせて-itd)

$ docker run -itd python:3.7 

この-itオプションとは、-iオプションと-tオプションの二つのことです。

-iオプション
-iオプションのiinteractiveiです。
コンテナとホストマシンの標準入力をつなぐオプションで、 これを指定することでホストマシンでの入力がコンテナに伝えられます。
つまり、このオプションを指定することで、ホストマシンからコンテナ内へコマンド等を入力できるようになります。

-tオプション
-tオプションのtttytです。
コンテナとホストマシンの標準出力をつなぐオプションで、 これを指定することでコンテナの出力がホストマシンに伝えられます。
つまり、このオプションを指定することで、コンテナの出力をホストマシンで確認できるようになります。

これらのオプションを指定することで、dockerコンテナは起動したままになります。

Docker Compose の場合は設定ファイルに書く

Dockerコンテナを管理するために、Docker Compose を利用しているケースもあると思います。
そのような場合に、dockerコンテナを起動したままにしておくのも簡単にできます。

Docker Compose では、docker run時に-itオプションをつける代わりに、docker-compose.yml ファイルに、tty: truestdin_open: true を書きます。
tty: truedocker run時の-tオプションにあたいするもので、 stdin_open: truedocker run時の-iオプションにあたいするものです。
つまり、Docker Composeを使う場合でも、指定方法が異なるだけで、やっていることは同じで、コンテナとホストマシンの標準入出力をつないでいます。

version: '3'
services:
  py:
    image: python:3.7
    tty: true
    stdin_open: true

まとめ

docker runでは-itオプションをつける
docker-composeではyamltty: truestdin_open: trueを書く

オープンソースでFirebaseの代替となる? 「Supabase」

f:id:utouto97:20220111022432p:plain

Friebase は Google のサービスですが、オープンソースで利用できる Supabase というサービスがあります。

TL;DR
Supabase使うと簡単にバックエンド構築可能
Postgres Database, Authentication, instant APIs, Realtime subscriptions, Storage が使える
Functions も近く実装予定
無料枠も結構ある!

Supabase とは

Supabase は、オープンソースのBaaSです。
メジャーな BaaS として Google の Firebase があります。
Supabase はオープンソースなサービスで Firebase を代替するものになるかもしれません。

公式HPのトップページには以下のように書かれています。

f:id:utouto97:20220111022842p:plain

Supabase を使うことで、簡単にバックエンドが開発できます。
使えるサービスは、Postgres Database, Authentication, instant APIs, Realtime subscriptions, Storage があります。
また、Serverless Functions もリリース予定のようです。

バックエンドを構築するうえで欠かせないデータベースや認証があります。

Supabase と Firebase との違いは?

Supabase と似たサービスで Google の Firebase があります。
では、Supabase と Firebase はどの辺に違いがあるのでしょうか。

まず、Supabase はオープンソースであるのに対し、Firebase は Google によって開発されています。

Supabase では、データベース、認証、インスタントAPI、リアルタイムサブスクリプション、ストレージがサービスとしてあります。
Firebase にも、それらに対応するサービスがあります。
例えば、データベースだと Firestore、認証なら Firebase Authentication、といった感じです。
さらに、Firebase には機械学習のサービスやホスティングのサービスもあります。

Supabase と Firebase では、サービス毎にも違いがあります。
データベースサービスを比較してみると、Supabase は RDB の一つである Postgres ですが、 Firebase は Firestore であり、これはドキュメント型の NoSQL です。
また、認証も対応しているSNSサービスなどが異なりますが、どちらも多くの認証方式に対応しています。

Supabase と Firebase はどちらも BaaS で、バックエンド構築に必須のサービスをどちらも提供していますが、多くの点で異なっています。

Supabase の料金プランは?無料枠はある?

Supabase には、三つの料金プランがあります。
Free, Pro, Pay as you go の三つです。

Free プラン

Free プランは無料枠です。
もちろん $0 (0円) です。

  • DB 500MBまで
  • Auth 10000ユーザーまで
  • Storage 1GBまで
  • など

Pro プラン

Proプランはベースとなるプランです。
1プロジェクトあたり月額 $25 です。

  • DB 8GBまで、自動バックアップ付き
  • Auth 100000ユーザーまで
  • Storage 100GBまで
  • Email サポート
  • など

Pay as you go プラン

Pay as you go プランはいわゆる従量課金プランです。
ただし、このプランはベースとなる Pro プラン + 従量課金といったイメージのプランで、Pro プランの範囲は1プロジェクトあたり月額 $25 で、超えた分は従量課金となります。

Firebase APIKey は公開してもいい?危なくない?

f:id:utouto97:20211223102910p:plain

TL;DR
Firebase の API Key は公開してもいい
何なら誰でも見れる場所に公開されている
ただし、権限の設定には注意(特に Firestore)

Firebase の API Key とは?

Firebase のサービスを利用するための API Key です。
一つ一つの Firebase プロジェクト毎にそれぞれ API Key が割り当てられています。

Firebaase Console でプロジェクト・アプリの作成を行うと生成されます。
プロジェクトの設定 → 全般 → マイアプリ の中で見つけることができます。
API Key とかプロジェクトIDとかいろいろ書かれています。

const firebaseConfig = {
  apiKey: "***************************",
  authDomain: "***************************",
  projectId: "*********",
  storageBucket: "***************************",
  messagingSenderId: "**********",
  appId: "***************************",
  measurementId: "*****"
};

この firebaseConfig に含まれる apiKeyappId 等は、クライアント側に埋め込んで利用するものです。
要はこのAPI Keyを通じて各アプリに対するクライアントの識別を行っています。
Firebase API は、このAPI Key を通じて、通信するアプリやデータベース、プロジェクト等を指定しているということになります。
このAPI Keyの情報には、認証情報は含まれていません。

Firebase の API Key は公開してもいいのか?公開すると危ないのか?

Firebase の API Key はソースコードに張り付けて利用するよう、ドキュメントには書かれています。
そうなると、クライアント利用者からそのAPI Key が見えてしまい、漏洩してしまうのではないかといった懸念があります。

Firebase の API Key は公開しても大丈夫?漏洩すると危険?といった心配がでてくることになります。

結論からいうと、Firebase の API Key は公開しても大丈夫なようです。
API Key が漏洩したからといって、認証情報が漏洩するとは限りません(設定次第では漏洩する可能性もあります)

Firebase の API Key はアプリやプロジェクト等の識別子であるだけであって、認証情報を含まないため公開しても大丈夫です。
つまり、API Key がわかったところで、どのアプリ・プロジェクトであるか、がわかるだけです。

Firebase Hosting を利用していると自動で公開されている

Firebase の API Key を公開してもいいということですが、Firebase Hosting を利用していると、次のパスで firebaseConfigが 公開されています。

公開ページのURL/__/firebase/init.js

(実際に、Firebase Hosting を使っているページに /__/firebase/init.jsを付けると、確認できます。)

Firestore 等の権限の設定には注意! 勝手にデータを操作される可能性がある

Firebase の API Key 自体は公開しても大丈夫です。

注意すべきは権限の設定です。

特に、Firestore 等のデータベースの設定を間違えると、保存している情報(個人情報も含むかもしれない)が漏洩する可能性があります。

例えば、Firestoreの権限の設定(ルール設定)で、テストモードを選んでいる場合は危険です。

f:id:utouto97:20220103235656p:plain

allow read, write の部分ですね。
このままだと、誰でも自由に読み書きができてしまいます。
そのため、権限の上手く設定する必要があります。

例えば、認証機能を追加していて、自分のデータのみを操作可能とする場合次のように設定すればよいです。
(内容取得と更新は本人のみ、作成は認証済みの人のみ)

match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }

ほかにも様々なルールも設定できます。
(かなり複雑なルール設定もできます)

ここでは、ルール設定についてはこれ以上触れませんので、詳細はググってください。

Firebase の API Key は公開してもいい

何なら誰でも見れる場所に公開されている
ただし、権限の設定には注意

半年ほど勉強してきて ~2021年 振り返り~

f:id:utouto97:20211231181833p:plain

約半年ほど学んできて

WEBの勉強を始めて半年以上が経ちました。
そこで一番考えたことは、「何をどの順で学べばいいか?」ということです。

私は独学で、本も買わずにネットの情報を拾いつつ手を動かして勉強をしてきました。
その第一歩の目標としては、バックエンドもフロントエンドも開発し、AWS等にデプロイし、動くものを作ることでした。
そこで、さっそく取り掛かろうと思うのですが、いきなり迷いがありました。
使う言語とフレームワークの選択肢が多すぎて、何を選んでいいのかわからない、ということです。
結局のところ、自分が使ったことある言語、または、自分が使ったことある言語に似ている言語を使うことにきめ、 フレームワークはその言語の中でもっともメジャーそうなものを選びました。
また、技術の幅も非常に広く、一つを学べば次に学ぶことが三つ増えるような状態で、学べば学ぶほど次に学びたいことが急増していきます。

試行錯誤は結構いい

使う言語、フレームワーク、学ぶ技術、などなど学んでいく上で選択肢が多すぎて迷うことがたくさんあります。
そんな中で、私は自分の使いたいもの、学びたいものをとりあえず学んだり触ったりしていきました。
そのため、それがベストではなかったこともあるし、遠回りになったこともあります。
しかし、周辺知識が広がったり、わからないところを深く調べることで詳しくなったりと遠回りしたデメリット以上のメリットがありました。
もちろん、時間に制限があり、呑気に学ぶ時間が取れないという人もいるでしょうが、時間がわりと多くある自分にとっては試行錯誤でいろんなことに手を出してみるというのは結構よかったです。

道筋を示してくれるもの

試行錯誤を繰り返し、手探り状態で新しいことを始めるのも結構いいです。
が、やはり多くの時間を必要とするし、全然成長を感じれなくてやめてしまいたくなることもあると思います。
ですので、学んでいく道筋を示してくれるものをいくつか↓に書いておきます。

フロントエンドとバックエンドのロードマップ roadmap.sh roadmap.sh

ウェブエンジニアになる人向けのQiita記事 qiita.com qiita.com

何を選ぶかという点に関していうと、独学で自分で決めてると迷子になりがちなので、人の書いたものは結構参考になります。
一方で、学ぶもの・使うものが決まれば、その言語やフレームワークの公式ドキュメントがかなり整備されていることがほとんどで、その公式ドキュメントのチュートリアルがわかりやすいことが多いです。
ですので、公式ドキュメントを最初に見に行くのはおすすめです。

と、まあ振り返りを兼ねて綴ったのですが、やり方というのは人それぞれだと思うので、自分に合ったやり方を見つけましょう。

Firebaseのプランどれにする?

f:id:utouto97:20211223102910p:plain

TL; DR
何も考えず無料で使いたい + Cloud Functions は使わない → Spark (無料) プラン
きちんと管理する → Blaze (従量課金) プラン
Cloud Functions を使う → Blaze (従量課金) プラン

Firebase のプランは二つ

Firebase は Google が提供する BaaS です。
データベースやホスティング、認証などのサービスが提供されていて、これらを組み合わせてサービスを構築したり、自分で開発しているバックエンドに組み込んで利用することができます。
Firebase を利用することで、スピーディーにサービスを開発することができます。

utouto97.hatenablog.com

便利な Firebase ですが、基本的には従量課金制ですが、無料枠も設けられています。
Firebase のプランは、Spark (無料) プランと Blaze (従量課金) プランの二つです。

  • Spark (無料) プラン
    無料で利用できるプラン、Firebaseの無料枠ということになります。
    上限・制限がありますが、ほとんどのサービスを無料で利用できます。
    上限を超えると接続拒否になり、追加の料金は発生しません。
  • Blaze (従量課金) プラン
    従量課金プラン、こちらが一般のプランです。
    Spark (無料) プランの無料分も含みます。
    Spark (無料) プランの無料分を使い切ったあと、従量課金となります。

Firebase で Cloud Functions を使うなら、Blaze (従量課金) プラン

Firebase では、Spark (無料) プランでほとんどのサービスが利用できます。
しかし、いくつかのサービスは利用できません。

その中で最も利用する可能性が高いのは、Cloud Functions だと思われます。
Cloud Functions はスケジュールやイベントを起点として、プログラム等の処理を実行することができます。
これによりビジネスロジックを構築することができます。
AWS においての、AWS Lambda のようなものです。

そのような Cloud Functions は Spark (無料) プランでは利用できません。
そのため、Cloud Functions を利用したい場合は、Blaze (従量課金) プラン一択となります。

Spark (無料) プランには、Cloud Functions の無料枠はありませんが、 Blaze (従量課金) プランには、Cloud Functions の無料枠があります。

つまり、Blaze (従量課金) プランを選択することで、Cloud Functions を一定数無料で利用することができます。

f:id:utouto97:20211227110905p:plain

Firebase の Blaze (従量課金) プランは要注意 !

Firebase のプランの一つの Blaze (従量課金) プランには注意点が一つあります。
Blaze (従量課金) プランは、Spark (無料) プランの無料枠を含み、さらに Blaze (従量課金) プラン独自の無料枠もあります。
そして、これらの無料枠をすべて使いきったら、従量課金となります。
ただし、Blaze (従量課金) プランには、一日当たりの上限というものも設定されており、これを超えると料金が発生してしまう場合があります。
(トータルの使用量が無料枠ないでも料金発生する可能性があります。)

*Blaze プランの無料使用は日単位で計算されます。Cloud Functions、Firebase ML、電話認証、Test Lab では詳細が若干異なります。
詳細については、FAQ を参照するか、課金に関するドキュメントを確認してください。

qiita.com

Blaze (従量課金) プランは、日割りの上限があり、思わぬ料金発生の可能性があるのでご注意ください。

何も気にせず無料で使うなら Spark プラン Cloud Functions 使うなら Blaze プラン

まとめになりますが、Firebase のプランで迷ったら次のような基準で決めればいいと思います。

  1. Cloud Functions を利用する
    → Blaze (従量課金) プラン
    ∵ Spark (無料) プランでは、Cloud Functions 利用不可
  2. とりあえず無料で使いたい + Cloud Functions は不要
    → Spark (無料) プラン
    ∵ Spark (無料) プランは料金発生の心配がない
  3. 管理をきちんとしながら使う
    → Blaze (従量課金) プラン
    ∵ Spark (無料) プランの無料枠に加えて、Blaze (従量課金) プラン独自の無料枠もあるのでお得