読者です 読者をやめる 読者になる 読者になる

Corredor

ウェブ、プログラミングの勉強メモ。

定数ってどう管理するのが良いかね

プログラミング哲学 設計 教えてください

プログラミングをしていて必ず出てくる定数。基本的に変更が発生しない値のことだけど、これをどこで管理するのが良いのか、考えたい。

定数の保管場所

定数を保管する場所、手段として思いつくものは以下のようなもの。Java 寄りな表現が多いかもなので各言語で対応するものに読み替えてください。

  • プログラム内に定数クラスを作る (Enum なり public static final なりの集合体的なアレ)
  • プロパティファイル (Properties なり XML なり YML なり)
  • DB にマスタテーブルを作る
  • JVM の起動オプションの引数として与える
  • OS の環境変数で設定する

さて、定数をどこで管理しようか。

先に結論

先に結論から話すと、全ての定数をどこか1箇所・1つの手段に集約することがベストではないと思う。定数と思っている情報の性質・適用範囲と管理方法の特性に合わせて都度人間が考えなくてはいけないものだと思う。

じゃあ、定数の性質とは、適用範囲とは、管理方法の特性とは何ぞや、とか、ベストプラクティスはあるんか?とか、そういうことを考えながら話したいと思う。

定数クラス

まず、public static final の羅列で膨らんだ定数クラスは止めるべき。どの定数がどの分野で使われるか分からないから。パッケージなどで区切り、その機能内でのみ使えるものにした方が良い。

で、定数クラスで持つのがベターな情報としては、

  • プログラム中で使うコード値や固定文言で、
  • 一度宣言したら二度と変更が入り得ないもの

に限定するべき、と思う。

例えば、ドルを円に変換する処理があちこちに出てくるような機能があったとしたら、日本の貨幣の単位は今後しばらく「Yen」という表記だろうし、金額の区切り文字は「, カンマ」から変更されることはほぼないだろう。

定数を変えるような事態が発生する時は、同時に必ずプログラム修正が入らないと筋が通らない、といったものであれば、プログラム内に定数クラスとして保持しても良いと思う。

あとは、Enum を使ったり、大きめな定数クラスの中に子クラスを作ったりすることで、見た目使いやすくしてあげられればなおよし。

プロパティファイル

ファイルに定数情報を外出ししておく手法。Java 系だと .properties 形式のファイルを見かけることが多いだろうか?適当にデッチ上げたが、以下のようにコード名称とコード値を「=」で結んで定義したりする。

# エラーメッセージの定義
ERR_NOT_FOUND=データが見つかりませんでした。
ERR_TIMEOUT=接続がタイムアウトしました。

ログラムモジュール内にプロパティファイルを置いた場合は、グローバルな定数クラスとあまり特性が変わらず、変更の度にコンパイルが必要になるワケで、メリットというメリットがない。

しかし、プログラムモジュールから完全に外出しするにしても、プロパティファイルの位置を示すための情報はモジュール内に書いておかないといけないので、開発環境と本番環境とかでどうしても環境別にプログラム変更をしないといけない部分は出てしまう。

ただ、プロパティファイルがモジュールの外にあるということは、モジュールはコンパイル・デプロイし直さずとも、プロパティファイルの書き換えだけで、プログラムの振る舞いを変えられるというメリットがある。

例えば、DB の接続先情報なんかはプロパティファイルに持たせておけば、環境別に切り替えがしやすいし、本番環境で使用する URL 情報などはハードコーディングしたりモジュール内に定数クラスで持ったりするよりは、プロパティで管理した方が、管理構成上のミスが出にくく、影響も少ない。

プログラムモジュールを変えることなく振る舞いを変えられる、という意味で行くと、プロパティファイルは DevOps の文脈の中でフラグによる機能のオンオフを切り替えるために使われたりもする。プログラム内にはその機能を仕込んでおき、リリース時はプロパティファイルでその機能をオンにする、ということをしてやるのだ。

ということで、

  • 1環境の中では変更されることはないが、環境ごとには変えたい情報

であれば、プロパティファイルの外出しが有効であろう。

また、ファイルの書き換えで変更できるので、

  • 割と変更される頻度が少なくない情報

も、プロパティファイルに書いておくと良いだろう。

