2015年5月30日土曜日

[大規模システムの設計]基本概念(2)

 大規模システムの原理原則は前述した通りであるが、例外事例について一応の補足を行う。
 管理者にとって、システムの運営は簡明かつ迅速なものでなければならないが、同時に大規模で複雑なシステムは様々な機密情報を取り扱うことも多い。そのような場合、車のキーを入れてエンジンをかけ、簡単に自動車そのものを運転して逃げられてしまうようなセキュリティにしておくと、重大な事故につながってしまう。
 大規模システムが目指すところは簡明かつ迅速な目的の達成、最大効率の実現であるが、システムのセキュリティを考えたとき、手続き的な安全策を入れることを忘れてはならない。たとえばインターネット上のWebサイトで入力を受け付けたら、同じネットワークでそれ以降の処理を進めてはいけない。受付のデータは必然、Webからアクセスできるマシンから参照できるDBに置かなければならないが、OSやミドルウェアにはどのようなセキュリティホールが隠れているか分からないから、オンラインからアクセスするマシンで全てのソフトウェア的な手続きができるようにしてしまうと、重大事故を招きかねないのである。
 このような場合Webで受け付けたデータはミラーリングで2つ以上のハードディスクに保管し、ある一定期間ごと(たとえば毎日午前0時)に1台のハードディスクを切り離して、Webからは参照できないネットワークに持って行って処理するべきである。HDDは一度スタンドアロンのマシンでウィルス感染をチェックし、DBのデータは1項目ごとにSQLインジェクションのような不正なコードがないか確認した上で、特定の形式に変換して抜き出し、更に別のネットワークでその変換後の安全なデータを処理すべきである。こうすることによって、Web上の攻撃者から全く推測のできないデータ形式で内部の処理は実施されることになる。また万一、データを移動するHDDにある不正なプログラムが自動実行されてウィルス感染したとしても、そこから外部のネットワークに接続できなければ情報を外に持ち出されることはない。HDDの内容を消去する不正プログラムを実行されても、内部のシステムをバックアップから戻せばよいだけであり、データを変える不正なプログラムに備えてデータチェックを別のスタンドアロンマシンで行えばよい。リスクは限りなく0に近づけることができる。
 このような一見煩雑な仕組み採用したとしても、HDDを切り離したり別のネットワークに接続する仕組みを機械化すれば、完全な自動化が実現できる。この管理体系全体をメンテナンス可能なものとすれば、ソフトウェア更新もメンテナンスもそれぞれ個別のネットワークやスタンドアロンマシンで行うことができ、入れ替えるソフトを上書きして再起動するだけでメンテナンスは終了する。適用したプログラムがヒューマンオペレーション(産業スパイによる人間の手動操作)で改変されたり、同じくヒューマンオペレーションによってネットワークを不正につなぎかえられたりしていないか不安だろうか。それは周期的に実行するチェックプログラムでチェックできるはずのことである。ネットワークの不正なつなぎかえも、データの改変も、接続しているネットワークの随時チェックやファイルサイズ、更新日時の簡単なチェックだけで異常を検出することが可能であり、どんなチェックが動いているか知らなければそれを回避することもできない。
 コンピュータシステムは処理にかかる時間が一瞬で、なおかつ複雑な挙動を実現することが可能であるため、従来では考えられなかったような複雑な異常検出、侵入検出の仕組みを組み込むことができる。しかもコンピュータは故障以外で誤動作しない。管理体系全体をいつでも予備系に切り替え可能な二重系統としておけば、より完璧である。
 通常はここまでのコストをかけられないので、「誰がいつ何をした」ということを後から追跡できるよう、紙ベースの申請書類を担当者に書かせた上で、2人以上で手動操作による更新を行い、それを更に管理者が確認し、作業しないときはマシン室に物理ロックをかける、といった手順が多くなる。このような場合、多少管理が複雑となり、ソフトウェア更新にも時間がかかることになるが、これはセキュリティ考慮上やむを得ないもので、許容されなければならない。
 前項で指摘したのは、セキュリティなどほとんど考えていないシステムでも、管理可能性を失っているものが多数存在する点である。ソフトウェア開発もこのような側面を次第に重視するようになってきつつあるとはいえ、まだ非効率があることを知りつつ更に複雑な手順を追加するなど、本末転倒な状況がそこかしこに散見されるがゆえの苦言である。大規模なシステムはちょっとしたことで管理可能性を失って混乱に陥りやすい。原理原則が守られているか、日常的に確認することが重要である。

