timakin.log

╭( ・ㅂ・)و ̑̑

#attefes Mercariのatte FeS【Go・Swift開発編】行ってたけど最高

どうもtimakinです。先日株式会社メルカリ様のグループ企業である、
ソウゾウ様の、「メルカリ アッテ」リリース記念のMeetupに行ってきました。
控えめにいうと最高で、技術勉強会という面から見ても非常に記憶に残る会でした。

何が最高だったか

・Go,GAE,RxSwiftという、本番導入の際に目新しさがありつつも、それをどう導入検討したか、実際書くときにどんな機能でそれが必要かが詳細に語られていて、実際に自分たちも使える可能性があるな、と強く意識できた点。
・技術要件だけでなく、ビジネス要件、組織として最適な形であるためにどんな技術を選択するべきか考慮された話だった点。
・技術面のトークに終始しており、参加者側として集中が途切れなかったところ。(むしろアッテ自体の紹介やリクルーティングの時間がほぼなかったのですが、逆に技術的なアピールポイントがあれば人は自然と寄ってくるという余裕があるように見えたので、好印象でした)
・ビール

印象的だった点

http://blog.mogmet.com/attefes-go-swift/blog.mogmet.com


プレゼンの網羅的な内容はこちらに記載されているのを見た方がより良いと思うので、印象的だった点を書いていきます。

鶴岡 達也さん【atte開発の技術 -GolangGoogle Cloud Platform-】

DAU数千万、グローバル展開、モバイルファースト前提という要件のお話しをまずされていました。
アークテクチャの一貫性を重視されていて、メルカリ時代に予想を上回る勢いでアークテクチャが変化していったため、その反省点を生かして、一貫性を重要な評価軸にしていたそうです。
ただ一貫性があれば保守的であっていいかといえばそうではなく、将来を見越してエンジニアにとって魅力的で、多様性のある技術開拓の場であれるかという観点も加えられていました。

GCPを検討する際には、Google担当者の方に1ヶ月ついてもらいつつ検証してみたということもあり、行動力とより客観的であろうという姿勢が魅力的でした。また逆にGoogle社も、数年前とは大きく状況が異なっていて、サポートが充実しているため検証もしやすかったそうです。

Goに関しては、もともとメルカリの方がミドルウェアでノウハウが溜まっていたとのことで、僕自身もwidebulletのスライドを見てすごいなーと勝手に思っていて、まあ主な導入理由はそこだろうという考えで行ったら、それに止まらず、割と初心者で固まって開発していたそうです。

widebulletについては以下参照。JSON-RPCのリクエストをnginx前段に立てて、REST API形式で叩くように変換してくれるミドルウェアらしいです。

speakerdeck.com


社内にGolang界ですごい人(gaurunやwidebulletのコミットからしてcubicdaiyaさんとかだと思いますが)がいたが、あえてGo初心者でチームを固めて、初動の学習コストをはかりに行くという大胆さについてお話しされていました。
それでも導入できたのでGolangの導入ハードルは低いというのを体を張って証明されていたようでした。

GAEの話に移って、主にハイスケーラブルであることを考慮して、NoSQLモデルを選ばれたとのことでした。
また、GAEについてるリアルタイムログ機能のおかげで、ビジネスサイドの分析時に有用になるデータのトレーシングが簡単にできる点もよかったとのことです。

あとかなり驚いたのが、Goをベースに立ってるインスタンスが、起動までに200msかからないとのことでした。

大庭 慎一郎さん 【SwiftとRxSwift】

このプレゼンが一番実際のスライドがあったら嬉しいのですが、前半に型の安全性を考慮して、SwiftやJSONRPC-kitを採用されたお話し、中盤からはRxSwiftを題材にリアクティブプログラミングのお話しでした。

必要な処理をストリームという単位で扱い、加工、フィルタリングを行う方式で、その実用例をコードを見つつ解説されていました。
インクリメンタルサーチや画像アップロード機能等、どの画面で必要になりそうかがわかる実例ベースで説明されていました。
RxJSでワイワイ言われてるときに入門し損ねたタイプだったので、非常にありがたく、mapとかreduceとかガンガン使っていけて、一つの処理をまとめられると確かに無駄にメソッドに切り出すこともなく綺麗でした。

