やってはいけないDITA(その2)

やってはいけないDITAの2つ目です.

PDFを埋め込んじゃう

以前ビックリしたことがあったのですがbookmap/frontmatterにいきなり次のようなtopicrefが登場していました.

<topicref href="hajimeni.pdf" format="pdf"/>

これは何を意図しているかというと、PDFの表紙や目次の前に、hajimeni.pdfで1ページを作って、読み手に最初の注意事項を読ませるものです.内容は「製品使用上の注意」とか簡単に言えば使用者が事故などを起さないようあらかじめ注意点をまとめて述べるような内容です.

しかしさすがにtopicrefでPDFを指しているのはそれまで初めてだったので驚きました.ただプラグインXSLTスタイルシートの実装は簡単で、このtopicrefに対してfo:page-sequenceを生成して、fo:external-graphicでこのPDFのパスを指定してやるだけです.

このようなbookmapのオーサリングは大きな問題を抱えています.PDFなので、プラグインXSLTスタイルシートは内容には一切タッチできません.なおかつ問題なのは、お客さんはせっかくCMSを導入したのにこのPDFの内容をCMSでは管理できない、つまり多言語展開もできないし、ましてや再利用もできないということです.

こんなことをするのは一にも二にも普通のトピックとは一風変わった内容を出力するこの部分のXSLTスタイルシートの開発費を投資するのがもったいないからと推測します.最近はMicrosoft Wordでいとも簡単にPDFができますから、お客さんはささっと「製品使用上の注意」の文書をWordで作って、CMSには画像として登録し、マップにtopicrefで書けばそれで済んでしまう方法を見つけてしまった訳です.

こういう例外的な方法を取りだすと、永久にコンテンツをCMSで一元管理することができなくなります.その時々では短期的にはXSLTスタイルシートに対する投資を削れても、DITAのマップとトピックとはかけ離れたところでPDFのコンテンツ(元のWord文書)を管理しなければならないので、その手間は永久に続きます.もしこのWord文書を各国語展開することになったら、CMSのコンテンツとは別のルートを通して、なおかつ各国語の翻訳版をバージョン管理して保管しておかねばなりません.

短期的な経費削減を考えて、長期的には損をする典型的な手法です.

本気でCMSでコンテンツを管理しようとする組織は、CMSのコンテンツをチェックアウトしてパブリッシュしてという当たり前の流れから外れる作業を極端に嫌います.たまたま便利に見えても、それは自分たちがやってきた努力を根底から崩してゆくものとわかっているからです.

まあお客さんはいろいろです.本気でやろうとしている方、この例のように昔の時代の郷愁にとらわれて、中途半端なところをうろうろしている方.XSLTスタイルシートを作る側からみれば、そういうお客さんの本気度が一発で見えてしまうので、あまりその気になっていないお客さんの仕事をやるのは気乗りがしません.終局的にはお客さんの利益にならないことがあきらかだからです.

やってはいけないDITA(その1)

DITA(Darwin Typing Architecture)の導入があちこちの組織・企業で行われています.もう今ではサブスクリプションばやりで、CMSも必要な機能だけ購入して必要な規模だけ使うので、昔は一番経営陣を納得させるのに苦労したCMS導入ってもはや問題にならないんだそうです.一番の問題はXSLTスタイルシートを作るのに必要なお金が高いんだとのこと.それでお給料をいただいている身からすると、何か悪いことでもしているのか?と思わず自答してしまいます.
でもXSLTスタイルシートってそう簡単には作れないです.そもそもお客様はCMS導入でトレーニングを積んで、コンテンツをコンバージョンしたりして作って、それで「ああしたい」「こうしたい」を私たちにぶつけてくるのですから、正直なところあんまりDITAに習熟していないです.
だから、とかくDITA本来というかDITAの仕様に決められたものを、「ご自分なりに解釈して」ここの出力はこうしてほしい、ああしてほしいと仕様がどんどん膨らみます.今回はそのような場合によく出てくる、ちゃっと首をかしげるパターンを紹介します.

「navtitleで出したい」

