RubyKaigi2024 お疲れ様でした。
別にRubyKaigi関係ないけど、 rspec-daemon の設定を今更してみたのでメモ。
ちょっとペアプロしたときに、動いてたはずのGuardが動かずファイル保存したらrspec実行みたいなことが上手くいかなくなっていた。
rspec-daemonは追加とかは公式ドキュメントを見ればいいだけなんだけなので、そちらに譲るとして、公式ドキュメントにはleaderで実行みたいなのしかなかったので、僕はこういう設定にして、保存したらrspecが実行されるようにしました。
vim.api.nvim_create_autocmd({ "BufWritePre" }, {
pattern = {"*_spec.rb"},
callback = function()
local specfile = vim.fn.expand('%')
vim.fn.system('echo ' .. specfile .. '| nc -v 0.0.0.0 3002')
end
})
rspec-daemonはデーモンを $ rspec-daemon
で立ち上げておきつつ、別でシグナルを送らないとrspecが実行されないのです。
が、逆に echo $specfile | nc -v 0.0.0.0 3002
の部分はデーモンが立ち上がってないと空振りしてくれるので、この設定で気に入りました。
Neovim って結構色々遊べそうですね。
ソフトウェアファースト
エンジニアを採用して、投資したら、ちゃんとその分以上の売上をペイできる会社というのはソフトウェアファースト企業ということです。
例えば、「エンジニアがこの機能をリリースしたら、XXX円の利益が出る。」「エンジニアがサーバーを落としたらXXX円の損失になる。」という状況が作れている会社です。
イメージしやすいのはソーシャルゲームの会社でしょうか。メルカリさんのようなC2Cの会社もトランザクション毎に課金が走るのでわかりやすいでしょう。食べログさんやクックパッドさんなどの有料ユーザーも良いUXの機能を実装することで、アドオンのサブスクが提供できるので、ある機能のリリースによって有料会員が増えた減ったにつながるので、ソフトウェアファーストになっていそうです。
B2Cサービス企業は、Web上で集客し、Web上でマーケティングし、自社サービスのコンバージョンさせます。
ですので、そんなの大きなコンフリクトは起こりにくように思います。
(自社広告チームなどB2Bチームが成長してくると、成長エンジンが違うところにも発生するので、実は出てくるのですが、一旦無視)
B2B SaaSもソフトウェアファーストな会社です。業界特有だったり横断的だったりは色々ありますが、社内のインフラをSaaSで一手に解決するわけです。エンジニアがいなければ機能を作ることができません。「この機能があれば導入したい!」「この機能があればもっとお金払いたい!」という顧客の要望を叶えるのは常にエンジニアですよね。
...
... Continue Reading
fish辞めた
fishすごく好きだったけど、起動が遅い気がしてやめた。
標準的なshellが使えないことがあるのもやっぱり不便だった。
fishはthemeとか補完とかが優秀で大体fisherでなんでも管轄するのが良い。
zsh使い始めた
その代わりzshにした。
zshはというと、そう言ったいけてるエコシステムがない気がする。
ohmyzshが圧倒的だけど、要らないものまでがっつり入ってきて起動が遅くなってしまったりして、嫌だ。まぁそれに自分を合わせる手もあるんだけれど。
Macのデフォもzshになったし、とある案件でzshを使ったときにかなり環境も整えたのもあって、zshの良さに気づいてしまった。
zshの設定は本当に最低限しか書いていない。aliasやfunctionは必要があったら足していってる。
自分で使うものだけ自分で管理できてて、大変気に入っている。
starship
fishやめてstarshipもやめた
Zshでも使えたけれど、なんとなく起動がもたつく感じがした。
と言うのと、後述のp10kの体験がとても良かった。
p10k
僕はp10kというのを使っている。これはVCSやらの情報を出すのに便利なのと早い。テーマも複数から選べるので万人に勧められる。
vimやめた
色々秘伝のタレを綺麗にしたので、いい感じになっているので、いつでも戻れる。
Lsp周りもちゃんと設定してるけれど、とある理由でやめた。
neovim始めた
Vimでちゃんと設定したんだけれど、neovimはcoc系に頼ってる。
正直いらないものがあるので、ダイエットしたい。
copilotがneovimに公式が対応しているので、一旦乗り換えた。
...
... Continue Reading
Twitter眺めていると楽しい機能の話です。
shared_examples
と shared_context
は実装的には同じものですが、
個人的にはdescribeがテスト対象の明示、contextがテスト条件の明示で使い分けるのと同じように以下のルールでやっています。
- itを共通化したいときは
shared_examples
- contextを共通化したいときは
include_context
- describeは共通化しない
shared_examples の使い方
Shared examplesのRSpec公式のドキュメント を見てみましょう。
RSpec.shared_examples "some example" do |parameter|
\# Same behavior is triggered also with either `def something; 'some value'; end`
\# or `define_method(:something) { 'some value' }`
let(:something) { parameter }
it "uses the given parameter" do
expect(something).to eq(parameter)
end
end...
... Continue Reading
うちのブログの 前回の更新 が man の話だったので、更新せざるを得ない。
ということで、これめちゃくちゃ便利ですね。
https://tldr.sh が公式ページです。
GitHubを見てみると、 かなりの数のコマンド が対応しています。
日本語 も結構対応していっていますね。
manよりもコミュニティドリブンなところがハマった人がすぐに貢献できそうで、tipsが貯まる感じになりそうで良さそうです。
例えば、 ls
をとってみると、、、
$ tldr ls
ls
List directory contents....
... Continue Reading
最近はVSCodeなどのIDEが開発に使う言語に問わずハイスピードで普及して、フロントエンドエンジニアでもバックエンドエンジニアでもコマンドを叩くことが少なくなってきたように思います。
若干老害トーク感がありますが、僕が新卒の頃は必ずサーバーにログインして何らかの作業を誰もが当たり前のようにやっていました。
それでも、少なくなったとはいえ、全くコマンドを叩かずに済むエンジニアはいないでしょう。まだ今日のGUIやその他のインターフェースは、CLI(Command line interface)より優れた部分はあれど、全てが優れているわけではありません。
CIやDocker、wikiではまだまだ現役のコマンド達
多くのCIはshellをサポートしていますし、Dockerでもやはりコマンドを使うことがあります。また、コマンドはコピペして簡単に再現できるので、まだwikiや手順書にこの順番でコマンドを実行してくださいと書かれることも多いでしょう。
意味がわからないコマンドに出会ったら?
wikiの中にわからないコマンドがあり、意味を知りたい場合はどうしましょう?
例えば $ ls -ltr
の意味がわからなかったとしましょう。 $ ls
の意味はわかっても、オプションの意味がわからない場合、あなたはどうしますか?
ls -ltr
とGoogleで検索すればある適切な結果が表示されるかもしれません。しかし、2020年現在全てのコマンドラインオプションで検索しても、なかなか Gooleは適切な答えを表示してくれません。とくに短いコマンドラインオプションについてはかなり不正確です。
manコマンドを使ってみましょう
man ls
としてみましょう。...
... Continue Reading
railsでテストコードを少なくする技術 - TDD on railsの間合い - Qiita
以前、上記のような記事を書きました。
「Model SpecやRequest Spec/Feature Spec(今ならSystem Spec)を中心に書いて、実装速度を上げていこう」という話でした。
その後、Ruby on Railsのコードを読み書きする中で、自分自信の考えが少し変化しました。ここで一度新しい僕のRuby on Railsでのテストとの向き合い方をまとめたくなりました。
いろいろと変化している部分があり長くなるので、今回はModel SpecのValidationの書き方を以前のコードと比べつつ見ていきましょう。
以前の記事に書いてあるModel Specのコード
前述の記事のvalidationのテスト という項目のコードです。(一部改変しています)
describe Post, type: :model do
describe '#validate' do
subject { Post.new params }
context '全てのデータが正しいとき' do
let(:params) { body: "iiyon" }
it { is_expected.to be_valid }
end...
... Continue Reading
... Continue Reading
randomにテストが落ちてしまう
どんな種類のテストでもrandomにテストは落ちてしまうことがあります。
Ruby on Railsを利用している場合にもっともこのような不安定なテスト (flaky test) になりがちなのは、Capybaraを利用したsystem test/system specではないでしょうか。
私がrandomに落ちるテストと戦った中で得た経験をここに記しておきます。
基本的に自前で sleep はしなくて良い
ページ遷移の直後や描画された直後にclick_linkやclick_buttonなどを実行すると、ブラウザの描画よりもブラウザを操作するテストの実行が早く走ってしまいrandom落ちを引き起こします。
そういうときの解決策として sleep 0.5
などとして、テストの実行を止めるアイデアを思いつくでしょう。
しかし、capybaraは Capbypara.default_max_timeout
までは、対象のコンテンツを探してくれるメソッドが用意されています。
ですので、基本的に自前でsleepする必要はありません。
例をいくつか挙げておきます。
click_link '次へ' # ここでrandom落ちしたら
within '.some_dom' do # 次への親要素を探すまで待たせる
click_link '次へ'
end
find('.next').click # 次へのリンクを探してからクリックする
... Continue Reading
別に問題じゃなさそうなことに問題って名前をつけたのは公式で用意してくれているバッチインターフェースが二つあって、いつも迷っちゃうからだ。
$ rails foo:bar:baz
のようにコマンドを作れるのがrake task
です。
これは普通にrails db:migrate
やrails g scaffold Foo
のようにいろいろなところで開発者が使うからおなじみのコマンドです。
もう一つのインターフェースが、rails runner
と呼ばれるやつで、こちらは引数に自由にruby(しかもrailsの資産をつかった)のコードを書くことができる。
普通にバッチを書くならどっちでも問題ない
基本的にどっちを使っても問題はありません。しかしrails runner
を作るときはインターフェースを自分で考える必要があります。以前言及した記事としては app/batches
配下にバッチフレームワークのようなものを作り、 rails runner FooBatch.run
のように書くものでした。
自前のバッチフレームワークのようなものが必要なのはひょっとしたら過去の時代の話かもしれません。例えばkuroko2やjenkins、rundeckのようなcron replacementと呼ばれるツール群を使えば、共通処理で書いていた排他制御やロギングなどをそちらに任せることができます。そしてkuroko2やjenkinsの先ではrailsの入ったdockerを実行させるようなことも簡単にできます。...
... Continue Reading
GitHub が新たに開発した GitHub用のCLIツールがめっさ便利なので、勢いあまって記事を書いたのですが、塩漬けにしていたので、とりあえず公開。
もう速報性はなくなってしまったけれど、便利に使っています。便利。
cli/cli: GitHub’s official command line tool
これね。
hubコマンドクッソ便利(でした)
$ git push origin feature-bransh
したあとは、そのまま
$ hub pull-request -o
とするのが手癖として根付いています。
hubコマンドに対する不満
手癖になってはいるのけれど、解決できていない問題がありました。
それはPull Requestをdraftで生成できないことです。
ですので、DraftのPull Requestを作りたい場合は $ hub browse
を使ってブランチを表示。その後、ブラウザ上でPull Requestを作成していました。
$ gh pr create -w という革命
$ gh pr create -w
これを使えば今までやりたかったPull Requestの作成が簡単になるだけではなく、全てをdraftで作ってから細かい点をブラウザ上で修正するというワークフローがやりやすくなりました。
見た目を伴う修正の場合は、スクリーンショットをPull Requestのdescriptionの項目に貼ったりしますので、この辺りも便利です。
...
... Continue Reading
オンラインコミュニティnoraneeresのメンバーと一緒に、愛媛県八幡浜市に行ってリモートワークをしてきました。
リモートワークで場所を変えるというテクニック
...
... Continue Reading
はい。 #しがないラジオmeetup 4 - connpass に参加してまいりました。
(そういえばpodcastの話はあんまりしなかったな〜)
しがないラジオmeetupとは
『しがないラジオ』というpodcastを一回でも聞いたことがある人が参加できるmeetupです。podcast好き率高めですが、エンジニアとかそういう縛りは特にありません。
今回は公募枠LT5枠とスポンサーLT1枠、パーソナリティのお二人のLT2枠と、懇親会という内容でした。
エージェント完全脱出マニュアルというタイトルでLTしてきました
見事、公募枠のLTに当選し登壇してきました。
最近、登壇とかやってなかったし、LTにしては10分と割と枠があったので、緊張感もあり楽しめました。
なんだか、見境のなくあやかりまくったスライドが気がついたらできてました。ごめんなさいmm
10分のLTにスライドは40枚。
緊張と早口で大阪弁全開でまくしたて立ったぜ。
...
... Continue Reading
流しのRails業でチームの中で共有したtipsをちょっとずつブログにも書いていくぞという。気持ち。
ちょっと初心者向けの話題のように思うかもしれないけれど、私もなんども苦しんだことなので。
$ rails g scaffold Book name:string price:integer
scaffoldでこのように生成したとしよう。
そうすると、BooksController#create
は以下のように生成される。
# POST /books
# POST /books.json
def create
@book = Book.new(book_params)
respond_to do |format|
if @book.save
format.html { redirect_to @book, notice: 'Book was successfully created.' }
format.json { render :show, status: :created, location: @book }
else
format.html { render :new }
format.json { render json: @book.errors, status: :unprocessable_entity }
end
end
end
もう少し簡易化してみましょう。
# POST /books
def create
@book = Book.new(book_params)
if @book.save...
... Continue Reading
プロジェクト管理ツールBasecampの最高技術責任者、デイヴィッド・ハンソンさんの仕事術 | ライフハッカー[日本版]
iA writerを知ったのも、この記事だった。
自分のタスク管理のやり方を見直そうとなんとなく調べていたら、こんな記事を見つけた。
確か、以前にも読んだことがある内容だったんだけれど、iA writerもタスク管理の方法も試せていなかった
DHHという憧れの人物のタスク管理が響かないタイミングもあるんだな。本当に人生はタイミングですね。
記事で印象に残ったこと
私はほとんどのことにNoと言っています。そうすれば、自分で本気で選んだ少数のことにだけに、完全にコミットできます。
余計なことは人生から取り除けば時間はたっぷりあるはず。
明日はいくつかNoと言えるようにしたい。
メールのInboxを空にすることには執着しています。
僕はメールはほとんど見ないけれど、DHHのGTDの基本はメールになっているよう。
また、slackは本当に有害だと思うので、どうにかしたい。
あとはtwitterを読まないということも大事だよなぁ。フォローを減らすなりリストしか見ないなり情報を減らす必要がありそう。
一般的に私がトラッキングするのは、自分のコントロールが及ばないことに関してだけ
私の場合はomnifocusを整理する必要がある。...
... Continue Reading
... Continue Reading
転職活動をすることを表明しましたが、
今現在自分が壁と考えていることを書きます。
権限の壁
私の経験上AWSの管理者権限をフリーランスエンジニアとして、任されることは少ないです。
AWSのサービスをフル活用して貢献するためには、
AWSやインフラに精通し、社外だとしてもこの人間に権限を委譲した方が生産性が高いと認定された場合に限ります。
こういった権限はAWSだけではなく様々な重要な意思決定に絡んできます。
組織の壁
...
... Continue Reading
rails 界隈では Sider の普及に伴い rubocop を業務で使っている方も増えてきたのではないでしょうか?
しかしながら、一度荒れ果てた荒野にrubocopを放っても成果はほとんど上がらないことでしょう。
必要なのは、すべてのコードを綺麗にするぞ!という高尚な志ではなく、現実を少し改善すれば、それでOKという意識低い気持ちな気がします。
--lint
オプション
rubocopには -l
または --lint
というオプションがあるのをご存知でしょうか?
こいつはlintオプションと呼ばれるやつで、bugに繋がりやすい警告レベルを指摘してくれます。
こいつをまずデフォルトにしましょう。
.rubocop
ファイルに --lint
と記述すると、rubocopのコマンドが常に--lintオプションがついた状態で実行されるようになります。
.rubocop
ファイルを使うことで、プロジェクトのメンバー全員がそのオプションをつけてrubocopを実行することができるため、「 rubocop -l
と実行してください!」などと呼びかける必要がなく便利です。
rubocop_todo.yml
と向き合う
次にこの状態で、rubocop_todo.yml
を生成します。
rubocop --auto-gen-config
プロジェクトにこれ以上 --lint
に違反するコードを入れないようにするためです。
rubocopを入れると、rubocop対応で色々と対応工数が増えてしまうと恐れている方もいらっしゃると思いますが、...
... Continue Reading
associationをデフォルトのfactoryではnilを渡す
一般的にFactoryBotは大きなプロジェクトになってくると無駄なデータを作成する可能性が増えてきます。
例えば、こんな時。
factory :tag do
article
end
it do
create_list(:tag, 10)
# 10個タグがある場合のなんらかのテスト
end
articleがtagを複数持てるDB構造になっているとして、
tagが10個以上付いているページのfeature specなどを書きたい場合がある時に、
上記のような書き方をしてしまうと、tagが10個だけできればいいものの、articleも10個できてしまうのです。
これを抑制するために、
factory :tag do
article { nil }
end
このようにartilceは敢えてnilを渡して、validateエラーが起こるようにしておきます。
そうするとうっかり、 create_list(:tag, 10)
なんて書いてもテストが落ちるようになり、、
it do
create(: article)
create_list(:tag, 10, article: article)
# 10個タグがある場合のなんらかのテスト
end
おそらく、このようなテストになってくれるはずです。
あくまでデフォルトの話であって、traitを使う分には特定のcontextの名前を入れることができるので、問題ないと考えています。
factory :tag do...
... Continue Reading
このテーマ。僕はずっとずっと悩んで来た問題です。railsdm周りで話題になってたっぽい。
ベストプラクティスというものはまだ見えない。
でも、いろいろな実績が出て来たし、自分でもいろいろやって見たのでまとめて行きたいと思います。
1. sprokets + turbolinks + webpacker + stimulus
basecamp wayですね。
それぞれハマりどころが多くrailsに精通していないと使いにくいと思います。
DHH信者にオススメの設定です。
気持ちはわかるけど、染まって見るのもなしではないかな。
2. webpacker + react(or other javascript view library) (+ some cssloader || sprokets)
部分的にreactなどのviewを使う設定。場合によってはcssもstylesheet_pack_tagを使うパターン。
個人的にはこのパターンってreact使う必要ある?という気もします。
が、例えばKPIに直結する非常に重要な機能だけをSPAにして、...
... Continue Reading
テストコードで再現テストをしてから、bugfixするやつ。
不具合にテストを書いて立ち向かう - t-wadaのブログ
これうまく行ったら超気持ちいいけど、いつも気持ちいいとは限らないのでメモ。
バグのパターンがユニットテストとしてエッジすぎ
だいたい再現テストコードがエッジなパターンすぎて、
仕様を説明する助けとして不適切になってしまう。
describe 'somemethod' do
subject { describe_class.new(params).somemethod }
context 'A' do
let(:params) { 'a' }
it { is_expected.to eq ('A') }
end
context 'B' do
let(:params) { 'b' }
it { is_expected.to eq ('B') }
end
# 再現テストのコンテキストがハイコンテキスト
context 'B and hogehogehoe' do
let(:params) { 'a' }
before do
# ハイコンテキストな記述
end
it { is_expected.to eq ('A') }
end
end
↑この程度なら全然いいんだけど野生のコードはこんなのじゃすまない。
このままマスターに入れてマージすると、仕様を説明することを阻害するよなぁ的に。
...
... Continue Reading
ブログ移管した
ブログを jekyll
+ github pages
での運用から、独自のCMS(heroku + rails)に移行しました。
移管した理由
オンラインからサクッと編集したい
記事の雛形は make post
みたいなコマンドを書いて、サクッと記事を書き始められるようにしてはいたのだけれども、、、
ちょっとした修正を出先や移動時間にするのにgithubに接続してブラウザから修正することにイライラしており、サクッと編集できるものが欲しかった。
jekyll疲れ
jekyllのプラグインとか拡張とかに限界を感じていた。
GitHub離れ
買収が発表される前から検討していたので、半分冗談ですが、移管完成がこのタイミングになったのはこれもある。
blogはコミットを外に公開したくなかったので、privateリポジトリで運用していましたが、
microsoft買収により自分が課金する必要もないかなと思いました。
このお金はherokuに払っていくぞ!頑張れheroku!
(あといくつかのprivateリポをgitlabかbitbucketに移管すれば、コスト削減も同時に達成できます。ありがとうmicrosoft。)
移管先の検討
wordpress
- 拡張性は高いものの、拡張しすぎると辛そうなので手を出すのをやめました。
- また移管したい気持ちになるので、その時は楽なんですけどね。
ブログサービス系 (medium/note/qiita/はてな/livedoor/line)
この辺りのツールはスマホからも修正がかなり簡単で圧倒的に使いやすいのです。...
... Continue Reading
前回 に続いてどうやってプログラミング覚えたか?シリーズです。
こうしてHTML/CSSをなんとなく覚えた私ですが、次は動的なサイトを作りたくなっていきます。
geocitiesからxreaの移行
geocitiesではhtml/css/javascriptは満足に動きますが、サイトを訪れた人が掲示板などサーバー上で動作するプログラムを置くことはできませんでした。
当時、ホームページを個人で運営している人は二つのいずれかの方法で、掲示板を運営していました。
- レンタル掲示板と呼ばれていた類のサービスを使う
- CGIが動くサーバーで、CGIスクリプトを動かす
前者は会員登録をすれば誰でも簡単に自分のサイト専用の掲示板を持てます。
後者はCGIの知識が多少必要とされますが、CGIスクリプトは配布されているものを使用すれば、動かすだけであれば、プログラミング自体の知識は必要ではありませんでした。
今でいうと、blogを始めるときにライブドアブログやアメブロを使うのか?wordpressやmovabletypeを使うのか?みたいな違いです。
wordpressを使えば様々なデザインや動きもカスタマイズできますが、ライブドアブログやアメブロではそこまでできません。
自分はカスタマイズも想定して、CGIが動くxreaと言うレンタルサーバーに自分のサイトを移管しました。
無料スクリプトをアップする
xreaにサイトを移管してから、配布されてるCGIスクリプトをサーバーで動かしました。...
... Continue Reading
どのようにしてHTML/CSSを身につけたか
きっかけはバンドを組んでないのにホームーページを作ろうとしたこと
中学校二年生の頃、バンドを組んでないのにバンドのホームページを作りたいと思っていました。
ある日、ある友達がホームページを持っていることを知り、彼にfront homepage express入門本を借り、早速サイトの制作に取り掛かりました。
その本を読み終え、geocitiesに簡単なテキストサイトを公開したように思います。
front homepage expressだけではいい感じのサイトにならず、どうしてもかっこ悪いデザインになってしまう。そこで本の巻末にあったメモ帳でhtmlファイルを編集する方法でサイトの更新を行うようになりました。
この時友達に質問したことを今でも覚えています。
sg「画像の横に文字書くのにはどうすんの?」
友達「罫線のない表を組めばいい」
爆誕tableレイアウトコーダー
tableレイアウトを覚えるとどんなデザインでも実現できるようになりました。
僕は様々なレイアウトのページをhtmlで作っていました。
htmlだけを作るのが楽しくなって、絵を描くようにいくつもサイトを作っていました。
サイトのメニューをいい感じに作れるようにframeタグもうまくつかっていました。
この頃にはエディタもterapadというお気に入りのエディタがありました。
「違う。。何かが違う。。俺のサイトはyahooとは全然違うぞ!!」
そう思った僕はありとあらゆるサイトを 右クリック→ソースを表示
を繰り返し、cssを学んでいきます。
ググりまくる中で、プロはレイアウトをdivで組むしいということを知り、floatレイアウトを覚えました。
...
... Continue Reading
jekyllにブログを変えてみました。
markdownで記事を書けるのはやはりすごい楽です。
お気に入りのエディタであるvimで書けることも素晴らしいです。
やったこと、やってないことをまとめておきます。
やったこと
bloggerで運営していたブログを移管しました。
一部labelページ以外を除いて、同じURLに移行しました。
bloggerで長らく運営していたこのブログですが、
bloggerのhtmlがなかなか弄りにくいことが主な要因です。
blogger自体テーマがあまり充実していないのと、良いテーマがあっても、
それをカスタマイズするのにhtmlのようなxmlを弄るのに疲れてしまいました。
wordpressという手段もあったのですが、静的サイトジェネレータに興味があったので、
今回のような形になりました。
ちなみに静的サイトジェネレータをjavascriptで作ろうとしたのですが、
そこは挫折してしまいました。。
なんでhugoじゃないの?とかなんでoctopressじゃないの?
って質問があると思うので、書いておきます。
hugoじゃない理由
rubyでpluginを作れることとgithub pagesでメジャーな手段になったことくらいでしょうか。
hugoは正直魅力的なので、どこかで試してみたいとは思っています。
octopressじゃない理由
htmlを弄りやすいようにしたいことが、今回の動機でもあったので、
octopressはテーマは充実していますが、htmlがそんなに得意ではない自分ではoctopressのテーマは弄りにくいなぁと思いました。
あと、jekyllの方がdocsも充実しているように見えたのと、コード自体の見通しもよかったです。
その他検討したもの
...
... Continue Reading