PhpStormと僕

日々周りを巻き込むことをモットーに。気まぐれでJetBrains製のIDEネタとか書いてます。

FirestoreのSubCollectionに対してQueryが使えない問題にどう立ち向かうか

Firestore、便利ですよねぇ。 ただ、2018/03執筆時点ではまだβなので荒削りだったり要件満たしにくい部分でつらいなぁっていう部分はいくつかあります。

その1つが表題の件の「SubCollectionにQueryが使えない」問題。 どういうことかというと、例えば「CDごとに曲名とその曲番号(連番)を保持する」構造を例に考えてみます。

- albums [collection]
    - title
    - musics [collection]
        - title
        - songNumber

Firestoreでどう表現するかというと、disksっていうCollectionを作って、その中にSubCollectionとしてmusicsを持つ形が一番シンプルに見えます。

f:id:rinrin900:20180309180400p:plain

こんなイメージ。ただ、この構造の場合は表題の制限があり、musics内のデータを直に参照したいケース、 具体的には「ユーザ属性は曲のタイトルを持っているが、その曲がどのアルバムに属しているか分からない(紐付けることができない)」時に、sounds内のデータを特定することができません。 この件についてStackOverFlowGoogleエンジニアが「Collection group queryという機能で提供する予定だが、提供はすぐではない」という回答をしています。

ObjectやArrayとして下位データを持つ方法もなくはないですが、そもそものSubCollectionのメリットを活かせないのではここでは考慮から外しつつ、 Collectionであることメリットを活かし現時点で解決できるパターンをいくつか見ていきます。

親CollectionにSubCollectionのキー一覧を持つ方法

f:id:rinrin900:20180309181719p:plain

親のCollection側に、soundsのキー一覧を持つのが一案としてあります。

soundKeys: [
    "1. 主よ,人の望みの喜びよ(In 4 Mix)"
    "2. 眠れる森~Sleeping Forest",
    "3. Mouring The Passing Time"
]

キー一覧を持つ際、上記のようにFirestore内のデータとして配列で持ちたくなります。 が、Queryでwhere in句のように配列を対象に検索することができないので、以下のようなObject形式で持つ必要があります。

soundKeys: {
    "1. 主よ,人の望みの喜びよ(In 4 Mix)": true,
    "2. 眠れる森~Sleeping Forest": true,
    "3. Mouring The Passing Time": true
}

sound側のkeyを持っている状態からこのalbums -> soundsのdocを取得する場合には

const userPlayingTitle = '2. 眠れる森~Sleeping Forest'
const querySnapshot = await db.collection('albums')
    .where(`albums.${userPlayingTitle}`, '==', true).get()
...

というような形でquerySnapshotを持ってくることができるようになりました。

Puppeteerで page.$(selector) で絞り込んだ要素から更に子要素指定を行う

最近がっつりとPuppeteerを触っている。 Puppeteer(書きづらい)とは、Headless ChromeをNode.jsから扱うためのライブラリ。

開発が速いのでググって出てくる情報は陳腐化していることがままあるので基本的には公式ドキュメントを読んでもらうのが大前提として、v1.1.1を触っている時点で得られた知見や小ネタちょこちょこと共有したい。

page.$(selector) で絞り込んだ要素から更にselector指定を行う

<div class="row">
  <div class="col">
    <div class="itemDetail">りんご</div>
  </div>
  <p class="price">120円</p>
</div>
<div class="row">
  <div class="col">
    <div class="itemDetail">みかん/袋</div>
  </div>
  <p class="price">520円</p>
</div>

もともと page.$ page.$$ で絞り込んだ子要素 ElementHandle は .$ .$$ メソッドを持っていなかったので、page.$$evalで指定してループ内で取り出す・・・みたいな必要があったが、 v0.13.0 からは以下のように、取得したSelectorのオブジェクト(ElementHandle)から更に絞り込むような書き方ができるので前よりだいぶ直感的に書けるようになった。

const rows = await page.$$('.row')
for (const row of rows) {
  const itemDiv = await row.$('div.col > div.itemDetail')
  console.log(await (await itemDiv.getProperty('textContent')).jsonValue())
  const priceDiv = await row.$('p.price')
  console.log(await (await priceDiv.getProperty('textContent')).jsonValue())
}