一番出てくるのが、topic/titleを表示するんじゃなくて、ある場合はマップのtopicref/topicmeta/navtitleもしくはtopicref/@navtitleを代わりに出力してくれ!というものです.最初は事情がとんとわからないかったのですが、これは例えば、ユーザーニュアルとサービスマニュアルで、たまたま同じトピックを再利用して使いたい、でもユーザーニュアルには大本のサービスマニュアルで出していたtopic/titleではなくて、マップに書いたnavtitleを出したいということのようです.

f:id:toshi_xt500:20220401101739p:plain

そういえば気が付いたんですが、このような要望は今まで結構ありました.(少なくとも4~5回は)

でもですね、たぶん今のDITA-OT(DITA Open Tool Kit)ではバグがあって、マップの側のtopic/topicmeta/navtitleをtopic/titleで上書きしちゃう場合があるんです.

topicmeta/navtitle is overridden by topic/title even if @locktitle="yes" #3708
https://github.com/dita-ot/dita-ot/issues/3708

Preserve topicref/topicmeta/navtitle when @locktitle is enabled #3746
https://github.com/dita-ot/dita-ot/pull/3746

お客さんからの要望もあって、必死にJavaのコード調べてプルリクエストをDITA-OTのプロジェクトに上げたんですが、マージの前のセルフチェックで何故かエラーが出てしまったためか採用してもらえせんでした.なので安心してnavtitleは使えません.もちろん手元でのテストは万全だったんですが、何故エラーになってしまったかは知るすべもありません.

で逆に何故こんなお話がお客様から出るのか?と考えたんですが、それは実はお客様がトピックレベルの共有(再利用)しかしていないから、そのまま何とかするために言われた要求であるということです.タイトルだけ変えたいということは翻って、topic/bodyは同じで良いことになります.

ならばライブラリ的なトピックを作って、サービスマニュアルのトピックからも、ユーザーマニュアルのトピックからもそのbodyの配下の要素をconrefなりconkeyrefなりしていただく、そして各々にふさわしいtopic/titleをつけていただく.で万事解決します.以下はdivで要素を再利用する例です.

f:id:toshi_xt500:20220401101645p:plain

これはそれまでの、Microsoft Wordなんかでパブリケーションをしていたステップから始まったとすると、まずマップとトピックで書くというのはDITAの基本なので、まずそれはいいんですが、そこから先に実は再利用はまったく進んでいないということになります.DITAは「トピックの再利用」がすべてではありません.もっともっと工夫すれば、自在にコンテンツを操れます.でもこういうことを理解するのはお客さんにとっては至難の業のようです.

なかなかDITAの再利用戦略を立てるって大変です.汗をかかなければなりません.でももしその努力を怠って、延々とトピックを書き続けていたら、それは単にそれまでやっていたMicrosoft Wordが形だけトピックに変わって、CMSにひたすら蓄積されているだけのことになります.

つまり、自らのコンテンツを支配(管理)するのではなくて、実はいまだにたまり続けるコンテンツに支配され続けていることに気が付かないだけなんですね.日本の企業ってそういうところは本当に閉鎖的で、せっかく世界規格であるDITAを使っても学ぼうとしない、外部からの指摘に耳を傾けないです.

日本でもDCJ(DITA Consortium Japan)で紹介された先駆的な企業さんは本当にこういう点で努力して汗をかいておられます. はたから見ていても尊敬するくらい喧々諤々と議論して自分たちのコンテンツを良くすることに真剣です.

そういう努力をしないと、数年前のDCJ主催のDITA Festaで紹介された有名な言葉「なんちゃってDITA」の導入になってしまうのでしょう.

バイクは冬眠中です

バイクは冬眠中です.ビラ配り専用のセローも、去年買ったSRも.バッテリーを外したんですが、右は台湾YUASAのセローで左はSRのもの.セロー(225CC)はセルがあるので排気量の大きなSR(400CC)より大きい. SRはミニバイク並みですね.SRはキックオンリーなのでEFI(Electronic Fuel Injection)を動作させるのにバッテリーは必須.上がっちゃうともはやどうにもならないと原田モータスさんから念を押されました.昔はキャブだったのでバッテリー上がってもガソリンが回ってキックして火花が飛べばなんとかなりましたが、今のバイクはイモライザ―もついていて電子部品の塊ですね.昔の方がシンプルで良かった.
バッテリーは家に置いて時々充電しています.