ただ一方で、大庭さんご自身が「リアクティブプログラミングに慣れすぎると、一からこの処理を書けって言われたときに案外忘れそうになって不安になる。プログラミング力が下がる恐れがある」とおっしゃっていて(実際大庭さんが下がっているとは思えないのですが)、隠蔽される箇所が多くなるのと、書き方間違えると他人に読みにくいコードになるだろうから、使う場所は最初は限定した方がいいかもなと思います。

石川 洋資さん 【アッテiOSの設計と開発フローの変遷】

Try! Swiftでご登壇されていた石川さん。
iOSがどうこう、というよりは、処理の共通化とキャッシュ戦略についてでした。

ページネーション、フォームのバリデーションなど、多くのページで共通で用いる処理をどう共通化するか、と言うお話で、Swiftプロトコルで処理のI/Oを記述しておき、実際の処理では全画面共通の機能を入れるとのことでした。それだけ聞くとまあ、という感じですが、実際にページネーションを例に、ページのリクエスト情報を受け取り、レスポンスと次のページがあるかというフラグを返すプロトコルにしておき、そのページをどう扱うかは各画面専用のクラスに任せており、責任の分割が綺麗にされていました。本当に共通化しているところがどこなのかを見極めて、小さな範囲でもそこだけは最低限安全に保つという方が、最終的に共通の処理を書き直してさらに共通化して...というような流れを踏まずに済みそうです。

キャッシュ戦略については、RealmとLRUディスクキャッシュ
のお話しでした。当初Realmで全てキャッシュしていたものを、レスポンスの永続化と、各画面で共通に変更を見たいようなデータの保存先として集中させる方針をとったそうです。というのも、基本的に大事なデータはサーバーが持っていてくれるだろという信頼がある前提で、捨てていけるデータは捨てていこうということでした。限られた範囲のビューで完結するキャッシュは、LRU(最近最も使われていないデータを最初に捨てることで、不要なデータをパージしてキャッシュ効率を上げる)という方式で、キャッシュを行っているそうです。

LRUキャッシュ実は勉強不足で知らなかったので帰ってgoのソースを見てたのですが、仕組みとしてはGetしたタイミングでList.MoveToFrontで要素を一番最初に持ってきて、Addしたタイミングで最も古いもの(リストの最後尾)を除去するという流れで、割とシンプルなオンメモリキャッシュでした。

参考

github.com

まとめ

総じて最高だった。
アッテチーム内で完結したノウハウではなく、今後参加者が学習 or 導入する上で踏みそうなポイントを踏まえて、概念の説明をしつつ導入でクリアした課題をお話しされていて、各位の強さが伝わってきました。

あと本当に凄いのは、最近話題になってた以下の記事であげられてる課題点が全てクリアされたプレゼンで、学習した実感がしっかり持てたことでした。本当に貴重なお話しをありがとうございました。

shin1x1.hatenablog.com


もっとこうして欲しかったところ

・正直トークの内容がよすぎてあんま気にならなかったのですが、最初マイク不調すぎだったので、よりよいマイクを...!
・登壇者の方だけで語り尽くせない部分もあったと思うので、もっとメルカリ社の方々とお話ししたかった気持ちもある。

余談

・ソウゾウの方々、自社のことをソウゾウ社って言ってて、最初なんやなんや世界を創ったんかという気持ちだったが、最終的にこれ言えると気持ちいいやつだなとほっこりして帰りました。
・個人的に懇親会も最高だった。
・mono-repositoryで開発されてるとのことだったのですが、マイクロサービス化とか検討しなかったんですか云々という質問をして、アッテのトートバックをもらいました。ペンギンがかわいい。

f:id:u_tis:20160420001802j:plain

以上だ!また勉強があったら行きたいです!

日本のWebエンジニアの大半と英語

d.hatena.ne.jp

なんか道すがらtwitter追ってたら例のごとくタイムラインが定期的な英語熱に見舞われてた。
原因が上記の記事っぽい。

偉そうに言えないけどツッコミたくなる点が多くて、主な意見としては

  • グラフを描くためのサンプル数とその中身
  • 取り上げる技術
  • 英語による成長角度の変化

といった点に筆者の個人的なバイアスがかかっていて、
大きすぎる主語と多大なミスマッチを起こしている、というのが違和感の根っこだと感じました。

