サンダーボルト

相手モンスターを全て破壊する。

Activity Log(2020年4月 第2週)

この記事は何?

技術に関する個人的な学びやアウトプットをまとめたもの。

インプット

Angular

アウトプット

ブログ

開発

  • 個人で作成中のWishesアプリの管理ツール(CLI)を実装してmasterブランチへマージした
    • もともと、Angular+Firebase Admin SDKでの実装を考えていたが、Firebase Admin SDKは信頼されたサーバー環境でしか動かないらしく(試してはない)、なのでNode.jsを使ってCLIツールを作成することにした。
    • 実装した機能としては以下の通り
      • ユーザーから報告されたセンシティブなコンテンツのレポートを閲覧する機能
      • センシティブなコンテンツにis_sensitiveフラグをたてる機能
      • 報告されたレポートを削除する機能
      • Cloud Functionsを起動するためのトリガーとなっているテーブルのデータを変更する機能(Cloud Functionsを定期実行したいが、それが無料プランでは無理そうなのでFirestoreのデータ変更をトリガーにして同様のことを行うため)

まとめ

  • 今週も先週に引き続きアウトプット多めになった。といっても、ブログを書いたり開発する上で様々なことはググっているので知識は着々と増えている実感はある。
  • そういう意味では「インプット」という言葉を再度定義した方がいいのかなぁ。今のところは公式ドキュメントとか、それなりにしっかりしたQiita等の記事をガッツリ理解したぞ!!っていうときのみメモしようと思っている。
  • 来週も引き続きアプリの開発をやることになりそう。もうちょっとAngularのインプットにも時間使わないとなぁ。

GraphQLでInt型引数にStringを渡しても動作するが、Bool型引数にString型を渡したらエラー

概要

Goで実装しているGraphQLサーバーがあって、そのQueryの引数にInt型とBool型を要求していて、それぞれ "1000" と "true" といった値を渡したときに、Intは正しく動いて、Boolは message: "cannot use string as Boolean" というエラーメッセージが返ってきた。

この違いは正しいのか?意図されている動きなのか?どこが原因なのか?を探った記事です。

環境

バージョン
Go 1.13.7
gqlgen 0.10.2

Intの引数にString型を与えてもうまく変換されていることの調査

gqlgenで生成されるgenerated.goから、ライブラリのソースコードをたどっていくとここへ行き着いた

github.com

UnmarshalInt関数の中で以下のように変換している。なるほど。

return strconv.Atoi(v)

意図してStringをIntに変換しているんですね。

BoolにString型を与えてもうまく動かないことの調査

エラーメッセージはmessage: "cannot use string as Boolean"だったのだが、まず気になったのはそもそも👆でintは変換しているので、boolでも同じようなメソッドがないかと思って調べてみた。そしたらあった!

github.com

return strings.ToLower(v) == "true", nil

ガッツリ変換してた笑

で、デバッグ止めようと思ってもここまでたどり着いてなかったんですよね。で、

github.com

このあたり👆にブレークポイント置いて調査してみたところ、、、見つけた!

github.com

gqlgenが依存している、gqlparserというライブラリの中でIntはStringを許可しているのに、BoolはStringを許可していませんでした。そして最初に見たエラーメッセージが生成されているのも確認できました。

この動作で正しいのだろうか?

と思ったので仕様書を見てみました。

Int

GraphQL

Input Coercion When expected as an input type, only integer input values are accepted. All other input values, including strings with numeric content, must raise a query error indicating an incorrect type. If the integer input value represents a value less than -231 or greater than or equal to 231, a query error should be raised.

Note: Numeric integer values larger than 32‐bit should either use String or a custom‐defined Scalar type, as not all platforms and transports support encoding integer numbers larger than 32‐bit.

数値を表す奴は数値型じゃないとエラーを出さなきゃダメ、Stringもエラー。 ・・・でも、全ての環境で32bit Intより大きい値を扱えるわけじゃないし、そういうデカい値扱うときは一旦Stringでも良い。

って感じでしょうか。なので、一旦Stringで受け取って、32bitより大きい値だったらエラーにする、という実装も許しているようです。

Bool

GraphQL

Input Coercion