f:id:toshi_xt500:20220223134355j:plain
SRとセロー225のバッテリー
f:id:toshi_xt500:20220223134430j:plain
バッテリーを外したSR

DT250

今日配信された「Your alert YAMAHA - DT 250 : 1 new ad」のメールを見たらポーランドの人がリビルドしたDT250(1976年モデル)を出品していてビックリ.右クランクケースカバーは粉体塗装がしてあって、写真を撮っている人まで映りこんでいます.ここまでピカピカに仕上げたコンペティションイエローのDTは日本では見たことないです.それでいて日本円に換算すると50万円台でなおオドロキ.日本だといわゆる「ヤレ」たボロでも平気で乗り出し価格90万円近くで販売しています.海外の方はバイク本当に大事にするんですね.この型のDTはタンクキャップの部分が上にちょっと突き出していて、マフラーの取り回しも斬新、デザイン的には最高です.

f:id:toshi_xt500:20220223133939j:plain
DT250 エンジン
f:id:toshi_xt500:20220223134000j:plain
DT250 右側
f:id:toshi_xt500:20220223134027j:plain
DT250

ヨーロッパのXT500

SRに乗って感じるんですが、低速で比較的高いギヤに入れてもトルクフルなエンジンがアクセルに「ドコドコドコ」ってついてゆくあの感じがたまりません.こんなオフ車があったら最高なのになと思います.それはやはりXT500です.実はほんの一時期SRの生みの親のXT500を持っていた時期があったんですが事情で短期で手放しました.XT500は日本では1976年に出てから比較的早い時期に国内販売は終了になってしまったように記憶しています.しかしヨーロッパでは人気が高く1989年まで販売されていました.この写真はドイツのバイク屋さんから送ってもらったものです.日本のマニアから見ると垂涎ものですね.ヨーロッパでは結構大切にメンテされている方がいらっしゃるようです.

f:id:toshi_xt500:20220223133008j:plain
XT500 エンジン
f:id:toshi_xt500:20220223133055j:plain
XT500
f:id:toshi_xt500:20220223133123j:plain
XT500

SR400を買いました.

実は昨年SRのファイナルエディションを買いました.地元のお店ではもう予約完売.グーバイクで見つけた群馬の原田モータースさんにお願いしてなんとか間に合いました.原田モータースさんにはわざわざ群馬より高速を乗り継いで納車に来ていただき感激です.

f:id:toshi_xt500:20220223132322j:plain
SR400
f:id:toshi_xt500:20220223132411j:plain
SR400 最も美しいといわれるエンジン

C#の由来を知る

C#って実は食わず嫌いでずっと触ったことがありませんでした.しかしWeb関連のプロジェクトでWebSocketによるサーバーとの通信をやらなければならなくなりました.クライアント側は当たり前のようにJava Scriptになります.仮想的にサーバー側をWindows上でどう作ろうか調べました.ところがVisual Studioでは、ASP.NET Core Web Applicationのテンプレートの存在する言語はC#かF#しかないのです.つまりVisual Basicは使えない.F#ってとっても魅力的ですが、まだまだ使える実力がありません.という訳でC#に弟子入りすることになりました.

まあ正直歳をとって新しい言語を覚えるのも大変なんですが、しかし必要となれば文句は言っていられません.まずは入門書から探そうと、Amazonを見てみると結構な数の本があります.私は変に凝る方なのであんまりというか1個しか書評のついていない、川俣晶さんの「楽しいC#入門」を買いました.さすがに今時の本で、Kindleオンリーです.

川俣さんはずっと昔からWebでVBXMLの連載記事をやっていて、ご本人にはお会いしたことはありませんが、いままでに幾度となくその丁寧で(ちょっと)オタクっぽい解説にお世話になっていましたので、内容は押して知るべしでした.

私が最初に本を見て驚いたのは以下のC#の最初の解説です.C#の元はBolandのDelphiだったんです.