僕も一応、この筆者が前回書いた技術は一通り試しましたが、自分がそれを勉強することでコストをかけた結果、
エンドユーザーが享受する価値が劇的に変わるのか確信が持てなかったので、
正直モチベが下がってしまったタイプです。(採用例意外と多いっぽくて学習しなきゃと思いつつ...)

なので、それに関しては言及する資格がないと思っています。

英語がわからない日本のエンジニア

一方、英語による成長度合いについての話は、自分の原体験と食い違いすぎている。
だいたい、英語がわからなくて成長が阻害されているエンジニア、見たことがない

「英語を先に学んでからプログラミングを勉強した方が、圧倒的にプログラミングの学習効率が高い」

この、英語とプログラミングの学習順序が逆になる人、
英語が原因で成長が阻害されるようなエンジニアって、本当にいるのかとすら思ってる。

業界の先駆者が英語を勉強しろって言ってるのって、単純に英語を読めるようになれとかじゃなくて、
ネイティブレベルで理解できるようになったりする話なのかと思ってた。
OSSでコミットメッセージ書くときや、フォーラムで議論するときに伝わりやすい文脈構成とか、
海外にいってミートアップで会話するときにパッと英語が出てこないときつそうだし、
そのための勉強をしとかないと、海外を視野に入れたエンジニアとしての働き方はできないゾ!という主旨なんだと。

その主旨で英語を勉強しようと言われるとわかるんだけど、そうでない限り英語が差別化要因になると全く思えない。
この筆者が言及してるレベルで英語に困ってる人、かつその結果プログラミング学習にも困ってる人、まじで見たことがない。
むしろ周り割と喋れる人多くて、「どんな記事ウォッチしてるんですか?」って聞いたときに
海外のサイトを候補にあげたり、ドキュメント読むときに書籍以外はほぼ英語とか、そういう状況になるのが自然で、
「ああ〜この業界英語リテラシー高いな〜みんなすごいな」くらいの所感だったので、そういう意味で原体験と大幅に食い違う。

英語を学べと言われる側として

凄腕ハッカーが英語は勉強しようってよくおっしゃってて、”エイゴは大事”みたいな雰囲気なんだけど、
そのアドバイスが受け取る側のレベルに合わせて曲解されると、これほど誤差を生む話題はそうそうないよな、と思っています。

凄腕ハッカーの方々、githubのスレで延々と議論してるタイプの方とかいて、
そういう方が「英語を勉強しておくと将来役に立つし、エンジニアとしての生命線になりますよ」とおっしゃったとする。
そのときに受け取る側が「俺もドキュメント読むときに文法整理できなくて読むのに時間かかるんだよなー」という
視点で理解すると、目的意識というか、視点がズレててヤバイ。結局生命線がなくて死に至る気がしている。

英語に関するアドバイスって、受け取る機会が大変多いので、
発言されている方がどんなバックグラウンドを経ているのか考慮しないと後々苦労する気がしている。
解釈によっては、もはや言われるたびに自分の英語へのハードルを見直さなきゃいけない文脈なので結構つらみがある。

まとめ

上記全て違和感の表明であり、割と取り止めがなくなりました。
僕の個人的なバイアスがかかってると思うので、強めに握った拳で反論する気はないです。
主張としては、「英語を学んで真にアドバンテージになる世界って結局コードを多量に書かなきゃ辿りつけない世界だろうし、
エンジニアの成長要因として真っ先に英語を題材にするの、曲解を生むのでよくないと思う」ということでした。

assets precompileがメモリ不足で失敗する

エラー内容

CapistranoAWS EC2インスタンスにdeployする時に、 以下のようなログが出てassets:precompileのタスクでプロセスが強制終了する。

SSHKit::Runner::ExecuteError: Exception while executing as xxx: rake exit status: 137
bash: line 1: 20652 Killed                  /usr/local/rbenv/bin/rbenv exec bundle exec rake assets:precompile
rake stderr: Nothing written

原因

結論としては、メモリ不足により強制終了されてました。(つまりメモリを多く積んだマシンを借りれない金の問題ということ) スワップ領域を拡張して処理落ちしないようにする、というのが解決方法です。

調査

エラーメッセージでググると以下のような参考記事が。

stackoverflow.com

When this is combined with lots of sass/css, the process uses tons of memory, and the OS kills it

と書いてあって、メモリ不足で停止するのか?という仮説が立つ。

sudo tail -n 100 /var/log/messages

で、EC2上のログを出力すると、

