taiki-t's diary

きぎょうにっき, React Native, Rails そして雑多な記録: The world is waiting for you to give it a meaning.

Install Bulma to Rails 5.1

in terminal

yarn add bulma

in app/assets/stylesheets/application.scss

@import "bulma/bulma"

That's it. Restart the server as needed.

May apply to other css frameworks.

bulma.io

感情を自由に書き表せたらな。ときどき、そう思う。そういうスキルが無い者としては、ただただ、その「表したい何か」を抱えて画面をじっと見ておくことぐらいしかできないのだけれど。自分の表したい気持ちを自由に文章に表せられるなら、それはどんなに素晴らしいだろう。無駄に一人でモヤモヤを抱えたまま、数時間を過ごすということも無いのかもしれない。書いた文章に対面する。そこには自分の気持ちが書いてある、整理される、納得する。そんなふうに物事が進むのだろうか。いや、それはただの願望かもしれない。それができたらきっと世の中の創造物なんてものはもっと少ないんじゃないだろうか。でも、一時だけでも、心のしこりを取り出して眺めることができたら。その一時がほしい。

昔は、もっと楽だった気がする。怒りたいときに怒って、泣きたいときには、いや。泣きたいときは怒っていた。そういう意味でこの感覚はやはり昔は良かったに類されるものだろうと思う。今はもっと、素直に泣けるようになったのではないだろうか。泣くにも資源が必要で、生きる上でその資源を得た気がする。もちろん、悲しかったり悔しかったりしたら小さい頃はよく泣いていた。それはあくまで自分の中の感覚が勝手にそうさせていた。今泣くとしたらそれは、それは目に映る世界の背景がもう少し見えるようになったからなんじゃないかと思う。進んで手に入れたかったわけじゃなかった気もするけど。まあでも、それも一味。

小学生に上がるかどうかってとき、100円のおもちゃを両親に買ってもらった。お菓子とおまけが一緒になっているようなやつ。ロケットのフィギュアがどうしても欲しかった。何度かねだった挙句買ってもらった時の嬉しさといったら。それは特別な時であり、ことだった。今、飲んでるコーヒーは345円。嘘。2杯目だから108円。このコーヒーの苦味を僕は今、その時の100円と比べている。これぐらいのことだったらいつでも好きな時に自分で手に入れられるようになった。あのおもちゃが4つも買える。大人がコーヒーを飲むのがずっと不思議だった。あんな苦いもの。どうやら甘みを感じる味蕾が減るから大人は苦いのが平気になるってその昔読んだ本に書いてあった。今単純に思うと、減るなら逆にもっと甘いもの食べたくなるんじゃないのって思うけど。感覚が鈍くなること。大人になること。

そういう感覚を言葉に表せないまま、コーヒーの冷たさに触れたままでいる。

Implement a simple caching for Relay Modern.

Unlike Relay Classic, Relay Modern doesn’t come with an automagical caching system out of the box. Instead, it has an utility class to help you implement a cache system.

In this article I’ll describe an example implementation of a simple caching. I don’t explain much of details but you’d understand if you’re already familiar with Relay Modern and I believe you’re so as trying to implement a cache.

Code

const {
  Environment,
  Network,
  RecordSource,
  Store,
  QueryResponseCache,
} = require('relay-runtime');

const yourEndPoint = 'https://example.com'

const headers = {
  'content-type' : 'application/json',
}

const cache = new QueryResponseCache({size: 100, ttl: 100000});

function fetchQuery(
  operation,
  variables,
  cacheConfig,
  uploadables,
) {

  const queryId = operation.name

  const cachedData = cache.get(queryId, variables);

  // Handle force option in RefetchOptions
  // See: https://facebook.github.io/relay/docs/pagination-container.html
  // https://facebook.github.io/relay/docs/refetch-container.html
  let forceLoad = cacheConfig && cacheConfig.force

  if (!forceLoad && cachedData) {
    return cachedData;
  }

  if (forceLoad) {
    cache.clear()
  }

  return fetch(`${yourEndPoint}/graphql`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      query: operation.text, // GraphQL text from input
      variables,
    }),
  }).then(response => {
    const data = response.json();
    // A cache key, queryId in this code, should be unique per query.
    cache.set(queryId, variables, data);
    return data
  });
}

