2008年11月アーカイブ

 アンケートシステムの番外編です。番外編を書く暇があったら、アンケーシステムを完成させろよと言われそうですが、気にせず書いていきます。

 以前の記事でアンケートシステムを簡略化すると書きましたが、どれくらい簡略化するかと言うと、一つしかアンケートを出来ないようにします。アンケートごとに関する表示を作成するのが面倒くさいので。メニューにするとこんな感じです。

1.アンケートの作成
2.アンケートの投稿
3.項目の一覧を表示
4.アンケートを削除

「1.アンケートの作成」で作成又は修正する感じです。作り的には、後々複数投稿するシステムに変更するのに、それほど難しくない作りだと思います。Rubyでプロトタイプをぼちぼちと作成しているのですが、作成して思った事を今回の記事では書きます。

 

 Javaで作成する事に慣れているので、やはりオブジェクト指向で考えてしまいます。Rubyもオブジェクト指向ですが、Javaとは違う箇所やJavaの作りでは出来ない処理も出来てしまいます(Rubyではそのような作りになっているので当然ですが)。

Javaでは、すべての作りがクラスで作成するようになっています。ちょっと待てよ、インタフェースは?と思う方もいるかと思いますが、インタフェースでは処理は作成できません。C言語でも、C言語はすべて関数で作成されているといった場合に、ヘッダファイルやマクロがあると反論しないと思います。実際マクロや構造体を処理するのは関数の中ですから、C言語はすべて関数で作成されているのだと言えます。マクロの定義は、オブジェクトファイルですべて置き換わっていますし、構造体はメモリ上に領域が確保されるだけです。

今、考えているのは、画面の情報を画面フォームオブジェクトに格納し、実際処理を行って、DBに格納するポーターオブジェクトに代入します。ポーターオブジェクトを使いDBで処理を行います。DBからデータを取ってくる場合は、この考え方の逆で行います。列挙すると以下の感じです。

1.画面から情報を受け取り、画面フォームオブジェクトに格納する。
2.画面フォームオブジェクトのデータを使い、処理を行う。
3.画面フォームオブジェクトをポーターオブジェクトに代入する。
4.ポーターオブジェクトのデータを使い、DAOでDBの処理をする。

上記の考えは、MVCの考え方や三層構造の考え方です。

画面フォームクラスは、画面の情報を基に作成されます。画面とプログラム(VIEW)のデータの橋渡しです。変数名や日本語名は画面名から導き出します。画面が変更されれば、画面フォームクラスも変更されます。又、DBのテーブルや項目の変更に影響されません。

ポータークラスは、DBの情報を基に作成されます。DBとプログラム(DAO)のデータの橋渡しです。変数名や日本語名はDBのテーブルや項目から導き出します。DBのテーブルや項目が変更されれば、ポータークラスも変更されます。又、画面の変更に影響されません。

作りとしては、オブジェクト指向の考え方に合致していますね。

 考え方として問題となっているのは、処理の部分です。オブジェクトで共通する処理がある場合を考えていきたいと思います。Javaでは、共通した処理を使いたい場合に、しばしば親クラスを作成し、継承させてクラスを作成します。それが、「is a」の関係になっていれば、良いのですが、必ずしもそうとは言えません。本来共通した処理がある場合は、処理だけを独立されてクラス等に使わせる必要があります。Javaなら処理するクラスを作成して、そのクラスを各クラスで使用しても良いと考えているのですが、親クラスで定義させることが多いですね。一般的に言われているユーティリティークラスはそのようになっているのですが...

 Rubyでは、Mix-inが利用できます。Mix-inとは、モジュールをクラス等に取り込むことで、クラスならクラスで定義したメソッド等と同じように操作できる事です。このため、クラス間で共通の処理がある場合は、モジュールで作成し、各クラスが共通のモジュールを取り組めば良いことになります。その事により(Javaとは違い)、無理やり継承(is aの関係)させる必要はなく、共通処理を行わせることができます。この考えは、オブジェクト指向の「has a又はpart of」の関係も実現する事が出来ます。Javaでは、「has a又はpart of」の関係を実現させるには、内部クラスで実現できますが、他のクラスで使用する場合は結局、継承させる必要があります。

 又、Javaのインタフェースを適切に利用しているシステムも少ないと思います。インタフェースの役目として、C言語のヘッダファイル(プロトタイプ宣言や定数の作成)、ポリモルフィズムの実現にも利用されなければなりません。


 好き勝手に書いてきましたが、理想と現実は違うという事ですね。と言っても、私に理想的な設計できる能力があるかと言われると、勉強中としか答えられませんが。Rubyのアンケートシステムは早ければ今月中に完成させる予定でいます。

日々反省する毎日