When expected as an input type, only boolean input values are accepted. All other input values must raise a query error indicating an incorrect type.

Booleanしかダメ!という方針みたいです。

ということで、IntとBoolの動作の違いは仕様書通りの作りになっていると言えそうです。

なるほどなぁ〜

補足

  • 読む仕様書が違う
  • 読む部分が違う

とかあったら優しく教えていただけると幸いです🙇

Activity Log(2020年4月 第1週)

この記事は何?

技術に関する個人的な学びやアウトプットをまとめたもの。

インプット

特筆するものはなし。

アウトプット

ブログ

開発

  • FlutterのProvider, ChangeNotifier, StateNotifierあたりを勉強して、それらを使った最小構成サンプルを実装した

  • 個人で作成中のWishesアプリについて、ブロックしているユーザーのブロックを解除する機能を実装し、masterにマージした。

    • この機能の実装には、ProviderとStateNotifierを利用した。freezedは使っていないが、たしかにcopyWith等の便利メソッドが欲しくなってきたので導入を検討中
  • 同じくWishesアプリについて、管理画面がなく、ユーザー対応が面倒だったので管理画面の作成にとりかかり、とりあえずAngularMaterialを使って画面を表示するまで。
    • とりあえず素早くやりたかったのでAngular + Firebase Admin SDKを利用することにした。セキュリティ等も面倒なのでローカルPCで起動して利用する予定。

まとめ

  • 先週はインプット多めでアウトプット少なめだったが、真逆の内容になった。
  • 来週ももう作るものが決まっているのでインプット少なめでアウトプット多めになりそうな予感。

deep-equalを使うとエラー:Uncaught ReferenceError: global is not defined

概要

Angularで開発しているときに、オブジェクトの中身まで比較して等価かどうかを判定したくなり、調べると以下が出てきた。

typescript-jp.gitbook.io

これによれば、

このようなチェックを行うには、deep-equal npmパッケージを使用します。

とのことだったので、npm i deep-equal して利用してみたところ見事に Uncaught ReferenceError: global is not defined エラーが出たのでその調査と解決の記事。

環境

ライブラリ バージョン
@angular/core 9.0.6
deep-equal 2.0.1

エラー詳細

ログは以下の通り

index.js:3 Uncaught ReferenceError: global is not defined
    at Object../node_modules/has-symbols/index.js (index.js:3)
    at __webpack_require__ (bootstrap:79)
    at Object../node_modules/es-abstract/GetIntrinsic.js (GetIntrinsic.js:39)
    at __webpack_require__ (bootstrap:79)
    at Object../node_modules/es-abstract/helpers/callBind.js (callBind.js:5)
    at __webpack_require__ (bootstrap:79)
    at Object../node_modules/regexp.prototype.flags/index.js (index.js:4)
    at __webpack_require__ (bootstrap:79)
    at Object../node_modules/deep-equal/index.js (index.js:5)
    at __webpack_require__ (bootstrap:79)

エラーを吐いている has-symbols/index.js はこちら

github.com

var origSymbol = global.Symbol;

たしかに、globalを使おうとしてる。ログからもわかるんですが、deep-equalが依存しているようです。(npm ls has-symbols した結果👇)

f:id:nao_666:20200403120544p:plain
npm ls has-symbols

解決策

ググると、「とりあえず polyfills.tsに(window as any).global = window;って書けばOK😅」みたいなのが出てくるんですが、もう少しだけ、JS初心者向けに説明します。

まず、Uncaught ReferenceError: global is not defined と出てくるのはブラウザ上のJSエンジンにてglobalが無いということです。Chromeのconsoleでglobalと打てば同じエラーを再現できます。

f:id:nao_666:20200403120913p:plain
`global` をConsoleで実行した結果

で、どうしてこういうことが起きるかというと、has-symbolsというライブラリがNode.js環境にはあるglobalという変数が存在する前提で作られているが、ブラウザのJSエンジンにはglobalという変数が無いからなんですね。

で、そのglobalというものの実態はブラウザのグローバルオブジェクトである、windowと同じで良いらしい(ここきちんと調べてない😅)ので、それをglobalとして使えるように、window直下に配置してあげる必要がある、ということですね。

