Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

「解決済みの質問を削除する」風習の調査(があったらいいな)

Web上のQ&Aサイトでは、質問をした後、回答が得られて問題が解決したら、質問者が質問を削除してしまうというケースが見受けられる。 特に技術的なQ&Aサイトの場合は、同じ疑問を持ったり、同じ問題にぶつかった人が解決方法にたどりつく機会が減ってしまうため、解決済みの質問を削除してしまうのは問題があると言える。たとえばteratailでは、質問者が質問を直接削除するのではなく、削除を「リクエストする」仕組みになっている。また投稿の削除ポリシー *1 で「解決済みの質問についている回答を消すことは、同じ疑問をもつ人たちから知識を奪うことになる」として、解決済みの質問に対しては削除リクエストも原則として行えないようにしている。

teratailのように、「回答が得られた質問を削除する」という行為は日本語のサイトでしばしば見られる。一方で、英語を主な言語とするStack Exchange(英語版Stack Overflowなど)では、回答がついた質問を投稿者自身が直接削除できる。ただし、承認された回答がある場合は削除できないなど、削除にある程度の制限をかけている *2 。Stack Exchangeでは、質問の内容が簡単な場合に、質問に対して回答でなくコメントを投稿することで答えを示しているケースが散見される。これは、この削除の制限への抵触を回避するという目的との関連が示唆される。

  • 解決済みの質問を削除する、という行為は特定の文化圏(地理的な文化圏、および専門分野による文化圏)に特有の事象なのだろうか?
  • 質問者が質問を削除するのはどういった動機によるのだろうか?
  • 質問者の勘違いが原因だったので恥ずかしいから?
  • 質問の内容が簡単すぎて、こんな質問をしていたということを残すのが恥ずかしいから?
  • 質問の対象になったソフトウェアやサービスなどに問題があるように見えるので、ソフトウェアの開発元やサービスの提供元に迷惑だから?
  • ソフトウェアやサービスについて議論が起こっているように見えるので、ソフトウェアの開発元やサービスの提供元に迷惑だから?
  • 議論が起こっているように見えるので、議論を起こしている人だという記録が残るのはいやだから?
  • 自分が質問した内容やもらった回答の内容に対して責任が持てないので、責任を持てないような内容を残すのは無責任でよくないから?
  • 自分の名前が記録に残るのがいやだから?

また、解決済みの質問を削除する行為は、どのような方法で予防できるのだろうか?こういった問題に対して調査・分析を行った論文はあるのだろうか?

非機能要件の安全率の事例収集

非機能要件の安全率として「どのくらいの安全率なら適切か」という値はありません(研究もないように思います)。 Qiitaの記事*1にあるように、1.2~1.5というのが感覚値ではありますが、これといった根拠はありません。

そこで、政府機関・自治体・各種団体・企業などで使われているシステムの安全率がどの程度か、事例を収集してみることにしました。

# 主管元 名前 安全率 URL
1 厚生労働省 オンライン資格確認システム 1.5 https://www.mhlw.go.jp/file/06-Seisakujouhou-12400000-Hokenkyoku/0000182053.pdf#page=78
2 厚生労働省 年金業務システム 1.2 https://www.mhlw.go.jp/sinsei/chotatu/chotatu/pdf/ikenshousei140806-01.pdf#page=19
3 厚生労働省 間接業務システム 1.3 https://www.mhlw.go.jp/sinsei/chotatu/chotatu/shiyousho-an/dl/090205-1b.pdf#page=3
4 内閣官房 接触確認アプリ 1.2 https://cio.go.jp/sites/default/files/uploads/documents/techteam_20200526_01.pdf#page=24
5 国土交通省 建設キャリアアップシステム 1.2 https://www.mlit.go.jp/common/001156807.pdf#page=364
6 電力広域的運営推進機関 OAシステム 1.5 https://www.occto.or.jp/soukaihoka/rijikai/2019/files/rijikai_236_gijiroku_1.pdf#page=147
7 環境省自然環境局生物多様性センター 巨樹・巨木林データベースシステム 1 http://www.biodic.go.jp/chousa/koukoku29/koukoku29_14_1.pdf#page=78
8 日立製作所 Hitachi System Information Capture 1.2 http://itdoc.hitachi.co.jp/manuals/3021/3021373200/H0373200.PDF#page=478 *2
9 ManageEngine EventLog Analyzer 1.3 https://www.manageengine.jp/products/EventLog_Analyzer/system-requirements.html *3
10 富士通 Interstage Business Application Server 1.25 https://software.fujitsu.com/jp/manual/manualfiles/M090098/J2X16030/08Z200/J6030-02-05-02-03.html *4
11 富士通 Interstage Business Application Server 1.5 https://software.fujitsu.com/jp/manual/manualfiles/M100002/J2UZ9110/02Z2C/irepad/irep0223.htm *5
12 富士通 Symfoware Server 1.5 https://software.fujitsu.com/jp/manual/manualfiles/m120023/j2ul1593/04z200/j1593-i-09-00.html *6
13 富士通 Symfoware Server 1.3 https://software.fujitsu.com/jp/manual/manualfiles/M100005/B1WS0831/01Z200/B0831-e-03-00.html *7
14 富士通 Interstage Shunsaku Data Manager 1.3 https://software.fujitsu.com/jp/manual/manualfiles/M060057/J2X11941/01Z202/usersad/users186.html *8