|

 今日は、電話対応でミスを連発してしまい、各リーダーや先輩から注意されました。注意された内容が意思表示です。意思の欠缺や瑕疵ある意思表示をしてしまい迷惑をかけてしまいました。なぜ、そんなミスを紹介したかと言うと、今日、たまたま宅建の勉強した箇所が意思表示だったからです。なので、強引に合わせましたが、日々反省する毎日です。


 そう言えば、C言語の勉強でもやっと「#ifndef」の意味が解りました。学生時代は、先生のソースをコピーしてこうすれば、とりあえず多重インクルードが防止できるというだけでした。その時には「#ifndef」の中の「n」にも気づいていませんでした。後、ためになったと言えば、#defineの多重定義は同じ定義ではコンパイルエラーにならなく、異なる定義ならワーニングで、typedefの多重定義はコンパイルエラーになると言うことぐらいです。後、ヘッダファイルでの#include処理。Javaに慣れているとそれすら面倒くさく感じます。Javaの入門書の中には、import処理はC言語で言う#includeみたいなものと教えていますが、「みたいなもの」や法令の「等」のように大分差がありますよね。そもそもJavaでは、一切importを記述しなくてもコーディングできてしまいますしね。そんなソース見たことがありませんが。C++なら#includeとusing namespaceの両方を使うので、勉強してて意識するのですが。どれも少しでもかじったことがある人は意味が解ると思います。

 プログラミングに関する記事として、最近ではRubyを取り上げているのですが、Rubyはアンケートシステムが終わり次第、中止しようと考えています。理由としては、仕事の次の案件で.NETを使用する為と訳あってLinux Cを勉強しようと持っているからです。

.NETは、以前勉強してあるC#を使用するので、文法ぐらいは調べなくても書けるよう復習に当てます。Cは、Win32 APIでしたら、そこそこ出来るのですが、Linux Cに関する事はさっぱりです。そもそもLinuxやUNIXに関する知識が乏しいからでもあります。勉強しようとしたら、Makefileが理解できずにストップしました。このままではまずいと思い、勉強しようと思ったのです。学校でスレッドやネットワークの初歩は習いましたので、一つ一つの処理が解らないという事はないのですが、Linux、UNIXに関連する知識や全体的な流れを把握するのが苦手としているところです。学校で習ったぐらいの知識や卒研などでは常にJavaを使用していた事もあり、中規模以上のプログラムをCで作成した事がありません。勉強を中心的に行うのは以上の項目です。Emacsもやっと起動方法と終了方法が分かったぐらいです。後、英語がさっぱりで苦手です。

Rubyでのアンケートシステムでは、DBの操作も出来た所なのですが、以前紹介したアンケートシステムより簡略したシステムで作成しようと考えています。

 前回のRubyの記事(Rubyで作成するアンケートシステム MySQL編)では、RubyからDBの操作を紹介しました。今回は、アンケートシステムで使用するDBの設計書を紹介します。今回はRubyと関係がありませんが何かの題材にでも。


 勉強用なので、設計書と言ってもERDとSQL文です。テーブル設計は無く、あるのはMySQLとPostgresSQLで試したSQL文ぐらいです。SQL文は、主にMySQLに対応していますが、テーブル作成部分は、PostgresSQLでも動作を確認しています。

ファイルにまとめました。説明もファイル中にあります。
QNS_RD.xls
テーブル作成.sql

 前回の記事(Rubyで作成するアンケートシステム Postgres編)では、PostgresのCRUD操作を投稿しましたが、日本語に対応できていませんでした。そこで、RubyやRailsで標準であるMySQLを使用することにしました。今回は、MySQLでのCRUD操作を紹介します。もちろん日本語対応です。

 Windowsでは、MySQL側を特に指定しなく、Ruby側でもオプションなどを指定しないくても日本語が表示されました。次回のRubyの記事では、アンケートシステムのDBの情報を投稿するつもりです。

 前回のRubyに関する記事(Rubyで作成するアンケートシステム ファイルの読み込み編)では、ファイルの読み込みを紹介しましたが、今回は、DB関連です。DBにも当然いろいろありますので、その中のPostgresの操作を紹介します。

 Postgresの操作を紹介するのは、CRUD操作です。ただ、私が使用しているバージョンでは日本語が扱えません。原因は分かっているのですが、とりあえず問題を置いて紹介しておきます。

 

require "postgres"

# 表示メソッド
def view(conn)
    res = conn.exec("SELECT * FROM USER_INFO;")
    res.each{|items|
        print items[0]
        (items.size-1).times{|i|
            print ",", items[i+1]
        }
    }
    print "\n"
end


conn = PGconn.connect("localhost",5432,"","","enquete","enquete","enquete")
# 本来は、ここでクライアントのエンコードを設定する
# conne.set_client_encoding("utf-8")

begin
    # データの挿入
    conn.exec("INSERT INTO USER_INFO(USER_ID,USER_NAME,PASSWORD)VALUES('user1','user1','pass');")

    view(conn)

    # データの更新
    conn.exec("UPDATE USER_INFO SET USER_NAME = 'user-1' WHERE USER_ID = 'user1';")

    view(conn)

    # データの削除
    conn.exec("DELETE FROM USER_INFO WHERE USER_ID = 'user1';")

    view(conn)
rescue => ex
    conn.exec("ROLLBACK;")
    print ex.message, "\n"
ensure
    conn.close()