Apr  5 15:16:31 ip-10-0-0-196 kernel: [2691172.158997] Out of memory: Kill process 24684 (ruby) score 314 or sacrifice child
Apr  5 15:16:31 ip-10-0-0-196 kernel: [2691172.162226] Killed process 24684 (ruby) total-vm:1237852kB, anon-rss:318164kB, file-rss:888kB

完全にメモリ不足で落ちてる。 「メモリ不足 assets compile」等でググったりしていると、

参考記事として以下が出てくる

qiita.com

upsnap.jp

qiita.com

EC2インスタンススワップ領域を増やせばいけそうなので、下記をインスタンス内部で実行する

sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
sudo mkswap /swapfile
sudo swapon /swapfile
sudo vim /etc/fstab

# 下記を追記
/swapfile swap swap defaults 0 0

その後、インスタンスを再起動したのち、デプロイすると、 スワップ領域が有効になったことで、OOMで強制終了されなくなりました。

わざわざ「React/Reduxって本番採用されてるんですか?」って聞く必要はなかった

React、もう「この技術はすぐ枯れないのかなあ」みたいなことを考えながら、割と長い時間がたった気がします。 Fluxフレームワークが乱立して、FluxxerやRefluxやらが使われた時期を通り越して、各フレームワークが「Reduxはいいぞ。そっちにいけ」みたいなことをREADMEに書き出した頃からさらに時間が経ち、React/Reduxがデファクトスタンダードになったように思います。

あるいはReduxとか使わずにFacebookのFluxライブラリ(Dispatcherのみの実装)だけ 使ったアプリなら書いたことある、とかは、周りで聞く限りありました。

React/Reduxの本番導入について

割と入門記事とか、Reactコンポーネントかくあるべし的なLTの資料とかはよく拝見する一方で、 うちは本番でこういう風に使ってますみたいな事例がなかなか見当たらないなーと思ってたところ、 Reduxの公式Issueにこんなものが1年近く前からありました。 周囲の友人とかに聞いても、管理ツールで導入するくらいの印象だったので、 ちょっと調べて見たところ、こんなものがありました。

github.com

Reduxをもし本番で使ってたら教えてくれ、という趣旨のスレなんですが、 ここにReduxを本番で使ってる or 今は準備段階で一部だけ採用してるけど、後々置き換えるよというサービスが載ってます。 大きなところだと、

  • Uber
  • Treasure Data

とかが採用してます。 日本企業だとランサーズさんも使ってたり、chibicodeさんのEdSurgeでも使ってるみたいです。 あと結構驚いたのが、Reduxであるかは定かではないですが、静的ページ制作のWixも、編集画面がReactで構成されてます。 結構採用事例としては思い切った導入の仕方で、たまたまソース見てかなり驚いた覚えがあります。

公式のIssue等でこういう事例をまとめておける場所があると、導入事例としてOSS開発者側も紹介しやすいし、 新たに導入する企業の人も意思決定の参考にしやすいと思うので、 新し目のソフトウェアではこういった資料が見れるとありがたいですね。

Goのインメモリキャッシュ用ライブラリ「go-cache」のご紹介

github.com

利用した動機

Perlで言うCache::Memory::Simpleのように、

メモリキャッシュを取り扱うためのライブラリを探してたら、

速攻見つかったので利用してみた。

ユースケース

今GithubAPIを利用したCLIツールを作っている。

その際にユーザーのリポジトリ情報とか取ってくるんだけど、 それを一度ならず繰り返し叩きに行く。

for分回している中で関数を呼んで、その中でAPI叩きに行く実装が入ってたら死ぬ。

なので結果を都度キャッシュしておけるようにgo-cacheを利用した。

内部実装

中身、非常に簡単で、Set用のキーをそのままcacheが内部で持ってるmapのキーとして使ってる。

この中にはunnamed typeなobjectと、有効期限を表すintを持った構造体が入ってる。

どこかに共通のキャッシュインスタンスみたいなのを持っておけば、有効期限まではその中のmapを参照して、キャッシュを得ることができる。

利用方法

あるプロセスの中で繰り返しキャッシュを参照したい場合は、一つのキャッシュ用のインスタンスを利用する必要があるので、以下のようにした。

// キャッシュを利用する場合にそれを格納するためのインスタンスを作る
type Instance struct {
    cache *cache.Cache
    client *github.Client 
}