*1:https://qiita.com/hot_study_man/items/43de9839a07dd6140937

*2:製品マニュアルで、システムではない

*3:製品マニュアルで、システムではない

*4:製品マニュアルで、システムではない

*5:製品マニュアルで、システムではない

*6:製品マニュアルで、システムではない

*7:製品マニュアルで、システムではない

*8:製品マニュアルで、システムではない

リテラルと定数とEnumとOTLTとResourceと……の使いわけ

プログラム中で変更可能なパラメータ(メッセージ、設定値、エラーコードなど)は、その記述方法を工夫することで、ソースコードの可読性やアプリケーション保守の容易性を向上させることができます。

一方で、大規模なチームでアプリケーション開発を行う場合、開発者のスキルや経験はピンキリです。そのため、何をリテラルとして記述するか、何をリソースとして設定ファイルに書くかの判断を個別の開発者が行うと、1つのアプリケーション中でも記述方法がバラバラになりかねません。

この記事では、一般的なエンタープライズアプリケーションに現れる各種のパラメータについて、それをどのように表現するかの案を提示します。

まず、パラメータの表現方法としては、大きく以下のようなものが挙げられます。

リテラル
  • 各ソースでバラバラに記述する。アプリケーション全体に対する一括修正が必要な場合、修正漏れや誤修正が発生しない仕組みが必要となる。
  • 修正にはビジネスロジックの再ビルドが必要。
  • リテラルを定義している箇所以外からはプログラム的に参照できない。
  • IDEの入力補助機能による値の補完は不可能。
  • リテラルの定義内容はビジネスロジックの作成者の責任範囲となる。
  • リテラルの内容に誤りがあった場合、ランタイムエラーとなるか、場合によっては誤ったまま動きつづける。
Enum
  • 修正のためにはEnumクラスの再ビルドが必要。ビジネスロジックの再ビルドは不要。
  • 値の参照範囲をある程度制御可能。
  • IDEの入力補助機能による名前の補完が可能。
  • パラメータごとに格納先が分かれる。パラメータの種別ごとに別々のEnumを作成する必要がある。
  • Enumの名前の打ち間違いはコンパイルエラーになる。
OTLT
  • アプリケーションのビルドを伴わずに修正が可能。
  • キーに対して複数の値を対応づけることができる。利用開始日や有効期限などのメタデータを利用した作りこみが可能。
  • 修正のために特別なアプリケーション(DBアクセス用ツール)が必要。
  • 設定の格納先は一元化されている。
  • IDEの入力補助機能によるキーの補完は不可能。
  • 言語化の仕組みが必要な場合はアプリケーションでの作り込みが必要。
  • OTLTのキーの打ち間違いは、多くの場合ランタイムエラーとなる。たまたま別のキーを参照していた場合は誤ったまま動きつづける。
