2010年10月19日 星期二

口乾欲殆,來瓶舒跑吧~

Don't Repeat Yourself (DRY) 以及 Duplication is Evil (DIE) 是軟體開發上的一種原則,盡量把重複的程式碼集中,把系統中共用的設定放在設定檔中,以減少日後系統維護的負擔;有趣的是,如同警語般,如果你不遵循這樣的原則,你會累到口渴絕望,最後還可能賠上一條小命!

以前開始寫程式的時候,根本不會想到這個層面,能夠順利的把程式寫出來,除錯無誤,依照需求功能正確執行,便覺得自己好神。

想當年,自己寫的不入流的小程式竟然能夠連接到所謂的『資料庫』,那種喜悅與榮幸至今仍然記憶鮮明。
後來發現有個Perl DBI模組能夠以一致共通的方式連到大大小小不同的資料,那種震撼更是難忘。

(來源: Programming the Perl DBI  http://oreilly.com/catalog/9781565926998)

幾乎每支程式都是類似下面這樣的寫法(repeat yourself?)

(程式碼來源 http://oreilly.com/catalog/perldbi/chapter/ch04.html)
#!/usr/bin/perl -w
#
# ch04/error/ex1: Small example using manual error checking.
  
use DBI;            # Load the DBI module
  
### Perform the connection using the Oracle driver
my $dbh = DBI->connect( undef, "stones", "stones" ) 
    or die "Can't connect to the database: $DBI::errstr\n";
  
### Prepare a SQL statement for execution
my $sth = $dbh->prepare( "SELECT * FROM megaliths" )
    or die "Can't prepare SQL statement: $DBI::errstr\n";
  
### Execute the statement in the database
$sth->execute
    or die "Can't execute SQL statement: $DBI::errstr\n";
  
### Retrieve the returned rows of data
my @row;
while ( @row = $sth->fetchrow_array(  ) ) {
    print "Row: @row\n";
}
  
### Disconnect from the database
$dbh->disconnect
    or warn "Error disconnecting: $DBI::errstr\n";
  

歸納各個步驟就是連結資料庫、準備SQL敘述、(代入參數)執行SQL、迴圈處理傳回資料、中斷資料庫連結。
問題是,如果需要處理十來個tables,這樣的程式碼肯定是不太好看以及不容易維護了!
尤其是,複雜一點的SQL Statement夾雜在程式碼裡面,肯定多少因而造成視覺的障礙,SQL敘述也必然會在程式碼之間重複出現!(寫程式真累人啊,有點口乾舌燥了~)

SQL::Library  模組,提供將SQL語法集中管理維護的功能,透過它,可以把所有用到的SQL放在一個(或多個)檔案中,然後在程式中以容易記憶的關鍵字來取用。使用方法如下:
## A sample library file 
[get_survey_questions] 
select question_no, question_text 
from question 
where survey_id = ? 
order by question_no 

[get_survey_info] 
select title, date_format( open_date, '%Y%m%d' ) as open_date, 
    date_format( close_date, '%Y%m%d' ) as close_date, 
    template_file 
from survey 
where survey_id = ?

使用方法

use SQL::Library; 
my $sql = new SQL::Library { lib => 'sql.lib' };
my $query = $sql->retr( 'get_survey_questions' ); 

然後再用針對$query開始prepare、execute、fetch....

這個方法把SQL敘述自程式碼中移出,減少了SQL重複的問題。

但是程式人員仍然需要了解SQL語法,以SQL的層次來思考與處理資料,這是沒有必要的細節重複,因為我們要處理的是商業資料邏輯,而不是資料庫資料邏輯,我們不想每次都要去複習資料表格之間的關聯性,那應該是別人的事。

DBIx::Class  模組是2005年父親節的時候出現的,它是ORM(Object-Relational Mapping),也就是物件-關聯對應,簡單的概念是將物件對應到關聯式資料庫,Class對應到表格,而Object對應到表格資料列,而Object的屬性便是資料列裡面的欄位。

也就是說,只要一開始正確的建立對應關係之後,就不用再透過SQL語法來處理資料庫,直接使用物件就可以了。

舉個簡單的例子來看
# 透過MyDB::Schema來建立ORM連結關係
use MyDB::Schema;

# 連接資料庫
my $schema = MyDB::Schema->connect($dbi_dsn);

# 取回Artist表格內所有資料
my @all_artists = $schema->resultset('Artist')->all;

# 取回Artist表格內,name欄位是John開頭的所有資料
my $johns_rs = $schema->resultset('Artist')->search( 
                          { name => { like => 'John%' } }
                      );
有關資料庫資料表格(如Artist)的資訊(如資料表格欄位、與其他表格之間的關聯性.... )通通集中放在MyDB::Schema裡面,任何程式需要使用的時候只要use MyDB::Schema、連接資料庫,再透過$schema來存取資料庫就可以了。

是不是簡單多了?

沒有留言:

張貼留言