IntelliJ IDEAのSplash Screenを集めてみた

IntelliJ IDEAの15 EAP使い始めてスプラッシュスクリーンかっこいいなーと思って、 ふと思いついたので過去のバージョンのも集めてみた。

下に行くほど新しいバージョンのやつ。バージョン9以降はUltimate EditionとCommunity Editionあるけど、とりあえずごちゃまぜで。

色々探しまわったけどバージョン4以前のはどうしても見当たらず・・・。

バージョン12辺りから急に洗練され始めた感。 最近のバージョンのスプラッシュスクリーンはEAPと製品版でも違ったりと凝ってるのでおもしろい。

f:id:rinrin900:20051119033542j:plain f:id:rinrin900:20150814121631g:plain f:id:rinrin900:20150814121632p:plain f:id:rinrin900:20150814121635p:plain f:id:rinrin900:20150814121637j:plain f:id:rinrin900:20150814121638j:plain f:id:rinrin900:20150814121639j:plain f:id:rinrin900:20150814121640j:plain f:id:rinrin900:20150814121641p:plain f:id:rinrin900:20150814121642p:plain f:id:rinrin900:20150814121644p:plain f:id:rinrin900:20150814121645p:plain

Scalaコップ本メモ

そんなわけで最近Scalaを書き始めているわけですが、1ヶ月ほど前に今更ながらScalaスケーラブルプログラミング(通称コップ本)読んだので、その過程のメモ書きをまとめてみます。

ちなみに全部じゃなくて17章まで読みました。

実際書き始めてみると全然理解しきれてないところも多いのでもう一周読みなおそう・・・

Scalaスケーラブルプログラミング第2版

Scalaスケーラブルプログラミング第2版