定数
  • 修正のためにはビジネスロジックの再ビルド(定数を参照している側のプログラムの再ビルド)が必要。
  • 値の参照範囲をある程度制御可能。
  • IDEの入力補助機能による名前の補完が可能。
  • 定数の格納先クラスを分けることは可能だが、定数を参照している側のプログラムの再ビルドが必要なので、修正の責任分界点の明確化にはあまり役に立たない。
  • ビジネスロジック中での定数名の打ち間違いはコンパイルエラーになる。
リソース(Javaの.propertiesなど)
  • アプリケーションのビルドを伴わずに修正が可能。
  • キーと値が一対一対応しており、利用開始日や有効期限などのメタデータを持たせることが難しい。
  • 修正のために特別なアプリケーションのインストールが不要。
  • 設定の格納先をファイル単位で分けられるが、逆に統一的な管理をしたければ作りこみが必要。
  • 言語化の仕組みが処理系に組込まれている。
  • IDEの入力補助機能によるキーの補完は不可能。
  • 処理系によっては、ファイルの内容をキャッシュする仕組みが組込まれている。その場合、アプリケーションを再起動しないと更新できない。
  • プログラム中でのリソースのキー名の打ち間違いは、多くの場合ランタイムエラーとなる。たまたま別のキーを参照していた場合は誤ったまま動きつづける。リソース自体の文法エラーも、多くの場合ランタイムエラーとなる。
  • リソースファイルを扱う言語組込みの仕組みがある場合(例:Java)は便利に使えるが、そうでない場合(例:COBOL)は定数や外部ファイルの方が扱いやすい。
外部ファイル(CSV, XML, JSONなど)
  • アプリケーションのビルドを伴わずに修正が可能。
  • キーに対して複数の値を対応づけることができる。利用開始日や有効期限などのメタデータを利用した作りこみが可能。ただし、データを追加するほど編集がややこしくなり、外部ファイル自体の文法エラーにつながる。
  • 修正のために特別なアプリケーションのインストールが不要。
  • 設定の格納先をファイル単位で分けられるが、逆に統一的な管理をしたければ作りこみが必要。
  • 言語化の仕組みは作りこみが必要。
  • IDEの入力補助機能によるキーの補完は不可能。
  • ファイルの内容をキャッシュしたい場合は自前で実装が必要。
  • プログラム中での外部ファイルのキー名の打ち間違いは、多くの場合ランタイムエラーとなる。たまたま別のキーを参照していた場合は誤ったまま動きつづける。外部ファイル自体の文法エラーも、多くの場合ランタイムエラーとなる。

プログラム中で扱われるパラメータごとに、上記のうちどれを使って表現するかの案を示す。