注意点は、ファイルのパスを示したりするためには、やはりモジュール内に手を加える必要があり、OS 環境が異なったりするとさらにモジュール内でプロパティファイルを取得するための考慮が必要になることだろうか。一度こさえておけばいいものではあるが、どんな環境でも万能なものではない。

DB 管理 (マスタテーブル)

定数チックな情報を DB で管理する手法。何かしらのマスタ情報を格納するテーブルを作っておき、ユーザ操作によって UPDATE が行われたりすることがないようにしておくのが基本であろう。

DB 管理のメリットは、マスタテーブルを、その定数値を使用した各テーブルの情報と結合して使いやすいことか。部署名を管理するマスタテーブルと、ユーザ情報のテーブルを結合させれば、ユーザの所属部署名をマスタテーブルから引っ張ってこられる、というような感じだ。

定数クラスやプロパティファイルよりも、DB の方が追加・変更がしやすいだろうから、

  • コード値を変える可能性がまぁまぁある
  • 一つのコード名称で複数の値が拾えて、その値が時によって変更・追加されるような類

であれば、DB 管理が向いていると思う。

JVM 引数

アプリケーションサーバのヒープサイズ設定とかは環境別にすることもあるだろうけど、それはプログラム内で使う定数でもないだろうし、定数として管理することもない気がする。JVM 引数からプログラムに値を渡したりするのも乱暴な感じする…。

というわけで選択肢から外す。

OS の環境変数

DB の接続先情報はプロパティファイルでなくて環境変数にしたりするかも。でもやはり、あんまり使おうとは思わないなぁ。ファイルを置きさえすればどこでも動くようなアプリケーションでありたい気がするので、OS まで手を入れたくない感じする。

というわけでこれも選択肢から外す。

変更が発生しうる頻度

個別の特徴を見てきたので、ここからは用途別に考えてみる。

定数とする対象の情報について、変更が入りやすい順に、どの手法がいいか、というと、

  1. DB 管理
  2. プロパティファイル
  3. 定数クラス

だと思う。コードに近いものほど変えにくい感じ。

情報の種類別にオススメ

ここまで書いてきたもののまとめみたいな感じだけど。

  • ユーザに見せない、プログラム処理で使うモノなら定数クラス
  • プログラムは同じままで、環境ごとに動きなどを変えたい情報はプロパティファイル
  • 定数の内容に追加・変更が入ってもプログラムの振る舞いが変わらない情報は DB 管理 (マスタデータ、な感じに近い)

こんなふうにぼくは思います。

以上

こんな場合はどうするのがいいか、とか、こういう場合はこうした方がいい、とかあればコメントください。

参考

Oracle DB に接続して SQL を実行する VBScript

WSH VBScript DB Oracle Oracle12c ODBC

SQL*Plus がない環境で Oracle DB を参照したくて、VBScript から DB 接続して SQL を実行するプログラムを作ってみた。

コード

初めに、できあがったコードは以下のとおり。Gist-it で GitHub のコードを埋め込もうとしたんだけどうまくいかなかったので GitHub へのリンクでご容赦。

使い方

この VBSQLipt.vbs (ダジャレw) をダブルクリックで実行すると、開始して良いか確認するダイアログが出る。「OK」をクリックすると、黒い IE が画面全体に広がって、DB に接続される。この IE がコンソール代わりになる。

メッセージを入力できるプロンプトが表示されたら、ココに SQL を入力する。SELECT 文を入力すれば結果を IE コンソールに吐き出すかどうかを選択できる。UPDATE なども可能だが、実行した瞬間にコミットされてロールバックはできないので注意。

SQL*Plus ではないので、Set 文など Oracle 独自の構文は不可。あくまで SQL として実行できる文のみ有効だ。

終了したいときは、メッセージプロンプトに「exit」か「quit」と入力する。

製作過程メモ

VBScript DB接続」とかでググってベースを作った。

IE をコンソールとして使うアイデアは、VBScript で進捗状況を示すウィンドウを IE で作った時の手法を流用した。

While True で無限ループが可能なアイデアをどこかで見かけたので、これでメッセージプロンプト表示と SQL 実行を繰り返させるようにした。「exit」か「quit」を受け取った時だけ、Exit DoWhile ループを抜けている。

取得した結果件数を取得するのに、カーソルロケーションをクライアントサイドカーソルにしないといけないらしい。これよく分かってない。