[大規模システムの設計]基本概念(1)

 大規模システムをどのようにして作るか、そのノウハウについて記述する。
 まず最初に、なぜ大規模システムが必要なのかについて説明する。
 大規模システムは、「人にとって役に立つ仕組みを作る」ために必要なものである。何らかの仕組みを作るとき、それが小規模なものであれば目的・用途は自由に決めてよいものだし、作っている途中で変えてもよい。しかし大規模システムの場合、最初に定める目的が間違っていると、途中も最後に出来る成果物にも大きな影響が出てしまう。まずは、基本となる概念をしっかり定める必要がある。
 電子計算機によるシステムは、狭義のシステムである。「システム」とは本来「体制・体系」を示すものであり、元々は電子計算機によらない仕組みである。簡単に言うと「ある条件に合致した場合に、ある動作をする仕組み」である。自動販売機にコインを入れると投入金額が表示され、購入可能な商品のボタンが点灯するが、これは「コインが投入された場合」に「金額を表示する」「購入可能な商品のボタンを点灯する」という「仕組み」が動いているからである。
 およそ人が作り出す決まり事、ルールは「システム」であるということができる。人は集団となって初めて力を発揮することは、今さら確認するに及ばないことであるが、この集団を最大効率で動かすために必要となる決まり事が「システム」なのである。
 「1人で自動車を作れ」といって、できる人間はまずいないであろう。部品1つ作れない人が大半であるはずだし、作り方の全てを把握している人がいたとしても、その人が1人で自動車を作り始めて完成させるまでには途方もない時間が必要になる。しかし実際には、毎日何千台、何万台という自動車が作り出され、世に送り出されている。人は群体でこそ、本当の力を発揮するのである。
 「システム」とは人が作り出すものであり、群体としての強みを極大化し、最大効率を目指すためのものであるということができる。社会そのものを統御、統括していくための仕組みであると、いってもいいだろう。

 システムが担う重要な役割は、次の通り。
 (1) 状況把握に要する時間を極小化する
 (2) 管理に要する時間を極小化する
 (3) 意図した挙動を速やかに実現する

 前述した車の例を考えても明らかである。車に乗る人はエンジンをかけて、アクセルを踏み、ハンドルを握るだけで車という複雑極まりない仕組みを簡単に動かすことができる。最近は故障を知らせてくれるディスプレイも運転席に標準搭載されているし、定期的にディーラーに行けば、1日以内にメンテナンスは完了する。上記(1)~(3)が全て成立しているはずである。
 たくさんの人が関わるイベントを企画するような場合を想定してみてもいいだろう。状況も分からない、作業者が思った通りに動いてくれない、管理に時間がかかる、では企画はすぐにダメになってしまう。そのどれが欠けても、たくさんの人が関わる大規模な仕組みを動かすことはできないのである。
 何か困ったことがあったらお役所やおまわりさんに相談する、急な病気になったら救急車を呼ぶ、これも全て特定の条件が成立したときに動く仕組みのことを指すものである。この社会は様々なシステムの集合体であるということができる。このうち電子計算機によるシステムは、電子計算機だけで完結することができる役割を自動化するものである。
 電子計算機によるシステムはこのように狭義のシステムであるが、役割はそれ以外のシステムと同じである。重要なことなので2回記述する。

 (1) 状況把握に要する時間を極小化する
 (2) 管理に要する時間を極小化する
 (3) 意図した挙動を速やかに実現する

 世の中にある電子計算機によるシステムを見ていると、この要件を満たしていないものが多い。何かトラブルが起きた時にログを開いても手掛かりになる情報が何も出ていない、ほんの1行実装を変更するだけでシステム停止から再稼働まで1日がかりの作業になる、システムを動かしたい場合に必要な手続き(ログインや紙ベースの管理書類提出など)が多くて時間がかかる、そういうシステムを見たことはないだろうか。これは根本的な誤りである。
 大規模システムとは、決して管理可能性を失ってはならないものである。最大効率を目指すものでなくてはならず、煩雑な管理が不要なものでなければならず、いつでもすぐに状況を把握できるものでなければならない。この上更に意図した挙動を速やかに実現して初めて、大規模システムが成立する。
 前段が長くなってしまったが、この原理原則を決して忘れないようにしなければならない。最終的にシステム管理者が内部構造を全く知らない状況でも、バッチを1つ叩くだけで状況を把握でき、問題解決を依頼しなければならない技術者を速やかに判別でき、問題を解決する技術者もどこを修正するのかすぐに判断できてこそ、優れた大規模システムが成立するのである。

