Subscribed unsubscribe Subscribe Subscribe

詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!

AsciiDoc(Asciidoctor)の文書をtextlintで校正する

JavaScript Ruby

AsciiDocはMarkdownのようなテキストマークアップ言語のひとつで、ページ内リンクや脚注などかなり機能が豊富なので、大きめのドキュメントを本腰を入れて書くなど、表現したいものがある程度複雑なときに便利。DocBookというフォーマットを通じて、HTMLだけでなくPDFとかroff形式にも変換できるらしい(やったことはない)。GitのドキュメントがAsciiDoc形式で書かれているのを見て知って、自分も個人的なドキュメントはREADME.adocなどとして、AsciiDoc形式で書くことがある。AsciidoctorはAsciiDocの実装のひとつで、Rubyで書かれていて利用が簡単なのでこれを使っている。

さて、上記の記事でtextlintなるものを知ったので、AsciidoctorのJavaScript実装を使ってプラグインを書こうと思いたったわけだ(標準で対応しているのはプレーンテキスト、HTML、Markdownのみ)。しかし取りかかってみるとこれがなかなか大変で、textlintの期待するデータ構造はテキストの行やカラム位置の情報まで求めるので、Asciidoctorのパーザに精通している必要がありそうだった。せいぜい校正項目のある行くらいが分かれば自分の目的は達成されるので、ここまでやるのは少し苦労が多そうだった。

そこで、一度プレーンテキストに変換してからtextlintで処理し、結果のエラーの行番号を元のファイルの行にマッピングする、という方法を取ることにしたのがこちら。npm install textlint してある前提。

Rubyのスクリプトで、指定されたファイルをAsciidoctorのAPIで解析し、構文木をたどりながらプレーンテキストを吐く。その際に各行と、そのソースの位置情報を記録しておく。プレーンテキストに対してtextlintを走らせて、結果をJSONで受けとり、元のファイル名に直して出力する。そのままVimのquickfixリストにできるフォーマット。

少しだけ変なハックを入れている。このスクリプトは通常はHTMLタグのみを消して出力する、つまりアンカーテキストなどは校正の対象となるのだけど、それで上手くいかない場合があった。codeタグの中に入ったアルファベットも日本語のルールで校正されてしまう、という問題だ。そこで -T オプションでそのタグの内容を墨塗りできるようにしてある。中身を消し去ってしまうと変な文章になるので、苦肉の策。墨塗り文字のくり返しがエラーになるので、そいつは無視する、ということもしている。

第三者のための『リーダブルコード』

新人エンジニアにオススメの本のひとつだよねー、などと言いつつ自身は読んだことがなかったので慌てて買って読んだ。

お題「リーダブルコード」

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

  • 作者: Dustin Boswell,Trevor Foucher,須藤功平,角征典
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2012/06/23
  • メディア: 単行本(ソフトカバー)
  • 購入: 68人 クリック: 1,802回
  • この商品を含むブログ (131件) を見る

なるほど当たり前のようなことでありながら短期的に意識して身につけるのは難しかったことばかりで、これがこのようにまとまった形の書籍になっていることはとてもありがたいことだと思う。規約を押しつけてるわけじゃなくて指針の集合なので、気楽さもある。

プログラム中で使用する英語動詞

本の中には「名前に情報を込める」という話があった。

非英語話者でありながらプログラミングに英語を使っている身としては、今ひとつニュアンスが分からない語がある一方、却って巷のソースコードから英語の利用例を知る割合が高くなるわけで、そうやって英語のプログラミング向けのサブセットを作ることもできそうだなと思う。

そこで現在こんな動詞をこういうニュアンスで使っていますよ、というのを雑に列挙してみる。語彙は使用するプログラミング言語やその著名なライブラリの語彙にかなり影響を受けるので、普遍的なものにはなり得ない。