1番詰まったのは、環境に合わせた ConnectionString の書き方。Windows 上で ODBC が登録されていれば、その名前を参照することで接続できたりするが、自分はできれば VBScript 内で接続情報を完結させたかった。

色々調べて、tnsnames.ora ファイルに書く接続先文字列をそのまま書くことで実行できる方法を見つけた。多分これは Oracle クライアントがインストールされていないといけないと思う。

ODBC 接続も可能だが、その際の接続先情報を VBScript 内だけで完結させる方法はちと分かってない。一応、登録済みの ODBC データソースの名前を指定する方法は、コード中にコメントで記載しておいた。この辺詳しくなりたい…。

SQL の妥当性チェックとか、動作中に IE が閉じられてしまった時のハンドリングなどはしていない。自分が使う範囲のスクリプトであれば、極端に異常系をチェックしたりしなくていいやと思ってる。気を付けて使えばいいんです。w

できたらいいなと思っているのは、SQL の複数行入力。IE は出力するだけで入力はできない作りなので、IE 上でテキストエリアとか置けたらいいのかしら?それなら HTML 中に VBScript 埋め込む作りの方がいいのかな。

入力内容の履歴保持もやれたら良いなーと思ってるけど、一旦これで事足りてるし、諦めている。

なんとなく GitHub リポジトリにしてみたので、何らかの依頼とかがあったら何らかの更新とかしてみようと思う。

参考

JScript と WSH と JScript.NET と .NET Framework と

JScript JavaScript JScript.NET .NET Framework VBScript VB.NET WSH

Windows で何かスクリプトを作るとなると、MS-DOS 上がりのコマンドプロンプトではイマイチ勝手が悪い時がある。PowerShell を使う手もあるが、実行するために環境設定が必要だったり、独特な言語仕様を勉強するコストが割とかかり、学ぶ気のない人には引き継げない。

そうなると、VBA や VB6 などの経験がある人は VBScript で、フロントエンドに明るいタイプの人には JavaScript によく似た言語仕様の JScript で、それぞれスクリプトを書くことになる。

んで、今回はそのうちの JScript について、最近 JScript.NET というものを知ったので、このあたりの内容をまとめてみる。

VBScriptJScript を動作させる環境が Windows Script Host

コマンドプロンプトよりちょっと高級なスクリプトが書ける、WSH って何だったのよ、という話。

Windows Script Host と呼ばれるものは、スクリプトの実行環境を指す。そして、どんな言語でスクリプトを書くか、というところで、標準サポートされているのが VBScript という言語と、JScript という言語、というワケ。両方とも Microsoft 製の言語なので、Windows OS 上、そして IE 上など、実行環境を意識することなく使えるような作りになっている、というワケだ。この「別け隔てない」感じが、混乱を招いているような気がする。

グラフィカルに動作するのが WScript (WScript.exe) で、コマンドライン上で動作するように最適化されているのが CScript.exe だ。例えば、以下のような VBScript (.vbs ファイル) があったとして、

' sample.vbs
WScript.Echo "ほげほげ"

これをコンソール上から

Wscript sample.vbs

と呼ぶと、画面上にダイアログボックスが表示されるが、

CScript sample.vbs

と呼ぶと、コンソール上にメッセージが表示される。

ただし、VBScript が持つ MsgBox 関数を使ったとしたら、これは CScript でもダイアログボックスが表示される。あくまで WSH が提供する機能の現れ方が、WScript と CScript で異なる、ということだ。

ちなみに、サードパーティ製だと、Perl が動作するようにする動作環境 (スクリプトエンジン) もあるみたい。

.NET Framework の登場と VB.NETJScript.NET

Microsoft は共通言語基盤という考え方を進めていくため、.NET Framework という開発・実行環境を作った。あらゆる言語で作られた言語を共通中間言語コンパイルすることで、コードが特定のプログラミング言語やプラットフォームに依存しないようにするという仕組みだ。WSH がやりたかったことを拡大解釈した機構、といったところか。

C#PowerShellVB.NET などが、.NET Framework を基盤として動作する言語としてよく知られているが、Java .NET Framework 上で動作するように移植した J#、PHP が動作する Phalanger、Python が動作する IronPythonRuby が動作する IronRuby などもある。これらは全て、それぞれの言語で書いた既存のコードはほぼそのまま動作する上に、.NET Framework が用意するクラスライブラリを使うことができるワケだ。

