4週間で KPTをどこまでアップデートてきるかチャレンジ!!!
こんにちは。
この記事は以下のアドベントカレンダーの一環として書かれています。 他の記事もぜひご覧ください。 qiita.com
さて、今回この記事でお伝えすることは、表題の通り、振り返り手法の一つである KPT
を アジャイルコーチにフィードバックをもらいながら1週間スプリント × 4回まわすことによって、どこまでチームの振り返りをアップデートできるかチャレンジしたことについて記載します。
この文章から
チームの概要
まずはじめに筆者の属性やチームの状態などを記載します。
前置きとしては長いので、不要な方は 振り返りをやってみた
まで飛ばしてください。
筆者個人の属性
- フロントエンドを中心にバックエンドやインフラもかじりつつエンジニア歴6年(記事執筆時点)
- CSMの資格を取得済みでチーム内でもスクラムマスターのような振る舞いもしている(いわゆるエンジニアとの兼任スクラムマスター)
チームの状態
- チームが立ち上がったのは2022/10からで、この記事公開時はまだ2ヶ月しか経ってない
- 今回のこのKPTをアップデートするチャレンジをしたのは11月(チーム発足後2ヶ月目)
- アジャイルやスクラムに対する個々人の理解度や経験値はバラツキあり
- スクラム未経験なメンバーもスクラムやアジャイルな開発をしていくことそのものには好印象
もともとの目的意識
チーム立ち上がり時の10月はわりとチームビルディングやざっくりとした「プロジェクトやチームそのもの」の方向性を議論する時間が大半でした。
議論の結果、大まかな方針が定まり、ある程度それぞれが動き出せそうな状態になり、チームの振る舞いも少し調整しようとなりました。
それまでは簡単なデイリーMTGのようなものはありましたが、定期的に立ち止まりチームとして振り返りができる場がほしいなと思い、以下のように組んでみました。
11月実施したチームの動き
実施した全体の動きは以下のようになりました。
- チームのデイリーMTGは引き続き継続
- 1週間を1スプリントとしてまわしてみる
- 水曜日の夕方にスプリントの終わりとして振り返るを実施、その後プランニングを実施
- 振り返り、プランニングそれぞれ各1時間
- プランニングの1時間はスクラムから考えると短いように思えるが一旦試運転な月でもあるので1時間で様子見することとした
- 振り返り、プランニングそれぞれ各1時間
さて、前置きが長くなってしまい恐縮ですが、以下本題に入っていきたいと思います。
振り返りをやってみた
なぜ4週間連続、なぜKPT
今回本格的に振り返りをするとなった際に チームとして振り返りすることに慣れよう
ということを意識しました。
本来の振り返りではチームやそのスプリントの状況によって振り返り手法を変えることで、より詳細にチームの課題感を深堀りすることができるかと思います。
一方でその当時のチームでは振り返りのやり方に気をとらわれ、課題を抽出したり議論を活発に行うことに集中できない可能性があると考え、あえて1ヶ月手法を固定してみました。
振り返り手法を固定にするにあたって KPT
を採用した理由としては、
筆者がそもそもKPTを今まで何度も利用してきたことと、「プラスな点(≒keep)」と「マイナスな点(≒problem)」と「どのようにカイゼンするか(≒try)」が1セットになっており、
この手法に沿って進めておけば振り返りするにあたって欲しい観点が一通り体験できると考えたためです。
スクラムマスターである自分とは別にチーム外のアジャイルコーチについてもらい、振り返りを観察していただき、終わったあとにフィードバックをいただきました。
1週目
実際に1週間スプリントをはじめてまわしてみたときのはじめてのKPTの図は以下になります
- ファシリテーターは筆者
- 振り返りのきっかけになればということでよくあるKPTのフレームワークに追加で「出来事」という枠を用意
- 例: 半日全社会がありました、祝日がありました
- 初回ということもあるし、keepやproblemを思いつく限りたくさん書いてほしいなということで少し長めに記載時間を取った(10分程度取っていた認識)
アジャイルコーチからのフィードバック
- ファシリテーター(筆者)がしゃべりすぎ
- 付箋とかをほぼ全部自分が読んで、詳細があれば書いた人に説明してもらったくらい
- 意見を付箋に抽出するためには余裕を持って時間を取るという選択肢だけではなく、たとえば「みなさん手が止まっているようですが、最後に一人一個ずつ、追加でなにか書いてみてください!」など声をかけたりするだけで意外と時間をかけずとも意見が出たりすることもある
- 「きれいに」終わりすぎているように見える
- tryまで出ているが、きちんと「本質的な課題」や「誰かが実は思っている違和感」などをちゃんと抽出した上でtryが出せているのかが怪しい
- 複数出たproblemに対して
全部
を一度に解決しようとしてしまっているように
フィードバックを受けて
何がなんでもtryを出さねば…
ファシリテーター(筆者)としては「まずは初回の振り返り、一通りまわして会として着地させたい!」というところに意識が向きすぎていて空回りしていたなと感じたところでした。
特に「付箋すべてに触れなければいけない」「tryを何がなんでも出さなければ」というある種の強迫観念のようなものすらあったなと思います。
その結果として「付箋全部に触れつつ、tryまで出したい」-> テキパキまわすために付箋は一旦自分が読んでしまおう、という振る舞いをしてしまいました。
意見の抽出方法
また、少し違うところとしては2つ目のフィードバックにある意見の抽出方法に関しても気づきをもらえたのはありがたかったです。
チームの中の視点としてはあまり違和感がないとしても、外部の目、特に有識者の目があるとこういった細かなtipsにも発展があるのがよかったです。
2週目
2週目のKPTはこんなかんじでした
- ファシリテーターは筆者が続投
- 別件で「アイスブレイクをはじめにしたほうがその後もみんな発言しやすくなる」という情報を手に入れたので、それを取り入れてみた。完全にプライベートで直近あったこと好きに書いてくださいというコーナーを用意し、そこをしゃべってから実際のKPTに入るようにした
- tryはある程度出せたらよい、ということを意識して進行
アジャイルコーチからのフィードバック
- アイスブレイクがとてもよかった
- 引き続きtryまで頑張って持っていこうという意識が前に出てしまっていたように見えた
- problemを全部見なければ、という意識も同様に感じたので、problemの中で投票して「どれから」話していくか取捨選択してもよさそう
- problemの中に「課題」というよりも「○○しなければいけない」といった具体的なアクション(につながること)などがわりと書かれていた
- keepの中にもkeepではなくいわゆる「good」に近しいものがあった
- 筆者がどの立場でしゃべってるのかたまに不明瞭なときがあった
フィードバックを受けて
アイスブレイク
アイスブレイクが好評だったのはありがたかったです。これはバイアスかもしれませんが、前回と比べて他のメンバーもリアクションが大きかったり、「大丈夫でーす」と声にしてくれることが多かったり、気になった点があったらすぐに言ってくれたりなどポジティブな印象を受けました。
一方でなかなか人のクセというのは抜けないもので、アイスブレイクの付箋も全部確認してしまい、ちょっと時間を使いすぎたかなと思いました。
付箋を書く分にはたくさん書いてもらいつつ、発表自体は一人1コンテンツだけ発表してもらう形式にしてもよかったなというところで次回に実施しようと考えました。
problemの深堀り
どうしてもtryまでたどり着かなければ!という気持ちが出てしまい、前回よりはproblemに出ている内容を話し合う時間に充てれたものの、最後はやはり駆け足になってしまったところはありました。
特にproblemに関してはさっと目を通して多少グルーピングなどをしたあとに投票してしゃべる内容を絞ってしまったほうがよいかもとアドバイスいただけました。
KPTというフレームワーク
今回は前回よりかはマシになったということもあって、KPTのフレームワークとしての観点からのご指摘もありました。
problemに関するものでいえば、メンバーは良かれと思って課題感からそのまま解決策もある程度見える形で書いてくれることがありました。
確かに議論としてはその解決策をそのまま受け入れるとスムーズではあるのですが、「本当に困っている点がそこなのか」であったり、「似たような課題感を持っている人の課題も、その解決策で解決できるのか」が怪しいなと考えました。
そういった点から、ある程度解決策が見えているものに関してもあくまで「課題や困っていること」だけ書いてもらうようにする必要があるなと思いました。
keepに関するところでいうとkeepではなくgood、良かったことなども結構散見されていました。
個人的には上記にもある通り、まずは振り返りに慣れてほしいこと、そして変に「これってkeepであってるかな…」と考え込むくらいであればざっくり「良かったこと」として書いてほしいなという気持ちがありました。
アドバイスいただけたこととして、まずは「good」から書き出して、その中から直接keepとして扱うものや、そのgoodがなぜ起こったかを考え、その起因となった行動などをkeepとして新たに書き出すなどして分けて考えてみるのもよいということでした。
このあたりはまだ厳密にはできてないですが、今後意識してやっていければと思います。
どの視点でしゃべっているのか?
前回のときも多少その影があったのですが、筆者が発言をするときにその発言が誰の視点なのかが曖昧なところが今回如実に出ていました。
端的にいうとファシリテーターの人格なのか、スクラムマスターの人格なのか、エンジニアの人格なのか曖昧でした。
受け取り方次第でその後の議論を惑わせ兼ねないところもあるなと思いそろそろ手を加えねばと思いました。
幸いこの2回でざっくりとは振り返りの雰囲気をメンバーが掴んでくれているということと、どのメンバーも場を回すことが極端に苦手とかではないため、
まずは次回からファシリテーターを当番制にすることにしました。
3週目
- ファシリテーターは別のメンバーが担当
- 雑談コーナーは前回の反省を踏まえて一人1コンテンツだけ発表
- problemの話し合いは付箋に投票することで議論する内容を決定
アジャイルコーチからのフィードバック
- 議論の時間が伸びていてよかった
- 引き続きproblemの付箋で解決策が書かれているものが見受けられる
- 付箋に対するコメントを事前にもらってもよいかも
- 前回のtryができているのかを確認する場があってもよい
フィードバックを受けて
ファシリテーター「じゃない」目線
まず筆者個人の感想として、ファシリテーターじゃないロールとして参加するとこんなにも安心して振り返りに参加できるのか、と感じました(笑)
次の工程や議論を集約させるところに必要以上に神経を尖らせる必要がなく、純粋に気になったところを質問したり、深堀りしたりするように促すことができました。
また、メンバーそれぞれで振り返りをするにあたって微妙にやり方が違うところがまた個性であったり、発見があって良いなとも思ったので、引き続きチームとしてはファシリテーターを交代しながらやりたいと思いました。
結果として議論の時間が伸びたのでよかったです。 ここに関しては今回ファシリテーターを担当してくれたメンバーが過去のフィードバックを活かしてくれたり、時間でしっかり区切ってズバッとやってくれたりしたおかげです。
各付箋との付き合いかた
とはいえ改善はできたものの、前回から引き続き「解決策」まで書いてくれてしまっているところがあったので、次は具体的に「課題や困っていること」だけ書いてもらうように促さなければならないなと思いました。
また、メンバーが多岐に渡って議論を展開してくれるため、各付箋を見て回り、そこに対して一言二言コメントするだけでもわりと時間を要してしまっていることがわかりました。
そのため、事前(keepやproblemを書く時間など)にある程度コメントできそうなものは事前にコメントしてもらうようにしたいと考えました。
あとは前回のtryが実際にどうだったかを観察できるとよいね、というところもあり、その点も次回に反映しようと思いました。
4週目
- ファシリテーターは別のメンバーが担当
- 前回のtryを確認するコーナーを用意
- keepの深堀りも一部実施(これは事前に意図したわけではなく、会の中で自然とそうなった)
- 「problemには困っていることや課題だと思うことだけ書いてください」と事前周知
- 余力があれば遠慮なくmiro上で事前にコメント書いてもらった
アジャイルコーチからのフィードバック
- 前回よりも議論の時間が伸びていてよかった
- 振り返りの段階はどこを意識していたのか
- チームとしてどうありたいのかを意識できるとよい
フィードバックを受けて
期せずして keep
の内容での深堀りができたのはよかったです。
端的にいうと「○○がいいかんじに進んでいる」といった内容なのですが、いい感じなのがチームとして合意が取れていつつ、その理由がわりと不明瞭だなと思ったので深堀りをしてみました。
今後も いいこと
の深堀りも意識したいなと思いました。
ある程度チームとしての振り返りの型が見えてきたこともあり、その他では細かなところでの指摘はほぼありませんでした。
その代わりもっと本質的なところでご指摘をいただきました。
振り返りの段階
アジャイル開発で欠かせない「ふりかえり」、チームを強くするための3つの段階とは|CodeZine(コードジン)
森さんのお言葉を借りると、振り返りには3つの段階があるといいます
- 立ち止まる
- チームの成長を加速させる
- プロセスをカイゼンする
上記のうちどこを意識していたかと問われました。
その点に関して筆者としては2番目の「チームの成長を加速させる」をその振り返りのタイミングでは意識していたと言いました。
一方でアジャイルコーチからは、「それであれば今回の振り返りでは焦ってtryを見出すところまでやらず。problemの言及に時間を使い切ってしまうのもアリだったのでは?」といただきました。
確かに意識していたことと、実際に起こしたアクションがずれていたのは良くなかかったなと思います。
そして、自分としてはそう思っていたとしても、チーム全体としてどういう意識だったかは曖昧だったなと思い、チーム全体としてどういう段階、どういう目的かを事前に共有すべきだなと考えました。
チームとしての在りたい姿
上記のところか通ずるところとして、「チームとしてどうありたいのか」というところもご指摘いただきました。
漠然とプロセスをカイゼンするだけだとカイゼンしていく向き先があっているのかわからない、適切に自分たちが思う方向に向かって進んでいけているのかわからないなと思いました。
振り返りを通じてチームの輪郭や、良しとされるアクション、推奨されないアクションなども見えてきたのでここいらでワーキングアグリーメントであったり、
「チームとしての在りたい姿」を今一度言語化し、それらを意識して振り返れるようにしたいなと思いました。
1ヶ月を振り返って
今までこのチームに所属する前も振り返りはやっていましたが、ここまで意識して振り返りをしたのははじめてでした。
これまでやってきた振り返りは「tryを出す」ために振り返りをしてしまっていたなと反省しています。
もちろんtryを出すことは大切ではありますが、きちんとチーム内でコミュニケーションが取れており、課題などにちゃんと向き合えることがまずは大事だなと思いました。
そしてその課題を解決するためにtryを出すことはありますが、それは枝葉のhowの部分を改良していくということではなく、チームそのものが学習し続ける習慣を作ることが大切だと思いました。
そしてその行く先としてチームとして自律的に考え、行動していける状態になることがアジャイルなチームなのかと考えています。
今後はそういった「チームにとってのアジャイルな姿」をチーム全員で意識し、その姿になれるよう振り返りを続けていきたいなと思いました。
※上記に書いてあるアジャイル、スクラムに関する内容は極力大本となる思想に沿う形で体現やフィードバックしていただいているつもりですが、一部筆者やフィードバックをしてくれた方の思想寄っているところもあると思うので、あくまでこういった考え方、選択肢もあるというふうに捉えていただけると幸いです。
AWS CDKでサーバーレスなフェイルオーバールーティングを実装してみた
大阪リージョンもついにローカルリージョンから正式なリージョンへと昇格したので、冗長化した構成を試してみたいと思い実装しました。
やったこととしては
- 東京リージョンと大阪リージョンにapi-gateway × lambda で簡単なAPIを用意
- Route53で東京リージョン側をPRIMARY、大阪リージョン側をSECONDARYとしてfailoverした際に切り替えれるようにした
フェイルオーバーの試し方
- CDKのスタックを流し、環境をつくる
packages/cdk/lib/config.ts
で設定したドメインを叩き、 東京リージョン側のレスポンスが返ってくることを確認する- 東京リージョン側のlambdaのレスポンスを意図的に失敗するようにする
- -> 30~60秒後に大阪リージョンからレスポンスがくるようになる
ハマったこと & 注意点
Route53の設定が Cfn
のメソッドで実装する必要があった(2021/04/02時点)
High Level Construct
がまだ提供されていないようだったので、 Low Level Construct
で実装する必要がありました。
そのため、Route53のCloudFormationの理解を求められました。
AWS::Route53::RecordSet
AWS::Route53::HealthCheck
- CfnRecordSet.failover の型は
string
だが許容される文字はPRIMARY
かSECONDARY
のどちらかのみ - CfnRecordSet. AliasTarget に設定する
dnsName
やhostedZoneId
はapi-gateway
のAliasDomainName
やAliasHostedZoneId
を使用する - api-gatewayで生成されるendpoint(今回healthcheckに利用するendpoint)は
https
でしか叩けないため、CfnHealthCheck. healthCheckConfig のtype
とport
にはそれぞれHTTPS
と443
を指定する必要がある - CfnHealthCheck. healthCheckConfig. fullyQualifiedDomainName はいわゆる
URI
の部分を差し込む必要がある- CDK上の
apigw.LambdaRestApi
からは urlForPath でapi-gatewayのendpointを取得することはできるがhttps://xxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/
として返ってきてしまい、https://
や/prod
の箇所が不要である - そのため
this.healthCheckDomainName = `${this.api.restApiId}.execute-api.${props.env?.region}.amazonaws.com`;
といったように自前で URI 部分だけstringに格納して、CfnHealthCheck. healthCheckConfig. fullyQualifiedDomainName
にわたす必要がある
- CDK上の
CfnHealthCheck. healthCheckConfig のデフォルトの設定値だと、failoverで切り替えするまでに時間がかかる
HealthCheck
を行ってターゲットを切り替えようとする際に、Route53では以下のように評価を行っているとのこと。
Route 53 はヘルスチェッカーからデータを集計し、エンドポイントが正常であるかどうかを判断します。
・18% を超えるヘルスチェッカーがエンドポイントを正常であるとレポートした場合、Route 53 はそのエンドポイントを正常と見なします。
・ ヘルスチェッカーが正常であるエンドポイントが 18% 以下であるとレポートした場合、Route 53 はそのエンドポイントを異常と見なします。
※Amazon Route 53 がヘルスチェックの正常性を判断する方法
そのため、エラーがおきたらすぐ切り替わるかというとそうではありません。
また、 HealthCheckConfig のデフォルト値は以下のような設定になります
- FailureThreshold : 3
- RequestInterval : 30
- Regions : [us-east-1, us-west-1, us-west-2, eu-west-1, ap-southeast-1, ap-southeast-2, ap-northeast-1, sa-east-1] (現在ヘルスチェッカーとして指定できるリージョンすべてから叩かれる)
18% を超えるヘルスチェッカー
がとあるため、Regionsの数が多くてFailureThresholdの条件も回数が多いと18%
に至るまでに時間がかかります。
※厳密に計測はできていないですが、上記のデフォルト値でfailoverさせると切り替えまでに1分以上かかっていました
そのためエラーが発生したらすぐに切り替えたい、ということであれば上記の値を低め、少なめに設定する必要があります。
今回試した値は以下のような設定値にしており、これだと30秒から長くても1分以内には切り替わるようになりました。
- FailureThreshold : 1
- RequestInterval : 10
- Regions : [ap-southeast-1, ap-southeast-2, ap-northeast-1]
このようにいろいろ考慮する必要はありましたが、ひとまずfailover routingはできたかなと思います。
Low Level Construct はしんどいな〜と思いましたが、本来 High Level Construct で書くときも同じくらい把握して書かないとだめだなと再認識しました。
Miroを使ってオンラインKPTAをやってみた
昨今のリモートワークの流れの中で、ご多分に漏れず私もリモートワークをしております。
そんな中で、どうにかしてオンラインでもいい振り返りを行うことができないか考えていたところ、別件で使っていたMiroというツールを使うと、効果的な振り返りができたので記載します。
振り返り
振り返りの手法としては KPTA を利用しています
いつもオフィスでやる際にはホワイトボードと付箋を使って実施していました。
もちろん今リモートワークをしているときには残念ながらどこかに集まって実施、とはできないので、なにかオンラインで同様のことができないか模索していました。
Miro
そんな中で見つけたのが Miro です。
オンラインのホワイトボード系のツールで、パーツも豊富で自由度高く操作することができます。
オンライン時のルールとして
まだまだ運用については発展途上なところがありますが、現状は以下のようなルールでおこなっています。
■運用事項 - 基本は一応ホスト(後述)の人が画面をzoomなどWeb会議で共有をしておくが、基本は個々人がMiroの画面を見て、操作することを推奨 - 基本は1KPTA 30分で想定 - 明らかに延長しそうな場合はMTG設定時に長めに確保すること(反省したいこと盛りだくさん、や、参加者が多いと長引きやすい傾向があるので、そこは見越して設定すること) - 開始前までに自分のKeep、Problem、Tryを書いておき、まとめて各エリア内に配置しておく。また他のメンバーが書いたものに目を通しておく ■ 役割分担 - ホスト : ・zoom(などのオンラインMTGツール)のURL準備と参加者に共有 ・全体の進行 ・グルーピングと、グルーピングした内容のタイトル付け(グルーピング自体は付箋を移動させる程度、清書は書紀の人に任せる) ・tryをベースにactionを決めていく - 書紀 : ・ホストの人が大まかにグルーピングした内容や付箋の配置などを見やすく再配置などする ・複数人KPTAに参加者がいれば、Keep、Problem、Tryにそれぞれ書紀を配置する ・関連性のあるものに対してや付箋間やアクションに対して矢印などをひっぱる
オンラインのメリット
事前に反省内容を列挙しつつ、他のメンバーの反省内容を把握した状態でMTGに参加することができる
オフラインでやる場合でも、自分の分は先んじて用意することは可能ですが、他のメンバーが書いた内容に目を通すことができるのはオンラインならではのメリットだなと思います。先に目を通すことができるため、各々が思っていることの「共有」自体にはあまり時間をかける必要がなくなり、「質問」や「議論」に時間を使うことができます。
MTG参加者がただ聞き手に回るだけではなく、付箋の整理などで全員でMTGをつくっていける
オフラインでやる場合は上記役割分担の「ホスト」に該当するような人が全体の進行などをしますが、他の人は付箋に課題を書き出したあとは聞き手にまわることが多いです。物理のホワイトボードだとどうしても複数人で触るには難しいのですが、オンラインだと複数人で同時に編集することが容易であるため、課題の列挙やグルーピングなどが(ホストに頼り切りになることなく)スムーズにできます。
また、各々がMTGに対して役割ができ、「全員でMTG」をすることができます。
過去のKPTAの確認がしやすい
現状の運用では、同一のMiroのボード上にKPTAのシートを適宜追加するようにしています。このことにより、以前のKPTAシートがすぐちかくにあり、新たにKPTAをするときも過去のものを確認しつつ実施することができます。
オンラインのデメリット
オンラインによる操作のしにくさや不慣れな場合に、リアルでやるときよりも時間がかかってしまう
オンラインKPTAを実践しはじめのときに顕著だったのですが、操作性に不慣れな中で、リアルのときと同じ運用をしてしまうと、時間がかかってしまうことがありました。ある程度オンライン用にやり方を変更(情報の「共有」にかける時間は極小化し、「議論」に時間を使うスタイル)をしてきてからはだいぶ完全されましたが、やはりオンラインの物理ホワイトボードと付箋での手軽さのノリとは勝手が違うなと思います
議論を深めたい場合、うまくホストがコントロールできないと沈黙が続いたり、誰かが一方的に意見を言ったりなど適切に議論ができないことがある。
これはKPTAに限らず、オンラインMTGの課題だと思います。KPTAの場合はactionを決める際に、tryが不足していたり、課題感が不明瞭だとメンバーの雰囲気がわかりにくければ更にactionに落とし込むのが難しいときがありました。運用やファシリテーションでうまく全員が意見を言い合えるようコントロールできればよいかと思います
最後に
オフラインにはオフラインの、オンラインにはオンラインの良さがそれぞれあるなと思います。対面でのMTGに慣れていた方はオンラインでのMTGでは難しさを感じることが多いかと思いますが、(自分も当初はKPTAをどうしようかと悩んでいました)Miroと組み合わせ、また、オンラインなりのやり方を模索したおかげで、今までより保存性・視認性に高いKPTAの運用ができるようになりました。
オンラインの良さを活かしてMTGができるとよいなと思います
ループ処理するなら forEach > for > while という順でmethodを検討すべき、と思っている理由
TL;DR
forEach などのarrayのインスタンスが持ってる「その配列の中身を操作する」メソッドの方が
無限ループ も起きないしいいよね、というところです。
はじめに
配列などの複数のデータに対して、何らかの処理をするとなった場合ループの処理を実装するかと思います。
その際に端的に言うとメソッドとして forEach、 for、 while あたりが選択肢になってくるかと思いますが、個人的にはforEach -> for -> while の順で使用するメソッドを検討したほうがいいと思ってます(forEachが使えるならforEachを使おう、使えないなら次にforが使えないか検討しよう、という意味です)
なぜ、この順番で検討したほうがいいかと思ってる理由を以下に記述してきます。
※一旦jsの話として書きますが、思想自体は他の言語でも共通だと思います。
ループ処理を使うときに意識したいこと
個人的に意識したいところとしては以下の2点です
- 無限ループ
- デバッグのしやすさ
無限ループ
意識したいこととして2点あげてますが、はっきりいってこれがメインの理由です。
警察につかまる騒動でも一時期話題になりましたが、ループでまわす処理が終わらずずっと続いてしまうあいつのことです。
クライアント側にしろサーバー側にしろメモリは食われて動作しなくなるし、100歩譲ってメモリが生きてても後続の処理は実行されなくなるので、絶対に避けたいところです。
デバッグのしやすさ
ループしたいデータの中身が絶妙にキレイではなく、特定のデータに対してバリデーションかけたりが必要だったりするパターンもあるかと思います。
その際に実行タイミングで確認したいとなったときに1件1件止めながらのチェックとかは、件数すくない場合はいいですけど、多くなるととてもじゃないけどそんなことはできません。
そのため確認がしやすい構造のほうがよいです。
※詳細は割愛します。
各methodの特徴
forEach
const sampleArray = [1, 2] sampleArray.forEach((sample) => { console.log(sample) })
jsで書くとなると上のようなかんじになります。
利点
確実に Array内の要素の個数 しか実行されません。 空の配列でも実行はされますが、エラーとかは履きません。 確実に無限ループを防げます。
またtypescript (× VSCode)の場合、
type SampleArrayType = { // SampleArrayTypeという型の規定です id : number text : string } const sampleArray : SampleArrayType[] = [ // ※ { id : 1, text : "Sample 1" }, { id : 2, text : "Sample 2" }, ] sampleArray.forEach((sample) => { console.log(sample.hoge) // <- "hoge"なんていない、とEditor上で怒られる }) // ※ ": SampleArrayType[]"の表記は はsampleArrayという変数は"SampleArrayType"という型の"配列"([])で変数定義します、という型定義です。 // そのため、 // { // id : "3", // text : "Sample 3", // name : "Lifebook" // } // とか突っ込むと「idがstringで定義されてるけど、SampleArrayTypeの型としてそれは駄目やで」と // 「SampleArrayTypeの型にnameなんてプロパティ存在しないで」と怒られます
forEach内の sample の変数が型推論で自動的にSampleArrayTypeの型として認識され、エディター上でエラーを吐いてくれます。
実行時のエラーじゃなくて、実装時にわかってくれるのは修正コストが一番低いのでめちゃありがたいです。
欠点(?)
ループ数が確実にArrayの個数に依存するので、forとかよりは多少自由度はさがりますが、そこは実装次第な気がします。
for
const sampleArray = [1, 2] for (let index = 0; index < sampleArray.length; index++) { console.log(sampleArray[index]) }
利点
上にも書いてますが、forEachよりは多少自由度はあるかなと思います。
スタートのindexを0ではない数字からスタートしたり、ループ数をindex < sampleArray.lengthではなく別の数字にしたい、などあればこちらをいじるといろいろできます。
欠点
ただし、個人的には上記をいじると無限ループのもとになりかねないと思っているので、それならforEach内で分岐書いたりしたほうがいいと思います
極端な話しですが、上の例でいうと let index = 3、 index > sampleArray.length と書いた瞬間に無限ループです。
const sampleArray = [1, 2] for (let index = 3; index > sampleArray.length; index++) { console.log(sampleArray[index]) }
画面ロード時に必ず実行されるタイプの処理であればテストのタイミングで気づくかと思いますが、何らかの処理(特定のタイミングでボタンを押した際に実行など)をしたタイミングでループがまわるものとかは時折テスト漏れで本番時に発覚するなどありえるため、実行回数が必ず決まっているもののほうがよいなと思います
While
const sampleArray = [1, 2] let count = 0 while( count <= sampleArray.length){ console.log(sampleArray[count]) count++ }
利点
正直上の例文ではwhileの必要性はまったくないですし、冗長になってますが、再帰的に何かを処理したり、ループしたい内容がループの処理をした結果増減する(ループする回数がループ前に確定していない)ものとかだとwhileを使わざるをえないかと思います
欠点
この3つのメソッドの中で一番取り扱いに注意が必要だと思っています。
上記forの話での無限ループの記述は若干冗談を交えているところはありますが、(とはいえ可能性は全然あると思ってます)
上のwhileの場合、 count++ の処理を消した瞬間に無限ループなので、本当に怖いと思ってます。
終わりに
ということでループ処理についてちょっとまとめてみました。
無限ループのくだりは初期実装時というよりも、とくに修正タイミングとかで如実になる内容かと思うので、メンテナンス性の高いコードを書くという点では意識するとよいのかな〜と思います。
IEでforEachが使えなかった(という誤解)
IEだと未だに使えないjsのmethod多いですよね・・・
(なぜまだ必死こいてIEのサポートをしなきゃいけないかなんて聞かないでください・・・)
結論
NodeList
は forEach
をサポートしていない・・・
やってたこと
const lists = document.querySelectorAll('.list') lists.forEach((li) => { // hogehoge })
- そもそも
アロー関数
のタイミングで怒られる function
に書き換えても「forEachサポートしてないから!」と怒られるArray.prototype.forEach
を見にいって、「IEもサポートしてるじゃん!」と勘違いする
developer.mozilla.org
- よくよく考えたら document.querySelectorAll
って普通のArrayじゃないもの返してきてた気がする(そして前も似たことやってた気がする) <- イマココ
終わりに
IEつらい・・・
Nuxt × Firebaseの環境を作ったときにcore-jsまわりで怒られたこと
nuxtとfirebaseを使って簡単なタイムラインぽいWebアプリを作ろうとした際に、buildしたタイミングでコケたという話です。
core jsが〜と怒涛のログが出てきました。。。
エラー時の状態
どうやって作ったか
npx create-nuxt-app hogehoge
といったよくあるnuxtプロジェクトの作成コマンドで作りました。
オプションはちょいちょい入れていますが、それらは package.json
参照ということで。
nuxtのバージョンは 2.11.0
でした
package.json
... "dependencies": { "firebase": "^7.8.0", "@nuxtjs/dotenv": "^1.4.1", "nuxt": "^2.0.0", "vuexfire": "^3.2.1" }, "devDependencies": { "@nuxtjs/eslint-config": "^1.0.1", "@nuxtjs/eslint-module": "^1.0.0", "@nuxtjs/vuetify": "^1.0.0", "@vue/test-utils": "^1.0.0-beta.27", "babel-eslint": "^10.0.1", "babel-jest": "^24.1.0", "eslint": "^6.1.0", "eslint-config-prettier": "^4.1.0", "eslint-plugin-nuxt": ">=0.4.2", "eslint-plugin-prettier": "^3.0.1", "jest": "^24.1.0", "prettier": "^1.16.4", "vue-jest": "^4.0.0-0" } ...
でたエラー
普通に yarn dev
と打ち込んだら
ERROR Failed to compile with 34 errors These dependencies were not found: * core-js/modules/es6.array.find in ./.nuxt/client.js * core-js/modules/es6.array.iterator in ./.nuxt/client.js * core-js/modules/es6.date.to-string in ./.nuxt/utils.js, ./.nuxt/components/nuxt.js * core-js/modules/es6.function.name in ./.nuxt/client.js * core-js/modules/es6.object.assign in ./.nuxt/client.js * core-js/modules/es6.object.keys in ./.nuxt/utils.js * core-js/modules/es6.object.to-string in ./.nuxt/router.scrollBehavior.js, ./.nuxt/components/nuxt.js * core-js/modules/es6.promise in ./.nuxt/client.js * core-js/modules/es6.regexp.constructor in ./.nuxt/utils.js * core-js/modules/es6.regexp.match in ./.nuxt/client.js * core-js/modules/es6.regexp.replace in ./.nuxt/utils.js, ./.nuxt/components/nuxt.js * core-js/modules/es6.regexp.search in ./.nuxt/utils.js * core-js/modules/es6.regexp.split in ./.nuxt/utils.js, ./node_modules/babel-loader/lib??ref--2-0!./node_modules/vue-loader/lib??vue-loader-options!./.nuxt/components/nuxt-build-indicator.vue?vue&type=script&lang=js& * core-js/modules/es6.regexp.to-string in ./.nuxt/utils.js, ./.nuxt/components/nuxt.js * core-js/modules/es6.string.includes in ./.nuxt/client.js, ./.nuxt/components/nuxt-link.client.js * core-js/modules/es6.string.iterator in ./.nuxt/client.js * core-js/modules/es6.string.repeat in ./.nuxt/utils.js * core-js/modules/es6.string.starts-with in ./.nuxt/utils.js * core-js/modules/es6.symbol in ./.nuxt/index.js, ./.nuxt/components/nuxt-link.client.js * core-js/modules/es7.array.includes in ./.nuxt/client.js, ./.nuxt/components/nuxt-link.client.js * core-js/modules/es7.object.get-own-property-descriptors in ./.nuxt/utils.js * core-js/modules/es7.promise.finally in ./.nuxt/client.js * core-js/modules/es7.symbol.async-iterator in ./.nuxt/client.js, ./.nuxt/components/nuxt-link.client.js * core-js/modules/web.dom.iterable in ./.nuxt/utils.js, ./.nuxt/components/nuxt-link.client.js To install them, you can run: npm install --save core-js/modules/es6.array.find core-js/modules/es6.array.iterator core-js/modules/es6.date.to-string core-js/modules/es6.function.name core-js/modules/es6.object.assign core-js/modules/es6.object.keys core-js/modules/es6.object.to-string core-js/modules/es6.promise core-js/modules/es6.regexp.constructor core-js/modules/es6.regexp.match core-js/modules/es6.regexp.replace core-js/modules/es6.regexp.search core-js/modules/es6.regexp.split core-js/modules/es6.regexp.to-string core-js/modules/es6.string.includes core-js/modules/es6.string.iterator core-js/modules/es6.string.repeat core-js/modules/es6.string.starts-with core-js/modules/es6.symbol core-js/modules/es7.array.includes core-js/modules/es7.object.get-own-property-descriptors core-js/modules/es7.promise.finally core-js/modules/es7.symbol.async-iterator core-js/modules/web.dom.iterable
To install them, you can run: npm instal ...
と言われたって「はいそうですが」とinstallはしないので回避策を調査。
とりあえず firebase
のuninstallしたらまたちゃんと動いたので、 firebaseのインストールが起因してることはわかった。(firebaseが悪いとは言ってない)
参考 qiita.com
結論
一旦採用したもの
@firebase/app @firebase/firestore @firebase/auth
個別にインストールしたらエラーが出ずにbuildされました。
公式の情報によると
v2.6.0時で、 nuxt.config.js
をいじってcore-jsの2系と3系を入れてbuildできるようにサポートしてるよ、とのこと。
nuxtjs.org
余談
firebaseが原因?
firebase
が悪いのか、と言われたらそのへんは厳密にはわからないかんじですね。
どちらかというと nuxt
と組み合わせるとコケてるよ、といった話が。。。
nuxt上でのissue
firebase
をキーワードにしたissueはあがってなさそう・・・?
github.com
core-js 3系のデフォルト対応
今回の件、わざわざconfigをいじらなきゃいけないというところもあって、本来ならnuxt側がそもそも対応してたほうがよいのでは?と思いつつ、v2.6.0以降のリリースノートを見てもcore-jsまわりの話はなさそう。。。
と、思ってたら3系にあげる動き自体はあるようです。
github.com
これが入ったらわざわざconfigいじらなくてもよくなるのだろうか・・・
今後のverupに期待。
「IT業界の病理学」を読んで
IT業界の病理学
完全にタイトルに惹かれて読みました。笑
各テーマ(ex: エンジニアリング、プロジェクトマネジメント)とかの解説書の一角に、「こういう問題が発生したら、こう対処したらいい」みたいな言説があったりするかもしれませんが、「IT業界」という大きな枠から「よくある問題とそれに対する解消法」といった観点で書かれている本は珍しく、読んでいておもしろかったです。
以下は読んで特に興味深かった内容です。
本からの抜粋
アジャイルのチェックリスト
チェック項目 | 判定 |
---|---|
ユーザーは協力的か | No -> アジャイル不可 |
開発メンバーのスキルは十分か | No -> 不可 |
サービス開始日は決められており、延長不可か | Yes -> 不可 |
ミッションクリティカルか | Yes -> 重大な被害が出ることがある |
ユーザー、メンバーは同じ場所で作業できるか | No -> 不可 |
厳密なタイムマネジメントで管理可能か | No -> 不可 |
開発のあと、別のベンダーが運用するか | Yes -> XP不可 |
このあたりの駄目なポイントは覚えておきたい。
そもそも導入可能か、という判断基準であるところはもちろん、
ものによっては時間経過によって変化し、駄目なパターンになってしまっていることもあるので、忘れずにいたい。
レビューの頻度ややり方など
重大欠陥を効率よく検出するレビュー手法の提案と
有効性の実験報告
https://www.juse.or.jp/sqip/workshop/report/attachs/2012/SQiP3-riku.pdf
https://www.juse.jp/sqip/symposium/archive/2013/day1/files/happyou_shiryou_A1-1.pdf
なんとなく「あまりサイズ感が大きくなく」「できるだけ早いタイミングで」「複数回やる」ほうがレビューはいいのかなと思っていたが、体系的にまとまってるものを見たことがなかったので、ちゃんと読んで説明できるようにしたい
バグレポートの改善に向けた 問題事例の調査とアンチパターン作成
https://www.juse.jp/sqip/symposium/archive/2014/day2/files/happyou_C3-3.pdf
こちらも同様。ちゃんと把握しておきたい。
DevOpsの体制
解決案としては「対等の連携ではなく、上下をつける」という方法が有効です。
・開発を上にして、運用部門を管理・コントロールさせる
・運用部門を上にして、開発は運用サイクルの一環という位置づけにする
DevOps内で開発と運用は対等な関係をイメージしていたが、たしかに対等だと対立が起きてうまく進まないことがあるのだなと改めて理解した。
開発を上にしちゃうとちょっと運用側がないがしろ、というか実装やリリースを優先されてしまいそうなイメージもあるが、運用側が強くなると、開発側が不満を憶えそうな気もする。。。
もちろんちゃんと歩み寄れ、という話ではあるが、どちらの体制がよいのかとても興味がある
高齢化するばかりの運用現場
これは単純に読んだ感想であるが、運用現場にも高齢化の波が押し寄せているのだなと思った。
過去の慣習がそのまま残り、職人芸化した運用手法や、それを変える風潮のなさ。
どんな場でも、どんどん日々勉強し、改善していくという環境を作っていく必要があるのだなと考えた。
マネジメント/リーダーシップ理論
以下あとで確認したい
レヴィンのリーダーシップ類型
ゴールマンの6つのスタイル
三隅のPM理論
納期の考え方
日本の納期はピンポイントの日付だが、本来は○○日~☓☓日と幅をもたせるべき
デコルマら「熊とワルツを」
冷静に考えると確かにピンポイントで決まってる必要はないなと思った。
もちろん何らかの公開日とかは定まってる必要はあると思うが、納期自体は幅があってもよいと思った。
大きなプロジェクトとなるとさらに不確定要素が多くなるため、柔軟性が求められる。
エンジニアをレベルアップさせる「ファシリテーション入門」
さすがWeb上になんでもある時代・・・
勉強します
https://gihyo.jp/lifestyle/serial/01/facilitation
全体の雑感
当たり前ではあるが、各テーマに対して深堀りした研究や本などもあって、あんまりそのへん勉強せず、過去の知識だけでなんとかしようとしているなと改めて思った。
本の中で記載のあった引用元の本を起点にもう少し勉強してみたいなと思った。
特にレビューまわりとか・・・