ベルリンのITスタートアップで働くジャバ・ザ・ハットリの日記

日本→シンガポール→ベルリンへと流れ着いたソフトウェアエンジニアのブログ

個人開発したウェブアプリに対して好き放題に感想を言ってもらいたい!願う!

個人開発したウェブアプリnode-node-nodeを先日公開して、ログ解析しても何しても、これからどうすればいいのか本当に分からないので率直な感想ください、というお願い。

今日で公開して3日なんだけど、アクセスはまずまずで、とにかくユーザーや投稿などの登録数が少ない。個人開発してる人は共通であると思うのだが、公開前までは自分のプロジェクトに惚れ込んでいる訳でして。恥ずかしいけど「これは世界を変える!」とか思ってしまう。

しかし完成していざ公開すると白昼の目にさらされて現実的には1日に700PVしかなく登録数もほんのわずかだけ。「え?なにこれ?全然ウケてないのか?この企画?」となっていろいろログ解析するけど、どこをどう改善すればいいのかまったく不明。

どれだけページ遷移やら数字眺めてもユーザー思考のしの字も分からない。もうここまで来たらハッキリとユーザーの皆さんから「○○がイケてねーんだよ!」と分かりやすく教えていただけますか?、と。

今回の経験を経て私もユーザーの立場で誰かが作ったウェブアプリにアクセスしたら、できるだけ素直な感想を書こうと思った。やっぱり個人開発のアプリはリソース足りてないし、どこかイケてないことが多い。正直、他人のアプリを見て「うわーこんなクソなモノをよく公開したな」と思ったこともある。ただクソでも作った人の苦労とか感じて悪い気がして「イケてない」の一言を伝えることができていなかった。

今だから分かる。「クソ」と思ってそっとブラウザを閉じられるのが一番キツい。クソならハッキリと「クソだ」と言ってあげるのが作者にとって有用なのだ。

ツイッターで呟いていただいた感想を見たけど、なんかちょっと褒め気味。それはそれで嬉しいけど、じゃあなんでこんなに登録数が少ないんだよ、と。なにかを改善するべきでその答えを知っているユーザーが無言でブラウザを閉じていることだけは分かっている。
なになんだぁああ!!出て行く前になんか言ってくれー!

しかしこう言ってはなんだが、このウェブアプリが仮にスベっていたとしても一定の効果はあると思っている。それは私がこのブログで主張している、海外でITエンジニアとして働くにあたって「あーこの程度のコーディングで海外行けるんだ」と思ってもらえること。おおーそうだよ。この程度でのうのうとヨーロッパでエンジニアやってますわ。ここまで来たら恥も外聞もねーわ。

こちらに「node-node-nodeに言いたい放題」を用意しました。匿名です。名前書くと思いっきり書けないかも、と思ったから。
書くのが面倒くさかったら点数だけでもOk。10点満点で「ナン点!」と言ってやって。
ぜひ率直な感想をお願いします!
https://goo.gl/forms/eXIkx3oNDdNmA6If2
node-node-nodeに言いたい放題


ちなみに公開したウェブアプリはこちら。(デスクトップ版のみです)

エンジニアの集合知をノードグラフで図解するSNS。
「node-node-node(ノード ノード ノード)デスクトップ版」
 https://www.node-node-node.com/

tango-ruby.hatenablog.com

GraphQLを導入してみて得た知見と雑感。GraphQLはタイタニックの救命ボードになりえるかも

GraphQLは実装内容に合えばタイタニックの救命ボードのように混沌から救い出してくれる。だからと言って全てのプロジェクトがタイタニックな訳ではないので、使い所が合わなければそんな救命ボードにもあまり意味は無い、という話。

先日、個人開発して公開したプロジェクト「node-node-node」はGraphQLを使っていて、このプロジェクト内容に対しては最高の親和性を発揮してくれた。

GraphQLのメリットを一言で言えば「クライアント=サーバー間での複雑なトランザクション処理の全てをGraphQLが吸収してくれる」ということに尽きる。ややこしい技術の詳細を書いたところでメリットはこれ以外に無い。

/usersや/postsというそれぞれのエンドポイントにリクエストを投げていたのがRESTful。
f:id:tango_ruby:20180208211439p:plain