コップ本メモ

  • Scalaは、配列から式に至るまで、あらゆるものがメソッドを持つオブジェクトだとすることによって、概念を単純化している(P62)

  • メソッドは副作用を持っていてはならない」というのは、関数型プログラミングの考え方の大きな特徴である。メソッドの作用は、計算して値を返すことだけでなければならない。このアプローチをとると、メソッドが入り組んだものにならないため、信頼性が上がり、再利用しやすくなる。(P63)

  • (関数型スタイルに慣れる)第一歩は、コードに現れる2つのスタイルの違いを理解することである。簡単な見分け方が1つある。コードにvarが含まれていたら、それはおそらく命令形のスタイルで書かれている。コードにvarが含まれていなければ、つまりvalだけが使われていれば、それはたぶん関数型のスタイルで書かれている。だから、関数型のスタイルに近づくための1角方法は、varを使わずにプログラムを書く努力をすることだ。(P72)

  • 関数が副作用を持つかどうかを簡単に見分けるには、結果がたがUnitかどうかを見ればよい。Unitとなっていれば副作用がある。Unitという結果がたは関数が意味のある値を返さないことを意味する。(P73)

  • Scalaは、toStringやHashSetといったキャメルケースの識別子を使うというJavaの習慣に従っている。アンダースコアは識別子の中で使ってよいことになっているが、Javaとの一貫性を保つため、またScalaコードではアンダースコアが識別子以外の目的でよく使われているため、Scalaプログラムの識別子にはあまりアンダースコアを使わない。(P121)

  • Scalaでは定数という単語はvalを意味するわけではない。valは初期化された後は一定だが、それでも変数と呼ばれる。たとえば、メソッドのパラメーターはvalだが、メソッドが呼び出されるたびに、これらのvalは異なる値を保持して良い。(P121)

  • valを使うチャンスを探そう。valはコードを読みやすく、リファクタリングしやすいものにしてくれる。(P129)

  • 一般に、varを避けるのと同じように、whileループも避けることをお勧めする。実際、whileループとvarはセットになっていることが多い。コードの中のwhileループには、疑いの目を向けてみるべきだ。whileやdo-whileを使う正当な理由が説明できないときは、これらを使わない方法を探してみよう (P131)

  • files <- filesHere というような構文はジェネレーター(generator)と呼ばれ、filesHereからの要素に対する反復処理に使う (P132)

    • はじめて呼び方出てきた
  • breakやcontinueを使わずにプログラムを書く方法はいくらもある。そして、関数リテラルを利用すれば、元のコードよりも短いコードが書けることが多い。もっとも簡単な解決方法は、すべてのcontinueをifに、すべてのbreakをBoolean変数に置き換えることだ。 (P141)

  • Scalaのスコープ規則はJavaのものとほとんど同じだということが分かるだろう。JavaScalaの違いは、Scalaでは入れ子になったスコープで同じ名前の変数を定義できることである。 (P143)

  • ScalaJavaの違いとして注意すべきなのは、Javaでは、外側のスコープ変数と同じ名前を持つ変数を内側のスコープでは作れないことである。Scalaプログラムでは、外側の変数は内側のスコープでは見えなくなるので、内側の変数は同じ名前の外側の変数をシャドウイング(shadow)するということができる。(中略)通常は、外側の変数をシャドウイングするよりも、新しい意味のある変数名を選んだほうがよい (P145)

  • 部分適用された関数とは、関数が必要とするすべての引数を渡していない関数呼び出し式である。必要な引数を一部または全く渡していないのである。部分適用関数式を作るにはメソッド名のうしろにアンダースコア書く。 (P157)

  • 最後の処理として自分を呼び出す再帰関数を末尾再帰(tail recursion)と呼ぶ。Scalaコンパイラーは、末尾再帰を検知したら、パラメーターを新しい値に更新した後、再帰呼び出しを関数の冒頭にジャンプするコードに書き換える。解が末尾再帰になっていれば、実行時に余分なオーバーヘッドがかかったりはしない (P167)

  • パラメーターなしメソッドは、Scalaでは頻繁に見られるものだ。それとは対照的に、 def height(): Int のように、空括弧付きで定義されているメソッドは、空括弧メソッドと呼ぶ。パラメーターがなく、ミュータブルな状態へのアクセスがオブジェクトのフィールドの読み出しだけなら、パラメーターなしメソッドを使うべきだとされている(特にミュータブルな状態を書き換えないことが大切)。この方法は、「属性をフィールドとメソッドのどちらで実装するかによってクライアントコードが影響を受けてはならない」という統一形式アクセスの原則に従っている。 (P184)

  • 原則として、Scalaの関数呼び出しでは、全ての空括弧を省略できる。しかし、呼び出されるメソッドがレシーバーオブジェクトのプロパティ以上のものを表す場合は、空括弧を書くほうが良いとされている。たとえば、メソッドがI/Oを実行したり、再代入できる変数(var)に書き込みを行ったり、ミュータブルなオブジェクトを直接または間接的に使って、レシーバーのフィールド以外のvarを読み出したりする場合には、空括弧を付けるようにすべきである。 (P185)

  • 合成と継承は、既存の他クラスから新しいクラスを定義するための2種類の方法である。主としてコードの再利用を追求する場合には、一般に継承よりも合成を選んだほうがよい。継承は脆弱な基底クラス問題を抱えており、スーパークラスを書き換えると、サブクラスが利用できなくなることがある。 (P196)

  • 配列の ++ 操作は、2つの配列を連結する(P197)

  • case修飾子が付けられたクラスをケースクラスと呼ぶ。この修飾子を使うと、Scalaコンパイラーはこのクラスの構文に適切な変更を加えるようになる。第1にコンパイラーはクラスと同じ名前のファクトリーメソッドを追加する。そのため、Varオブジェクトを作るのに、 new Var("x") と書く代わりに、少し簡潔に Var("x") と書くこともできる。第2にコンパイラーは、ケースクラスのパラメータリスト内の全てのパラメーターに暗黙のうちにvalプレフィックスをつける。そのため、パラメーターはフィールドとして管理される。第3に、コンパイラーがクラスにtoString, hashCode, equalsメソッドの「自然な」実装を追加してくれる。最後に、コンパイラーは変更を加えたcopyを作成するために、クラスにcopyメソッドを追加する。このメソッドは、1つか2つの属性が異なるだけでほぼ同じクラスのインスタンスを新たに作成する場合に便利だ。

  • headやtailはともに一定の時間で実行されるが、initとlastはリスト全体をたどらないと結果値を計算できないので、リストの長さに比例する計算時間を要する。データ構造を設計するときには、リストの末尾ではなく、先頭にアクセスして操作できるようにするとよい。(P297)