メッセージID・エラーコード(画面やログに出力されるメッセージと1対1対応するID)
ビジネスロジック中にリテラルとして定義する。もっとも大きい理由は、特にメッセージの数が多い場合、定数化してもSoft Codingにしかならないことが多いため。定数にしない理由は、メッセージの意味を定数の名前とメッセージ本文(後述)の両方に書くことになってしまうため。またEnumにしない理由は、Enumにするとメッセージの追加時にリソースファイルとEnum両方を修正する必要があり、修正をミスしたときにリソースファイルとEnumのどちらを間違えたのかの切り分けが必要になってしまうため。なお、命名規則でメッセージID・エラーコードであることが明確に分かる命名規則にすること*1。また、メッセージIDを他の文字列リテラルの一部に含めたり、メッセージIDをビジネスロジックで組み立てたりしてはいけない。必ずメッセージIDだけを独立したリテラルにすることで、ソース中から任意のメッセージIDを検索した場合に誤検出や検出漏れがないようにする。
メッセージ本文(画面やログに出力されるメッセージ)
リソースファイル中に定義した上で、アプリケーション本体とは独立したファイルとしてデプロイする。こうすることで、業務面の要請からメッセージの修正が必要な場合に、本番環境へのプログラム追加なしに顧客が直接メッセージを修正できる *2。多言語化が必要な場合、基本的には処理系組込みの多言語化の仕組みを利用するのがよい。ただし、言語以外のメタデータが必要な場合はCSVのフォーマットを使うことを検討する。特に、ログ出力用メッセージ本文の管理において、メッセージのメタデータとしてログの出力レベルを持たせる場合は、本番環境での障害原因調査の際に特定のログメッセージの出力レベルを変更できるようにしておく(罠掛けに使う)ため、ResourceやCSVなどの外部ファイルにして、追加プログラムなしで修正可能にしておくと便利。
メッセージパラメタ(メッセージの一部を置き換える値、いわゆる埋め字)
埋め字は変数の名前など、ビジネスロジックの内容と密接に関連することが多い。そのため、多言語化の必要がなければプログラムのロジック中に直接埋め込んでもよい。多言語化が必要な場合はリソースに記述することで、処理系の多言語化の仕組みを利用できる。リソースに記述する場合、ビジネスロジックと密接に結びつく内容ため、warに含めるなどしてビジネスロジックと常にいっしょにデプロイされるようにする*3。なお、リソース化する場合はリソースのファイル名およびキー名の設計が必要。たとえば、サブシステムIDをファイル名に、変数の完全修飾名をキーにしたりする。
ラベル(ビジネスロジックの分岐に関係ない、画面に表示される値)
ユーザが表示言語を変更する操作をした時にサーバサイドでレンダリングが走るアーキテクチャの場合は、表示言語の変更によるレイアウト崩れなどの確認をしやすくするため、表示用リソース(HTMLなど)に直接埋め込む。SPA等で表示言語変更時にリロードが走らない場合は、i18n機能の仕様に合わせて別ファイルにラベルの内容を切り出す。たとえばAngular+ngx-translateであればJSONファイルへ切り出す。この場合、アプリケーションのリビルドなしでラベルの修正が可能となる一方、開発時には画面レイアウトの確認にアプリケーションの実行が必要になる。そのため、特に業務処理の実装に着手できていないアプリケーションの開発初期において、業務処理の開発と画面デザインの検討の並走が難しくなる点に注意すること。
設定値(ビジネスロジックの分岐を制御する値)
再ビルドを伴わずに修正する必要のある値(パッケージソフトウェアの導入担当者が、導入先顧客毎に変更する値など)は、リソース化した上で、アプリケーション本体とは別ファイルとしてデプロイする。これは、ビルド作業とデプロイ作業の責任分界点を明確にするためと、デプロイ作業を行う環境ではOS組込みのエディタしか使えない場合が多いため。一方、アプリケーションのエディションの違いなど、ビルド時に値が決定する場合はEnumにするのが望ましい。これは、ビジネスロジック中で1つの値を参照する箇所が多く、IDEによる補完が効いた方がよいため。また、値の変更にリビルドが必要なようにして、カジュアルにエディションを変更されるのを避けるため。また、たとえばアプリケーションの操作権限(管理者・一般ユーザ・ゲストなど)についても、選択肢が固定であればEnumにすることが望ましい。これは、不正な値を設定しようとした場合に正しくランタイムエラーとなり、セキュリティ上問題となるケースを避けられる可能性があるため *4。もちろん、ユーザ操作でロールを追加・削除できるような仕組みの場合は、権限設定であってもEnumにはできず、ビジネスロジックから変更可能なDBのテーブル上に設定を持たせる必要がある。
業務コード(業務中で使用される何らかの値に対応するID。たとえば成田空港を表す"RJAA")
ビジネスロジック中での参照箇所が限られている場合(特定の業務でしか参照されないなど)、リテラルとして定義するのがよい。参照箇所が少ない一方でコードの種別が多いため、定数化してもSoft Codingにしかならないことが多いため。ビジネスロジック中で広く参照される場合は定数化やEnum化してもよいが、コードテーブルがアプリケーションの再ビルドなしに変更可能な一方、定数やEnumは再ビルドが必要となるため、再ビルド不要という利点を相殺してしまう点に注意すること。いずれの場合も、命名規則がアプリケーションではなく業務上の要求によって決まるため、「ここで使われているこのリテラルは業務コードである」ということが明確に分かるの望ましい。たとえば業務コードは、業務コード値を参照するメソッドの引数にのみ使用してそれ以外の場合は使用しない、など。業務コードの値によってビジネスロジックが分岐する場合も、判定を単純なequals()で行うのではなく、業務コードを格納するためのクラスと、そのクラスの比較専用のメソッドequalsCode(String code)などで行えば、どのリテラルが業務コードかコードの文面から判別がつくため、文字列検索による業務コードの使用箇所調査が容易になる。
業務コード値
単純に業務コードとコード値とが一対一対応するだけの場合はリソース化してもよい。コードに対応する値が「標準値」「省略値」など複数ある場合はCSVまたはOTLTを用意する。特に、業務コードの管理元が一元化されており、コードの種別ごとにCSVファイルが作成するのが煩雑な場合はOTLTとするのがよい。多くの場合、業務コードの追加・削除はシステム修正として扱われる(例:元号の追加)ため、コード値の修正に特別なプログラムが必要だったりシステムの再起動を伴ったりしても、問題になるケースは少ないと思われる。