// Create a network layer with the fetch function
export const network = Network.create(fetchQuery);

Related tweets.

曲作り 8/22

息抜きに曲を作った

と言っても出だしだけ、簡単に。

soundcloud.com

人は悲しみを抱えて生きている

しかしその中にも一筋の輝きが差す

それは大切な人からの贈り物かもしれない

溢れた涙に反射する光も時間が経てば

大切な輝きだったと思える日がくるかもしれないと

そう感じさせてくれる


そんな感じ

仕事が好きな理由1

仕事が好きな理由はいくつかあるけど、その一つは「好きなだけ打ち込めるから」。

好きなことに打ち込めるというのは大事で、しかもその対象が人間でないということが重要。 どんな人でも一人の人間の思いを全て受け止められる人などいない。

一人の人間に自分のすべてを注ぎ込もうとすると、その先には破綻しかない。

仕事に打ち込むことで、やり場がないにも関わらず溢れ出る自分の気持ちを昇華させることができる。 つまり仕事がやり場ということになるのだけれど。

ああ、プログラミングというものが世の中に存在していてよかった。 プログラミングを介しての創造は自分にとっての精神安定剤だと思うことがままある。

気が狂いそうな時に、全てを忘れて取り組める何かがあるということは幸いでしかない。

現実と狂気の間の橋渡し。

アイディアを寝かせることと生産性

今作っているアプリLylicaのMap機能を改善しようと思ったのだけれど、 なかなか腰が重かった。そもそも機能自体もどうして良いかあまりわかっていなかったし、 技術的にも大変そうだなあと感じたので。

そのまま着手したらだらだらやり続けることになりそうだったので、 前から積んであった別の大変そうなタスクに着手した。 (より大変なタスクが入ると以前は億劫だったものがやりたくなるという心理は便利かもしれない。)

そのタスクを足掛け10日ほどでこなして、いよいよMapに着手するぞって機能始めた。 で、思ったより簡単にできた。

10日ほど寝かせていたことでアイディアが熟成され輪郭がはっきりとなり、 どこから着手すれば良いか糸口が見つかっていたのと、 技術的にもっと簡単にできないかな?という方面で解決策が見つかったからだ。

アイディアを寝かせてよかったなと思った。

しかしこれが会社勤めでスケジュール通りにタスクをこなさなきゃならないとなっていたら、 なかなかそんな風にはできなかっただろうなと思う。 生産性の低い、モチベーションの上がらない日々を過ごしていたんじゃないだろうか。

ということでやはり自分の会社に開発チームができたら、 2週間ぐらいを機能追加の一単位として、そして週4日稼働で余裕で終わるぐらいの開発量で回すようにやっていこうと思った。

机にかじりついていれば生産性が最大になるというのは幻想で、 風呂に入ってたり散歩だったり昼寝だったり、そういうときに僕は鍵となるアイディアや解決策を思いついたりする。

ので、やはり個々人が自由に自分のペースで開発できる、つまりクリエイティビティを発揮できる環境を整えたいと思う。

オブジェクト指向設計実践ガイド」という本に(ステマ)、プログラマーは組み立てラインの作業員ではない、という旨のことが書いてある。その通りだと思う。 もちろん筋肉をつかってもりもり書けば終わるというタスクはあるけれど、 それを可能にする根本的なところやアイディアというのはおおよそその対極にある。

40年近くたった今も、スティーブ・ウォズニアックはApple IIを改良する方法を思いついて目を覚ます | TechCrunch Japan」 こんな記事があるけれど、ウォズニアックは机にかじりついて思いついたわけではない。