GraphQLにするとエンドポイントを気にすることなく「これとこれが欲しい」という感じで投げればGraphQLが理解して返してくれる。
f:id:tango_ruby:20180208211502p:plain

なぜ個人開発のプロジェクトにGraphQLが大ハマりしたかを書く。このプロジェクト実装のポイントはRESTで言う複雑なGETにあった。

親子関係が何回も続く階層構造になったノードがサーバー側のDBにあって、クライアントは適切なノード情報をサーバーから取り寄せる必要がある。全てのノードは以下のようになっていて、親子関係がずっと続く。

ジジイ、ババア、ジジイ、ババア
|
親、親、親、親
|
本人、兄弟、兄弟、兄弟
|
子、子、子、子
|
孫、孫、孫

できるだけサクサク感を出すためにクライアントはユーザが今アクセスしているノードから次にクリックするかもしれないノードの情報を非同期でサーバーから集めている。ユーザーがクリックするころには既に裏側で集めておいた情報を出すだけ、とした。
この設計の場合、ユーザの置かれた状況によって、裏側で集めるべきノードが異なってくる。

例えば上のジジイ側から本人へ下りてきたユーザの場合、裏側で集めるべきノード情報は子や孫だけになる。なぜならジジイ側から下りてくる過程で既に本人より上の親ノードの情報は持っているから。
逆に孫側から上ってきたユーザーの場合は集めるべきは親やジジイになる。上がってくる過程で子ノード以下の情報は持っていることになるから。
兄弟の兄側から来た場合は末っ子側のノード情報が必要になる。

で、これを丁寧にRESTfulで書いていくとすごい数のエンドポイントになっていった。

ざっくりと親から、子から、兄弟からと3パターンだけ示したが、それ以外にもLikeした情報がある場合、無い場合、とかそれぞれのエンドポイントに独自の情報の有り無しを加えていったのでパラメータまで煩雑な状態となっていた。私はDHHのルーティングを支持しているのでCRUDアクションindex、show、new、edit、create、update、destroyのみを使うようにして、これ以外が必要な時は新しいコントローラーを作っていた。するとスゲー数のエンドポイントになって、Reactで作ったクライアントは状況に合わせてエンドポイントを使い分ける必要があって、どれがどれか混乱してきて「キー!」となった。

で、これをGraphQLに移行することでクライアント=サーバー間にあったややこしい部分をクエリ言語が全て吸収してくれた。クライアントからは欲しい情報を書いてリクエストすれば、それをそのままサーバーが返してくる仕組み。
そしてエンドポイントはたったひとつに、バージョンも何もない、ただひとつ!

例えば親側から来たユーザー向けに子情報が欲しい時のリクエストがこれ。要はchildrenをよこせ、と。

# client => server へのリクエスト(query)

query {
  Nodes {
    id
    message
    children {
      id
      message
    }
  }
}

するとサーバーからのレスポンスはこうなる

# client <= server レスポンス
  "data": {
    “Nodes”: {
      “id”: 3,
      “message”: “Hi I’m CEO.”,
      "children": [
        {
          “id”: 4,
          “message”: “Hi, I’m CTO.”
        }
      ]
    }
  }

つまりリクエストとまったく同じ形でレスポンスが返ってくる。
親情報が欲しければただリクエストにparentをつければいいだけ。めちゃ楽ちん。

ページネーションはこんな感じに実装した。例えばたくさん子ノードがあって3ページ目が欲しい場合はchildren(page: 3)とするように。

query {
  Nodes {
    id
    children(page: 3) {
      id
      message
    }
  }
}

ほとんどのウェブサイトにおいてクライアントが欲しい情報が1種類ではない。記事情報とユーザー情報とそのユーザーへの通知情報、となったりする。RESTfulの場合はそれぞれを

GET api/v1/users
GET api/v1/posts
GET api/v1/notifications

という感じで3回リクエストしてそれぞれの情報を集める。

GraphQLの場合は全てを1発のリクエストにして放り込める。

例えばこんな感じで、PostsとUsersとNotificationsをまとめてよこせよ、と。

query {
  Posts(page: 0) {
    id
    message
  }
  User {
    id
    name
  }
  Notification {
    id
    status
  }
}