英語 用途 備考
search データベースなどからの複数のデータを取得する。 なんで select じゃないのかは不思議
find データベースなどから条件にしたがってデータをひとつ取得する。
insert データベースへデータを挿入する。 SQLからの連想
delete データベースからデータを削除する。 SQLからの連想。データ構造からのデータの削除にも使う
update データベースのデータを更新する。 SQLからの連想
load 外部リソースをメモリ上のモデルへ展開する。 load したものは save する
new (これは動詞ではないが)インスタンスを生成する。 言語の機能になってることが多い
make データ構造を作成する。
generate IOをともなわずに値を生成する。
fetch HTTPなど比較的重いIOによってデータを取得する。
request HTTPリクエストを送信する。
require データ構造のある部分を要求する。存在しなかったら例外を投げる。
ensure データ構造のある部分が存在しなければ作成する。

addとかremoveとかもっといろいろあるやん……と思ったけどキリがないのでやめておく。

これらは低レイヤの処理として使われたときにこういう名前を使いますという類のもので、より抽象度の高いレイヤにおいてはもっと自由に名づけられると思う。こうやって読んでみるとどんなリソースにアクセスするのか、を意識してるな。

ちなみに自分は ensure を上記のように考えていたんだけど、require のように使う、という意見もあった。たしかにプログラムの次の行に到達したときに、求める状況になっていることを確実にできるという点では同じであるなあと思う。

コメント中の意見に署名する

TODOなんて書かれたコメントは放置されるものだ。というか、放置されたものだけが生き残るわけなので、他人に見られるのは放置されたものばかりになるのだといえる。そして生まれてすぐの早いうちに誰も対処しなかったTODOは、やがて消して良いのかどうかの判断もできなくなってコード中の定位置を確保する。

そこで最近はTODOやらFIXMEといったコメントを書くとき、# TODO(motemen): 処理を切り出す というように、自分の名前を入れるようになった。これはGoを書いているうちに知ったものだけど、まあ源流がどこかにあるんだろう。この署名を加えることで、例えば手を付けられないままそのTODOが生き残り誰かの目に触れたとしても、ははあこれはあいつに訊けばよいのだなとなって、まったく判断できないということは避けられる。その他同様に、コメントにコードを補足する事実でなく意見を書くときには、誰が書いたかを明らかにする。

プロジェクトによっては人名だけでは足りないとして、詳しい情報をつけ加えるようにしているところもある模様。

ソースコードの第三者

……というようなことを考えながら読んだ。その他にもコードの役割を細かく、とか制御構造を読みやすく、という話題があったけど、それらはコードに向き合っているうちに自ずと実現されるように思う。

10年前の自分は知らなかったことだけど、プログラミングにおいてコードを書く際には、書き手の自分とそれを受けとるコンピュータのほかに、第三者としてソースコードの読み手が存在する。昔の自分も当然その存在を知ってはいたものの、ちゃんと認識できてはいなかった。プログラマは読み手として多くの時間を過ごすものだと気づけたのは、実際にそれだけの時間を費やしてからだった。いや、それよりも自分が過去に書いたコードを他人に読まれるようになったからかな……。

人間が書いたプログラムの意味(何をするべきか)をコンピュータは解釈して間違いなく書かれたとおりに実行するけれど、ソースコードがそのまま人間の意図(何をしたいか)や書かれた文脈(何故そうするのか)を表現しているとは限らない。最悪、意図と意味が異なっていることだってある。第三者がコードを読むとき、コンピュータのために書かれた意味から意図を取りだすことは簡単だとは限らない。書き手のほうはもちろん意図を実現するものとしてコードを書いているから、この差に気がつかないと、後から読んだときに読み手が困るようなコードが出来上がることになりがち。

もちろん、デザインパターンとか、名前のついたアルゴリズム、フレームワークなど人間のあいだの共通言語を強化することでソースコードの意図を分かりやすくすることはできる。また、抽象度を高めることで、書かれたコードと意図とのあいだの距離を縮めようとするって手もある。その場合も抽象化を受け持つ層のことが人びとによく共有されていないと結局動きを把握するためにコードを潜るはめになって、却って苦労が増すことになる。このあたりは業界の潮流とかプログラミングのパラダイムにも大きく影響を受けそうなところ。


なんか、若い人のほうがこういうところきっちりできる印象なので(冒頭に書いた言葉とはうらはらに)、むしろ自分の身につまされる本だった。プログラムって人間とコンピュータのあいだの言葉であるのと同じくらい、人間と人間のあいだの言葉でもあるなと思った。

この記事は次の酒を飲んでいる最中に書かれました:

リスクを直視しないという罪:『熊とワルツを』

