WIP:トイルの倒し方

運用上で発生する手作業のことをトイルと言うらしい。

現在自分のチームでもトイルが発生しており、自分の練度では始めからそれを避けることが難しく、これからも継続的に発生することが予想される。

そこで、トイルが解消されていく過程の中に幾つかの段階を見出し言語化することで、開発や改修の際にどのクオリティを目指すか、自分たちが今どこにいるのか共通認識をとることを試みる。

状況設定

新人エンジニアのAは、内製ソフトウェアの開発運用チームに所属している。彼は上司のBの指導のもと、開発業務を覚えつつ、日々発生する手作業による運用のカバー業務を全うしている。

永続化されない知識

この段階でAのチームにはドキュメントがなく、トラブルを解決するための知識が属人化している。

Aがユーザーからの問い合わせを受けると同じ内容をBに問い合わせるしかなかった。

多くの場合はBの時間を奪うことでうまくいったが、Bが会議中の時はユーザーを待たせるしかなかった。

検索できない知識

Aはこの状況に耐えかねて、自分が知っている問題への対応方法をドキュメントにまとめた(えらい)。彼はそれを社内のドキュメント管理システムに登録し、既知の問題であれば自力で解決できるようになった。

ある時、同僚Cがその問題について質問してきた。Aは例のドキュメントが役に立つと判断し、チャットでリンクを送った。

その後もCは繰り返しその問題の解決方法を問い合わせてきた。三度ほど同じ回答をするとそれは収まったが、新しい問題が発生するたびにAは質問に答える必要があった。

この段階では、解決方法そのものは永続化されているが、問題からそれを導くために必要なポリシーが属人化している。

ファジーな質問

Aはドキュメント管理システムのタグ機能を使ってトラブルシューティングを分類した。これにより検索性が向上し、チームは自力で問題を探すことができるようになった。

しかし、10件の問い合わせのうちの6件は要領を得ないもので、チームは適切なトラブルシューティングを見つけるための追加のコミュニケーションに足をとられ続けた。

この段階では、問題から解決を導く方法がポリシーが永続化されたが、質問を問題に落とし込む方法は属人化している。

構造化された質問

Aはユーザー向けの問い合わせフォームを設置することで、チャット上に溢れるプレーンテキストを駆逐することを目指した。

問題についての報告は、チャット履歴ではなくチームが管理するデータベースに挿入されるようになった。報告はいくつかのタイプに分類され、必要なヒントが適切なカラムに挿入された。

チームはそれらの情報をもとにドキュメント管理システムを検索したり、ハイパーリンクを辿ったりすることでトラブルシューティングにアクセスできた。

またそれが不十分であった場合にも、チームがユーザーに対してとるべきコミュニケーションは明白だった。その際にユーザーに投げかける問いは、多くの場合フォームと同じ構造を持っていた。

この段階では質問を問題に落とし込むためのポリシーがフォームに永続化されている。これにより全てのポリシーが属人性から解放されたように思えたが、不思議なことに運用のための手作業は依然存在している。

アクセスできない機能

Aは、問い合わせられる問題のいくつかが一意の解決方法と対応しており、よってオペレーターの手を介さず自動的に解決できるものであることに気付いた。

そこでAは問い合わせフォームに似た画面をシステム上に実装し、その内容をもとにプロセスが自動で呼び出されるようにプログラムした。

しかしそれをリリースしても、フォームからの問い合わせは一向に減らなかった。ユーザーは問い合わせフォームを開くことはできても、機能にアクセスすることができなかった。

この段階では、ユーザーが解決策に辿り着くためのポリシーを持っていないため、チームに頼らざるを得ない結果となった。

ヘルプガイド

Aはこの状況を受けて、チームが管理している構造的なドキュメントをエンドユーザー向けに書き直し、システムに同梱することにした。

ユーザーは必要に応じてそのガイドにアクセスし、いくつかの問いに答えることでトラブルシューティングに辿り着くことができた。その問いはドキュメントや問い合わせフォームの構造と非常に似通っていた。

この段階では、ユーザーは問題を一意に特定し、その解決方法を決定するポリシーにアクセス可能になった。