[業務知識][生命保険]事業方法書

 略して事方書と書くこともある。保険業法第4条第2項に定めるところにより、保険会社が事業を行う上で内閣総理大臣宛てに提出しなければならない経営についての方針を記した書類で、主に保険募集に関わることが記載されている。実際の事業方法書は機密文書であり、外部に情報を漏えいしてはいけない。
 ただし実際には保険会社各社の事業方法書の内容はお互いに知られていることが多い。なぜかというと、中途採用の社員から情報が入ってくるからである。終身雇用が当たり前でなくなってきた現在では、生命保険業界でも労働力の流動化が進み、他の生命保険会社で働いていた人材を、即戦力として中途採用することが多くなってきているのである。求人サイトなどでチェックしてみても、「事業方法書の作成に詳しい方」といったように募集要項にストレートに書かれていることも少なくない。
 内閣総理大臣宛ての提出文書であるが実際の所管は金融庁であるため、主に金融庁との折衝に必要な資料となる。全くノウハウのないところから新しく事業を起こす場合、他の生命保険会社の事業方法書作成のノウハウは必須である。

[業務知識][生命保険]約款

 約款とは保険契約を締結したときに保険会社から渡される書類で、保険契約に関する事項が記載されている。保険は金融庁が保険会社に認可を与えて初めて売り出すことができるが、金融庁に許可をもらうときにも約款は必要となる。
 保険にまつわるトラブル、たとえば保険金が支払われないといった問題が起きたときに、法的な解決を図るための根拠となる資料であり、契約者と保険会社の間の保険契約全般について記載する。約款は膨大な資料で内容も難しい文言を使っていることが多く、契約者がその全文に目を通して保険契約を締結することはまずありえないが、法的なトラブルとなった場合は「読んでいなかった」ということはできない。保険契約を締結した時点で、約款に同意したものと扱われる。
 難しい文言で書かれている読み切れないくらい膨大な資料を「読んでいなかった」で済まされないというのは、一見乱暴に過ぎる公平性のない判断であるように見えるが、実際にはそうではない。前述した通り、新しい保険は保険会社が金融庁に許可を取って初めて販売できる。公的期間である金融庁が「yes」と言わない限り決して世に出すことはできない。つまり、事前に厳重なチェックがかかっているということである。高い月払保険料を取って、ほとんど保険金が支払われないような違法性が高い保険商品などを売り出そうとしても、許可が下りないのである。
 もし仮にとてつもなく契約者に不利で、お金ばかり取られてしまうような保険が本当に世の中に出てしまった場合、当然大量の保険契約者から訴訟が起こされることになる。そのような事態になり、状況がメディアを通して伝わるようなことになれば、生命保険全体の信用、金融庁の信用を大きく損ね、生命保険の契約は激減し、その後も10年単位で保険が売れない状況が続くことになるだろう。そのような事態を起こしては、生命保険業界全体が大打撃を受けてしまう。一部の悪質な保険会社が生命保険業界全体の秩序を乱さないよう、金融庁によるチェックは厳しく行われているのである。

2015年5月6日水曜日