で、polyfills.tsはTypeScriptなので、

window.global = window;

ではglobalなんてフィールド無いぞ!ってエラーが出ますから、一旦anyにキャストしてあげて

(window as any).global = window;

ってのをpolyfills.tsに書けば良いという話ですね。

雑にConsoleで試すとこういうこと👇です。

f:id:nao_666:20200403122339p:plain

エラーが出なくなりました。

FlutterのProviderまわりについて整理したい

これは何?

Flutterでアプリを作っているのですが、今まで自分はsetState + StatefulWidgetしか使っていませんでした。で、色々調べたら今はProviderを使うのが良い感じらしいことが分かりました。

そして、Providerについて色々調べていると、

  • Provider
  • ChangeNotifier
  • ChangeNotifierProvider
  • StateNotifier
  • StateNotifierProvider

といった言葉が目に付きました。え、"Provider" だけでは状態管理は良い感じにならないの??Providerはライブラリ?クラス?単体としての役目は何??ってグチャグチャになってきたので一旦整理したいと思い書きました。

前提

バージョン

Flutter v1.12.13

言葉の整理

Provider

  • InheritedWidgetを便利に使えるようにwrapしたもの
  • 状態管理を特別いい感じに実装できるように作られたパッケージというわけではない
  • providerというパッケージがあり、その中にProviderというクラスが存在する

ChangeNotifier

  • 直訳すれば「変更を知らせる者」という通り、Listnerとかそこら辺の機能を持つクラス
  • Providerと組み合わせるといい感じに状態管理を実装できる
    • 「View」と「状態&ロジック」を切り離すことができる
  • これを利用するために外部ライブラリに依存する必要はない(Flutter内にある)

ChangeNotifierProvider

  • ChangeNotifierのために作られたProviderの一種(クラス)
  • providerパッケージの中に同梱されている

StateNotifier

StateNotifierProvider

  • StateNotifierのために作られたProviderの一種(抽象クラス)
  • こちらはproviderパッケージの中には入っておらず、flutter_state_notifierパッケージに入っている

まとめ

状態管理をいい感じにしたければ、ProviderとStateNotifier、そしてStateNotifierProviderを使っておけば良さそう。あとfreezedという奴もいるらしいがこれはまだ調べてない。

ChangeNotifierとStateNotifierを使った最小構成のサンプルを作ったのでよければ見てみてください。 こちらを見れば「View」と「状態&ロジック」になっているか、「View」と「状態」と「ロジック」と分かれているかがすぐわかると思います!

ChangeNotifierのサンプル

github.com

StateNotifierのサンプル

github.com

Activity Log(2020年3月 第4週)

この記事は何?

技術に関する個人的な学びやアウトプットをまとめたもの。 自分リリースノートなる取り組みに影響を受けているのである。

インプット

Flutter

npm

Angular

Linux

アウトプット

ブログ

開発物

  • 個人で作成中のWishesアプリの開発を再開し、ちょこっとソースを書き始めた
  • angular-cliをローカルでビルドしてそれを使ってng serveを実行できた
    • ngというファイルはVSCodeで実行してブレークポイントを止めることができた
    • しかし、まだビルドあたりのソースではブレークポイントは止められていない (angular devkitまわり?)
    • これをやる中でシバンやenvのトリック的用法を理解できた

まとめ

  • 久しぶりに個人アプリ(Wishes)の開発を再開した。それまでsetStateばかり使っていたのでprovider, state_notifier, freezedまわりを調査し始めた。
  • Angularをローカルでビルドしたangular-cliを使って ng serve したいという欲が出てきて、それをやっている内にシバン等を知れてよかった。
  • インプットばかりであまりソースコードを書けていないので次の週はたくさん書けるといいなぁ〜

FlutterでiOSまわりのビルドでつまったときの対応策

私はiOS弱者であるので、Podsのバージョンがグチャってなったり文法エラーが起きたり、ライブラリどうしで揉めてたらすごく困る。 なので、とりあえずどうすべきかをまとめておく。

その1

qiita.com

その2

XcodeからFlutterアプリを起動して、詳細なログを見る

その3

訳わかんなかったらとりあえずライブラリ全部最新にしちゃう

ほんとにPods嫌い...