写経しながらメモってたやつ

  • Scala Worksheetが便利。IntelliJ IDEAから立ち上げられる。RubyのPry的な感じでガンガン使ってる。

  • 再帰構造の基本形

def approximage(guess: Double): Double =
  if (isGoodEnough(guess)) guess
  else approximage(improve(guess))
  • カリー化を使うことによってクライアントプログラマーが中括弧の間に関数リテラルを書き込めるようにできる
withPrintWriter(
  new File("data.txt"),
  writer => writer.println(new java.util.Date)
)

val file = new File("date.txt")
withPrintWriter(file) { writer => writer.println(new java.util.Date) 

株式会社nanapiを退職しました。

個人的な近況報告です。 7月下旬を持って株式会社nanapiを退職しました。

2013年1月に4人目のエンジニアとして入社したので約2年半ほど在籍してたことになります。

在職中は色んなところに手を出していて主に

・・・とか、大企業ではあまり経験できないようなスピード感の中いろんな業務を経験させて頂きました。今年からはリードエンジニアという立場でチームや組織を俯瞰して見ることが増えて、様々な面で成長出来たなーと実感出来る日々でした。

辞める理由は大きくネガティブな理由はなく、自分の技術的な興味の移り変わりが大きな理由です。優秀な同僚が多く、切磋琢磨し合える環境で働くことができたのはとても感謝しています。

エンジニアの採用サイトがリニューアルしていたので、せっかくなので貼っておきます。 辞めた身でこういうこと言うのも変な話ですが、nanapiはエンジニア以外の人のマネージャ・経営層も技術に対して理解があるので、新しいことにチャレンジし続けたい人にはとても働きやすい環境なんじゃないかなあと思います。

ちなみにあまり表に出てなかったですが、1年ごとに5万円までデバイス端末を購入補助される制度とか、入社時に2万円までPC周辺機器を自由に購入できる制度とかもあったりします。

recruit.nanapi.co.jp

次はフリークアウトで働きます。Scalaを書くのでPhpStormRubyMineも使わなくなりますが、引き続きがんばります。(もちろんIntelliJ IDEAは使う予定)

Wishlist貼っておきます。

http://www.amazon.co.jp/registry/wishlist/2NSGRH85BZA7E

IVS CTO Night & Day 2015 Spring powered by AWS Staff Report

M1100033.JPG

これはなに?

6月10日〜12日で宮崎のシーガイアで開催された IVS CTO Night & Day 2015 Spring powered by AWSAmazonさんと一緒にスタッフとして参加してきました。

スタッフという形ですが、発表やアンカンファレンスはほぼ全て見ることができました。めちゃくちゃ濃くて、そして心身共に疲れ果てた3日間でした。

同じようにスタッフ枠という形での参加があるかどうかわからないですが、今後同じような枠を頂いたときにエントリする人に「スタッフがどんなことするのか?」「IVS CTO Nightってどんな雰囲気なのか?」を触りだけでも伝えるということがこのレポートの目的です。

なお、具体的にどんな内容の発表があったかなどはAWSソリューションアーキテクトの篠原さんの以下のブログが参考になります。

【開催報告】IVS CTO Night & Day 2015 Spring powered by AWS

スタッフとしての仕事

Amazonさんが9名と、外部スタッフ(自分たち)が3名の合計12名。 基本的な大枠の進行やMCはAmazonさんが持っていたので、自分たち外部スタッフ3名で以下を分担しました。

  • 受付関連
  • LT/各発表のタイムキーパー
  • LT/各発表のモニタ接続確認
  • 会場移動時の誘導
  • ビデオ撮影

開催がまだ2回目ということもあり体系だった形になっていないので、状況を見て臨機応変に動きまわることが大事だなーという感じでした。

いろんなパネルを固定したり、会場設営したり、マイク回したり、後片付けしたりetc... みたいな細々したことをやってました。

(余談ですが、2日目は一日中立ちっぱなしだったのでエンジニアになって始めて足が棒になる感覚を味わいました。感無量。)

3日間の流れ

初日は基本的にウェルカムパーティなので受付及び入り口の確認がメイン。稀にIVS(CTO Nightじゃない方)の方が間違って会場来てしまうことがあるので常に出入口を見ている感じ。

二日目は朝8時〜受付とかモーニングセッション準備とか。 基調講演とメインセッションが10時〜で60分くらいの登壇が4本くらい。 夕方からはアンカンファレンス形式で複数あるテーマのうち、自分が議論したいテーマごとに分かれてテーブルで話し合う形式。 19時半くらいからはCTO Nightパーティ二日目。22時くらいに解散。

三日目は朝8時半〜IVSのメインイベント(多分)のLaunchPad。 誰か一人常に受付にいる必要があるが、基本的にはローテーションで会場内の発表に注視。

11時〜午前中いっぱいTechPitchという形式の、CTOによる技術LT。 午後は各テーマごとのパネルディスカッション*4つ。 最終日は18時半〜CTO Nightパーティ三日目。最終日だけ会場が別で、受付に人が要らないので自分たちも混ざって他のCTOと少し話した。

印象に残っていること

スピード感

kobito.1435137746.688501.png

面白いなと思って一番印象に残っているのが2日目のアンカンファレンスの「エンジニアの交換留学」について。 元ネタは今年の4月に行われていたpixivさんとドリコムさんの社会人交換留学について。

このテーマの元にどう思うか、自分たちの会社だったらどうか、という話が繰り広げられていた。 かなりポジティブに話が進んでいたらしく、具体的にそのアンカンファレンスの参加者の数社で交換留学をやってみよう、 という結論を1時間の中で出して、具体的なタスク化まで落としこんでいた。

コードを書き続けている人が多い

CTOが約100名と言っても会社規模はバラバラで、エンジニアは自分ひとりという会社もあったりするのでコードを書いているのは当たり前な部分もあるが、上場企業とかエンジニア規模百人以上の企業のCTOでも今でも日常的に(そして業務外で)コードを書き続けている人が多くとても刺激になった。

最近なんだかんだ言いつつ本とか(あとゲームとか)ばっかでコードから離れ気味になっている自分への戒めになった。

CTOは超パワフル

一部のCTOを中心に夜二次会、三次会〜に行って、朝4時くらいまでカラオケした後帰ってきて、その後朝8時半のLaunchPadには普通に参加しててすごかった。

食べ物が豪華

宮崎牛のローストビーフとかステーキとか食べた。

まとめ

とにかく刺激の連続なので、特に現場のエンジニアこそ機会があれば是が非にでも参加すべき、というのが個人的結論でした。 刺激だけじゃなく、CTOが感じていること・考えていることの高さまで強制的に目線を上げることができる3日間なので、コードを書いている以上に得られるものはとても多いと思う。 (1日中気を張っているからめちゃくちゃ疲れるけど!)

現場からは以上です。

2015初夏のKindle散財メモ

初夏というよりもはやもはや真夏の暑さだけど。 Kindleで50%オフ、というか厳密には50%ポイント還元してたので久しぶりに散財した。 最近もっぱらオーディオブックばっかりであまり紙の本とか電子書籍読む習慣がなくなってるので暫く積ん読になりそうではある。

組織パターン

組織パターン

Effective Ruby

Effective Ruby

AWK実践入門

AWK実践入門

The DevOps 逆転だ!究極の継続的デリバリー

The DevOps 逆転だ!究極の継続的デリバリー

ヒストリエ(1)

ヒストリエ(1)

ヒストリエ(2)

ヒストリエ(2)

ヒストリエ(3)

ヒストリエ(3)

ヒストリエ(4)

ヒストリエ(4)

ヒストリエ(5)

ヒストリエ(5)

ヒストリエ(6)

ヒストリエ(6)

ヒストリエ(7)

ヒストリエ(7)

ヒストリエ(8)

ヒストリエ(8)

ヒストリエ(9)

ヒストリエ(9)