するとこの型のまま記事とユーザーと通知の情報の入ったレスポンスがひとかたまりで得られる。クライアントからすれば欲しい時に指定した欲しい情報だけが取れる。(最初これを実装して本当にその通りにレスポンスが返ってきた時になぜが声出して笑った。)

限りなく薄いGraphQLが理想

ある記事でRailsにGraphQLを入れた場合、MVCで言うところのMVC全てがGraphQLに集約されてしまう、みたいなのを読んだ。これ明らかにおかしい。初めてGraphQLに出会った際には「これスゲー!」と興奮してなんでもGraphQLに入れ込みたい気持ちは分かるが、そんなことしろ、なんて公式サイトのどこ見ても書いてない。ファットコントローラーと同じくファットGraphQLはメンテナンス不能でたちが悪い。

GraphQLの作者Lee Byron氏も言うように「なんでもできるGraphQLだが、GraphQLはできるだけ薄く保つのがいい」と。GraphQLの責務と役割はquery(RESTfulのGET)とmutation(POSTもしくはPATCH)だけであって、それ以外は無い。したがってresolve ->(obj, args, ctx)の中にロジックがあったら、その責務はどこが持つべきか考えてそこに移すべき。

GraphQLが遅いって?それ設計の問題では

GraphQLのディスり記事にスピードに関する言及が多かった。例えば「まともにキャッシュが効かねー」とか。これは間違い。もう既に数々のキャッシュ方法がクライアント、サーバー共に提案されている。実際、前述のnode-node-nodeにおいてもキャシュを入れている。大きめのqueryでキャッシュ無しだと300msかかっているレスポンスがキャッシュで3msとかで返すことができている。そこはキャッシュ使うので当たり前なんだけど、スピードを議論するのであればキャッシュどうこうではなく、クライアントが欲しい情報を何msで取れるのか、とすべき。多少GraphQLのあるクエリが遅かったとしてもリクエストを1発でまとめて入れてるのでRESTfulで5、6回繰り返して「はいできました」となるまでにかかる時間と比較して必ずしも遅いとはならない。

N+1問題

GraphQLはN+1問題を誘発する、というディスり記事もあった。もうこれはハッキリしていてN+1問題なんて出てる時点でそれをクエリ言語のせいにするのはお門違い。確かに気付かないところでN+1を含むおそれはあるが、百歩譲ってもそれGraphQLじゃなくて、あなたの設計の問題ですから、と。

GraphQLはちゃんとハマればハッピー

本記事の冒頭でGraphQLをタイタニックの救命ボートに例えたが、既存のプロジェクトの船底に穴が空いて沈みかけてるのに船の上で上品なお食事を楽しんでいる人達みたいに気付いていないだけ、というのがよくある。熱い技術なのでGraphQLが合うかどうかぐらいは確かめた方がいいと思う。

以上がGraphQLを使ってみて得た雑感でした。


これがGraphQLで実装したプロジェクトです。よろしければぜひお試しください!
良くても悪くても叱咤激励のコメントお待ちしています。(反応無しが一番辛い。。。)

エンジニアの集合知をノードグラフで図解するSNS。
「node-node-node(ノード ノード ノード)」
 https://www.node-node-node.com/


tango-ruby.hatenablog.com
tango-ruby.hatenablog.com
tango-ruby.hatenablog.com
tango-ruby.hatenablog.com


tango-ruby.hatenablog.com

エンジニアの集合知をノードグラフで図解するSNSサイトを作った。「ノード・ノード・ノード(デスクトップ版)」

サイトコンセプトはエンジニアの集合知をノードグラフにして図解するSNS。
サイト名は「node-node-node(ノード ノード ノード)」。デスクトップ版のみ。

エンジニアの集合知をノードグラフで図解するSNS。
「node-node-node(ノード ノード ノード)」
 https://www.node-node-node.com/


考えたのは「新しい技術を学ぶ時に各技術要素の関係が分かりにくい。ググればピンポイントで内容が分かるが各技術の関係は不明なまま。そこを集合知を使ってシステムが自動的に図に示してしてくれればいいのに」と。

トップページはこれ。

f:id:tango_ruby:20180205184519p:plain