続きは今度書く

茨城のひっくい山に登った

有給を使って茨城県日立市にある山に登りました。

日立市東海村との境にある久慈川と西側の多賀山地、東側は太平洋に囲まれた地形です。ガラス張りになっている駅から見える海が綺麗なので、チャンスがあれば茨城県民は行ってください。毎回登山のためにしか行かないのでそれ以外の魅力を知りませんが...

今回行ったのはこの多賀山地に属する神峰山、高鈴山、御岩山が連なるエリアです。この辺りは昔日立鉱山があったところで、至る所に当時の人々の暮らしの痕跡である廃墟や建物の基礎を見かけます。夜に通ると多分めっちゃ怖いです。

この辺りで最も象徴的な建物が、昔煙害が問題になった際にその対策として建てられた大煙突です。日立駅を中心とする市街地からこの煙突の横を通って山に入っていくルートが、学生の頃からの定番になっています。

今回はこのルート上で度々土砂崩れの跡を見かけ、ひどいところでは道路が派手に崩落していました。しばらく茨城を離れていた間に何かあったらしいです。

f:id:kantarow2813:20231230154813j:image

f:id:kantarow2813:20231230171350j:image

日立鉱山は昔に閉山され、大煙突も折れて短くなっていますが、現在はJX金属(ENEOSグループ)の工場がこの辺りで操業されており、日鉱記念館という施設では鉱山の成り立ちやその後の歴史が紹介されているため、その面影を見ることができます。今回僕たちも日鉱記念館に立ち寄りました。

今では廃墟をポツポツと見かける程度ですが、日立鉱山が操業されていた頃は最大で一万数千人がこの山の中に住んでおり、その日暮らしの傾向が強い鉱夫とその家族が安定して暮らせるようにさまざまな福利厚生を提供していたそうです。禁酒会を発足して劇場を作ったり、スポーツクラブを立ち上げて地域全員で応援するなど、鉱山と企業を中心とした暮らしだったことが窺えます。

印象的だったのは米の値段で、市価よりもだいぶ安く供給されており、米騒動が起こった際でも安定させていたようです。このように生活必需品を低価格で供給する一方で、市価との差額を半ば強制的に貯金させるなど、低賃金の者でも物価高騰の中で十分に食べれて貯金もできる状況を実現していたようです。

このような福利厚生施策が高じて、結構外からも人がたくさん来ていたみたいです。先ほど紹介したルートを見ると分かりますが、常磐線が通る日立駅からは歩いて行ける(普通歩きませんが)くらいの距離で交通の便が良いことも要因だったそうです。

日立鉱山を立ち上げた久原房之助は鉱山理想都市構想というものを掲げており、今で言うモデル都市のようなことをやろうとしていたようです。以下の論文が詳しいので貼っておきます。ここに書いてることは概ね日鉱記念館とWikipediaとこの資料をもとにしています。

日立鉱山草創期にみる鉱山共同体の形成 https://ic.repo.nii.ac.jp/record/607/files/KJ00006128279.pdf

オイルショックや、硫化鉄鉱・銅の需要低下による不況を経て鉱山は閉山してしまったのですが、ここに暮らした人々は日立で再就職することが多かったらしいです。日立製作所などの関連企業があるのと、一山一家的な価値観が地域にも拡大しており、地縁での就職がうまく行きやすかったようです。

 

鉱山の次は霊山の話です。

今回登った御岩山ですが、この山には至る所に神様が祀られていて、その総数はなんと188柱もあります。縄文時代の祭祀遺跡が見つかったり、常陸風土記にその名を記されていたりと、由緒ある霊山らしいです。

ここに登ったのが山に入って二日目で疲れていたので適当に流してしまったのですが、なんかすごい杉が生えていたり、根本だけ残った巨木や地蔵に苔がびっしり生えていたりと、全体的にホーリーな雰囲気でした。

そんな御岩山の登山道はすなわち参道であり、表参道と裏参道の2種類があります。僕らは全員逆張りだったので裏参道から登りました。

道中で足元の悪い山道を足袋で駆け降りる山伏とすれ違いましたが、めっちゃかっこよかったです。修験者とか山伏とかってなんかこう、名前からしていいですよね。