[Java][Servlet]サーブレットからJSPに渡すパラメータについての補足

 サーブレットからJSPに渡すパラメータはgetter/setterを持つクラスとすることができるのは前述した通りだが、このクラスをどこまで共通化するかについては、設計時に検討を要する。
 ユーザ入力内容を保持する(いわゆる前値保持)のために出力パラメータクラスを使う場合、同じまとまりにある画面間全てに共通する内容を定義すべきである。たとえば掲示板プログラムで「トップ画面」「カテゴリ一覧画面」「スレッド一覧画面」のような大きなまとまりがあった場合、それぞれのまとまりごとにパッケージ(フォルダ)を作ってソースコード管理を明確化にすることは別記事で紹介した通りである。
 同じようにまとまりの中で使う前値保持のための出力パラメータクラスも共通であることが望ましい。画面遷移していく際に全ての画面で個別の出力パラメータクラスを作成すると、前値保持しなければならないパラメータが増減しただけで、全ての出力パラメータクラスを修正しなければならなくなる。少なくともまとまりごとに共通の出力パラメータクラスを作成することが推奨される。

[Java][Servlet]JSP・サーブレット間のパラメータ受け渡し

 Webアプリケーションではサイト内で入力した内容をサーブレットに渡し、データベース検索や登録などの処理を行う。ブラウザ上で入力した内容をサーブレットに渡す方法について、解説する。
 Webアプリケーションでユーザ入力をサーブレットに渡すためには、まずJSP内に入力用のタグを記述する必要がある。単純なテキストボックスを使った入力を行うためのタグ記述方法は、次の通り。

    <form action="/bbs/top/index.html" method="post">
        <input type="input" name="inputString">
        <input type="submit">
    </form>

 <form>は投稿するデータのフォームであることを示すタグである。<form>~</form>までで囲まれた範囲がフォームであることを示している。<form>タグのactionを "/bbs/top/index.html" としており、methodが "post" となっているが、これは当該フォームが「/bbs/top/index.html」というアクションをPOSTで実行することを示すものである。formタグの中に <input type="submit"> というタグがあり、当該アクションを呼び出すためのサブミットを行うボタンを画面上に配置している。このサブミットボタンが押されることで、アクションが実行される。このとき呼び出されるアクションは、前述した記事に掲載しているサーブレットである。
 <form>内にあるもう一つの<input type="input>というタグは、入力用のテキストボックスである。ブラウザ上にはテキストボックスが出現し、ユーザ入力を行うことができる。ここで入力した文字列は「inputString」という名前で、サーブレットにPOSTされる。
 サーブレットプログラム側ではHttpServletクラスのdoPostメソッドがTomcatから起動される。このとき「request.getParameter("inputString")」と記述して引数のHttpServletRequestから値を取得すると、画面で入力した値を取得できる。
 サーブレットで処理したデータを画面に渡す場合は、同じHttpServletRequestクラスに(レスポンスクラスではないので注意!)に「setAttribute([キー], [値]);」の形式で設定する。例えばトップページのサーブレット出力パラメータの場合「setAttribute("top", servletOutputParameter);」のように設定する。「servletOutputParameter」はgetter/setterから形成されるクラスで、Listなどの繰り返し項目も含めることができる。JSP側でサーブレットが設定した出力パラメータを取得する記述方法は、次の通り。

<input type="hidden" name="lastInputString" value="${top.lastInputString}">

 別記事で掲載したEL式を使えるweb.xmlの記述を行っておくことで、上記のようにservletOutputParameterクラスから値を取得することができる。上記記述の場合、hiddenに「lastInputString」というservletOutputParameter内のデータを設定していることになる。(内部的には「servletOutputParameter.getLastInputString();」を呼び出している)
 hiddenはサーブレット・JSP間で受け渡されるデータを保持しておきたい場合に使うもので、ユーザが入力した内容を保持しておくために用いられることが多い。(hiddenはブラウザ表示上は見えないが、実際には値を保持している)ただしユーザがURLを直接入力するなど、想定されていない画面遷移方法を行うとPOSTメソッドによる受け渡しがなされないため、保持していた内容は消えてしまう。

[Java][Servlet]web.xmlの記載内容

 StrutsやSpringなどのフレームワークを利用する開発プロジェクトが主流となった今、サーブレットプログラムは次第に利用されなくなりつつあるが、Webアプリケーションがどのように動いているか、その仕組みを知っておくことは重要である。最小限のサーブレットアプリケーションは以前の記事で掲載したので、ここでは最も基本的なサーブレットプログラムの仕組みをより詳しく解説していく。
 伝統的なサーブレットの設定ではweb.xmlにサーブレットとURLの対応関係を書くことが多い。web.xmlは次のような<web-app>タグによって開始・終了される。

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