人間の面白さと不思議さだけど、ある種の熟成を得て問題がある日解決するということは起こるのだ。

気が向いたら昼寝したり、散歩に行ったり、カフェにいったりということは、プログラマの創造性と生産性に寄与することだと思う。10時間机にかじりついても解けない問題が、ふと思いついたアイディアで5分ほどで解決できる問題になる、ということも起こるのがこの世界だ。

根性という幻想を打ち捨て個々人が精神の緩急を自分のペースで営み、いきいきと創造性を発揮し日々を楽しく生きる世界を実現したいものだ。

話がややそれたところで終わり。

Relay Modernに移行した

今作ってるアプリ、Lylica - 街のおすすめが分かるSNSをRelay ClassicからRelay Modernに移行した。

動機

今後機能を追加していくにあたり、今のうちにえいやとやっておきたかったからだ(とある機能の追加に腰が重かったから先にこっちに着手したというのは内緒)。

以前 Relay Modernへの移行検討をした - taiki-t's diary という記事を書いてその時にはいわゆるlocal stateがサポートされるまでModernに移行するつもりはないと言っていたけど、結局まだサポートされていない*1まま移行した。まあえいやって思っちゃったから。

パフォーマンス

体感的にまあアプリのパフォーマンス的にはそこまで変わりはない。計測はしてない。OptimisticResponseはClassicの頃から最強。サーバから返ってくるであろうデータをあらかじめ定義することで、サーバからデータが返ってきたものとしてビューを更新してくれるので爆速。サーバー側のエラーなどでデータ更新ができなかった場合は自動でロールバックしてくれる。更新できたら見た目にはそのまま。さいつよさしかない。バックエンドherokuで動かしてレイテンシ800msとかあっても感じさせない、というか原理的に見ためには存在しない。やばい。

気分

気は楽になった。Classicのスタイルでコンポーネントやmutationを追加するときに「うっ」って思ってたのが消えた。 そして、来たるSubscriptionsに対応できるぞーという楽しみができた。よかった。最高。

かかった手間

これ:

上記はほぼmutations以外のRelayを使ったコンポーネントを置き換えた時間。スパイク的に1箇所ぐらいmutationも書き換えたと思う。 で、上記以外のmutationsの書き換えにかかった時間は、9時間53分*2。1日かけて15個ほど書き換えた*3

手順

親切なことに移行の手順書みたいなのが用意されているのでそれをベースにやった。

Conversion Playbook - Relay Docs

上記の手順通りにうまくいったのは Step 0: Install Relay v1.0 までだった

Step 1: Incrementally convert to Relay Compatで、用意されていた移行スクリプト(まじ親切)を実行し、 シンプルなコンポーネントは自動でcompatモードに移行できた。

しかしその後、「手動でやらなきゃいけないよ」と上述のスクリプトが親切にコメントインしてくれた箇所は、compatモードで動かないことが試行錯誤ののち判明した。 ので、該当箇所は1箇所ずつ手動でいきなり Modernにえいやしていくことにした。 結果として手順は

  1. Relay Modernのインストール
  2. スクリプトで一部コンポーネントをcompatモードに移行
  3. ファイル名をCamelCaseに変更
  4. 自動でできなかったところをcompatを経由せず一つ一ついきなりModernに移行
    1. 実験的に途中1箇所mutationを置き換え
  5. データ取得については全てModernに移行(Relayの読み込み元をreact-relay/compatからreact-relayに移行)
  6. mutationsを一つ一つ手で書き換え
    1. 途中cacheを実装。Relay Modernではデータのcacheは自動でやらなくなったため。cacheの実装については別途記事にしようかと思う。
  7. 完全にRelay Modernに移行 (react-relay/compat, react-relay/classicからの読み込みを全てreact-relayに。)

ハマったとこ

コンポーネント、ファイル名

手順にもちょろっと書いたけど これ:

ので、ファイル名とimportしてるところをガッと書き換えた。そこまでやって、一部機能がcomapモードに対応してないことが試行錯誤の結果判明したので結局いきなりModernにいくことに。

Rootのクエリ名

上記についてはまあ最初からファイル名もCamelCaseで書いてある人には関係のない話だったろう。Facebook内部ではそういう規約でやってるんだと思う。他、ルートとなるクエリの名前にもFacebook内部の仕様が漏れ出ててる雰囲気があって、Queryっていう名前じゃないとcompatモードを通せなかった。RootQueryってしてたからそこもはまった。この制約はcompatモードのみで、Modernに完全に移行してしまえば関係ない。関係あったらアプリの後方互換性的にしんどかったなあ。この問題は今後のアップデートで解消される予定

キャッシュ

キャッシュをするなら手で有効にする必要がある。キャッシュ機構自体はあるので、それをちょろちょろっと組み合わせればできる。でも知らなかったしドキュメントもなさげ。

追記 2017-09-05: キャッシュの実装についてサンプルを書いた: Implement a simple caching for Relay Modern. - taiki-t's diary

Connections

例えばモデルとしてポストがあって、ポストがたくさんコメントを持つというとき、コメントを取り扱うのがconnections。has manyな関係を取り扱う感じ。書き方がだいぶ変わってて、あとcompatモードじゃ動かなくて、ドキュメントも薄かった。まあやった。自動で変換してくれないところの一つ。てか自動で変換してくれないところはそれぞれやはりつらみがある、 Relay 1.2.0が都合よく移行中に出てきたので、それで助かった部分もある。Connectionsの再取得の書き方など、1.2.0より前は大変そうだった。

mutation成功、失敗時の処理

ClassicではonFailure, onSuccess的な二つのコールバックでサーバーからのエラー、成功時処理をそれぞれ書いてた。Modernになってからは見た目にはonErroronCompletedというコールバックになってて、そのままClassicの感じかなと思ってたら挙動が異なっていた。サーバーからのレスポンスは失敗でも成功でもonCompletedで処理するようになっててonCompletedでサーバーから返されたエラーのハンドリングができるとはwebのドキュメントにはなかった(レポジトリのやつは更新されてた)。onErrorRelayがエラーに直面した時に呼ばれる。

さいごに

全体的な感想としては、やってよかったなと。書くようになったところと書かなくてよくなったところのバランスが、Classicと比べてよくなってると思う。特にmutations周りはよくできてるなーと言いたくなった。ただ、書くようになったところのドキュメントがまだ薄いので、ね。ドキュメントもっと充実するといい。

まだ色々あったようなきがするけど疲れたのでここら辺で。気が向いたら or リクエストがあれば追記しようと思う。ところでこの記事誰かの役に立つのだろうか?笑

リンク

Relay - A JavaScript framework for building data-driven React applications

Don't break in compat mode when root field is not named Query by robrichard · Pull Request #1962 · facebook/relay · GitHub

GraphQL error handling in Relay Modern · Issue #1913 · facebook/relay · GitHub

[Compat] Filename is expected to use the same case of container variable · Issue #1893 · facebook/relay · GitHub

[Modern] Paginating a connection in the root query · Issue #1705 · facebook/relay · GitHub

Lylica - 「街のおすすめ」が分かる位置情報SNS

Lylica - 街のおすすめが分かるSNSを App Store で


*1:機能はあるかもしれないけどドキュメントがなく誰も使い方がわからない [Modern] Client schema docs and examples · Issue #1656 · facebook/relay · GitHub

*2:

  1. terminal: 6h24m
  2. simulator: 1h37m
  3. localhost:8081: 40m
  4. github.com: 36m
  5. 他ツール: 12m

計測には RescueTime 使ってる。いい。

*3:今は自分しか開発陣はいないので、やりたい時にやるスタイル。逆に4時間とかしか稼働しない時もある