2018 年 7 月 10 日に天神の Fusic 社で開催された Scrapbox Drinkup #5 に参加した。

Scrapbox Drinkup #5 Fukuoka Edition (2018/07/10 19:00〜)

Scrapbox Drinkup #5 Fukuoka Edition (2018/07/10 19:00〜)

## Scrapbox Drinkupについて Scrapbox Drinkupは『チームのための新しい共有ノート』であるScrapboxのユーザー(にこれからなる人も含む)と開発者で集まってカジュアルに 情報交換をしようという会です!! Scrapboxの近況と今後の...

nota.connpass.com

Nota 社の皆さんが福岡に訪れてユーザーと情報交換するという趣旨のイベントのようだった。 Scrapbox はほとんど使ったことなかったが、 @masui 先生や @shokai さんの発表が聞けるということなので行ってみることにした。

Nota 社のイベント、他社の採用目的感あふれるイベントと異なり牧歌的な感じがとてもよかった。 Nota 社の皆さんも参加者と同じテーブルに座ってピザ食ったりビール飲んだりでざっくばらんな感じだった。

最初にパスタケさんの概要説明的な話があったあと、 @masui 先生や @shokai さんの発表を聞いて「使ってみたい!」という気持ちが強くなり、発表を聞きながら一つプロジェクトを作った。