// インスタンス作成用のメソッド
func New() *Instance {
    httpClient := newAuthenticatedClient()
    client := github.NewClient(httpClient) 

    I := &Instance{
      // 特定のキャッシュを5分間だけ残しておく
      // 30秒ごとに失効済みキャッシュを廃棄する
        cache: cache.New(5*time.Minute, 30*time.Second),
        client: client,
    }

    return I
}

// 自分のユースケースだとGithubのNotification情報を取ってくるので、こんな感じ
func (i Instance) GetNotifications() []github.Notification {

  // cv(cached valueの略のつもり...)
  // キャッシュがあれば取ってきてそれを返す。
  // go-cacheでは第2の戻り値に、キャッシュの存在有無のフラグ(以下ではfound)が入ってくる。
    if cv, found := i.cache.Get("notifications"); found {
        cachedNotifications := cv.([]github.Notification)
        return cachedNotifications
    }
    
    // APIからのresponse
    opt := &github.NotificationListOptions{All: true}
    notifications, _, err := i.client.Activity.ListNotifications(opt)
    if err != nil {
        log.Fatal(err)
    }
    
    // キャッシュがなかった場合は次回のためにSetする
    i.cache.Set("notifications", notifications, cache.DefaultExpiration)
    return notifications
}

総括

Goの利用ケースってjson等々の返却用のAPIか、CLIを作るような気がする、

というかそんなことをGopher Nightで渋川よしきさんがおっしゃってるし、

僕とかもCLIツール作るときに利用してる。

www.slideshare.net

自分が今作ってるツールだと、並行して複数APIを叩くことがないので、

goroutineを使うまでもないけど、そのような場合でもgo-cacheを使うことができれば

尚一層早く処理が終わるのではと考えていて、これはよいものだと思う。

DeNAを辞めて2週間が経った件と進捗

ご報告

タイトルの通りで、2016年1月末日で株式会社DeNAを退職してた。
今はトランスリミットというベンチャーで働いてる。
2週間報告をしなかったのは、しっかり振り返りの時間を取りたかったから...というわけじゃない。
普通にプライベートで色々あったり、友達と飯食ってただけで、つまり惰性。

退職エントリとか書くほどのアレもないけど、周りの同期に煽られたなそういえば、
書かなきゃなあと思い続けて早2週間がたったので、煮え切らない感じを断ち切るために書く。

厳かな退社

お世話になった先輩方や同期に見送ってもらい、非常に厳かな雰囲気の会がいくらか開かれた。
先輩方との飲み会はなかなか写真もなかったが、
同期に送別会を開いていただいた際には記録のために写真を撮った。

みんな、涙を流して別れを惜しんでくれた。
しんみりと、大人っぽいムードで酒を飲み交わした。
今後の将来について語り合う最高の同期を得て僕は感動している。

f:id:u_tis:20160214172147p:plain f:id:u_tis:20160129205410j:plain f:id:u_tis:20160129205922j:plain f:id:u_tis:20160129212036j:plain f:id:u_tis:20160129214925j:plain f:id:u_tis:20160129230104j:plain

完全に学生だった。
スマブラで花を持たせるとかそんなことは一切なく、スミノフを無尽蔵に
消費するだけの実りのある会だった。
ともあれ最高の同期を持ったというのは間違いなくて、今もその繋がりを大事にしてるし、
なんなら翌日普通に飯食ってた。
さらには2日前にも飯食ってたしもう家族。

繋がりを〜みたいな話をすると、クックパッド、DeNA、サイバーの同期とは今も一部結構仲良くしてて、
sotomukiという名前で集まりを作っている。
以下の会のときにできた集まり。

techlife.cookpad.com

この前はみんなで登山(肉)をした。
渋谷にはヒマラヤというどでかい肉を出す店があって、そこでみんなで肉を食い荒らす会をした。

f:id:u_tis:20160131192616j:plain

f:id:u_tis:20160131214424j:plain

肉が当たって高熱を出して苦しんだ同期がいたらしく、芸人魂が輝いててやはり最高の同期最高の仲間だと思った。
溜まった知見としては、やはり肉はどんだけでかくてもちゃんと中まで焼くということ。

進捗

年末とかはitamaeいじったりしてたし、capistranoプラグインとかちょくちょく書いてrubygemsにあげたりしてた。
でもそれより大事な進捗があって、社会人としての自己管理用にbotを作ってた。