JScript.NET もその流れの1つである。Microsoft 製の JScript .NET Framework 基盤に乗った仕様、ということだ。

WSH で動く JScript と、JScript.NET の違い

では、JScriptJScript.NET で何が違うか、というと、簡単にいえば、WSH が提供していた機能は使えなくなる。例えば先述の WScript.Echo("文字列"); は、JScript.NET では使えない。代わりに、import System; 文で System をインポートし、Console.WriteLine("文字列"); と書くことになる。ちなみに、print("文字列"); であれば、JScript の組み込みなので、JScript.NET に移植する際もそのまま使える。

WScript.sleep() なども同様だ。実行環境 (WSH .NET か) が異なるので、実行環境に依存した構文はどうしても影響を受ける。WSH を使っていたが、.NET Framework は知らない、という人は移植のために勉強が必要になるだろう。

また、JScript.NET をどう実行できるようにするか、というところで、大きな違いがある。WSH 上の JScript の場合、.js ファイルを関連付けしておけば、ファイルのダブルクリックで実行可能であった。これに対し、JScript.NETjsc でのコンパイルが必要なのだ。

Rem .NET Framework のフォルダにある jsc.exe を使用してコンパイルする
C:\Windows\Microsoft.NET\Framework\v4.0.30319\jsc.exe sample.js

こうすると、sample.js と同じ階層に sample.exe が出来上がるので、これを実行する。

ちなみに、JScript.NETコンパイルする jsc.exe の他にも、VB.NETコンパイルする vbc.exeC#コンパイルする csc.exe なども、.NET Framework のインストールフォルダ内に置いてある。言語が違うだけで使い方は同じなので、気になる人は調べてみるといい。

JScript.NET の認知度の低さ

さて、C#VB.NET など、.NET Framework を基盤とする代表的な言語と比べて、Microsoft 製の言語なのになぜ JScript.NET の認知度が低いのか。

一つの原因は、JScriptVisual Studio (IDE) での開発に対応していないのだ。代表的な開発環境がなく、なぜか jsc.exe が放り込まれているだけなので、その存在もあまり知られていなかったりする。

もう一つは、ベースとなる JavaScript という言語の標準を策定しているのが、Ecma International という別の団体 だからであろう。Visual BasicC#Microsoft 製の言語だが、ECMAScriptJavaScript はそうではないため、あまり手厚く見てもらえていないのかもしれない。VB の元となっている BASIC や、C# の元となる C よりも歴史が浅く、ブラウザベースの言語として発展してきた経緯もあり、スクリプト言語としての利点がそんなにない気もするし。

そんなワケであまり陽の目を見ない JScriptJScript.NET だが、JavaScript から入った人間は VB 系の言語仕様にイマイチ慣れないこともあり、なんだかんだとこの陰キャラを愛している、のかもしれない。

参考

WebLogic Scripting Tool (WLST) を使って WebLogic Server をコンソールから操作する

WebLogic Server WebLogic Server 12c Windows Windows コマンド

これまで WebLogic Server の操作というと、ブラウザ上で管理コンソール http://localhost:7001/console/ にログインして GUI で操作していたが、同様の操作をコンソール上から行えるようにするためのツールが標準装備されているらしい。これを覚えれば GUI 操作のミスをなくしたり、バッチスクリプトにして自動化したりできるかもしれない。

ということで、この WebLogic Scripting Tool (WLST) をコマンドプロンプトから対話形式で使うための手順をまとめておく。

先に接続までのコマンドを。

Windows 環境で、WebLogic Server 12c を操作する前提で。

Rem 環境変数を設定するコマンドファイルがあるフォルダに移動する
Cd C:/Oracle/Middleware/wlserver_12.1/server/bin/

Rem WLS (WebLogic Server) の環境変数を設定する
Call setWLSEnv.cmd

Rem WLST を起動する
Java weblogic.WLST

Rem 起動完了

Rem connect('<ユーザー名>', '<パスワード>', 't3://<管理ホスト>:<管理ポート>') で管理サーバに接続する
wls:/offline> connect('Neos21', 'NeosPassword', 't3://127.0.0.1:7001')

Rem 終了する時は exit()
wls:/offline> exit()