</web-app>

 web-app開始タグの横にある「xmlns」で始まる内容は、EL式を使うために必要な記載事項で、googleを「web.xml web-appタグ」などのキーワードで検索すれば、サンプルが出てくる。EL式は移植性の高いコード記述を行うことができるため、非常に重要である。(JSPファイルにJavaのコードを直接書かず、タグによって可変部分を記述できる)
 この書き方はweb-appタグが新しくなるにつれて若干変わってくる。(EL式を使うためのXML設定がバージョンアップされる場合がある)そのためこの部分の記述については、使いたいタグライブラリなどのバージョンに合わせて変える必要がある。これは前述したgoogle検索で記事を発見できるので、その記事を参考にして実装し、テスト・検証を行う。

 次にサーブレットプログラムとURLの対応関係について記述する。
 Tomcatプロジェクトとして作成したWebアプリケーションを起動するには、TOMCAT_HOMEのconf配下にドキュメントルートを記載したXMLファイルを配置する必要があるのは、前述したサーブレットの最小限プログラムの記事を参照されたい。例えば掲示板プログラムを作成してプロジェクト名をbbsとした場合、Tomcatを起動してブラウザからアクセスするためには、次のURLを記述する必要がある。
http://localhost:0880/bbs

 ただしこの状態だと、まだbbsというドキュメントルート配下のどのサーブレットを起動するか分からない。そこから先のURLの対応関係の記述は、次のようなものとなる。

    <servlet>
        <servlet-name>top/index.html</servlet-name>
        <servlet-class>main.servlet.top.IndexServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>top/index.html</servlet-name>
        <url-pattern>/top/index.html</url-pattern>
    </servlet-mapping>

 <servlet>タグによって「top/index.html」というサーブレットが、Javaの実装クラス「main.servlet.top.IndexServlet」に対応する旨、定義している。ここから先のweb.xmlの記述で「top/index.html」というサーブレット名が出てきた場合、それは「main.servlet.top.IndexServlet」というJavaクラスを指す、という意味になる。
 次に<servlet-mapping>タグによって、「top/index.html」というサーブレット名が「/top/index.html」というURLパターンに対応する旨、定義している。これによってブラウザから「http://localhost:8080/bbs/top/index.html」にアクセスした場合、「main.servlet.top.IndexServlet」というJava実装クラスが呼び出される。
 URLパターンに「.html」という拡張子を採用し、あたかも単純なHTMLを読み込んでいるかのように見せている。(攻撃を受けないための初歩的な仕組みとしてこのように記述することもあるので、本サンプルで紹介した)
 「top/index.html」のように「top」というパッケージを入れるのも、初歩的だが重要なテクニックである。例えば掲示板サイトの場合、入り口(トップ画面)があって、カテゴリ一覧画面があって、スレッド一覧画面があって、といったように複数の大きなまとまりでサイトが構成されることが多い。ポータルサイトなどでも同じである。ニュース、路線検索、天気予報のようにお互いに異なる複数の大きなサイトのまとまりがあるはずである。この大きなまとまりごとにサーブレットやJSPを配置し、メンテナンス性を高めるためにパッケージを使うことが多い。
 このサンプルでいうとトップ画面のサーブレットやJSPは「top」というパッケージ(フォルダ)配下にソースコードが集められることになる。カテゴリ一覧に飛んだ場合は「category」というパッケージ(フォルダ)配下に、カテゴリ一覧のソースコードを集める。
 サーブレットプログラムはPOSTパラメータやhiddenタグを使って画面間のパラメータ受け渡しを行うが、ユーザが直接URLを指定した場合はそのようなパラメータ受け渡しが無効になる。このような場合はそれぞれのまとまりごとのデフォルトページに飛ばすのが、一般的なやり方である。上記サンプルでいうとトップ画面なら「top/index.hmtl」、カテゴリ一覧なら「category/index.html」といったように、それぞれのまとまりごとに持っているデフォルトのページを表示する。