Alfred で /Applications にあるアプリケーションがサジェストされないときの対処法
以下を実行して1〜2分ほど時間を置いたところサジェストしてくれるようになった。
ちなみに使っている Alfred のバージョンは 4.3.1, macOS のバージョンは 10.15.7 (Catalina)。
参考: Alfred is not finding apps on Catalina - macOS 10.15 Catalina Bugs & Issues - Alfred App Community Forum
sudo mdutil -a -i off
sudo mdutil -a -i on
mdutil
は Spotlight が使う metadata を管理するためのコマンドで、-a
オプションは全ての Volume にある全ての metadata の store に対して処理を実行することを表し、-i on|off
オプションは metadata の indexing の on|off を設定することを表している。
最初は https://www.alfredapp.com/help/troubleshooting/indexing/#rebuild に従って permission を付与したり index を rebuild したりしたのだけど問題が解決しなくて困ったのだけど、解決して良かった。
2020年のまとめと2021年の抱負
年末年始は主に RiJ の配信を見ていました。ファイナルソードの "西が出ちゃいましたね" が最高でした。
仕事
2019 年 11 月から 2020 年 4 月ごろまではスタディサプリの中学生向け個別指導コースを担当するチームに所属していました。
入社直後は新規事業のチームに所属していたので、既存のスタディサプリのチームに所属するのはこれが初でした。とはいえ仕事の多くは限定的なドメインの問題を解決する Web アプリケーションをゼロから書くもので、実質新規事業のような雰囲気でした。Go で API サーバーを書いたり React (TypeScript) でフロントエンドを書いたりと、これまで仕事では触れてこなかった技術を扱う必要があり良い機会でした(Go はあんまりコミットできなかったな…)。唯一雰囲気が違った仕事は既存のサービスに大きな機能追加をするプロジェクトで、自分はそのプロジェクトの開発のリードを任せてもらったのですが、甘い見積もりに基づく意思決定とメンバーへの信頼を欠いたマイクロマネジメント等をし、結果としてやや火が見えるプロジェクトとなったのでした…。なかなか苦い思いをしましたが、次に繋がる良い経験だったと今では捉えています。おそらく就職してから最も働いた期間でしたが、自分が長時間仕事をすることよりも自分の意思決定によってメンバーが長時間仕事をしているのを見続けるのがなかなかに堪えました…。
2020 年 4 月中旬ごろから現在までは入社後最初に所属したチームとは別の新規事業のチームに所属しています。
就職後所属したチームの中でもおそらく最大の開発チームで、大人数でのチーム開発の難しさを日々感じています。技術的にも色々とチャレンジをしていて、クライアント-バックエンド間・バックエンドの各サービス間の通信全てのインタフェースを GraphQL にして Schema Driven な開発を試みたり、社内のサービス全て(多分)が入っている monorepo から外れてチーム専用の新 monorepo を作って開発を進めていたり、サービスのキーコンポーネントの1つとして VSCode の Extension を作ったりしています。コードはフロントエンドに限らず TypeScript が過半数。入社当時は Quipper といえば Ruby の会社というイメージでしたが、現チームの外を見ても Go を書く人が増えていたり Elixir を書いている人たちがいたりと、Ruby を多用しつつも拘らずに要求に合う言語を選択して学習・実践する人が多い組織だなと今では思っています。
自分はこのチームの中で Embedded SRE 寄りの Web Developer のようなポジションにあり、SRE チームと連携しつつ K8s cluster 上で Web アプリケーションやバッチジョブが動くように環境を整備したり CI/CD のパイプラインを整備したりするのを主な担当領域としつつ、必要に応じてフロントエンド・バックエンドのコードも書くという感じで活動しています。コードを書くにあたっては TypeScript の型付けについての知識の無さがしばしばネックになっていて、最近は『プログラミングTypeScript』を読んだり TypeScript exercises をやったりしていました。
仕事は 2020 年 2 月末ごろからずっと家でしています。机はこんな感じ。
元々作業環境はそれなりに整えていたので、追加で導入したのは電動スタンディングデスク(FLEXISPOT E6)くらいでした。ただ作業部屋に空調機が無いために夏冬が厳しく、妻もリモートワークとなったものの人間2人が仕事をするには手狭な部屋だったため、意を決して引っ越しを敢行。今では作業部屋にも空調機が付き、部屋も全体的に広くなってグッと快適になりました。
仕事以外
基本的に引き籠もっています。
2019 年には毎週のように行っていた飲み会も 2020 年 3 月以降行ったのは去年から予約していた会 1 つだけでした。2021 年も妻以外の人と会って食事をするのは基本的に避けるつもりです。その影響もあってか、家でもお酒をあまり飲まなくなりました。以前は週にビール 2〜3 本程度は飲んでましたが、今では 2 週間に 1 本飲むか飲まないかといった程度に。飲むこと自体は今でも好きなのですが、質の悪い睡眠で体の調子が落ちることへの嫌悪感が強まり、頻度も量も自然と落ちました。親族から送られてきた日本酒はどうしようかしら…。
食事はコロナ禍以前とあまり変化なく、朝は米、りんご、パンなどを適当に食べ、昼はインスタントのちょっといいカレーかちょっといいパスタ、夜はありがたいことに妻が作ってくれることが多いのでそれを食べる、という流れが多いです。途中 nosh を試すも高く感じて停止中。しかし健康的な食事が脳死で得られることを思うと安い気もしてきた。
運動については僕は元々運動不足だったのですが、より顕著になったように思います。平日は基本的に外出せず、運動と言える運動は仕事の集中力が切れたときに作業机の隣に置いている自転車に乗って 10~20 分ペダルを回す程度。体重は年初と比較して落ちているんですが、筋肉量が落ちた結果と思っています。
そんな運動不足な人間が部屋に籠もっているからなのか、自律神経失調のような状態になることが増えたような気がします。具体的にはすぐに立ちくらみをしたり、急にドキドキしたり、大したことをしていないのに消耗して無気力になってしまったり、起き抜けから不快感で頭がいっぱいになってしまったり。ひとまず今は湯船に浸かる頻度を増やしたり、日の光を浴びたり、休日含めてあまり生活時間帯を動かさないことを意識して過ごして様子を見ています。が、正直なところあまり元気でない日が少なくないです。妻にも心配を掛けてしまっているので何とか改善していきたい。
2021 年
去年に引き続き、楽しめる事柄を増やしたり楽しそうなチャンスを得られるように知識を付けたり実績を積んだり縁を広げたりしていきたいですね。あと漠然と興味を持ちつつも現実味を覚えず何も行動していない D 進について、進学へのイメージをカラフルにした上でする・しないのおおよその決定を今年はしてしまいたいなと思っています。解像度が低い状態でぼんやりと道が浮かび続けるのが気持ち悪い。
そんなところで、今年もどうぞよろしくお願いいたします。
Shopify/graphql-batch がどのように batching するのかを追う
この記事は GraphQL Advent Calendar 2020 4日目の記事です。
前回の記事は @qsona さんの 動的型付け言語での GraphQL Client でした。
題の通り、Shopify/graphql-batch がどのようにリクエストを batching するのかをコードを読みつつ追っていきます。
時間の都合で、この記事ではシンプルな単一の Query のみ(Mutation でない)を実行した場合を対象とします。また Loader については README に記載されている RecordLoader の実装をそのまま使います。
3行まとめ
- graphql-ruby の lazy-loading class として Promise を使う
Loader.for(Klass).load(object.klass_id)
が呼ばれるたびに Loader に Promise を登録する- Query にある遅延評価しない field を全て解決した後、Promise を解決する
コードリーディングに使ったサンプルコード
require 'bundler/inline' require 'logger' gemfile do source 'https://rubygems.org' gem 'graphql' gem 'graphql-batch' gem 'activerecord', require: 'active_record' gem 'sqlite3' # gem 'pry-byebug' end ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') ActiveRecord::Base.logger = Logger.new(STDOUT) ActiveRecord::Schema.define do create_table :courses, force: true do |t| t.references :textbook end create_table :textbooks, force: true do |t| end end class Course < ActiveRecord::Base belongs_to :textbook end class Textbook < ActiveRecord::Base has_many :courses end textbook1 = Textbook.create! textbook2 = Textbook.create! textbook3 = Textbook.create! Course.create!(textbook: textbook1) Course.create!(textbook: textbook2) Course.create!(textbook: textbook3) class RecordLoader < GraphQL::Batch::Loader def initialize(model) @model = model end def perform(ids) @model.where(id: ids).each { |record| fulfill(record.id, record) } ids.each { |id| fulfill(id, nil) unless fulfilled?(id) } end end class TextbookType < GraphQL::Schema::Object field :id, ID, null: false end class CourseType < GraphQL::Schema::Object field :id, ID, null: false field :textbook, TextbookType, null: false def textbook RecordLoader.for(Textbook).load(object.textbook_id) end end class QueryType < GraphQL::Schema::Object field :courses, [CourseType], null: false def courses Course.all end end class MySchema < GraphQL::Schema query QueryType use GraphQL::Batch end result = MySchema.execute(<<~GQL) query Courses { courses { id textbook { id } } } GQL pp result.as_json
1. graphql-ruby の lazy-loading class として Promise を使う
- この辺り: https://github.com/Shopify/graphql-batch/blob/7c7e3016923f9aa346d0cd3b9be40f85bf61a3a1/lib/graphql/batch.rb#L18-L43
- Lazy Execution に関するドキュメントはこちら: GraphQL - Lazy Execution
MySchema
が参照されるとGraphQL::Batch.use
が実行される- この中で、
GraphQL::Batch::SetupMultiplex
を Multiplex instrumentation の instrumenter として登録し、また lazy-loading class としてPromise
(promise.rb) を、値を取得するメソッドとして:sync
を登録する
- この中で、
2. Loader.for(Klass).load(object.klass_id)
が呼ばれるたびに Loader に Promise を登録する
- この辺り: https://github.com/Shopify/graphql-batch/blob/7c7e3016923f9aa346d0cd3b9be40f85bf61a3a1/lib/graphql/batch/loader.rb#L47-L52
textbook
field を resolve した際の返り値としてはインスタンス変数@source
にRecordLoader
のオブジェクトを持つPromise
のオブジェクト(文字で表すとややこしい)となる
3. Query にある遅延評価しない field を全て解決した後、Promise を解決する
- この辺り: https://github.com/rmosolgo/graphql-ruby/blob/ea571fd8db2b20f46299313c544ba0690869df28/lib/graphql/execution/multiplex.rb#L82-L87
Promise
オブジェクトを返す field はGraphQL::Execution::Lazy
としてハンドリングされ、次実行対象の Query(複数あるときはそれらに含まれる全てっぽい)にある Lazy でない field を resolve するフェイズのあとに resolve される- Loader に cache していた Promise の object を sync するのは
multiplex.schema.query_execution_strategy.finish_multiplex(results, multiplex)
から進んでいったここ: https://github.com/rmosolgo/graphql-ruby/blob/ea571fd8db2b20f46299313c544ba0690869df28/lib/graphql/schema.rb#L123 promise.sync
が実行されるとGraphQL::Batch::Loader.resolve
が実行され、RecordLoader
に実装していたperform
が実行される
所感
思ったより理解に時間がかかり(そしてまだ十分に理解できていない)複雑度に対してだいぶラフなまとめになってしまったのですが、graphql-batch がどのように batching するか、また graphql-ruby についてもその実装の一部を理解することができ便利でした。
そしてコードリーディングってスコープを決めてやらないと一生終わらないですよね。楽しい。