end

 例外処理を設けて、ロールバックしていますが、例えば、挿入後に例外が発生して、ロールバックしても挿入はコミットしてしまいます。たぶんプログラム上で、自動コミットしないようにしないといけないのですが、その情報もまだ知りません。やはり、postgresでは、情報が少ないので、そろそろ区切りをつけてmysqlで素直に作成しようと考えています。

 クライアントのエンコード設定は、postgresドライバのバージョンによって設定が違っているようです。今回使用したのは、0.4.0で、Webの情報によると0.7.1では「set_client_encoding」メソッドが使用できるようです。ただ、gemでアップデートしようとしましたが、失敗しました。どうやら他も同時にアップデートして、バージョンをそろえないといけないみたいです。情報は現在こんなところです。
 タイプトレーナー Trr を試すスコア編から再度挑戦したので追加します。まだ、目標まで届かずですが。

trr_2.png
trr_3.png
trr_4.png
 ミスを点数に入れなくても300点まで届かず。知らない単語と知っている単語では結構差が出ますね。知らないと一文字一文字確認する必要が出てくるので、知っている単語を増やせば何とか300点越えは出来そうです。

 Rubyで作成するアンケートシステム 仕様編の記事でアンケートシステムにはファイルを入出力するが必要という事で今回はファイルの読み込みを投稿します。

# ファイルの読み込み(IOクラスの制御なし)
open("db/UserInfo.txt").each{|line|
    line.chomp!     # 行の末尾の改行文字を削除
    dates = line.split(",")
   
    dates.each{|date|
        puts date
    }
}

# ファイルの読み込み(IOクラスで制御あり)
open("db/UserInfo.txt"){|io|
    io.each{ |line|
        line.chomp!     # 行の末尾の改行文字を削除
        dates = line.split(",")
       
        dates.each{|date|
            puts date
        }
    }
}
 

2つの処理を作成しました。

  「ファイルの読み込み(IOクラスの制御なし)」では、open()メソッドを呼び出し、eachメソッドでテキストの1行をline変数に代入しています。ちなみに「#」以降は、コメントになります。C及びJavaの「//」と考えて下さい。「line.split(",")」で配列を取得し、eachメソッドでデータを1つ1つ表示させています。

 「ファイルの読み込み(IOクラスの制御あり)では、IOクラスにデータを代入して、それから処理をしてます。IOクラスを使用することによって、読み込みだけではなく、書き込みやファイルポインタを使った制御が行えます。

 他の言語でファイル処理をした事がある方は、何か足りない事に気が付くと思います。openメソッドを呼び出しているのに、closeメソッドらしきものが呼び出されていない。Rubyでもcloseメソッドは存在し、closeメソッドを呼び出す必要があります。ただ、今回の場合は、ファイルをopenメソッドで呼び出し、{}のブロックの中で処理を行わせています。よって、ブロックを閉じると自動的にclosメソッドが処理されるため、ブロックに渡した場合は、closeメソッドを呼び出す必要はありません。Rubyでは、このように、ブロックにデータを渡して処理させることが多々あり、ファイル処理ではcloseメソッドの書き忘れが無いメリットがあります。

 ファイルで作成すると前回の記事(Rubyで作成するアンケートシステム 仕様編)で書きましたが、やはりDBで処理する方が楽という事で、RubyでDBのアクセスができるように情報を集めました。次回のRubyの記事では、DBの操作に触れたいと思います。

 私が所属するWEB-DBチーム内では、新たな言語やフレームワークなどを取得する為に、お題としてアンケートシステムの作成を各自で進めています。私は始めにRuby on Railsで作成しようとしましたが、まずは、Rubyの基礎をつけるという事で、Rubyでアンケートシステムを作ることにしました。どう考えてもRubyで作る方が時間がかかると思いますが、Rubyの勉強にもなるという事で...。


 アンケーシステムの全体の動きとしては、最初に認証画面が表示され、認証後はメニューが表示されると考えています。
メニューには、


1.アンケートの作成
2.アンケートを選ぶ
3.アンケート一覧

のようにアンケートを選ぶメニュー、後は項目の作成、修正及び削除などのように階層的に展開する。

アンケートとして認証するユーザや投票結果などを格納する物としてはどうするかですが、DBに接続しないで、基本らしくテキストで処理しようと考えています。あまり複雑な事はしたくないので、テキストは次のように分け、中身は次のようにします。

1.ユーザ情報
 ユーザID,ユーザ名,パスワード
2.アンケート
 アンケートID,アンケート名,期限
3.アンケート項目(各アンケート)
 項目名,投票数
4.ユーザ投票記録
 アンケートID,ユーザID[,ユーザID]

 先ほど、説明していませんでしたが、アンケートシステムは匿名投票を考えています。投票は、1つのアンケートに対して1回だけと制限する為に、ユーザ投票記録に記録します。既にアンケートIDに一致するユーザIDがあった場合は投票できない事にします。DB無しで制御すると面倒ですが、そこはあまり考えない事にします。ユーザIDは投票したらどんどん後ろに追加する形で制御します。

 次に、Rubyでテキスト処理の勉強が出来ていないので、まずは、テキスト処理から取り掛かることにします。次回のRubyの投稿でテキストの読み書きを投稿する予定でいます。