2015/03/09

ADO 是個好東西,不用嗎?

ADO--ActiveX Data Object

在RAD Studio裡被歸類在「ADO Express」元件盤中,RAD Studio 2006後則改名為「dbGo」。

ADO架構
圖片來源:MSDN Microsoft Data Development Technologies: Past, Present, and Future


ADO的缺點在於,全世界的作業系統中,只有Windows才有具備Ole Provider。

換言之,ADO只能運行在Windows的世界。

然而在深入了解ADO後,發現ADO的核心概念和DataSnap幾乎一樣,透過Windows平台內建的OleDB engine,要單層開發、兩層開發,有狀態還是無狀態形式的公事包開發都不是問題,一切只需要一個ADO元件就可以完成。

ADO是個好東西,不用嗎?

單機,對於Access、Excel都有非常多的範例和很極佳的效能。
兩層,對於SQL Server的連線效能極佳,又額外提供其它資料庫的Ole Provider可以擴充。

無狀態的儲存,我們可以採用「公事包」的方式,把ADODataSet的Data另存為實體檔案,待網路順暢時再行傳輸。

「公事包」這名詞,微軟是這麼說的:

使用公事包同步 -- Windows 7 說明
您可以使用 [公事包] 來讓兩部不同電腦之間的檔案保持同步,即使電腦不在相同的網路上。 如果電腦不在相同的網路上,您可以使用卸除式媒體從一部電腦將檔案複製到另一部電腦,再使用另一部電腦處理那些檔案,然後使用 [公事包] 對原始電腦進行變更同步。

ADO 裡的 LockType 中,ltBatchOptimistic 參數便是對應公事包特性。
更淺碟一點的說法,就是「離線編輯」。

實際的範例用法如下:
dfm:

object ADOConnection1: TADOConnection
  Connected = True
  ConnectionString =
    'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=root;' +
    'Initial Catalog=AdventureWorks;Data Source=127.0.0.1;password=ILoveEden!'
  KeepConnection = False
  LoginPrompt = False
  Mode = cmReadWrite
  Provider = 'SQLOLEDB.1'
  Left = 60
  Top = 34
end
object DBNavigator1: TDBNavigator
  Left = 42
  Top = 25
  Width = 240
  Height = 25
  DataSource = DataSource1
  TabOrder = 0
end
object ADODataSet1: TADODataSet
  Active = True
  Connection = ADOConnection1
  CursorType = ctStatic
  LockType = ltBatchOptimistic
  CommandText = 'select * from Emp'
  Parameters = <>
  Left = 60
  Top = 86
end
object DataSource1: TDataSource
  DataSet = ADODataSet1
  Left = 58
  Top = 136
end
object DBGrid1: TDBGrid
  Left = 12
  Top = 62
  Width = 379
  Height = 171
  DataSource = DataSource1
  TabOrder = 1
  TitleFont.Charset = DEFAULT_CHARSET
  TitleFont.Color = clWindowText
  TitleFont.Height = -11
  TitleFont.Name = 'Tahoma'
  TitleFont.Style = []
end
object TrackBar1: TTrackBar
  Left = 464
  Top = 13
  Width = 79
  Height = 32
  Max = 1
  Position = 1
  TabOrder = 2
  OnChange = TrackBar1Change
end
object Label1: TLabel
  Left = 406
  Top = 23
  Width = 52
  Height = 13
  Caption = 'Connected'
end
object CheckBox1: TCheckBox
  Left = 406
  Top = 56
  Width = 97
  Height = 17
  Caption = 'Offline Mode'
  TabOrder = 3
  OnClick = CheckBox1Click
end
object Button1: TButton
  Left = 410
  Top = 86
  Width = 75
  Height = 25
  Caption = 'ApplyUpdate'
  TabOrder = 4
  OnClick = Button1Click
end
object Button2: TButton
  Left = 410
  Top = 122
  Width = 101
  Height = 25
  Caption = 'Save Package'
  TabOrder = 5
  OnClick = Button2Click
end
object Button3: TButton
  Left = 410
  Top = 153
  Width = 101
  Height = 25
  Caption = 'Load Package'
  TabOrder = 6
  OnClick = Button3Click
end

