AtCoderProblemsに「またあとで解く」を追加するChrome拡張を作りました

# 背景
AtCoderで問題を解くとき、[AtCoderProblems](https://kenkoooo.com/atcoder/#/table//)様をポータルサイトとして利用している人は多いと思います。一度解いた（ACした）問題は緑でハイライトされ、まだ解いていない問題も一目瞭然で把握できます。

ところで私は問題が解けなかったとき、解説をみながら実装し、とりあえずACします。しかしその後解説を見ずにACできるか不安になります。復習は大事ですよね。マメな人は問題をスプレッドシートで管理してるようですが、私のようにそれができない人間のための「またあとで解く」機能をChrome拡張で作りました。

[ソースコードはGitHubで公開しています](https://github.com/taketakeyyy/solve-later-again)。

# インストールと使い方
## インストール方法
[ChromeウェブストアでSolve Later Again](https://chrome.google.com/webstore/detail/solve-later-again/emndffmnlppiaelhdneheagpaancfahk)をインストールしてください。

## 使い方
### ステップ1
インストールすると、AtCoderProblems の Table ページに以下のようなSolve Later Again セクションが追加されます。

各問題の横にチェックボックスも追加されます。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78100/46f63bd0-7464-e546-15ab-b3aa4de2458c.png)


### ステップ2

「これまたあとで解きなおしたほうがいいよな～」って問題のチェックボックスにチェックを入れると、Solve Later Againテーブルに問題が追加されます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78100/d255aee6-f33f-de41-825c-f7f5ab748f36.png)


### ステップ3

解いたら Solved 1 のチェックボックスにチェックを入れます。すると解いた日付が印字されます。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78100/14f897a2-0c71-b4bb-ca77-a56fb85ec589.png)


### ステップ4

7日経過したら以下のように Solved 2 がハイライトされるので、再度解けるかチャレンジしてください。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78100/076eff16-575e-5303-e211-06c6ffa93cff.png)


同様に、30日経過したら Solved 3 がハイライトされるので再度チャレンジしてください。3回解けたらもう身についたと言っていいのではないでしょうか？


### その他

* Deleteボタンをクリックで、Solved Later Again テーブルから問題を削除できます。
* ReAgainボタンをクリックで、その問題の状態を初期化します。気が済むまで解き直してください。


# おまけ

以下は、どういう風に開発を進めたかの話です。

## 設計

あれこれ考えて、以下のような要件を定めました。

* 解きなおしたい問題はChromeに保存させる
  + 当たり前の機能。
* 復習は3回解きなおせば十分だと思うので、そういうUIにする
  + 忘却曲線を雑に参考にすれば、初回、1週間後、1か月後の3つ。
* AtCoderProblemsのTableページだけで完結させる
  + できるだけページ遷移はしたくない。導線も小さくしたい。めんどくさいので。
  + Chromeのオプション画面も使いたくない。拡張ボタン探してクリックする行為が嫌いなので。

要件を紙に書き出すとどういうふうに作ればよいのかのイメージが湧いてきたので、あとはコードを書きながら状況に応じて適当に決めました。

## テスト運用期間
一般公開する前に1週間ほど自分でテスト運用してみて、問題がないか確認しています。自分の好きなように作っていてもあとから「ここ微妙だな」「こういう機能あったほうがいいな」といったものはまあ出てくるもので、適宜に修正・妥協・機能追加しリリースしました。


## 開発言語
Chrome拡張なのでJS系統のどれかなのですが、今回は生JSを触りたいという欲求があったのでそうしました（たまにjQueryを業務使いするのですが、jQueryの構文と生JSの構文の区別がつかない程度の知識だったので、生JSをちゃんと知っておきたいというモチベーションがあった）。

最近のJS事情を知るために、下記のURLでお勉強をしました。

### 参考URL

* [イマドキのJavaScriptの書き方2018](https://qiita.com/shibukawa/items/19ab5c381bbb2e09d0d9)
    * const使うとか、let使うとか、即時関数でラップしてスコープを汚さないとか基本的なことを押さえました。
* [ES2015(ES6) 入門](https://qiita.com/soarflat/items/b251caf9cb59b72beb9b)
    * 同上
* [ライブラリを使わない素のJavaScriptでDOM操作](https://qiita.com/kouh/items/dfc14d25ccb4e50afe89)
    * とても有用でした

## Chrome拡張

Chorme拡張を作るのは初めてだったので知らなかったのですが、Chrome拡張の仕組みは思ってた以上に難しかったです（適当にJS書けばいけるでしょの認識だった）。一から仕組みを勉強するために以下のURLを参考にしました。

### 参考URL
* [Chrome拡張の開発方法まとめ　その1：概念編](https://qiita.com/k7a/items/26d7a22233ecdf48fed8)
    * 「Chrome拡張は思ってた以上に難しそう」ということがわかりました
    * のちのち「どういう仕組だっけ？」の備忘録として非常に有用でした
* [Google Chrome拡張機能入門 - ドットインストール](https://dotinstall.com/lessons/basic_chrome_v3)
    * 思ってた以上に難しく適当な記事を読むだけでは理解が追いつかなかったので、とりあえず課金して一通りの機能を舐めました
* [Overview](https://developer.chrome.com/extensions/overview#arch)
    * Architecture の図が良い

## Promise

非同期処理のあれこれはPromiseで書きました。いろんなサイトを見て回りましたが、主として以下のサイトを参考にしました。

* [Promise.prototype.then() - MDN web docs
](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
    * 結局自分で書かないと理解できなかったので、書きながら試行錯誤できるこのサイトを最終的に良く使いました。
* [GoogleCloudPlatform/nodejs-docs-samples](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/functions/sendgrid/index.js)
    * 「人々はPromiseを実際どう書いてるの？」というとき、GCPのSendGridのチュートリアルの書き方がきれいで参考になりました。


## Content Scriptのファイル分割(webpack)
Chrome拡張のContent Script（いわゆる `content.js` ）はisolated worldという特殊環境なのでES2015のimport, export を使おうとすると[Uncaught SyntaxError: Unexpected token](https://stackoverflow.com/questions/48104433/how-to-import-es6-modules-in-content-script-for-chrome-extension)エラーが出て使えなかったので、[Chrome拡張の開発でwebpackを使わずにES6のimportを有効にしたい](http://otiai10.hatenablog.com/entry/2018/03/27/212836)の記事を参考にしたところ、結論が「webpack使お」だったのでwebpackを使いました。

webpackを使うのは初めてだったので、以下の記事を主として参考にしました。

### 参考URL
* [面倒なJavaScriptコードのとりまとめがこれ1つで可能に、「webpack」入門](https://knowledge.sakura.ad.jp/21623/)
    * webpackはどういうものか、何が嬉しいのか、どう書くか、などをわかりやすく日本語でまとめてくれています。
* [Installation | webpack](https://webpack.js.org/guides/installation/)
    * 公式サイト

## 感想
* AtCoder Problems はページ遷移がなく仮想DOMによる差分レンダリングをしていて、特定のDOM読み込みの判定などに苦労した
* 「Chrome拡張作るか～」の軽いノリと軽い実装量を見込んで始めたら知らないことが多すぎてとても勉強になった
* `$ ./node_modules/webpack-cli/bin/cli.js -w` でwatchモードにしたあと、watchモードから抜ける方法がわからないので、ご存知の方教えてください
* <del>次は TypeScript を使いたい</del>TypeScript化した

## 不具合報告
不具合など見つけましたらお手数ですが[GitHubのissues](https://github.com/taketakeyyy/solve-later-again/issues)、またはコメントでお願いします。