C#はアンダース・ヘルスバーグらによって、米マイクロソフト社で開発されたプログラミング言語です。公開されたのは2000年です。つまり、C#は誕生してからすでに10年以上が経過しており、けして新しい言語ではありません。 では、C#のルーツはどこまで遡れるのでしょうか。 C#のルーツはDelphiという言語にあります。Delphiとは、C#を産み出したアンダース・ヘルスバーグがマイクロソフト社に移籍する前に、ボーランド社で開発したプログラミング言語です。その母体は、それ以前にアンダース・ヘルスバーグが開発したTurboPascalという開発言語にあります。TurboPascalは、Pascalというプログラミング言語を拡張した統合開発環境で、1980年代のヒット開発言語の1つです。では、Pascalとは何でしょう? それはニクラウス・ヴィルトが1970年に発表し、1970年代にパソコンの次世代の主力開発言語の座をC言語の争ったライバル言語なのです。最終的にC言語が勝利するまでは次世代プログラミング言語の本命の二強と言われた2つのプログラミング言語の一つです。
川俣 晶. 楽しいC#入門: .NET 5 RC1対応版 (COOL C# CREW Series) (Kindle の位置No.757-767). Kabusikigaisha pi-de-. Kindle 版.


実はBolandのDelphiは1.0の時から買っていて、2.0が出てからこれでどのくらいプログラムを作ったかわかりません.なぜDelphiなんか好きだったかというと、大学の研究室で卒論を書くときに作ったプログラムは当時のDEC(Digital Equipment Corporation)のPDP-11というマシンのPascalだったからです.ここで構造化プログラミングというのに初めて接しました.就職してからはCOBOLアセンブラばかりでしたので、Delphiが出たときは、「Bolandよくぞやってくれた!」という気持ちで自費購入して勉強していたのです.

ところがBolandはいろいろごたごたがあって、アンダース・ヘルスバーグはMicrosoftに移ってからC#を発表しました.当時BolandからMicrosoftに移ると給料も10倍になったとか言われていて、どうもその成り筋に自分の気持ち的に納得がゆかず、C#には触ることもなかったのです.後になって、アンダース・ヘルスバーグが移籍した理由は主にBolandの決定的な方針転換についてゆきようがなくなった技術者がみんな移ったと知って誤解とわかりました.Wikipediaを見るとC#の開発にはDelphiの開発者も多く加わっていたとのことです.

開発にはボーランドのTurbo PascalDelphiを開発したアンダース・ヘルスバーグを筆頭に多数のDelphi開発陣が参加している。
From https://ja.wikipedia.org/wiki/c_sharp


また川俣さんの本には

注意することが1つあります。 C#は歴史的経緯によりC言語風の文法を持っていますが、ルーツはC言語のライバルPascalにあります。そのため、細かい部分でC言語の常識に沿って動作しない仕様を含みます。表面的に似ているからと言って、C言語やほぼ上位互換のC++と一緒に学ぶことはお勧めではありません。
川俣晶.楽しいC#入門:.NET5RC1対応版(COOLC#CREWSeries)(Kindleの位置No.771-774).Kabusikigaishapi-de-.Kindle版.


とあってルーツはC++ではなく、あくまでObject Pascal(== Delphi)なんですね.それならはるかに親近感が湧きました.

さて、はじめて作ったC#のプログラムはMSDNのサンプルから改造したものです.

ASP.NET CoreでのWebsocketのサポート
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/websockets?view=aspnetcore-2.1

ソースコード
https://github.com/dotnet/AspNetCore.Docs/tree/master/aspnetcore/fundamentals/websockets/samples/2.x/WebSocketsSample

このプログラムはクライアントの入力文字列を単にエコーするだけなんですが、実際にはこれを改造して一定の手順でJSONをやりとりしながら、サーバー側の情報を定期的に得るものを作りました.

こういうのがいわゆる今時のWebものなのでしょうね.初心者であってもC#Visual Studioの手厚いサポートでコーディング/デバッグはスゴク楽、あとクライアントのJavaScriptVisual Studio Code+ブラウザのF12でのデバッグでなんとかなりました.