ウィッシュリストに入れてたのを同僚が贈ってくれた。

熊とワルツを リスクを愉しむプロジェクト管理

熊とワルツを リスクを愉しむプロジェクト管理

リスクのあることを知りながら何もアクションをおこさないことは罪である……といったエピソードからこの本は始まるのだけど、もうこの言葉だけで重要なことはほとんど言ってしまっているような感すらあった。自分が今までしてきたのこれは罪だったんだ! と知らされる衝撃があった。いわゆる罪の文化というのもあるのかなと感じる。

もちろんこのことは導入であって、より詳細に、

  • リスクとは何なのか
  • リスク管理をする理由・しない理由
  • リスク管理の方法

といった話がメインの内容として続く。

リスクとは何なのか

この本では、リスクとは顕在化する前の問題であり、逆に問題は顕在化したリスクであるという風に描かれている。ふたつは表裏一体である。プロジェクトを進行し、スケジュールの見積もりをある程度の確度をもって定めるには、リスク管理を行うことで問題を発生させないこと・軽減させることに努めなくてはならない。リスクが問題に移行する前に策を打っておくことで、リスク軽減できるというのもポイントだ。

リスク管理において陥りがちな問題のひとつに、プロジェクトに関連する、チーム外の部署に任せている部品に関するリスクを知らず知らずのうちに無視してしまう、ということがある。発注したコンポーネントの完成は当然期限に間にあうもので、そうでなければ請負先の責任、という態度だ。

これがメインプロジェクトの主要な箇所を構成する要素であればプロジェクト全体のスケジュールや完成度に多大な影響が及ぶわけだから、そのリスクに無頓着でいられるはずもない。本来ならば、発注側がそのようなリスクの管理においては責任を負わなければならない。別にチームやプロジェクト単位の話に限らず個人のレベルでも同じようなことは言えて、たとえば他の人に依頼した仕事のその後をトラッキングせずにただ待つというのもよくないことなのだと思った。

リスク管理の方法

このように不明瞭だったリスクの責任の所在を、リスク管理を行うことで明らかにできる。リスク管理は以下のような手順で構成される。

  • 問題になりそうなこと(リスク)を洗いだす。これには過去のプロジェクトにおける問題が参考になる。きのうの問題は今日のリスクである。
  • それぞれのリスクが生じた時のコストと発生の確率を見積もる。
  • リスクを軽減するための方法と、そのコストを検討する。この軽減コストはプロジェクトのコストに上乗せする。
  • リスクが問題に移行する前兆(移行指標)を検討する。ボールが転がってきたあとには、かならず子供が走ってくるといった具合。

リスクを真剣に考えていくと、これが現実になったらプロジェクトそのものが立ち行かなくなる、というようなものもある。これをショーストッパーという。この概念を知れたのもよかった。ショーストッパーに関してはプロジェクトの管轄の範疇外とならざるをえないので、そのリスクを抱えるのはプロジェクトの発案者となる。プロジェクトの中の人はそれを仮定として受けとるしかない。

肝心なのは考えられる限りリスクを洗い出すこと。チームとして他人と一緒に仕事をしているわけなので、なんとなく、プロジェクトをはじめようというときにネガティブなことを言ってやる気を削いだり白けさせてしまってはいけない……などと考えてしまうのも人情(西洋でもそういうものらしい)。なのであえて儀式として取りおこなうとよい。その際、このプロジェクトにおいて考えうる最も破滅的なシナリオは何か? とそれぞれに問う。いわば悪い方を向いたブレインストーミングだ。

ソフトウェア開発プロジェクトにおける、よくあるリスク(「曖昧な仕様書」など)についてもいくつか挙げられていて、参考になる。その他数値的なツールの紹介もされているのだけどあまり興味がなく読み飛ばした。

心配しないこと

エントリを書くにあたって本を読み返してみると、以下のような言葉が目を引いた:

リスク管理は、プロジェクトについて心配することとは違う。

また、

リスク管理が個人的な心配という形でしか行われない場合、それはコミュニケーションの断絶を意味する。

個人の心配をチームのリスクへと昇華させ、プロジェクトの責務の一部としてその軽減にあたりましょう。とまとめられると思う。面白い本だった。