この先は…?

どのような操作ができるかは help() を参考に。

何やら MBean (Managed Bean) という、管理対象を表す Java オブジェクトが用意されており、これを触ることで、ブラウザ上の管理コンソールでできる操作が同じようにできるようだ。管理コンソール上のヘルプを見ると、画面上で変更できる項目に対応する MBean を調べることができる。

Java オブジェクトなので、Java プログラムから同様に操作することも可能なようだ。

ちょっとずつ勉強していきながら、「ところでこれを使って具体的に何がしたいんだっけ?」を考えることにする。w

Windows10 のエクスプローラのフォルダツリーから要らないメニューを消す

Windows Windows10 Registry Explorer Gist

久々に更新します。

Windows10 のエクスプローラのフォルダツリーには、普段使わない「ピクチャ」や「OneDrive」が表示されていたり、なぜか外付け HDD が2つ重複表示されていたりする。これらを解決する。

外付け HDD が重複表示されるのを解消する

レジストリエディタで
[HKEY_LOCAL_MACHINE\SOFTWARE \Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace \DelegateFolders\{F5FB2C77-0E2F-4A16-A381-3E560C68BC83}]
または
[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\DelegateFolders\{F5FB2C77-0E2F-4A16-A381-3E560C68BC83}]
を削除

配布されているレジストリファイルの内容は以下のとおり。

Windows Registry Editor Version 5.00

[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\DelegateFolders\{F5FB2C77-0E2F-4A16-A381-3E560C68BC83}]

[-HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace\DelegateFolders\{F5FB2C77-0E2F-4A16-A381-3E560C68BC83}]

「ピクチャ」や「ビデオ」など不要なメニューを消す

サブキーと削除できるフォルダは以下のとおり。

  • {088e3905-0323-4b02-9826-5d99428e115f}:ダウンロード
  • {24ad3ad4-a569-4530-98e1-ab02f9417aa8}:ピクチャ
  • {3dfdf296-dbec-4fb4-81d1-6a3438bcf4de}:ミュージック
  • {d3162b92-9365-467a-956b-92703aca08af}:ドキュメント
  • {f86fa3ab-70d2-4fc7-9c99-fcbf05467f3a}:ビデオ
  • {B4BFCC3A-DB2C-424C-B029-7FE99A87C641}:デスクトップ
Windows Registry Editor Version 5.00

[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{088e3905-0323-4b02-9826-5d99428e115f}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{24ad3ad4-a569-4530-98e1-ab02f9417aa8}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{3dfdf296-dbec-4fb4-81d1-6a3438bcf4de}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{d3162b92-9365-467a-956b-92703aca08af}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{f86fa3ab-70d2-4fc7-9c99-fcbf05467f3a}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}]

[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{088e3905-0323-4b02-9826-5d99428e115f}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{24ad3ad4-a569-4530-98e1-ab02f9417aa8}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{3dfdf296-dbec-4fb4-81d1-6a3438bcf4de}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{d3162b92-9365-467a-956b-92703aca08af}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{f86fa3ab-70d2-4fc7-9c99-fcbf05467f3a}]
[-HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}]

WOW6432 というのは、64Bit Windows で 32Bit のアプリを動かす時に使うモノらしい。

「OneDrive」の表示を消す

Dropbox を使っていて OneDrive は使っていないのでこれも削除する。

HKEY_CLASSES_ROOT→CLSID→{018D5C66-4533-4307-9B53-224DE2ED1FE6}
と階層を開いていき、右画面の「System.IsPinnedToNameSpaceTree」を右クリック、修正を選択します。
値のデータを0に設定してOKをクリック。

これだけレジストリの位置が違うみたい。とりあえず上記の方法で消せたので、これをレジストリファイルに書き直してみる。以下の記事を参考に書いてみた。

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}]
"System.IsPinnedToNameSpaceTree"=dword:00000000

これで動作した。

1つのレジストリファイルにまとめておこう

これらの設定を1つの .reg ファイルにまとめておき、いつでもサクッと設定できるようにしておく。.reg ファイルにおけるコメントアウトは、行頭にセミコロン ; かスラッシュ2つ // のいずれかでできるみたいなので、注釈を入れてみた。

完成したファイルは以下。

GitHub の Contribution、Gist 投稿でも草生えてくれたらいいのにな~。