実は Drinkup 参加前に @ssig33 さんが書いていた Scrapbox についてのブログ記事(ssig33.com - Scrapbox Drinkup #4 にいってきた)を読んでいて「ふ〜ん」くらいに思っていたのだが、実際に利用事例やできることを知って、確かにこれは面白いものだなと思った。

@ssig33 さんが書いている通り、 Scrapbox は単に知識を集めて検索可能にするためのものではなく、コミュニケーションツールだなという感じがする。なので MTG の議事録などを複数人でとって理解が曖昧だったところを確認・補強したりするのに非常に向いてるだろうなと思った。リモートワーク主体のチームが Scrapbox を導入したら MTG の生産性が高まるのではないかと思う。

個人的に Scrapbox に対して良いなと思ったのは以下だ。

  • 共同編集
    複数人で同時に編集できる楽しさ
  • ドキュメント間のリンクが容易
    ハッシュタグやリンクは相互参照される
  • 動画や画像を簡単に貼れる
    コピペで画像をアップロードできる
  • 投稿・入力の敷居の低さ
    枠や升がなく、必須入力やバリデーションなどもほぼほぼなさそう
  • 検索

それぞれはすでにすぐれたツールが存在していると思うが、それが一つのツールですべて使えるようになっているところが便利なのだと思う。

以前アウトライナーについて記事を書いたことがあるが(アウトライナーで文章を書く - portal shit!)、その中で紹介したものに WorkFlowy というアウトラインプロセッサーがある。個人が思考を整理しながら文章を書くのに非常に適したソフトで、 Scrapbox に似ている側面があると思った。

WorkFlowy はアウトライナーからファイルやタイトル、ノードという概念の区別を取っ払い、すべての情報をノードとして扱いツリー構造にしてしまう。おかげですべての情報が容易に検索可能になり(情報がファイルで分割されない)、検索性も向上して知識の保存と参照が劇的にしやすくなる。 Scrapbox では階層構造を作ることはできないが、すべての情報はフラットな空間に書きためられ、それぞれの情報を非常に参照しやすいかたちでリンクさせることができる。

Scrapbox と WorkFlowy が大きく異なる点は、これらの情報を容易に共同編集できるかどうかだと思う。 WorkFlowy は非公開状態がデフォルトで、他者に閲覧を許可したり共同で編集したりするためにはその為に専用のリンクを発行して共有のレベルを設定しないといけない。 Scrapbox はデフォルトが公開状態で(少なくともプロジェクトの参加者の間では)、特に設定することなく情報を共有したり共同で編集したりできるようになっている。 URL は当然ながらドキュメントを作成したタイミングで生成される。わざわざ共有用 URL を発行する必要はない。デフォルトでは URL が存在しないため、 WorkFlowy ではドキュメント間のリンクもしづらい。

このように Scrapbox で初めて得られる文章編集体験というものが確実に存在すると思う。


個人的に作ったやつは会社の G Suite 内の Google Maps にあったランチスポット情報を集約したやつをエクスポートしたもの。Drinkup で @masui 先生が「ヘルプドキュメントの類を Scrapbox で構築したら便利なはず」という話をされていた1のに着想を得た。職場が福岡市の中心部でもマイナーなエリア(旧来の博多の街の中心部だけど天神と博多駅からも微妙に離れていて飲食店が少ない)にあり、食べログなどで探してもあまり有益な昼食スポットの情報が得られないため、これまで社内で情報をストックして共有していたが、この手のものは一社で作るよりも界隈にお勤めの皆さん全体で共有した方が効率がよいはず。 Scrapbox がこの用途にはピッタリなのではないかと思って作ってみた。

呉服町ランチ

呉服町ランチ

はじめに / 味どころ 希彌 / ふるさと / 【ランチ営業終了】うどん酒家 かみや / 瑛琳 / 釘本食堂 / ステーキハウス听 / たくみちゃん / あかちょこべ / 【閉店】明星飯店 / ビストロ サイダ / 釜揚げうどん 中洲川端店 / 金菜亭 / 牛豚馬鶏 / テ...

scrapbox.io

Spread Sheet や Google Maps の Data Table による管理では複数人からの情報を良い感じにまとめることができず、多くの人から情報を集める、という点で難があった。 Spread Sheet は入力しやすい UI であるとは言えないので、入力する側に根性や気合い、熱意が求められた。 Scrapbox であればテキストファイルに文章を入力するのと同程度の手軽さで情報を入力していくことができる。入力欄に枠や升があるわけではないので自由気ままに書くことができる。これは書き手にとって大いにストレスの軽減になると思われる。

もし福岡市地下鉄貝塚線呉服町駅周辺のランチスポット情報をお持ちの方がおられましたら以下のページから登録して情報共有しませんか。よろしくお願いいたします。

Scrapbox

Scrapbox

scrapbox.io


  1. 実際に Scrapbox のヘルプページは Scrapbox で作成されている。 Scrapbox ヘルプ 

契約中のサービス

Apple Music

何度も一ヶ月だけ契約して試しては解約し、を繰り返していたけど、 Circle 2018 に行ったあとに出てた人たちの音楽をまとめて聞きたくなって契約した。全部アルバム買うと 2, 3 万になるのがファミリープランでも 1480 円/月で済むのはいい。人間は音楽を買ってもそのうち聞かなくなる。聞きたい間だけお金を払うのが正解なのかもしれない。

ただ有名ミュージシャンの曲や懐メロのオリジナル版は相変わらず Apple Music にはなくて(カバーはいっぱいある)買わないといけないので注意が必要。ゴレンジャーの曲とか聖闘士星矢の曲のオリジナル版は iTunes Store で買った。

Spotify にしない理由は macOS や iOS との統合された使い勝手を重視しているから。たまに切り替えて使ってみるのもよいかもしれない。

Netflix

深夜食堂を見たくて入ってる。その他、アメリカのドラマも時々見る。電車の中で見たいけど結構エロシーンが多くて困る。イギリスのクッキング対決番組も面白い。とはいえ元とれてる感じはしないので Rebuild で話題になるドラマなんかをさっと見て解約したい。

Amazon Prime

Amazon のクレジットカード( Master )の特典で付いてくる。様々な割引を組み合わせたカードの年会費が 3940 円でプライム年会費と同じ。 Master カードはコストコでの支払いにも使えるようになったので便利。 1% ポイント還元。

Prime ビデオに関しては割と頻繁にラインナップの見直しあってて見たいやつがなくなるので見られたらラッキーくらいのつもりで利用しないと逆にストレス溜まる。

The Old Reader

RSS リーダーの中で最安なので使ってる。検索が厳しい。たぶん全文検索エンジン使ってなくて DB から LIKE サーチしてる気配を感じる。 Inoreader に乗り換えを検討した方がよいかもしれない( Feedly は好きになれない )。

さくら VPS 2GB プラン

このブログを動かしている。まぁまぁ高いが AWS や自宅サーバーで運用するのに比べたら十分経済的。

AWS

Route 53 と S3 、 CloudFront のみ利用している。 毎月 200 〜 300 円くらい。

解約したサービス

GitHub private repo

Microsoft に買われて自分ごときの金なしおじさんが利用料を払う必要もなかろうと思い解約。大したコード上げてなかった。秘密情報的なやつは GitLab に移した。

Flickr Pro

自己顕示欲を満たすために人に写真を見せる、ということがなくなったので解約しようと思っていたが、 2 年おきの更新なのでうっかりしてて 2020 年まで自動更新されてしまった。とりあえず自動更新を停止にした。

iTunes Match

Apple Music に移行したので自動更新を停止した。

Facebook にウェブサイトの URL をはっつけるとき参照される HTML メタ情報の仕組みに Open Graph Protocol ってのがある。 Facebook に URL を貼ると bot が URL の内容を読みに行ってページの概要や画像を取得し Facebook 内に埋め込み表示するというもの。 Facebook を見ている人はリンク先の内容をクリックする前に概要を把握できるので、リンクをクリックして見たい情報じゃなかった、ということを避けられる。 Facebook が考案して策定した仕組みだけど、 Facebook に限らずいろんなサイトで OGP タグを出力してるし読み込んでる。 Twitter にも似た仕組みあって Twitter Card という。この辺の対応は結構前にやってた。

アドベントカレンダーに備えて Open Graph protocol に対応

アドベントカレンダーに備えて Open Graph protocol に対応

昨日飲みに行って今朝起きてからふとコード書きたくなって、アドベントカレンダーもあることだし(去年の Adventar で自分のブログだけ og:image がなくて画像が出てなくて残念だった)、このブログを Open Graph protocol に対応させることにした。T...

portalshit.net

ただ自分のサイトが OGP タグを提供するだけではつまんないなと思ったので自分のブログにペロッと URL を貼ったときに相手先に OGP タグがあればそれを出力するようにしてみた。こんな感じ。

OGP Preview

しかしここで困ったことがあって、↑でリンクしてる Circle のサイトは HTTPS で配信されておらず、単純に Circle のサイトで og:image に指定されている画像を SSL 化されているこのブログで読み込むと Mixed Content になってしまう。せっかく HTTP/2 で配信していたのに台なしになってしまう。またそもそも og:image は Facebook でシャアされることを想定されていることがほとんどなので、画像サイズがデカすぎていい感じにスクエアに表示するためには CSS の小技を駆使したりする必要があった。

いい感じに解決する方法ないかなと調べていたら良いのが見つかった。

willnorris/imageproxy

willnorris/imageproxy

A caching, resizing image proxy written in Go. Contribute to willnorris/imageproxy development by creating an account on GitHub.

github.com

Go で書かれた Image Proxy Server で、 HTTPS Proxy は当然のこと動的リサイズもできる。使い方は簡単でバイナリを落としてきて動かすだけ。 Go なんで ImageMagick をどうしたりとかを考えなくて良い。 そもそも Docker イメージも提供されているので Docker をインストール済みなら docker run するだけでも動く。 めっちゃお手軽。

こいつのおかげで HTTPS で配信されていないサイトの OGP タグを読み込んでも Mixed Content にならずに済むようになった。また og:image は適切にリサイズできるようになった。画像変換サーバーとかは結構難しいいやつで個人のブログでこんなに簡単に使えるものだとは思ってなかったので正直ビックリした。

AWS の登場で大企業じゃなくても CDN 使ったり仮想サーバーでウェブシステムを構築したりできるようになった。さらには Go や Docker といった技術のおかげで複数の込み入ったソフトウェアを組み合わせて構築していく必要があったシステムが、まるで jQuery を使うような感覚でポン付けで使える時代になってきている。とても素晴らしい。

ちなみに OGP の取得には open_graph_reader という gem を使っている(昔からある opengraph という gem はメンテナンスされておらず最近の Nokogiri で動かない)。 open_graph_reader の作者が結構 Opinionated な人で、以下のような Anti-featurs を掲げている。

open_graph_reader Anti-features

http://ogp.me/ の仕様に準拠していないサイトのことは完全無視というつくり。個人的にはこういう思想は好みだが、現実問題として使い勝手が悪い。例えば hitode909 さんのブログの OGP タグを取得しようとしたところ以下のようなエラーを出して取ってくれなかった。

スクリーンショット 2018-05-26 10.08.47.png

article:published_time は ISO8601 形式の datetime であるべき、とのこと。はてなブログはかなりシェアが大きくリンクする機会が多いので残念。

先日書いた Day One のバックエンドで障害 - portal shit! について、 Day One のヘルプページで詳細を説明する記事が掲載されていました。

May 2018 Day One Outage Postmortem | Day One Help

May 2018 Day One Outage Postmortem | Day One Help

help.dayoneapp.com

ウェブアプリケーションエンジニアの皆さんが読むと参考になるのではないかと思い、翻訳の可否をたずね許可をもらったので翻訳します。


2018 年 5 月の Day One 障害報告

執筆者: Paul Mayne (訳注:Day One の創業者)
今週更新(訳注:障害復旧日の午後に公開されました)

2018 年の 5 月 7 日から 10 日にかけて、 Day One は重大な Sync サービスの停止に陥りました。ユーザーの皆さんから堅牢な Sync サービスを期待されていることはわかっていますし、この出来事は我々の基準を満たすものでもありません。何が起こったのか、そして将来にわたってどのようにこの問題を回避していくかをユーザーの皆さんにお伝えしたいと思います。

簡単なまとめ

5 月 7 日にハードウェア障害が発生し、最初の Sync サービスの停止が発生しました。バックアップデータが不完全だったことが原因で、 5 月 8 日の Sync サービスの復旧処理中、一部のユーザーのアカウント ID が既存のユーザーのものと重複してしまいました。結果、一部の新規登録ユーザーは他人の記事を見ることができる状態となっていました。問題に気がついてすぐに Sync サービスを再び停止させました。対象のユーザーは 106 人で、これは我々のユーザー全体の 0.01% よりも少ない値です。

現在、 Sync サービスは正常に復旧しており、記事が他人に見られることはありません。近日中(訳註:すでにリリース済みです)に意図せず共有されてしまった記事を削除するアップデートを提供します。

End-to-end の暗号化を施していた記事は今回の事故の対象外です。

いかなる偶発的な個人情報の漏出も信用を毀損するものであると我々は認識しています。この不幸な状況にあって我々は、正直に状況を説明することが最善だと思っていますし、また信頼を回復するために全力を尽くしています。今回、個人情報の流出被害にあった 106 人のユーザーには終身の Premium メンバーシップを無償提供し、それぞれ個別に連絡を取っています。自分たちにできるあらゆることを行ってみなさんの信頼を回復していきたいと思っています。

障害の詳細

5 月 7 日月曜日、 Day One の社員が DB サーバーでハードウェア障害が発生していることに気がつきました。問題のあるサーバーをデータベースクラスターから取り除く作業とデータを残りのサーバーに分散する作業を始めました。

データの分散処理に失敗します。これが最初の障害です。すぐに Sync サービスを復旧させたかったため、新しいデータベースクラスターを作成して最新のバックアップデータを読み込むことにしました。新しいクラスターがセットアップされ、バックアップが読み込まれました。

5 月 8 日火曜日の早い時間に復旧処理が完了し、 Sync サービスを再開しました。当初は順調に動いているように見えました。しかし数時間で「自分の記事ではない記事が見える」という問い合わせが何人かのユーザーからありました。これは由々しき事態であり、我々はすぐに Sync サービスを再停止し、これ以上被害が拡大しないようにしました。

この時点で、問題と対応方法の調査を行う間、 Day One Sync を無期限に停止する旨をソーシャルメディアに投稿しました。何が原因なのか、何が起こっているのか、そしてもう問題が起こらないと確信できるまで Sync サービスは再開できませんした。

5 月 9 日水曜日の午前、問題の根本原因を突き止めました。復旧処理に用いたバックアップデータが不完全だったのです。記事データは完全なものでしたが、ユーザーアカウントデータに欠落がありました。具体的には、 3 月 22 日よりも後に作られたユーザーアカウントデータが含まれていなかったのです。その結果これらのユーザーはログインすることができていませんでしたし、特定の記事データが意図せず他人から見えてしまうという問題につながりました。

それぞれの記事データベースは “accountID” というフィールドを持ち、どのアカウントがその記事の所有者であるかを判断しています。全ての記事データは正しく復旧されましたが、ユーザーアカウントデータはそうではなかったため、データベースに所有者が存在しない記事ができてしまいました(例えば “My Travel Journal” という記事は 123456 というアカウントのものだったとしましょう。しかしそのアカウントが存在しなくなってしまったということです)。新しいユーザーアカウントの ID は連番で作られます。復旧されたデータは最新のユーザー情報を含んでいなかったため、 5 月 8 日に新規登録したユーザーは本来よりも小さな値の ID で登録され、既存のユーザーアカウントと重複することになったのです。その結果、これらの新規ユーザーはすでに存在する他人が書いた記事を読めるようになってしまったのです。

5 月 8 日の問題が発生していた期間のうちに、 326 アカウントが正しくない account ID で作成されました。その 326 個の ID のうち、 106 個が別人によって書かれた既存の記事データに結びついていました。 2018 年の 3 月 22 日から 23 日に作成されたアカウントは他人から記事が見られる状態になっていたということです。それらは account ID 1104506 から 1104831 の人たちでした。

現在のところそれらの記事のうちどれくらいが end-to-end の暗号化処理をされていたかはわかっていませんが、 end-to-end の暗号化をしていた記事は今回の問題でも他人に見られることはありませんした。

水曜日の調査の後、元のデータベースでデータの分散処理に失敗する問題を解決することが最善の選択肢だと判断しました。いくつか設定ミスがあり、データベースの負荷が高まる原因になっていることがわかりました。この負荷が原因でデータの分散処理が失敗していました。

水曜日の午後、この問題を修正し、元のデータベースクラスターで分散処理が正しく完了することを確認しました。しかしエンジニアチームとサポートスタッフが万全の態勢で臨めるよう、 Sync サービスの再開を木曜の朝まで遅らせることにしました。山岳時間で 5 月 10 日木曜の午前 8 時、 Sync サービスは再度有効化されました。

同期サーバーには大量の待機処理があったため、それらの処理が終わるまでは少しパフォーマンスに問題があるかもしれませんが、なるべく遅延が発生しないように対処しています。

今後どうするのか?

意図せず共有されてしまった記事を削除する機能が入った Day One.app のアップデート(バージョン 2.6.4 )をすぐにリリースします(訳注:すでにリリース済みです)。このアップデートをインストールすると、未ログイン状態のユーザーの端末からは非公開の記事はすべて削除されます。対象ユーザーはアップデートのインストール後 30 日以内に Day One アカウントにログインすることが必要で、このログインをもって Day One.app はログインユーザーを記事の所有者であると認定し、記事を復元します。 Day One.app は影響を受けるユーザーに対してこの変更内容を通知します。

今後、同様の問題が起こらないように、近々以下の改修を同期サーバーに対して施します。

  1. account ID の新規作成時、すでにその ID で記事が作成されていないかをチェックします
  2. 新規の account ID に対しては、連番の数字に加えてランダム生成された二桁の数字を末尾に付加することにします。将来、同じような問題が発生して連番 ID が若返ってしまったとしても ID の衝突が起こる可能性は非常に小さくなります。
  3. いくらかのユーザーアカウントがバックアップ対象から除外されてしまう問題を修正します。

他人に記事を見られてしまった 106 人のユーザーに対しては真摯に謝罪します。対象のユーザーには終身 Premium メンバーシップを提供するとともに、その他懸念点がないか個別に連絡をとっています。今回、大規模な情報流出は起こっていません。第三者がデータベースに侵入したということもありませんし、すべてのデータは我々のサーバーで安全に保管されています。しかしながら 106 人のユーザーの我々に対する信頼は失われてしまいました。信頼は獲得するものであり、与えられるものではないということを承知していますし、再び皆さんからの信頼を取り戻せる機会を得たいと思っています。ユーザーの皆さんには 2017 年 6 月にリリースした end-to-end の暗号化機能を利用することを推奨します。この機能は今回のような事故やその他の問題があったときにもあなたの個人情報を保護します。

今回の障害で Sync サービスを利用できなかった間、辛抱して下さったユーザーの皆さんに感謝します。皆さんが Day One を使って大事な思い出を記録していることを理解しています。今後、よりよくしていくことをお約束します。信頼を回復するため、全力を尽くします。

— Paul

Day One という日記書きソフト、愛用しているのだけど今週頭に障害が発生して日本時間で 2018/05/11 の明け方まで同期ができない状態になってた。

Sync Status | Day One Help

ユーザーとして不便だったけど復旧にかなり時間がかかったのがソフトウェア開発者の一人として興味深かった。何が原因で復旧が遅れたのか推測した。

Day One のバックエンドは AWS に構築してあるようで、負荷でサーバーがダウンしたのなら EC2 インスタンスを追加してサーバー再起動すれば良いはずなのですぐ復旧できるはずと思ったが、一向に復旧しない。復旧作業の状況報告ページにしきりに “server rebalance” というフレーズが出てきており、アプリケーションサーバーで “rebalance” なんてことはやらないから、どうもデータベースがクラッシュしたようだった。

Day One のバックエンドエンジニアの採用情報見たら技術スタックが書いてあって、開発言語は Scala で DB は Couchbase を使ってるとのことだった。で、 Couchbase では Shared Cluster の rebalance という作業が必要らしい。

Couchbase は CAP 定理のうち一貫性と分断耐性を保証していて、その代わりに可用性が犠牲になっている(Couchbase Server - Wikipedia)。 Day One では複数のクライアントからほぼ同時に同一ドキュメントに対して更新が走ることが多いし、 iOS からは不安定なモバイル回線経由で接続される。かつては Dropbox や iCloud も同期のバックエンドとしてサポートしていたが、コンフリクトしたり意図せぬデータ欠落などがあったと思われ、自前のバックエンドシステムに移行したのだろう。一貫性と分断耐性に特化した Couchbase はユースケースとして最適に思えるが、障害が起こるとリバランスに手間取り復旧の難易度が上がるようだった。

自分は大規模分散データベースみたいなやつは受託の会社に勤めてた下っ端の頃にしか使ったことがなく、自分でがっつり運用・構築したことがないので大規模データベースに対する知識が足りていないと思う。大した考察は出来ていないが、今後もバックエンド API おじさんとして余生を過ごしていく上で参考になる出来事だった。そのうち詳細な post-mortem が Day One のエンジニアによって公開されるようなのでこちらもあとで読んでおきたい。

あまりに復旧が遅かったのでこのままサービス終了するのではないかと心配になったが、何とか復旧出来たようである。 Day One のバックエンドの皆さんおつさまでした 🍵

🤩人気記事を表示するようにした - portal shit! で人気の記事を表示するようにしたけど、人気のエントリー(直近一ヶ月間でアクセス数が多い記事)に加えて、ホットエントリー(はてなブックマークでブックマーク数が多い記事)も表示するようにしてみた1ところ興味深い結果になった。

スクリーンショット 2018-02-08 10.09.53.png

短期的に膨大なアクセスを集める記事と長期的に安定したアクセスを集める記事は全く異なる。はてブのようなサービスで見つけられるのは前者で、後者のような記事を見つける場所が意外にネットにはないのではないかと思う。前者を動的な人気記事だとすれば、後者は静かな人気記事だと言えるだろう。こういう静かな人気記事だけを紹介するウェブサービスがあっても面白いのかもしれない。ちなみに人気のエントリーのリンク元は Google を除くとだいたいヤフー知恵袋か 2ch の過去ログが多い。


  1. このサイトの はてブの RSS を利用しています