一瞬真面目な話を書くと、僕は振り返り作業というのが苦手だ。
ブログを書くのもそうだし、文章を打ってたり、過去のことをまとめなきゃいけないとき、思ったより労力がかかっててぶっちゃけめんどい。

でも、DeNAでやってたのはその性格と全く逆のことで、分報とか書くようにアドバイスをもらった。

c16e.com

これは僕の性格とは反対だけど、でも詰まったら長く考えがちでいつのまにか問題が整理できなくなるとか、
優先順位付けがバラバラになったり、見積もりがが長くそれがちだったりする僕にはマッチしていた。
これを勧めていただいたことに関して深くお礼申し上げたい。

ともあれ、こういうのベンチャー行ったりすると、フェーズによっては誰が育ててくれるわけでもない状況になったり、
新卒じゃなくなった瞬間にこういう振り返りがおろそかになって、自己成長が鈍化するのが、特に僕の場合は目に見えていた。

なので、以下のようなbotを作った。

github.com

名前をganbaruzoiという。
もちろんNew Gameは全巻買ったし読んだ。

ganbaruzoiについて

これは何をしてくれるかというと、分報の結果日報を生成してくれたり、
見積もり、そしてその修正があったときに全部日報に記録してくれる。
また、日々の課題意識とそれに対応して今日ないし今週どうするみたいな、
自分でKPT的なレビューとアクションを回せるようなフォーマットになっている。
ちなみに全てES6で書かれている。いいぞ。

TODOリストとかだと僕の場合本当チェックしないし、
特に嫌なのが、見積もりの修正に耐えられないリストだったときの面倒くささ。
だから基本slackでブツブツ言ってる方が向いてるんだけど、それと一緒に自分の振り返りも軽くできたらいいな、という想いで作った。

これ本当はもっと早く出来上がるはずだったんだけど、まじでQOLが不安定だったのと、
途中からES6のgenerators使えば対話式にできるとか、もうちょっとコードをきれいにしたいとか、
試験運用してたりしたら時間かかっちゃった。

今後の成長戦略について

thebridge.jp

たまたま流れてきたこの記事だけど、まあまさにこれで、基本振り返りとか個人的問題解決等々のテーマ設定が大事。
でもそういうの監視されたり、言われて報告するのほんと嫌で、だいたいうまく回らない。
問題解決している気になって増長するのも間違いだけど、
監視する/されるの関係も間違っていると思う。
いろいろ文句をいうけど、本質的にはだいたいそういうのは誰の責任でもなく、やり方が間違っていると思うことが多い。

仕組みをちゃんと作ることで、他の人から何か言われないとできないみたいな状態を避けられたらそれが一番良くて、
ganbaruzoiはまさにそのためのもの。

Twitterで毎日抱負掲げたり自戒を込めたりするのとか、逆にあんまこういうのやらずに過ごすとかもありなんだけど、
僕はそういうの冷めた目でみちゃうし、仕組みを作らないとほんとなにもしない。
ので、仕組みを作った今これを使って初心を忘れず成長していきたい。

技術的な話と今後のこと

技術的にどうするみたいな話だと、このbotみたいに、何かガワをどうこうしたみたいな表面的な技術の触り方が多くて、
がっつり公式仕様を勉強してそれに関連するライブラリを作りました、とか、
プロダクトを作る中で新しい技術に触れました、みたいなことがないまま老害になるのがすごく怖い。

DeNAの人たちはその辺すごくて、みんなコアから勉強してたし、深く読み込んでからコード書き始める習慣が板についてて、
ああこの人たちが"エンジニア"なんだなとつくづく思ってた。
各位、「普通やるでしょ」とか言ってたけどその吸収度と広範さがドン引くレベルだった。

僕はその辺入社してからもしばらく甘くて、かなり理解度が低くご迷惑をおかけした。
でも代わりに、「何がわからないのかわからない」という状況が最近ほとんどなくなっている。
だいたいそういう溺れてる感覚は、本当にコアから読みこなせてないか、
目の前のコードを一行一行整理して理解できてないから起こる問題だとわかったのは、大きな収穫だった。

自分が使っている技術が本当に自分の言葉で平易に説明できるレベルで理解しているか、
その辺の姿勢が、一番勉強させていただいた部分だと思っているので、その姿勢を損なわないように勉強を続けていきたい。