親ノードについた子ノードはパラっと開いて、グリグリとドラッグできる訳でして、こうして階層構造の技術リンクをマッピングしていけば理解しやすいかな、と。

f:id:tango_ruby:20180205204551g:plain


例えば私の専門はバックエンドなのでインフラやバックエンドの処理はそれなりに把握しているが、JavaScriptをはじめとするフロントエンドの知識はあまり無い。今回のnode-node-nodeのフロントエンドはReact+Reduxで作っていて、その技術情報を手探りで集めてコードを書いた。するとフロントエンドの専門家なら常識でも、専門外の人からは謎な用語がポンポン出て来る。

npm, Babel, webpack, ES2015, Enzyme、とか。

これらの用語についてはググればヒットするし、一応は分かる。仮にnpmがナニなのか知らなかったとしても、ググれば一瞬で分かる。それでも本当に分からないのはこれらの技術要素の関係。各々の技術については分かったつもりになっても、npmとES2015はどんな関係なのか。それぞれ把握しておかなければならないのか、その技術の関連性はずごくあるのか、またはまったく無いのか、などだ。

ここでは誰もがよく知る技術用語だけをピックアップしたので「そんなもん分かるだろ」と思われたかもしれないが、以下のサッカー戦術用語の場合はどうだろう?

トータルフットボール、ゼロトップ、ミケルス、オフザボール、ポゼッションサッカー、ゲーゲンプレス、4−4−2、ゾーンプレス、アリーゴ・サッキ

これらの用語の相互関係が頭の中に描ける人はある程度サッカーに詳しい人だろう。サッカーに詳しくない人でも、用語をググれば分かる。でも各用語が分かったとしても現在のサッカーシーンの主流戦術や、今までの歴史を俯瞰した概念はなかなか得られない。
そこは「各要素の関係図」を示してもらえれば分かるし、初学者が学ぶ際に役に立つ、というのが本サービスのコンセプト。

これはRailsに必要な技術をマインドマップに示した図。分かりやすいが、そもそもこれを作ったのはきっとRailsのエキスパート。
f:id:tango_ruby:20180205030352p:plain:w400

こういうのはひとりのエキスパートに頼るよりも、ネット文化に添って集合知を結集して自動作成されるようにしたかった。「人気のあるノード=有用なノード」として目立つ場所に出てくるようにした。

例えばJavaScriptはこんな感じ。
f:id:tango_ruby:20180205205225p:plain
そもそもJavaScriptの初学者はフレームワークとしてReactやらAngularJSがあって、それらがJavaScriptである、ということから理解する必要がある。で、このノードのつながりを見れば一目瞭然かな、と。

早くたくさんの人に使っていただいて、もっといろんなノードが付いて欲しいなーとか思ったりしている。


モバイル版を無視して、デスクトップ版しか出さないのはいかがなものか、というご指摘もあるかもしれないが、基本的にPCでコードを書くエンジニアに向けたサービスなのでご了承ください。とにかく公開してその後のサービスの使われ方を見て変更をかけていくつもり。

ご自身が書いた技術記事が有用だと思う方や、他の人が書いた役に立つ技術記事をご存知の方は、ぜひその記事リンクを貼ったノードを作っていただけますでしょうか。
原理的にはどこまでもスクロールできるほぼ無限大に大きなノードグラフができる。
いつの日か考えもしなかったような巨大な集合知のノードグラフがnode-node-nodeにできていることを願って公開した。


使った技術
個人的にはGraphQLがこのサービス内容に対しては最適だったな、と。
料金はドメイン登録料だけで他は無料で済ませることができた。GCPの永年無料枠サイコー。

Front-end

  • React
  • Redux

Back-end

  • Ruby 2.5
  • Rails
  • GraphQL

Infra

  • Google Cloud Platform
  • heroku
  • MongoDB
  • Redis
  • Cloud flare
  • SendGrid
  • NewRelic

エンジニアの集合知をノードグラフにして図解するSNS。
「node-node-node(ノード ノード ノード)」
 https://www.node-node-node.com/

良くても悪くても賞賛でも罵倒でもなにかコメントか反応いただければ嬉しいです。反応ゼロが一番辛い。。。