f:id:kantarow2813:20231230164858j:image

頂上からは多賀山地に連なる山々を一望でき、同行した友達がデカい声を出すとやまびこが返ってきて面白かったです。僕も頑張って声を出しましたがやまびこは返ってきませんでした。デカい声が出ない。

 

全体的に地味な登山ですが、実はバーベキューなどもやっています。山で肉焼いて飲酒、最高ですね。逆に言えば肉焼いて飲酒しただけなのであまりここで触れることがありません。

最後に登山前、下山後に立ち寄ったお店を紹介して終わります。

 

COFFEE STAND GENKAN

https://www.instagram.com/coffeestandgenkan?igsh=MTh1NnpmZG9oZTUyYw==

日立駅から歩いて行けるところにあるコーヒースタンドです。そこそこ早い時間から開いていて、気の良さそうなお兄さんが1人でコーヒーを淹れていました。

「予約」と称してお金だけ置いて後からコーヒーをとりに来るおばちゃんが現れたり、地域の人から愛されてる感じがしてよかったです。いいですねこういうお店。

 

ゆりかご

https://g.co/kgs/MNr6D6P

f:id:kantarow2813:20231230175225j:image

f:id:kantarow2813:20231230175345j:image

ドールやフェルト人形、綺麗なお花が一面に飾られている喫茶店で、登山後に訪れるには少し抵抗があったのですが普通に地域のおっちゃんが茶を飲んでいたりして、不思議な感じでした。

いちごのパフェを頼んだのですが、クリームモリモリで最高でした。

GASで複数ページのPDFを出力する

個人的な備忘録です

サンプルコードやスクリーンショットはありません

 

なぜGASでやるか

PDFをサーバーサイドで生成するには色々な方法がありますが、最近wkhtmltopdfがアーカイブされて選択肢が一つ減らされた感があります。

代替策としてヘッドレスブラウザを使う方法があるみたいですが、アプリケーションのイメージを重たくしたくなかったのでGASでやることにしました。成果物をドライブにアップロードしても構わないという要件だったので、連携の容易さの面でも良いチョイスだと思います。

ざっくりとした流れ

以下の図のようになります

指での作図は難しいですね。

基本的な戦略は、GASプロジェクトと紐付くスプレッドシートをテンプレートとして運用し、別のシートにコピーして値をはめ込んでいくというものです。

テンプレート用のスプシにシートを追加していってpdf化しても良いのですが、テンプレートは読み取り専用にしたかったという意図があります。

詰まったところ

簡単なようで意外と詰まりました。いくつか紹介します

PDF化のオプションがわからない

PDFダウンロードする時はダウンロードパスからフェッチしてくるのが良いらしいです。ここではURLパラメータで細かいオプションを指定できて大変助かります。

ところがどっこい、このオプションがよく分からず狙ったPDFを出さなかったので、サードパーティの記事に頼りました。ありがたい🙏

https://jidou-ka.com/gas-spreadsheet-export-pdf/

ドキュメントの向きとサイズ、垂直方向のアラインと罫線の非表示などをこの記事を参考に調整しました。

シートへの変更が反映されない

setValueなどのインターフェイスを用いてシートに変更を及ぼした際、後続の処理でPDF化を行なっても内容が変更されませんでした。

調べてわかったのですが、スプレッドシートでは、パフォーマンスのためにシートへの変更が即座に反映されない場合があります。そのように保留された変更を一度に反映させるのが SpreadsheetApp.flush() です

https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app?hl=ja

シートに変更を与える処理の後でこのメソッドを呼び出すことで解決できました。

Driveにアップロードされたファイルの版管理ができない

PDFファイルが変更された場合、ドライブ上でバージョンを追跡できるようにしたかったのですが、Drive Appにそのようなインターフェイスは見つかりませんでした。そこで、Drive APIという拡張を使います。

https://developers.google.com/apps-script/advanced/drive?hl=ja

Drive.files.updateというメソッドが新しい版のアップロードを可能にします

https://developers.google.com/drive/api/reference/rest/v2/files/update?hl=ja