Pas:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, Grids, DBGrids, DB, ADODB, ExtCtrls, DBCtrls;

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    DBNavigator1: TDBNavigator;
    ADODataSet1: TADODataSet;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    TrackBar1: TTrackBar;
    Label1: TLabel;
    CheckBox1: TCheckBox;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure TrackBar1Change(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ADODataSet1.Connection := ADOConnection1;
  ADODataSet1.UpdateBatch;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ADODataSet1.SaveToFile('OfflinePackage.data');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ADODataSet1.Close();
  ADODataSet1.LoadFromFile('OfflinePackage.data');
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  ADODataSet1.Connection := nil;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  ADOConnection1.Connected := (TrackBar1.Position = 1);
  ADODataSet1.Active       := ADOConnection1.Connected;
end;

end.

成果圖:

ADO 公事包範例

故可從以上得知,ADO 真的是很棒的架構。

公司採用 SQL Server,以及沒有跨平台需求的專案,ADO 真的可以完全符合需求。

安全性則可以透過 VPN 和 NAT 來解決。



DataSnap 好像又不是這麼必要了。是嗎?

對 dbExpress 的誤會

dbExpress是個「單向」和「唯讀」的資料集,嚴格來說,它只是個「游標」,連資料集都不算,有什麼好期待的?

按過往的批評dbExpress的文章來看,大部份比較的對象都是BDE和ADO。

然而,dbExpress本身就不負責BDE和ADO內三分之二的工作,要說它爛是不是有點搞錯對象。

dbExpress提供的是「架構」層面的思考,和BDE、ADO本身要求速效的概念,是先天上的不同。

深入推廣的DataSnap才是dbExpress的戰略目標。


只是戰技(Driver)和戰術(3rd Party)搭配的實在是不高明,領教過的開發者應該很明白這件事。

戰技缺點多,Driver的相容性和臭蟲不少,官方修正力道很微弱。
戰術閉塞不開,3rd Party在dbExpress官方的臭蟲影響下,也很難有伸展的空間。

甚至Devart的Document是這麼寫的:
We tried to include maximal support of server-specific features in both dbExpress drivers and DACs. However, the nature of dbExpress technology has some restrictions that cannot be overcome.

話雖如此,dbExpress概念是良好的,因為中間層的確是不需要太多狀態的資訊存在,而dbExpress也確實做到這一點,所以dbExpress的簡易和輕量化在這訴求下是必需的。

dbExpress最初立意是良好的,只是Borland手上的好牌被玩爛了,這實在是非戰之罪。

現在在行動裝置上,DataSnap也漸漸復活了,當初採用dbExpress的開發者應該開始嚐到一點開發甜頭了吧!

2015/03/08

現在是開發兩層還是三層?

dbExpress的開發畫面大概是這個樣子:
 

DataSnap的開發畫面大概是這個樣子:
Server端設計畫面
Client端設計畫面

好像有點一樣,又好像有點不一樣。
如果dbExpress改一下,就變成下面的畫面:
增加建立一個DataModule放dbExpress元件

ClientDataSet還在原來的位置,只是ProviderName會是DataModule.DataSetProvider1
相較之下,dbExpress好像只差了一個TDCOMConnection元件外,和DataSnap長相簡直一模一樣。

也難怪dbExpress要被人說閒話了,這複雜難用的神馬東西。

說易用沒有BDE來得自動化:TQuery + TUpdateSQL,BDE小小調整一下,收工。
說功能沒有ADO來得全面:光是ADOConnection的Properties內容就可以談上十餘頁A4紙;ADOQuery幾乎把BDE元件所有功能包完。

反觀dbExpress,Driver Params就只有幾項,光產出的元件就比BDE多,程式的所有細節居然還全都要人工硬嗑,就算不寫程式碼,需要看的資料也絕對不下於ADO。

那dbExpress的架構到底是什麼?Borland開發這個是拿磚頭砸自己的腳嗎?(是的,它是)


用到現在,我終於參悟了dbExpress到底是什麼,算得上是三層嗎?



如果只能用一句話來描述dbExpress的層數,那我想我會說:





「兩層以上,三層未滿」(友達以上,戀人未滿)


2015/03/05

該放棄Web還是C++ Builder?

回補一下關於Delphi/C++ Builder在Web上的開發方案,我整理了以下的簡圖:
WebBroker, Internet Express, WebSnap and IntraWeb concept


不論是WebBroker、Internet Express還是WebSnap,最大的問題在於「HTML、CSS、JavaScript」等Browser Client的糾結。對於已經習慣VCL元件的開發者,勢必又是另一個頭痛的戰場。

直接看一下沒有HTML和CSS概念下,所產出畫面:
Internet Express能提供標準HTML標籤
再來看現在新版JQuery UI基本款可以做到什麼樣的畫面:
JQuery UI提供的GridView
圖片來源:Jquerygridview.com
雖說美感是見人見智,但大多數人應不滿意標準HTML的表現,不然也不會有JQuery UI的產生。

只是忙於商業邏輯就無力分身的開發員,還要學習Browser Client技術,VCL的優勢明顯派不上用場。

此時VCL for Web,也就是現在的IntraWeb,解決的就是這個問題。

原有Win Form的開發概念可以照搬上Web Form來進行開發。

IW有個最大的優點,也是最大的缺點--RunTime時期針對不同呼叫的Browser,產出配合Browser的HTML。

也就是說,原Win Form的開發者不再需要考慮Browser版面的處理,完全交由IW做自動最佳化的處理。

這是優點,反過來說也是缺點,對於Browser版本的限制,導致必須隨著Browser升級,或變更時,也要跟著升級IW。

另一方面,IW是版權軟體,當時的相容性又堪慮。在這種花錢還受罪的場合下,綜合得出C++ Builder沒有更為合適的Web開發的解決方案。

砍掉C++ Builder重練是否為最好的選擇?

再談Web化
會採用Web化的原因是,現在所有的作業系統中,一定會有瀏覽器,所以就沒有軟體安裝的問題,Web的安全性也相對得要比Win Form要來得好一點。
2014蔚為流行的瀏覽器綁架事件之一
圖片來源:Google 圖片

但事實上,如果Web安全性這麼高,就不需要防毒軟體存在。

從瀏覽器被綁架的事件滋生不斷中就可以得出,Web安全性也有它的漏洞存在。

被封裝好的執行檔(EXE)就一定不安全嗎?

在人手一機,還必備防毒軟體的現況下,執行檔有個什麼閃失就容易被防毒軟體抓去「收容」,執行檔就必不安全?

執行檔還有另一問題,就是部署了。

Inno Setup、InstallAware和InstallShield等都是解決部署問題的方法。

那麼執行檔變Portable(免安裝)化不可以嗎?

要讓使用者享受物聯網服務,就只有Web可以選擇?

說穿了,最終就只是載具問題罷了。

那穿透網際網路,執行檔直接穿透網際網路連接資料庫,光是安全性話題就足夠戰好幾回合,在這邊就不表了。

而C++ Builder有什麼可以跨網際網路的資料連結方案?

現成的概念就是MIDAS--分散式應用系統。




於是我就擁抱Delphi了。

2015/03/03

客戶的要求,Web化

其實這篇的內容比較和DataSnap沒有直接的關聯。

話說,客戶要求Web化的理由很簡單,就是希望能在出差的時候也能掌握設備的動態。

這不就是互聯網的概念嗎!想法很先進,可惜太早了,Delphi引進物聯網概念也是2014年時的事情。

當時有考慮過IntraWeb,只是當時它的支援度很另人緊張——因為並不支援當時全球第一大瀏覽器:Internet Explorer 6。
Atozed Software - IntraWeb
圖片來源:Atozed

幾經試作後,IntraWeb的開發方式比較接近ASP.NET 1.0的網站絕對定位設計方法,甚至IntraWeb還可以做到不需要了解HTTP、CSS和JavaScript就能完成網站的架設。

你棒棒你,想不到這產品這麼威能。

可惜, 最後還是敗在不能提供IE6的網頁的缺陷下而被否決。

最後在當時個人實力有限的慘況下(另一說是IntraWeb花了太多時間練習),只好請功力深厚的同事操刀,最終拍案,採取PHP來進行網站後端程式開發。

而使用PHP開發,想當然爾,資料庫九成九一定會選擇MySQL,果真沒錯,就是MySQL。

兩種異質資料庫並行的情況下,資料同步又是另一個問題,而且又是要讓PHP讀取即時資料,採C++ Builder進行資料同步勢必還是有延遲時間。(事後回過頭來想,好像也沒有延遲多久,多慮了)

但才剛改成FireBird資料庫的我,還沒來得讓我思考PHP能不能連結FireBird,主管早搶一步表示案子進度已經燒屁股了,怎麼有膽量再去挑戰PHP和FireBird的相容性。



再把FireBird換回MySQL吧!


dbExpress經驗值 + 2。

RAD Studio 2015 Roadmap

以下內容雖是正式內容,但EMBT不做任何保證。

平台和編譯器方面:
增加iOS 64位元編譯程式。
Windows 32位元的C++編譯器:
基於LLVM工具集,以近似於C++ 64位元版本編譯器特色(含C++11)。
(LLVM based toolchain similar to the 64-bit Windows compiler language features, including C++11)


寫程式的開發環境(IDE):
提高對大量記憶體的系統下,開發環境的穩定性。
整合Library管理功能。
主要增強FireUI對多平台裝置的設計,也包含其預覽功能。

Windows 10
具體支援Windows10:
VCL和FireMonkey。
新增許多元件和Library。
封裝更多的API。
整合新的Windows 10平台技術。

VCL和Run-Time Library:
改善VCL表現風格,支援4K螢幕、大型文字和其它增強。
提供VCL(含FireMonkey)應用程式分析。
提供原生HTTP(S)用戶端程式庫給全部平台。

FireMonkey
擴充FireMonkey控制項,包括:
新的行動裝置元件,如Maps。
被遺忘的元件,如WebBrowser。
更多iOS平台控制項和更佳的視圖層(z-order)管理器(iOS限定)。

物聯網
更貼近行動裝置的整合,預計支援Beacon技術。
基於元件形式的模組化以連接不同的裝置,和控制異質API的小工具。
遠程端點(裝置)的資料收集和分析。

企業和多層架構
FireDAC:新的企業級資料庫驅動程式以強化效能。
InterBase XE7變更視圖(Views)項目。
更緊密的整合EMS(Enterprise Mobility Services)。
NoSQL資料庫支援。
EMS:推播訊息和數個擴充。
DataSnap 在核心Web技術上的清理和改善。

其它平台下的了解和調查
觀注2015年iOS和Android的走向。
研究Web Service 應用程式(如WebBroker, DataSnap和EMS)對Linux伺服器站支援。
選擇性支援Android Intel平台。
Mac OS X 的64位元工具集。

預計第一季釋出新的版本和其它廢話。

大致上沒有太亮眼的功能。
以上

資料來源:Delphi & C++Builder 移動開發FB社群