今日は心底自分にあきれ果てた。ある問題に悩み始めたのが15時ごろで、終わったのが22時だから、7時間かかったことになる。その問題の解決方法が分かったときには正直自分を殺したくなった。本当は夕方から筋トレにいって、ごはん食べながらNetflix見て、ギター弾いてとかたくさんできたし、技術だけをやっていたとしても、7時間あったら、相当勉強できるしコードも書ける。そんな目にもうあいたくないので、今回の原因を分析して、メソッドに落とし込んでみた。
今回起こった問題の整理
私の解こうとした問題は簡単だった。というか過去にも似たような問題を解いたことがある。自分が今日は思ったように貢献できなかったら、今日一つぐらい貢献して帰ろうと思って、過去にやったことある問題をピックアップした。問題は単純で、.NET Core 3 のアプリをデプロイする ARM template とスクリプトを作成するというものだ。時系列に起こったことを書くとこんな感じ。めんどくさいと思うので読まなくていいと思います。つまりそれぐらいつまんない試行錯誤しているということです。
経緯
- ARMテンプレート、それを実行するスクリプトを書く。BadRequestのエラーが出るが、それは、VSCodeのARMテンプレートのプラグインを入れて、問題を発見。そこは修正できたが、、、
- そのテンプレートは2つのリソースをクラウドにデプロイするのだが、1つめは出来るのに、2つ目がデプロイできない。エラーの内容は、1つ目のリソースが見つからないというメッセージ
- 試行錯誤を開始、リソースの名前の長さや文字の内容に制限があるのか?違うリージョンならデプロイできるのか、ARMテンプレートの書き方が違う書き方なら通るのか、StackOverflowでエラーメッセージや、GitHubにあるIssue を読んだりして、そこで書かれている対策を試してみる
- もしかして、デプロイで使っているCLIのバージョンが古いのではないか?と思い立つ。リリースノートを見ると実際古い。
- CLIをアップデートしようとすると、ライブラリを解凍、展開するところで、スタックして動かない。Issueものだったので、それ見て解決。
- クラウドのコンソールで、最新のCLIを使って、.NetCoreのラインタイムが載ったPaaSをデプロイできるかを調べてみるが、どうやら、CLIは最新の3.0のランタイムを最新のバージョンのCLIでも対応してなさげというのがわかる。ここで、ARMテンプレート一択になる(PowerShellという手もあるが、本質は、RESTAPI直たたきしかない。ARMテンプレートという方式がその方式)
- すでに40回ぐらい試行錯誤してデプロイしているが問題が解決しない。もう万策つきて、SNSにARMやってられんとか愚痴をこぼす。ARMデバッグめんどくさすぎやねん。とか
- ARMの天使が登場し、なんとデバッグを手伝ってくれるらしい。本人は楽しんでいる様子。素晴らしいの一言。
- 天使が私のARMテンプレートをそのままつかってやってみると、WestUSは動かんかったけど、japaneastはデプロイできたとのこと。なんでやねん。天使はほんの5分でデプロイ可能に。
- 自分もjapaneast でデプロイするが以前と全く同じエラーが出る。ARMテンプレートはたぶん問題が無い。サブスクリプション(私のサブスクリプションは特殊なので)の制限か?とか考える。
- 天使にどんなパラメータでデプロイしたか聞いてみる。(ネーミングの制限を疑っている)同じようにしても動かない
- 天使が実際に使ったシェルファイルをシェアしてくれたので、それを使ってJapaneastにデプロイする。動くやん。
- 天使のスクリプトと、自分の書いたものを見比べる、本質的に同じことをやっている。天使のはデフォルト値を多く使っていて、自分のはコンフィグしている違いはあるが本質的に一緒。天使のスクリプトからコピーしてやってみると動く意味がわからない。
- 一文字一文字天使のスクリプトと比較して、パラメータのファイル指定のところに、
@
が抜けていることに気づく。問題はそこ。
だらだら書くとこんな感じだ。私が出会ったエラーは、下記のようなもので、devsecopsstweb-plan
というServerFarmという種類のリソースが見当たらないというもの。
しかし、ポータルを見てもちゃんとリソースは出来ている。
あるやん!しかし、このエラーにはご丁寧に解説のページまである。
ちなみにARMテンプレートはこんな感じ。
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"subscriptionId": {
"type": "string"
},
"name": {
"type": "string"
},
"location": {
"type": "string"
},
"hostingEnvironment": {
"type": "string"
},
"hostingPlanName": {
"type": "string"
},
"serverFarmResourceGroup": {
"type": "string"
},
"alwaysOn": {
"type": "bool"
},
"sku": {
"type": "string"
},
"skuCode": {
"type": "string"
},
"workerSize": {
"type": "string"
},
"workerSizeId": {
"type": "string"
},
"numberOfWorkers": {
"type": "string"
},
"currentStack": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2018-11-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[parameters('location')]",
"kind": "",
"dependsOn": [],
"properties": {
"name": "[parameters('hostingPlanName')]",
"workerSize": "[parameters('workerSize')]",
"workerSizeId": "[parameters('workerSizeId')]",
"numberOfWorkers": "[parameters('numberOfWorkers')]",
"hostingEnvironment": "[parameters('hostingEnvironment')]"
},
"sku": {
"Tier": "[parameters('sku')]",
"Name": "[parameters('skuCode')]"
}
},
{
"apiVersion": "2018-11-01",
"name": "[concat(parameters('name'), 'msg')]",
"type": "Microsoft.Web/sites",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Web/serverfarms', parameters('hostingPlanName'))]",
"[concat(parameters('name'),'ai')]"
],
"properties": {
"name": "[concat(parameters('name'), 'msg')]",
"siteConfig": {
"appSettings": [
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "[reference(concat('microsoft.insights/components/', parameters('name'),'ai'), '2015-05-01').InstrumentationKey]"
},
{
"name": "ApplicationInsightsAgent_EXTENSION_VERSION",
"value": "~2"
},
{
"name": "XDT_MicrosoftApplicationInsights_Mode",
"value": "default"
},
{
"name": "DiagnosticServices_EXTENSION_VERSION",
"value": "disabled"
},
{
"name": "APPINSIGHTS_PROFILERFEATURE_VERSION",
"value": "disabled"
},
{
"name": "APPINSIGHTS_SNAPSHOTFEATURE_VERSION",
"value": "disabled"
},
{
"name": "InstrumentationEngine_EXTENSION_VERSION",
"value": "disabled"
},
{
"name": "SnapshotDebugger_EXTENSION_VERSION",
"value": "disabled"
},
{
"name": "XDT_MicrosoftApplicationInsights_BaseExtensions",
"value": "disabled"
},
{
"name": "ANCM_ADDITIONAL_ERROR_PAGE_LINK",
"value": "[concat('https://', parameters('name'), 'msg', '.scm.azurewebsites.net/detectors')]"
}
],
"metadata": [
{
"name": "CURRENT_STACK",
"value": "[parameters('currentStack')]"
}
],
"alwaysOn": "[parameters('alwaysOn')]"
},
"serverFarmId": "[concat('/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
"hostingEnvironment": "[parameters('hostingEnvironment')]",
"clientAffinityEnabled": true
}
},
{
"apiVersion": "2015-05-01",
"name": "[concat(parameters('name'),'ai')]",
"type": "microsoft.insights/components",
"location": "westus",
"properties": {
"ApplicationId": "[concat(parameters('name'), 'ai')]",
"Request_Source": "IbizaWebAppExtensionCreate"
}
}
]
}
要約すると3つのソリューションがある。
- Dependency をセットする。ServerFarmのリソースが作成中なのに、WebAppのリソースを作って、ServerFarmのリソースを参照するとまだできてないから、問題になる。Dependencyを設定して、ServerFarmが出来てから、WebAppのリソースを作るような設定にする。-> 出来てた。
- ServerFarmと、WebAppが違うリソースグループの場合にこのメッセージが出る -> 何回も確認した。
- リソースが同じテンプレートにあるかを確認する -> 同じテンプレート。というかそもそもポータルから、手動でデプロイしたときのテンプレートをダウンロードして使っているので、間違いっこない。
他にもStackOverflowとかで、"name": "[parameters('hostingPlanName')] ",
こんな感じでスペースがあっても起こるみたいなことも書いてあった。
ちなみに決め手となった問題のスクリプトの部分は、
Cannot find ServerFarm Errorが出る
az group deployment create --debug --name WebApps --resource-group $resourceGroupName --template-file ./template.json --parameters ./parameters.json --parameters subscriptionId=$subscriptionId name=${webAppName} location=$resourceGroupLocation hostingPlanName=${webAppName}farm serverFarmResourceGroup=$resourceGroupLocation sku=$sku skuCode=$skuCode
天使が書いたスクリプト
正しく動作
#!/bin/bash
RESOURCE_GROUP=Stress01
LOCATION=japaneast
NAME=tsushist
SUBSCRIPTION_ID=$(az account show --query "id" --output tsv)
az group create --name $RESOURCE_GROUP --location $LOCATION
az group deployment create --resource-group $RESOURCE_GROUP --template-file template.json --parameters @parameters.json --parameters serverFarmResourceGroup=$RESOURCE_GROUP location=$LOCATION subscriptionId=$SUBSCRIPTION_ID name=$NAME hostingPlanName="$NAME-plan"
問題は、--parameters ./parameters.json
で、テンプレートのパラメータファイルの指定がそれではなく、--parameters @parameters.json
でないといけいないのがポイント。
お分かりだろうか。わたしは、7時間かけて、az group deployment create
コマンドのパラーメータファイルには@
が必要であると学んだだけなのだ。というか、以前のスクリプトでは、私も@
を使っているのだ。
自分の理想とする解決スタイル
正直私の周りの人でこんなしょーもないことで7時間使う人は見たことがない。私が問題視しているのはこんなクソ下らんことに7時間も使っている自分だ。それは、問題が解けたからよしではなく、むしろ解けなくても、良いとすら思う。7時間こんな無駄につかわないのであれば。
確か去年だったが、私はこういう問題解決の理想形を見た。たしか、IoTのデバイスのアプリだったと思うが、Issue的なものを見つけて、プロダクトチームにたずねたら彼が自分のビルに来てくれないか?というので行ってきて問題解決を試みた。
彼がやったことは、自分と会話をしながら、彼はいくつかのコマンドを叩いて原因の調査を行った。問題は再現した。そして、その原因調査の手順は、まったくの重複がなく、極めてロジカルで、問題の可能性を一つ一つ確認していった。30分もしないうちに彼はすべての調査を終えて私に言った。「この問題はすぐにはわからない。ただ、再現はしているので、原因がわかったら連絡するよ」そうやって、調査を終えたのだ。確かに何も解決していないが、ロジカルに考えうる可能性を、重複なく網羅して、「わからない」という結論をさっと出した。
自分だったらわからなかったら、あれこれ、ためしてあーでもない、こーでもない、、、とかやって下手したら数日使うケースかもしれない。かれは、たった30分しか使ってないのだ。彼はそのあともきっとコーディングを続けて価値をだしたのだろう。私が、helpを読んだらわかるような、@
問題に7時間かけるのと比べるとめちゃくちゃな違いじゃないか。
ロジカルな問題解決方法を行っていたならば
さて、今回の問題をロジカルに、重複なく問題解決を行っていたならどうなっていただろう?彼のやっていたことを思い出して自分なりに考えてみる。今回の問題で関係あるパーツを整理してみる。
過去のはまり経験から導出されるTips
何回もはまっているので、過去のはまり経験から導出される問題解決のポイントは
- 大抵の場合、クラウドやツールは悪くない。自分が書いた部分に問題あがある
- 大抵の場合、解法はドキュメントに書いている。英語を億劫がってとばして読んでないとかはない?ドキュメントは大抵正しい。
- すぐに解けない問題の場合、大抵は誰かがすでに体験している。つまりIssueがある
- 試行錯誤は行わない、ロジカルに思考する。例えば、直感で、ServerFarmの文字数制限や、使えるキャラクターの上限に達しているのでは?と思っても、試行錯誤するのではなく、ドキュメントで仕様を確認して、そこに書いてあるならば、それ以上の試行はしても無駄。
- ログメッセージをちゃんと読んでいるか?とばしていないか?
- もっとログを出せないか?verboseモードとか、debugモードとかは無いか?
- 最終的に仕様に関する情報が得られない場合コードを読むのが早い、もしくは、Chromeの開発者ツールなどツールを使って、さらなる情報を得るのは意味のある行為
- この手のはまりで、自分の知らないものが解法であったためしは無い。ただ、単純にロジカルに考える
あと、今回の問題で思い出したけど、ワインバーグさんの言っていたことで
9.「そこにある」と思ったところには問題はない
も加えてみよう。
とか、思いついた。やっぱ今回もこれにバリバリに当てはまっている。
ロジカルに分析してみる
さて、自分が解法をしらないとして、ゼロから分析をしてみる。まず、今回の関係するプレイヤーを整理してみよう。
今回の問題の場合、クラウドである、Azure、このLocale(リージョン)があり、その中にリソースグループという区分がある。そこに、デプロイされる予定の、WebApp が ServerFarm という本来存在するリソースが見当たらないというメッセージのため作成できない問題が起きている。エラーメッセージは問題そのものをレポートしていることもあれば、思ってもいない原因でそのメッセージが返ってくることもある。それはプログラムを組んだことがあれば身に染みているだろう。
それらのリソースは、Azure の REST API の仕組みを通じて、クライアント(今回はazコマンド) から、POSTリクエストが送信される。BODYは、ARMテンプレートと呼ばれるjsonファイルそのものになるだろう。認証がAzureADで行われる。Azコマンドは、ネットワークを介してコントローラにリクエストをポストする。今回のコマンド実行は、シェルスクリプトの中で行われていて、ARMテンプレートと、パラメータファイルがその中で使われている。
まず自分の書いた部分から調べる
Tipsはありがちなものから並べているので、それにしたがって考えていこう。
Tip. 1 を考えると、大抵の問題は、自分の書いたコードだ。となると、ARMテンプレート、パラメータファイル、シェルスクリプトのいづれかとなる。この3つが最もあやしい。特にARMテンプレートは、エラーメッセージが、ServerFarmが参照できないという内容がAzureから帰ってきているので、最も怪しい。ただ、MECEで考えると、エラーメッセージを疑う必要はないが、メッセージ通りの原因とは限らない。よって、怪しい順番に、それぞれ調べていこう。
Tip. 2 のドキュメントをちゃんと読む。今回のエラーメッセージの意味と対処方法はどこかにないだろうか?調べてみるとStackOverflow と、公式ページにもエラーメッセージにヒットするところがあるので、対処策ではなく可能性のある原因を理解する。公式ページがあるのであるあるなのだろう。この3つのポイントをチェックしよう。 -> こんかいはヒットなし。
ARMテンプレートが文法的に間違っている可能性はないか?もしそうなら、BadRequestになるはずなので、それは無さげ。パラメータファイルに問題は?これは、自分が書いてない。ダウンロードしたものなので、Tip. 1からすると可能性は低い。のこりは、スクリプトになる。スクリプトでエラーが出ている箇所を見つけよう。az group deployment create
だな。自分の記述があっているのかを一つ一つ見てみよう。Tip2.でしっかりドキュメントを読んでみよう。
az group deployment create --debug --name WebApps --resource-group $resourceGroupName --template-file ./template.json --parameters ./parameters.json --parameters subscriptionId=$subscriptionId name=${webAppName} location=$resourceGroupLocation hostingPlanName=${webAppName}farm serverFarmResourceGroup=$resourceGroupLocation sku=$sku skuCode=$skuCode
マニュアルはと、、、
az group deployment create --help
Command
az group deployment create : Start a deployment.
Arguments
--resource-group -g [Required] : Name of resource group. You can configure the
default group using `az configure --defaults
group=<name>`.
--handle-extended-json-format -j [Preview] : Support to handle extended template
content including multiline and comments in
deployment.
Argument '--handle-extended-json-format' is in preview. It may be changed/removed in a
future release.
--mode : Incremental (only add resources to resource group)
or Complete (remove extra resources from resource
group). Allowed values: Complete, Incremental.
Default: Incremental.
--name -n : The deployment name. Default to template file base
name.
--no-wait : Do not wait for the long-running operation to
finish.
--parameters : Supply deployment parameter values.
Parameters may be supplied from a file using the `@{path}` syntax, a JSON string, or as
<KEY=VALUE> pairs. Parameters are evaluated in order, so when a value is assigned twice, the
latter value will be used. It is recommended that you supply your parameters file first, and
then override selectively using KEY=VALUE syntax.
--rollback-on-error : The name of a deployment to roll back to on error,
or use as a flag to roll back to the last
successful deployment.
--template-file : A template file path in the file system.
--template-uri : A uri to a remote template file.
Global Arguments
--debug : Increase logging verbosity to show all debug logs.
--help -h : Show this help message and exit.
--output -o : Output format. Allowed values: json, jsonc, none,
table, tsv, yaml. Default: json.
--query : JMESPath query string. See http://jmespath.org/ for
more information and examples.
--subscription : Name or ID of subscription. You can configure the
default subscription using `az account set -s
NAME_OR_ID`.
--verbose : Increase logging verbosity. Use --debug for full
debug logs.
Examples
Create a deployment from a remote template file, using parameters from a local JSON file.
az group deployment create -g MyResourceGroup --template-uri
https://myresource/azuredeploy.json --parameters @myparameters.json
Create a deployment from a local template file, using parameters from a JSON string.
az group deployment create -g MyResourceGroup --template-file azuredeploy.json --parameters
'{
"location": {
"value": "westus"
}
}'
Create a deployment from a local template, using a local parameter file, a remote parameter
file, and selectively overriding key/value pairs.
az group deployment create -g MyResourceGroup --template-file azuredeploy.json \
--parameters @params.json --parameters https://mysite/params.json --parameters
MyValue=This MyArray=@array.json
For more specific examples, use: az find "az group deployment create"
ん、なんか違ってね? -> Done.
既に終わった
と、このTipに従ってるだけでこの時点で終わってるやんけ!少なくともここで、修正しているだろう。もしかすると、組み合わせ問題で、現在つかってたリージョンがたまたまデプロイできなかったとして、調査を進めてみよう。どのようにロジカルに考えられるか?
自分のコード以外を確認していく
自分のコード以外に問題があることは多くないが、一つ一つ確認していこう。
az コマンド
可能性としては、バージョンが古い、バグがあるなどが考えられるだろう。Azure CLI と、エラーメッセージの組み合わせで検索して、Issue や、Stack Overflowを確認する。その前に、リリースノートを見て、それっぽいアップデートがあったら念のために最新バージョンにしておく方が良いかもしれない。Issueはいいのがなかったが、Azure CLI リリースノートを見ると、現在73だけど、最新は77だな、ARM系のアップデートがあるので、念のために最新にしてみて、1回だけ実行してみよう。
参考までだが、ソースがみたければ、こちら。ここでも、@parameter.json
の存在に気づいて DONE かも。
Network
Chrome の開発者ツールや、フィドラーなどを使って、ネットワークのパケットを見ることもあるが、今回は、Tip 6. に従うと、先ほどのコマンドで、--debug
や --verbose
があるので、それをONにするのが最初やな。詳細のエラーを見ても、帰ってきている情報は最初にゲットした情報とかわらないので、ネットワークの問題ではないな。
Azure
Azureがもし、問題だったら、現在障害が起きているな。ヘルスチェックのページを確認しよう。うん障害ないな。
Location
ロケーションによって使えるリソースとか、使えないリソースとかあるので、いくつかのロケーションにデプロイしてみよう。westus がダメなら、ちょっと特殊なwestus2 それと、eastus, central us 程度を試せばどれかヒットするだろう。場合によっては、サブスクリプションが特殊なケースもある(AD絡みは特に)ただ、その場合は、ドキュメントに書いてある。App Service Planのドキュメントを見直すが特に記述はない。試しに、ポータルからデプロイしてみて、デプロイできれば、そのロケーションはそのリソースが使えるはず。そうでない場合は、クオーターにかかっているケースもあるけど、その場合だと、それっぽいメッセージがいつも出るよな。多分、たまたま使えないリージョンをつかっていても、この時点でDone 少なくとも。残りのリソースもロジカルに考えてみる。
Resource Group
そいうえば、さっきのドキュメントで、WebAppと、ServerFarmのリソースグループが違う場合問題とかいてあったな。しかし、それは先ほど確認して、同じだったので、問題ないだろう。
ServerFarm (App Service Plan)
これ自体はデプロイできている。だから、これが参照できないのは、リソースがまだできていないのに参照した場合、もしくは、リソースが不正な状態にある場合。これも先のドキュメントにあった。ちなみに、@parameter.json
の指定を忘れていることで、WebAppに対するパラメータが不足している。特にメタデータのdotnetcore
のメタデータは渡っていないことになる。
AppService
これは、できていないので、問題があるとすると、ServerFarmを参照する部分の記述か、DependOnの記述。書き方をもう一度確認しよう(しかし、ARMテンプレートの調査で既にやってる)
もしまだ解けていなければ
ここまでの調査を重複なくする。すると、たぶんそんなデプロイを何回もすることはなく、1時間ぐらいで終わるだろう。もしまだ解けていなければ次のリソース。すべてのリソースは一応1通り確認した。今までの自分だったら自分がミスしているかもしれないと何回も確認するところだけど、それはしない。
代わりに人間のリソースを考える。ここまでやって解けない問題の場合、他人が解ける問題、もしくは、誰も解けない問題。つまり、自分ではもう解けない問題なので、人に聞いてみたり、人に来てもらって自分の目以外で見てもらう。今回は実際にARM天使のおかげで問題解決できた。
まとめ
Tipsを思い出して、重複作業をせず、ロジカルに考えるだけで、何回も既に解答に到達することがわかった。今後は、試行錯誤はやめて、図を書いて、Tipsを当てはめて解いていくことにしよう。この手のはまりで、自分が知らない問題には出会ったことがないのだから。つまり、ハマりとは、本来そこにない、とおもったものがそこにあるだけであって、難易度が高いのではない。難易度が高いものは逆に問題の発見はやりやすいものの気がする。次のはまり機会が楽しみになってきた。
このメソッドはクソはまる自分が考えたものなので、たぶん普段からはまらない人はもっといい思考回路をしているかもしれません。そういう方は是非コメントなどをいただければ嬉しいです。
追記 師匠と先生から
自分にはプログラミングの師匠と、尊敬するしばやん先生がいるが、このエントリを書いたら、しばやん先生がコメントを、かずき師匠がなんとブログを書いてくれたのでシェアしたい。どちらも必読ですわ。
師匠の言葉
まずは師匠のブログから。そもそもハマらないために、わからないことがあったら、簡単なことでも調査して、理解して、ブログを書くことをが推奨されてる。たしかに私は「こうしたらこう動作する」というのは理解していても、本当にその「かんたんなこと」を理解できているのかは不明だ。だからはまりやすいのがありそうだ。だから、今はかんたんなことと思うことでも理解があやふやなら先に調査してから、取り組むほうが結局速いとのこと。だから今はそうしています。
## しばやん先生の言葉
しばやん先生は、「問題の切り分けのためシンプルな構成で試すのが鉄則」と言ってくれました。確かにARMテンプレートをデプロイするのは、Azure CLI を使っているわけですが、そこに問題があるかもしれないので、まずARMから動くかPortalで試すという考えになり、そこで、すでに、ARMは動作するという知見がえられていたかもしれません。また、私はパラメータファイルの指定と、パラメータの指定を同時にやっていたのですが、それはしばやん先生からすると「複雑」に感じたようです。私はそう思ってなくて、そこが問題かも。しばやん先生は私から見たらものすごく難しい問題を一瞬で最適な方法で解決する人なのですが、この箇所に「複雑」と感じるセンスがあるということです。かずき師匠も、単純なことを馬鹿にしないとおっしゃっています。出来る人はやっぱり、シンプルのセンスがあるようです。自分は「できた」らいいという考えが強い気がします。そうではなくて、人間は難しいことはできないので、愚直なぐらいに単純化したほうが良さげです。過信してはいけなさそうです。シンプルな構成で試すのと、複雑なことをしないというのはやってみたいと思っています。ついある程度スクリプトが出来ていたらエラーがでても、そのままで直しちゃおうとしてしまうから、複数の失敗要素があり、こけた時にどれかわからなくなりそうです。
まかべ師匠
まかべ師匠は次のようなメソッドを使っている様子。ランニングとかしたら、運動不足も解決するし、今回みたいなしょうもない原因のはまりを減らせそう!
追記のまとめ
師匠、しばやん先生のように自分が見たエンジニアのなかでも最も優れているお二人からコメントがいただけて、しかも良いフィードバックが得られて最高です。少しづつでも彼らに近づけるようにがんばってみようと思います。まずはシンプルなことを馬鹿にせず、愚直に。