*1:メッセージIDの命名規則は多くの場合アプリケーションアーキテクチャ内に閉じており、業務面の制約を受けにくいことも、リテラルとする理由のひとつ

*2:アプリケーションの再起動は運用担当者が日常業務として実施するという前提をおいている

*3:ビジネスロジック本体の修正と独立に、埋め字の内容が変更されてしまうのを避ける。

*4:セキュリティ事故の責任を問う裁判で「プログラム中でEnumを使ってれば事故が防げたのに、Enumを使ってなかったから過失」みたいな判例があったように思うのですが、探しても出てきませんでした。

How to add a JMS queue corresponding to jboss.naming.context.java.jboss.resources.xxx.yyy.zzz with jboss-cli

Context

  • You are building a Java web application with JMS.
  • You have added a reference to JMS queue with <res-ref-name>xxx/yyy/zzz</res-ref-name> in web.xml.
  • You have changed the configuration file from standalone.xml to standalone-full.xml to use JMS module.
  • You have added a JMS queue with jboss-cli.
  • Now you are going to deploy the application to Wildfly with ActiveMQ.

Problem

  • You will get the WFLYCTL0412 or WFLYCTL0180 error when you deploy the application. It says that you could not find jboss.naming.context.java.jboss.resources.xxx.yyy.zzz.
  • The error will be not resolved when you add a JMS queue with following command in jboss-cli:
jms-queue add --queue-address=xxx.yyy.zzz --entries=xxx/yyy/zzz
  • You will get another error when you try to add a JMS queue java:comp/env/xxx/yyy/zzz with following command in jboss-cli:
jms-queue add --queue-address=xxx.yyy.zzz --entries=java:comp/env/xxx/yyy/zzz

Reason

  • jboss.naming.context.java.jboss.resources.xxx.yyy.zzz in the error message correspond to a JNDI name java:jboss/resources/xxx/yyy/zzz.
  • java:comp/env/ is ENC (Environment Naming Context). It is a naming convention to refer JNDI resources from web application. You cannot use ENC in application server settings (it does not tied to specific web application).

Solution

You can add a JMS queue corresponding to jboss.naming.context.java.jboss.resources.xxx.yyy.zzz with the following command in jboss-cli:

jms-queue add --queue-address=xxx.yyy.zzz --entries=java:jboss/resources/xxx/yyy/zzz

Note that xxx.yyy.zzz in --queue-address option is an arbitrary name of JMS queue. You can see this name in the result of /subsystem=naming:jndi-view.

「基く」は「もとづく」か「もとずく」か

私(1981年生)は小学校か中学校かで「もとづく」が正しくて、「もとずく」は誤りだと習ったように思います。

ところが1955年(昭和30年)の第3期国語審議会では、「もとづく」か「もとずく」かは「原則を決めてもなおかつかたづかない」(吉田委員)ものという意見が出ています*1。「原則を立てても無益である」(金田一副会長)というのです。

どうやらこの回では結論らしきものが出ていません。さてどうしたものか、と思ったのですが、発見がありました。なんと上皇陛下が論文「ウロハゼの学名について」(魚類学雑誌 13巻 4/6号, 1966年)*2で「高木 (1962) もこの KOUMANS' の考えにもとずき,……」と書いてます!*3 これはもう「もとずき」もアリでいいんじゃないだろうか(乱暴)