レベル: 中級 山元 和斗志, , リコーテクノシステムズ株式会社
2004年 04月 15日 実際に動作する掲示板ソフトの開発をとおして、アプリケーション開発の上流過程からコーディングまでを実践的にご紹介します。
※この講座はリコーテクノシステムズ株式会社 山元和斗志様の投稿講座です。
0. はじめに
インターネットに存在する情報源として最も巨大なもののひとつが「匿名掲示板」と呼ばれるもので、日本におけるその筆頭は「2ちゃんねる」と言ってよいでしょう。
『2ちゃんねる』は「掲示板」の集合体で、掲示板毎に、扱う話題が設定されています。
その掲示板には「スレッド」と呼ばれる話の流れが複数存在し、そのスレッドの中で、議論や情報交換を行います。『2ちゃんねる』は「read.cgi」というプログラムで動作しており、同一、またはバージョンの違うプログラムを利用した同様の匿名掲示板は、多数存在します。
ここでは、情報交換の場となりうる「掲示板システム」を、Webアプリケーションで構築するまでを、設計段階からご紹介します。よろしくおつきあいください。
1. 掲示板を設計する
設計に当たっては、3つの視点で掲示板を見て、必要と思われる機能をリストアップします。
匿名性について
さて、掲示板を設計するには、まずその掲示板が持つ機能と、その使い方について考える必要があります。
匿名掲示板に限らず、世の全てのものには長所と短所、利点と欠点が存在します。
匿名であると、普段は(何らかの理由で)口にすることができないことも、発言できるようになるため、本音の意見交換が期待できます。しかし、その反面、投稿された内容の真偽は、閲覧者の判断に任されます。
「顔も見たことのない相手の言うことを、お前はなぜ信用する気になるのか?俺を信用する根拠は何だ?お前はただ、俺の言うことを盲目的に信じることしかできない。盲目的にな」
「嘘を嘘と見抜けない人には、(匿名掲示板を利用することは)難しい」
と言われる所以はそこに集約されるでしょう。
また、匿名であることは容易に理性を弱め、特定の個人または団体への攻撃がなされることもあり、何度かは訴訟となった上、匿名掲示板の管理者に罰金が科せられることもありました。
以上のことから、この掲示板では、匿名性はある程度制限することにします。
- 利用に当たってはユーザーIDとパスワードを要求する
- ユーザーIDの取得にはメール・アドレスが必須(メール・アドレスは非公開)
- メール・アドレス一個につき一個のユーザーIDを取得できる
- メール・アドレスのドメイン(またはアドレスそのもの)によっては、ユーザーIDを取得できない
上記より、以下の機能が掲示板に実装される必要があると思われますので、リストアップしておきましょう。
- ユーザー登録
- 個人情報設定
- パスワード初期化
- ユーザー情報管理(管理者のみ)
- ブラックリスト編集(管理者のみ)
※ブラックリスト=使用不能ドメイン・アドレスのリスト
構造について
掲示板の構造については、あまり独自性を発揮する余地はないでしょう。「掲示板」レベルでは「サイエンス」や「スポーツ」など、大まかに話題のジャンルを規定し、たとえば「サイエンス」掲示板の中で「火星探査機あれこれ」や「ナノマシン実用化近し!?」などの話題を「スレッド」として具体化し、その中で議論や情報交換を行うスタイルです。
「掲示板」レベルは管理者に任せて、ユーザーは「スレッド」を作ることができるようにすると、管理者が特に何もせずにいても、話題が提供され、掲示板が利用されていくでしょう。
しかし、場合によっては、不適切な発言がなされ、それを公開したままにしておくことができない場面もあるでしょうから、発言を削除することができなければならないでしょう。発言をユーザーが編集できると、発言の気軽さから、不用意な発言を抑制する力が弱まることが予想されますので、管理者のみ、しかも削除のみ行えるようにしたほうが良いでしょう。
- 掲示板の作成は管理者のみ
- ユーザーはスレッドを作成することができる
- 発言は編集・削除不能だが、管理者のみ、しかも削除のみ可能とする
上記より、以下の機能が掲示板に実装される必要があると思われますので、リストアップしておきましょう。
- 掲示板閲覧
- 掲示板作成(管理者のみ)
- 掲示板削除(管理者のみ)
- スレッド作成
- スレッド削除(管理者のみ)
- 発言(投稿・メッセージ)作成
- 発言削除(管理者のみ)
管理について
管理(=管理者専用の機能)については、一般の機能と表裏一体となっており、既に大半はリストアップされているものと思いますが、大半に過ぎません。管理機能はあらゆるシステムのキモです。
例えば、管理者が各種掲示板を用意したとして、ユーザーには「サイエンス」掲示板に「独身"漢"料理スレッド」を作成することが可能なのです。これについては、スレッドを掲示板レベルで移動させる機能を実装して対応することができるでしょう。
また、いわゆる「荒らし」行為を繰り返すユーザーにはお引取り願いたい、と切実に願う場面もあるでしょうから、ユーザーIDを無効にする機能(単なる削除とは違う)を実装する必要があるかもしれません。
自分だけで管理することに限界を感じたら、管理権限を持つユーザーを幾人か増やすことも必要でしょう。また、通常は画面に表示されない情報も、管理の上で必要になる可能性があります。
上記より、以下の機能が掲示板に実装される必要があると思われますので、リストアップしておきましょう。
- スレッドを掲示板レベルで移動させる
- ユーザーIDの無効化(ユーザー情報管理に統合可能)
- 管理者権限の付与&剥奪(ユーザー情報管理に統合可能)
- 非公開属性の閲覧
完璧には程遠いですが、実装する機能としてはとりあえずこの辺で中断しましょう。
設計を進めるにつれて新たに仕様に追加するべき機能が浮かび上がるのが世の常です。完全な設計の行き着く先は永遠の未完成です。
とりあえず、ここまでをユースケース図にまとめることにしましょう。
図1. ユースケース図
2. 掲示板をデザインする
ここで言う掲示板のデザインは、画面上の配色などをさすものではありません。デザインというよりは、画面の遷移を考えること、といったほうが正しいかもしれません。
画面遷移は掲示板のリスト、スレッドの一覧、議論の閲覧などに大きな影響を与えます。
それぞれの画面について、考察していきます。
メニュー画面(ログイン直後)
ログイン直後には「利用上の注意」を掲げたいところです。「管理者からのお知らせ」も重要です。「1. 掲示板を設計する」の「匿名性について」でも述べましたが、掲示板の利用規定を定めておくことは、いわゆる「荒らし」行為への対処法を明確にし、管理者の負担を減らすことになります。
メニュー画面ですから、現在の掲示板一覧は必須でしょう。ここで掲示板を選択し、スレッドを表示する、というのが、どうやらよさそうな気がします。
スレッド一覧(掲示板選択後)
スレッド一覧を表示する前提として、掲示板の選択があるでしょう。全掲示板の全スレッドが一覧表示されては、なにがしたいのか、さっぱり意味がわかりません。
掲示板の選択は、メニュー画面についての考察と矛盾しませんので、よしとしましょう。
このとき、スレッド一覧を表示していても、掲示板一覧も表示しておきたいところです。掲示板の変更の際にわざわざメニュー画面に戻るのは、結構手間がかかりそうですので・・・。
このスレッド一覧から、スレッドを選択し、スレッド内の議論を閲覧できるようにします。
議論の表示(スレッド選択後)
スレッド内部の議論を一覧表示します。議論の表示は管理機能の次にキモです。そして、掲示板の個性はこのレベルで発揮されると言って過言ではないでしょう。
掲示板の使い勝手はこのレベルの設計に大きく左右されますので、じっくりと設計しましょう。
(1)匿名掲示板として実績を誇るread.cgiタイプ
特徴:
- 投稿された順番に発言が記録され、表示される
- http://...の自動リンクや、返信先を参照するための書式などの機能が充実
- 使用法も比較的周知されている
長所:
- 議論の記録の検索が容易
- 使用法が比較的周知されており、使いやすい
- ある程度の非匿名性(ID等)と発言番号を利用した返信先参照で議論の流れを追うことができる
短所:
- 返信先参照のための番号記述ミスを防げない
- 発言するスレッド自体を間違えることがある(どのスレッドも外見が同じのため)
- 表示毎の転送データ量が多い
(2)スタンダードなCGIBBSタイプ
このタイプの掲示板は、よくある個人のWebサイトに設置されている伝統的なデザインの掲示板です。
しかし、機能を解析すると、(1)匿名掲示板として実績を誇るread.cgiから、スレッド機能を取り除いたものであることに気がつくことでしょう。
(3)階層返信タイプ
特徴:
- 投稿はほとんど「返信」の意味で行われ、返信は対象の発言を選択してから入力する
- 議論の中身を閲覧するには、各発言の題名が発言本文へのリンクになっている
長所:
- 議論の流れが把握しやすい
- 発言に返信する形式なので、使いやすい
- 基本的に非匿名的使用法を想定しており、議論の流れがそれにくい
短所:
- 議論の検索が難しい
- 発言の作成画面では返信先が表示されるため、ご返信などがほぼ発生しない
- 表示毎の転送データ量が少ない
世に掲示板はあふれていますが、機能面でまとめれば上記のものに当てはまると思われます。その他、機能的に充実(色を変える、発言者の肖像として画像を添付等)をしているものもありますが、根本的な掲示板としての機能は変わっていません。
さて、この分析から、長所のみを抜き出してスーパー掲示板を作るのが理想的ですが、世の中そんなに甘くありませんので、実現したい機能(要件)を満たすように、特徴・長所・短所を取捨選択しましょう。
- 議論の検索が容易
- 非匿名での使用を想定し、議論の流れがそれにくい
を、なにはともあれ実現したいところですので、階層返信タイプの、しかも発言内容が全て表示される方式を採用することにしましょう。表示は遅くなる可能性がありますが、ページに分割するなりなんなり、回避策はいくらでもあろうというものです。
また、階層返信タイプを選択すると、自動的に、
が採用されます。
このあたりで、掲示板を使用する上での画面遷移が固まってきたようですので、途中経過を図にまとめてみましょう。スレッド作成や掲示板作成など、決定しなければならない仕様はまだ山積みです。
図2. 画面遷移図(部分)
3. クラスを洗い出す
そろそろ機能やデザインが形になってきたので、クラスを洗い出していきましょう。繰り返しになりますが、完璧に設計して段階を進もうとは思わないことです。
当初の設計が、コードィングの過程で実現不能であることが判明したり、よりよいアイデアが天から降ってきたり、はたまた追加要求が突きつけられたりすることは世の常であることを忘れないでください。
図3. クラス図
上記クラス図を暫定的に作成しました。ログインや表示のために、ユーザークラスは必須でしょう。
また、発言(メッセージ)はユーザーと1対1の関係になっています。
ひとつの掲示板に複数のスレッドが存在しますので、掲示板クラスとスレッドクラスの関係も明らかです。
スレッドの作成はユーザーに任せる、というスタンスで設計していますので、掲示板にスレッドがひとつもない状況も想定されます。
スレッドには複数のメッセージがあります。しかも「最初の発言」がなければ議論が始まりませんから、これを必須とすると、0であることはありえないことになります。
ここであげられたクラスはすべて「エンティティー」と呼ばれる種類のクラスですので、これがDBの設計にも影響していくわけですが、重要なのは、このクラスで、ここまでに考えた機能が実現可能か?ということです。
これまでに出た機能で、実現可能かどうかを検討する必要とするのは、階層返信タイプの画面表示機能です。
階層返信タイプでは、投稿された時間順には並びません。しかも、ある発言に返信があるかどうかは、全てのメッセージを走査しなければ判断できません。返信の数も、同様です。
返信が書き込まれると「返信数」の値を増やしますか?メッセージIDの関連のみを抜き出したクラスを追加して、メッセージ一個毎に、返信全てを取得しますか?
・・・どうも、あまり効率がよくない方法のようです。
そこで、筆者が、小一時間腕組みをして、天井を睨んで、閃いたことは以下のことでした。
- メッセージには「最初の発言」と「返信」があるが「最初の発言」と「返信」は本質的に同一である
- つまり、メッセージ(最初の発言)は、0〜n個のメッセージ(返信)を内部に保持する
- つまり、返信(メッセージ)も0〜n個のメッセージ(返信)を内部に保持する
- 個々のメッセージが自分に対する返信のみに責任を持てば万事OK?
- キーワードは再帰的呼び出しだ!
図3a. クラス図
といわけで、クラス図を編集しました。
ちなみに、図3aが完成する前には、下の図3bに示すようなクラス図が(筆者の頭の中に)できました。
図3b. クラス図(図3aの前段階)
図3bに「最初の発言と返信は本質的に同一である」という条件を適用すると、図3aになるわけです。
このあたりで、メッセージ・クラスのサンプル・コードを書いてみましょう。
頭の中で考えた「再帰的呼び出し」が、実際にコーディング可能で、しかもクラス図と矛盾しないか?
乞うご期待といったところですね。
4. サンプル・コード
ここでは、メッセージ・クラスの再帰的呼び出しについて、サンプル・コードを書いてみます。
パッケージ名などもいずれ決める必要があるのですが、とりあえずsample.bbs.entity.Messageクラスにすることにしましょう。
private ArrayList response = new ArrayList(); //自分に対する返信を格納します
private String message_id = ""; //メッセージIDを格納します
private String parent_id = ""; //返信先のメッセージIDを格納します
private String content = ""; //メッセージの本文
|
と、それぞれのSet/Getメソッドが、とりあえず用意されていると考えてください。
あるメッセージ・クラスが、メッセージ・クラスを引数として受け取ります。このとき、受け取ったメッセージが自分に対する返信なのかどうかは不明です。
setResonseメソッドでその判断を行い、自分に対する返信であれば自分のresponseとして格納します。自分に対する返信でなければ、自分に対する返信に対する返信(ややこしくなってまいりました・・・)である可能性を考えて、自分に対する返信のsetResponseメソッドに処理を引き継ぐわけです。
自分に対する返信に対する返信に対する返信かどうかは考慮する必要がありません。それは、自分に対する返信のsetResponseメソッドで判断され、処理されます。これが再帰的呼び出しのいいところです。
図4-1. Messageクラス・サンプル・コード(1)
このsetResponseメソッドがクラス図の「レスポンス格納()」にあたります。
再帰的呼び出しで格納したものは、再帰的呼び出しで展開することができそうです。実際のコードではHTML(JSP)との連携も考えなければなりませんが、まずはサンプルですので、気楽にいきましょう。
次の図4-2は「レスポンス展開()」にあたります。
図4-2. Messageクラス・サンプル・コード(2)
この2つのメソッドと、テスト用コンストラクターを用いて、次のようなテスト用クラスも作ってみましょう。
テスト用コンストラクターは、引数としてメッセージIDと返信先メッセージIDとメッセージの本文の3つを要求するものとし、ローカル変数に格納します。
実行結果は以下の通りです。
さて、少々駆け足でしたが、図2のデザインは実現可能である、との見通しが立ちました。
ほっと一息(あるいは、思わずニンマリ)したところで、今回は切り上げるとしましょう。何事も根を詰めすぎると良くありません。
よろしければまた次回、お会い致しましょう。
おつかれさまでした。
参考文献
著者について  | |  | 山元 和斗志,リコーテクノシステムズ株式会社 |
記事の評価
|