Tuesday, June 23, 2009

Xả xì trét


Share/Bookmark
Xuất phát :
6h lên đường


Dọc đường đi







Đến Quảng Ninh, vào đớp rồi mới ra tàu =p~

1h30 ra tàu ^0^

Tranh thủ ra mũi tàu buôn cá tí :-"

Pose cái cho nó có dấu đi chơi =)).
Cũng phải nghĩ ra ối trò mà vọc chờ tàu ra đến đảo. Mất 4h30ph chứ ít đâu :|
Đi về đi cano có chưa đến 1h cho nó tàu nhanh ạ :(


3 tác phẩm tự sướng được :






Hóng mát trước khi làm giấc chờ xe về ks :p


Nước biển ở đây trong ác

Rất sạch nữa

Hoàng hôn quá tuyệt mỗi tội tấm này chôm của bạn, chớ hôm í mình ngủ đẫy đến 8h :">




Sáng dậy quần bóng, cát bãi 1 rất sắc, chú ý :|.
Đảo này có 3 bãi thì 3 loại cát khác nhau :-j

Đường chui qua rừng thông ra bãi tắm 1

Phó nháy bị chụp :-"



Ra ca no về nhà

Trên đường về tranh thủ vợt mấy cái pic cho đủ





Trên xe về kết thúc 3 ngày đày nắng, gió và etc... goobye.


Năm sau mà có dịp mình lại ra đây tiếp, hoang sơ và sạch sẽ :x

Saturday, June 13, 2009

Xe :-"


Share/Bookmark
Iem này đã dc kéo với tốc độ 50Km/Tuần =))

Hôm bữa thằng Ốc vác ra đi qua trường Gia Thiều, có chú CA lon ton đi ra, chợt chú liếc mắt thấy con xe, chán quay về chỗ cũ =]]

Phantom of the opera


Share/Bookmark
The phantom of the opera

Is there

Inside my mind...




Friday, June 12, 2009

Những áng văn bất hủ kì thi 2009


Share/Bookmark

Việc chấm bài thi tốt nghiệp THPT môn Ngữ văn của giám khảo chúng tôi, đến hôm nay (11/6) đã được già nửa chặng đường...."về đích". Đồng nghiệp của chúng tôi chia sẻ: "Đi chấm văn bây giờ có nhiều cảm xúc từ bài làm của thí sinh lắm...!"

Càng cảm xúc, hồi hộp hơn, vì đây là những bài văn của lứa học sinh đầu tiên, kiểm nghiệm thành quả của chương trình phân ban. Ai cũng muốn xem chất lượng làm bài của học sinh phân ban đầu tiên này có gì khác biệt, nổi trội hơn so với các thế hệ học trò cải cách đã qua không?!

Mỗi giám khảo, thanh tra chấm thi chúng tôi đã thẩm định, đánh giá không dưới trăm bài thi, thực tế, không có gì khác mấy so với các năm trước, thuộc hệ cải cách. Bên cạnh một số ít bài văn tốt, diễn đạt hay, viết văn có cảm xúc, sáng tạo, chúng tôi còn bắt gặp vô vàn các bài văn hạn chế, yếu kém.

Biểu hiện cụ thể của nó thì cũng hết sức đa dạng, phong phú: Chữ viết cẩu thả, trình bày tệ hại, sai chính tả, câu què, câu cụt, diễn đạt, ý tứ sai lạc, vụng về, tối nghĩa, rối rắm...

Do dung lượng trang báo có hạn, ở bài viết này, chúng tôi chỉ dẫn ra những ví dụ được xem là tương đối "đặc biệt" trong các bài làm văn của thí sinh:

1 - Sai lạc đến chết người

- Lỗ Tấn, sinh năm 1985, mất năm 1963, quê quán ở tỉnh Bắc Ninh, gốc Ba Tàu, từng có 3 đời vợ, 5 người con.

- Hạ Dụ là con của bà cụ Tứ, con ruột của Tràng, từng bị trận đói năm 1945 hành hạ, đe dọa cho tơi tả, xơ xác mướp. (Sau đó, câu chuyển sang Hạ Du - một người cách mạng trong quân ái quốc. Dùng bánh bao để trị bệnh điên cho Hạ Du).

- Tô Hoài sinh năm 1920, quê Nghệ An, năm 1960 ông có 200 bài thơ và đạt kỹ luật (kỉ lục) nhà thơ Việt Nam.

- Tô Hoài là người chiến sĩ cách mạng đã từng sống và chiến đấu trên vùng đất...Tây Nguyên.

2 - Các câu văn ngây ngô... không nhịn được cười:

- Các bạn không được đọc những cuốn sách đồ trị (đồi trụy) mà nhà sách cấm nhé!

- Người xưa từng nói: "ăn gì bổ nấy". Việc đọc sách cũng vậy.

- Cho nên chúng ta hay đọc xách (sách) trong những giờ rãnh (rảnh) rỗi, chúng ta đọc không phải mằm (nằm) chổ (chỗ) này đọc, hay ngồi chổ (chỗ) kia, ngồi chổ (chỗ) nào có đủ lượng ánh xáng (sáng) chiếu vào để k (không) thể tăng cho mắt chúng ta bị cận được.

- Ông Tô Hoài đã giết chết Mỵ nhưng vì Mỵ có sức sống tiềm tàng nên cho Mỵ sống lại, để tiếp tục chung sống với Pa trá.

- Mị sinh ra trong 1 gia đình nghèo, nghèo từ trong trứng nghèo ra.

- Khi A Sử thay đồ chuẩn bị đi chơi. Mỵ cũng xin A Sử cho đi theo nhưng A Sử không cho mà còn đánh đập, trụt quần và trói Mỵ vào cái cột.

- Mỵ muốn được chơi nhảy như bao người khác. Hình dáng Mỵ đẹp tuyệt trần, đôi mắt long lanh lúc nào cũng buồn, hàm răng đẹp, gò má cao, đầu tóc dài xinh đến không thể tả được chỉ có một cái là Mỵ hơi ốm một tí mà thôi. Nhớ tới Mị là em nhớ đến những thiếu nữ Hà Nội tha thướt bên Hồ Gươm chiều chủ nhật.

- Vợ chồng thống lí đại diện cho phái ác. Hắn ức hiếp Mị, làm cho Mị không có lối thoát, còn vợ hắn thì lấy cớ đó đánh đập tàn nhẫn cho rằng Mị đụ dỗ chồng bà ta.

- Tô Hoài như đang đùa giỡn khi xây dựng Mị như vậy... Có lẽ Tô Hoài cũng đau xót. Nhưng thật khó để mà hiểu biết được một tác giả lớn Tô Hoài: vùi dập, khai mở rồi lại vùi dập. Những hy vọng sống của Mị lại bị A Sử cho đi vào ngõ hẻm.

3 - Những câu văn so sánh thuộc hàng... siêu so sánh

- Khi A Phủ đến thuê cho nhà thống lí với công việc chăn trâu, sau một thời gian qua Mị vẫn ngồi trong chuồng heo, giống một con heo đang tìm chỗ trốn mà cứ người khác.

- Người nhà Pa tra đánh cho A Phủ đến ngất sỉu (xỉu) rồi đổ nước cho tỉnh lại. Thể hiện con người nhà thống lí độc ác, dã man, đánh người đánh như con chó.

- Được thả A Phủ chạy ra khỏi nhà thống lí như một con trâu điên và vài phút do dự, sửa sang lại trang phục Mị đã chạy theo A Phủ như mây bay, gió thổi.

- Có thể thấy, việc Tô Hoài xây dựng một con người với những phẩm chất đẹp đang bị vùi dập và đang như tan chảy giống như phiến băng để trên một lò lửa, tan ra và khi chỉ còn là nước nó chỉ chờ đủ độ 100 độ c để sôi thôi.

- Sông Hương to như một con thuồng luồng đực cụp đuôi, to lớn, lượn quanh những khúc cua của đường đua công thức một...Sông Huơng với ba màu khác nhau có lúc là màu tím của gương mặt người thấm đẫm rượu say.

4 - Những dẫn chứng ví dụ... độc chiêu

- "Quê hương tôi có con sông xanh biếc.
Nước chảy mãi hai bên bờ."

Trong bài thơ Nhớ con sông quê hương của nhà thơ Tế Hanh, chúng tôi chưa bao giờ thấy có câu thơ thứ hai như thí sinh đã dẫn: "Nước chảy mãi hai bên bờ".

- "Trong tập sáng tác ca dao tục ngữ Việt Nam có câu:

Giang hồ hiểm ác anh không sợ
Chỉ sợ đường về vắng bóng em

Anh tôi đã "lấy 2 câu thơ làm của riêng". Chỉ câu nói ấy thôi mang anh đã tán được nhiều người, người ấy bây giờ mà tôi gọi là "chị hai". Đã thấy được sức hút của việc đọc sách làm cho con người ta sống vui tươi và hạnh phúc hơn".

Vừa dẫn ca dao tục ngữ, vừa chứng minh về tác dụng, ảnh hưởng của nó đối với đời sống tình cảm của anh trai mình. Đúng là một ví dụ khó ai mà nghĩ ra được!

5 - Râu ông nọ cắm cằm bà kia

- Đang giới thiệu về Tô Hoài lại chuyển sang nói về Tố Hữu; chẳng ăn nhập vào đâu: "Tô Hoài là một trong những cây bút văn xuôi hay nhất nền thơ ca Việt Nam hiện đại. Thơ Tố Hữu trữ tình lãng mạn luôn nói về những số phận đâu (đau) thương của con người và lên án sự bất công của các thế mạnh đã đem đến cho con người."

- Đề bài yêu cầu làm về Vợ chồng A Phủ, thì một thí sinh lại say sưa phân tích về các nhân vật trong Vợ Nhặt của Kim Lân đến 3 trang. Giám khảo chào thua.

Xin dẫn một đoạn: "Nạn đói trong năm 1975 thât khủng kiếp. Nạn đói tràn đến xóm ngụ cư, mọi người lâm vào tình trạng khốn khổ vô cùng. Tô Hoài đã miêu tả không gian trên đường Tràng về nhà thật bi thảm...."

Thursday, June 11, 2009

Mô hình MVC: Vai trò của các thành phần và các vấn đề thiết kế trong các Web Framework


Share/Bookmark
@author pcdinh
@since July 26, 2008
@version 1.0.0
@link http://dev.wvb.com/pubdocs/software_design/mvc.txt
@note Tài liệu được viết trên Notepad (plain text) và xem tốt trên font Courrier New và encoding UTF-8 ở chế độ Word-wrap. Firefox hỗ trợ Wordwrap trên màn hình View Source (Ctrl + U) , chọn View - Wrap long lines

CHANGE LOG
+ July 26, 2008: 1.0.0 - Viết lần đầu

Disclaimer: Bài viết này phản ánh quan điểm của tôi. Nó không phản ánh quan điểm của World'Vest Base hay các software architect mà tôi có dịp làm việc cùng.

----------------------------------------------------------------
MÔ HÌNH MVC TRUYỀN THỐNG TRONG CÁC WEB FRAMEWORK
----------------------------------------------------------------

Trong mô hình MVC truyền thống, Controller là thành phần đóng vai trò trung tâm trong việc tiếp nhận và chuyển tiếp yêu cầu của user đến các thành phần có liên quan trong đó có 2 bộ phận chính là Model và View. Trong đó Model đóng vai trò là thành phần cung cấp dữ liệu và các dịch vụ có liên quan đến dữ liệu. View đóng vai trò là thành phần cung cấp các logic và cấu trúc liên quan đến việc trình bày dữ liệu.

Tuy nhiên với mô hình này, Controller đóng vai trò là trung tâm điều khiển. Model không biết Controller nào sẽ lựa chọn nó. Nó là Passive Model. Tương tự, View không biết Controller nào sẽ gọi nó ra và cung cấp cho nó dữ liệu gì. Nó là Passive View. Bằng cách đó, View và Model không hề biết nhau. View và Model không biết đến Controller nhưng Controller thì lại biết cả 2 và thậm chí là cả sự phụ thuộc về dữ liệu giữa View và Model.

Như vậy trong các web framework hỗ trợ MVC truyền thống thì

CONTROLLER

Controller là các lớp điều khiển application flow, tiếp nhận user input thông qua HTTP header, chuyển tiếp nó đến các lớp phụ trách trực tiếp xử lý yêu cầu. Tùy theo cách thiết kế kế lớp mà chúng ta thường thấy Controller gồm
+ Front Controller
+ Dispatcher
+ Action Mapping
+ Action Filter
+ Action: lớp xử lý các sự kiện chính, nơi dẫn đến application flow chủ yếu (Main Event Handler)
+ Response
+ Request: xử lý một phần user input ở mức GET, POST và PUT
+ Session: xử lý một phần user input ở mức SESSION

Tùy theo user input, Controller sẽ thực hiện các phép lọc (với dịch vụ lấy từ Model), các tính toán lựa chọn (Action Mapping) dựa trên kiến trúc và cấu hình nhằm xác định thành phần lớp chính sẽ thực hiện yêu cầu của user. Đây chính là chức năng điều khiến application flow của Controller. Vì là nơi đón nhận user input cho nên thường thì các thành phần xử lý form (ví dụ ActionForm trong Struts) sẽ thuộc về Controller. Controller cũng sẽ có chức năng validate form đơn giản nhằm thực hiện chức năng điều khiển luồng của mình.

Một khi xuất hiện các Event phức tạp, như là một Observer, Controller cần bổ sung thêm các lớp mới vào để xử lý chúng theo các quy trình độc lập, giúp phân tán bớt code tập trung vào lớp Action. Do là thành phần điều phối, Controller không nhất thiết phải tương tác với Model rồi mới tương tác với View. Bất cứ lỗi ngoại lệ nào xảy ra hay một trạng thái request không mong muốn xuất hiện thì Controller có thể phản ứng bằng cách chọn View trực tiếp.

Khi giao tiếp với Model, Controller sẽ tiến hành 2 cách
+ extract dữ liệu hay state
+ update dữ liệu
Ví dụ:
// Trong lớp Action của Controller
$productId = $this->request->get('product_id');
$electronicWarehouse = new ElectronicProductWarehouse();
$availableProducts = $electronicWarehouse->findAvailableProductsById($productId);


Sau khi có được dữ liệu, theo cách hành xử thông thường, View thích hợp sẽ được lựa chọn. COntroller sẽ chuyển tiếp dữ liệu vào View để nó xử lý

Ví dụ:
// Trong lớp Action của Controller

// Load the PHP Savant2 class file and create an view instance.
require_once 'Savant2.php';
$view = new Savant2();

if (true === $availableProducts->empty())
{
// Assign values to the Savant instance.
$view->assign('products', $availableProducts);

// Display a template using the assigned values.
$view->display('products.tpl.php');
}
else
{
// Display a template using the assigned values.
$view->display('products_unavailable.tpl.php');
}

CakePHP, Zend Framework, Symfony, Ruby on Rails, Struts hay Spring MVC lựa chọn cách làm này. Bằng việc xóa khỏi bộ não View kiến thức về Model, Controller có thể thay thế nhiều Model, các API trên Model mà nhưng không cần phải nhắc View về điều đó. Điều này là đặc biệt quan trọng khi mà kiến trúc ứng dụng đòi hỏi phải phù hợp với việc các lớp Model cần thay đổi 1 cách linh hoạt (ví dụ như có sự can thiệp của Dependency Injection). Nhưng có vẻ như đây là nhiệm vụ của tầng Integration. Trong bài viết sau chúng ta sẽ xem xét lại vấn đề này với MVC Pull.

Có một số người khi thiết kế ứng dụng theo MVC đã cố gắng dồn hết chức năng điều khiển luồng vào lớp Action cho nên dẫn đến hiện tượng Fat Controller. Ví dụ như những người code Rails sau khi đã định nghĩa Model dựa trên ActiveRecords để làm các công việc như extract data, update data và validate dữ liệu thì họ bỏ hết trách nhiệm xử lý business logic sang cho Controller. Thực tế là
+ Fat Controller, hay Thin Controller là các từ gọi nôm na của một thiết kế tồi. Từ Fat có lẽ đến từ thế giới Ruby on Rails khi mà nhiều người ở đó quá cứng nhắc trong việc tuân thủ theo mô hình Rails mà không biết rằng bản thân Controller cũng có thể có các sub layer giúp giải phóng các tác vụ dạng thủ tục thành các thành phần nhỏ riêng biệt, nhưng vẫn thuộc về Controller. Hoặc theo 1 hướng khác, Model tỏ ra vô tránh nhiệm với dữ liệu trả về khiến cho công việc điều khối của Controller thêm nặng nề. (xem bên dưới)
+ Tôi cho rằng Controller cần làm đúng nhiệm vụ của nó. Nó không phải là God Class. Nó không thể đẩy trách nhiệm cho Model hay cho View chỉ bởi vì nó có nhiều việc hơn 2 thành phần kia trong 1 hay 1 số user case cụ thể nếu như giao diện giữa chúng đã đủ compact.
+ Theo code mẫu trên thi View có vẻ như hơi ít trách nhiệm. Một phần trách nhiệm xác định cấu trúc để hiển thị đã được đẩy sang cho Controller. Đây cũng là vấn đề làm cho Controller trở nên nặng nề hơn.

Do tính chất công việc của Controller là khá phức tạp và đa dạng cho nên việc Event Handler Controller có thể tiếp tục tách ra nhỏ hơn cũng là điều cần tính đến thay vì thực hiện việc xử lý tất cả các signal, user input ... trên cùng một lớp.

MODEL

Model là các lớp cung cấp dữ liệu, dịch vụ liên quan đến dữ liệu và business logic. Chúng có thể là

+ Đánh giá tính hợp lệ của dữ liệu.
Ví dụ kiểm tra user input có đúng với rule của hệ thống không (ví dụ user credentials...)
+ Chuyển đổi dữ liệu:
Ví dụ convert định dạng file, chuyển đổi tỉ giá, language translation ....
+ Đưa ra quyết định về nghiệp vụ:
Ví dụ đưa ra các dữ liệu, lời khuyên tư vấn đầu tư dựa trên user input và các dữ liệu đang có
Ví dụ có tính integration: thực hiện chính sách của công ty là từ ngày 20 - 24 thì áp dụng cách tính giá của phòng Sale 1. Sau thời điểm đó thì áp dụng cách tính giá của phòng Sales 2.
+ Thực hiện việc xử lý dữ liệu theo một quy trình (workflows): ví dụ controller tiếp nhận yêu cầu xuất kho 300 chiếc ô tô từ kho A từ user. Sau khi kiểm tra tính chính quy của việc gửi yêu cầu, Controller chuyển yêu cầu này thành lợi gọi hệ thống để thông báo cho Model. Tuy nhiên việc xuất kho 300 chiếc ô tô cần phải được thực hiện theo 1 workflow mà chỉ có Model biết. Tạm thời bỏ qua sự xuất hiện của một rule engine, chúng ta có thể thấy Model thực hiện một số đoạn code có tính thủ tục như: 1) Thông báo với module sales về việc bán được 300 chiếc ô tô và yêu cầu trả lời. 3) Model sales ghi nhận và kiểm tra chính sách hoa hồng và thời điểm hiện tại và chuyển tiếp yêu cầu đến module Inventory và module Accounting 4) module Accounting thực hiện việc tính toán, báo giá thanh toán theo USD và VND với tỉ giá ở thời điểm hiện tại cũng như không quên trừ triết khấu và hoa hồng và gửi kèm thông báo thanh toán theo theo yêu cầu xuất kho 5) module Inventory kiểm tra yêu cầu xuất kho từ Sales và thông báo thanh toán từ Accounting để xuất kho, và ghi nhận giao dịch bằng cách ghi lại mã số yêu cầu của Sales và mã số thanh toán của Accounting. module này tiếp tục kiểm tra số ô tô có trong kho theo chất lượng và đặc tả yêu cầu rồi trả lời: có được hay không 6) Nếu được, nó sẽ thành lập thông báo xuất kho ..... Cuối cùng Model trả lại trạng thái xử lý và dữ liệu nếu có.

Do có 2 vai trò tương đối tách biệt cho nên một Model thường được tách thành các lớp có các domain xử lý khác biệt
+ Business logic thường là xử lý rule hay policy của nghiệp vụ cũng như business workflows. Tầng này có sự góp mặt của các rule engine và các integration engine (trong đó có Spring bên Java và Flow3, Scarlet, Seasar, PHPCrafty bên PHP).
+ Domain data: Cung cấp/lưu trữ dữ liệu và việc chuyển đổi dữ liệu thành các dạng khác nhau theo yêu cầu. Các tầng như Persistent Layer nằm ở đây. Vì thế chúng ta sẽ gặp các lớp của PDO (PHP Data Object), Pear MDB2, PHP Doctrine, JDBC, JTA, JPA, Hibernate, JDO ... và cả các lớp thực hiện DAO.

Trong các tình huống đơn giản, Model chỉ làm vài thao tác đơn giản như fetch dữ liệu từ database. Trong các tình huống phức tạp, việc xử lý có thể là tổ hợp của hàng trăm lớp diễn ra trên 1 hoặc vài server hoặc thậm chí dữ liệu hay quyết định được đưa ra từ Model lại là tổng hợp kết quả từ 1 vài data center nằm rải rác trên vài lục địa. Do vậy trong Model không chỉ có các thao tác trên database và có còn là file system, memory, networking I/O ...

Worlflow mà Model điều khiển hoàn toàn có tính nghiệp vụ đặc thù. Nó khác với Application Flow vốn có tính hệ thống và thiên về technical analysis (phần cứng hay phần mềm) của Controller. Applicaton flow được xử lý như thế nào chủ yếu là do software architect xác định nhưng với workflows thì đó là do các business analyst xác định do nó thiên về nghiệp vụ (gần với cuộc sống và cách tổ chức quy trình làm việc của 1 tổ chức chứ không phải là quy trình kĩ thuật của thiết kế hướng đối tượng).

Model là Passive để hoạt động như là một Service Layer nhằm có thể re-use giữa các Controller nhưng nó không phải là dead-end. Thay vào đó nó cần biết giao tiếp với Controller như thế nào cho có hiệu quả. Sự hiệu quả này thể hiện ở 2 hướng

+ Signal hay message
+ Data type

Một software architect của Microsoft thường nhấn mạnh đến The Power Of Sameness trong software development trong đó bao gồm
+ Coding standard
+ Naming matters
+ Common interface

Khi Controller gọi Model thông qua API của Model, nó cần biết 1 số behavior chung của Model (tức là common interface). Ví dụ:

+ Cách Model đó gửi signal về quá trình nó xử lý yêu cầu. Có hay không có Exception, kiểu của Exception, Exception trong trường hợp nào. Những cái đó cần được comment chi tiết
+ Kiểu trả lại cần nhất quán và well-defined

Cái mà Controller quan tâm đến output của Model chính là trạng thái (message : false, true) hay dữ liệu. Vì Model thực hiện phần nghiệp vụ nên dữ liệu trả lại của nó cần phải phản ánh tính nghiệp vụ. Thông thường một kiểu trả lại được coi là well-defined nếu nó là một BO (Business Object) tức là một lớp getter/setter để nhận và xuất dữ liệu. BO thường là có kiểu phản ánh bản chất dữ liệu mà nó có ví dụ như

+ User
+ Product
+ Employee

Bằng cách trả lại các đối tượng được định nghĩa rõ ràng, Model trả tỏ ra có trách nhiệm với Controller hay các thành phần gọi nó để giúp các thành phần này bớt confused (giảm các đoạn mã if/else/switch/instanceof/try/catch) và tạo ra sức mạnh của cái gọi là The Power Of Sameness. Tuy nhiên, việc BO có thể chỉ là một data container thuần túy hay là một Domain Object thì còn đang gây tranh cãi vì getter/setter thuần túy sẽ gây sự nghi ngờ về tính hợp lệ của encapsulation. Tuy nhiên tôi vẫn có một quan điểm khác về kiểu của BO trong khi lập trình PHP.

Tương tự như trong trường hợp Controller lấy state từ Model, khi Controller cung cấp thông số cho Model để Model trả lại state theo hướng mà Controller mong muốn từ Controller cũng phải định nghĩa được 1 common interface.

VIEW

View là các lớp định nghĩa cách thức trình bày dữ liệu (không update dữ liệu). Trong các web framework, nó gồm 2 phần chính:
+ Template file định nghĩa cấu trúc và cách thức trình bày dữ liệu cho user. Ví dụ như layout, color, windows ...
+ Logic xử lý cách áp dụng dữ liệu vào cấu trúc trình bày. Logic này có thể bao gồm việc kiểm tra định dạng dữ liệu, chuyển đổi định dạng dữ liệu sang một sạng dữ liệu trung gian để có thể hiển thị với cấu trúc template đang có..., kiểm tra trạng thái và đặc tính của dữ liệu để lựa chọn một cấu trúc hiện thị phù hợp. Tất nhiên là trong Passive View thì việc lựa chọn cấu trúc hiện thị đôi khi lại do Controller.

Bản thân View cũng là một tổ hợp của nhiều lớp. Và nó cũng có thể có SubView để giảm tải trên 1 số lớp chính và để sử dụng lại mã. Và do vậy tính logic của View có thể là logic của một cây phân cấp.

Trong mô hình truyền thống, View có trách nhiệm chuyển đổi dữ liệu hay state của Model thành cấu trúc visual. Do vậy dữ liệu của Model cần well-defined (xem ở trên). Sự tách biệt của 2 thành phần này sẽ giúp cho người lập trình phân định được 1 biên giới rõ ràng giữa cách thức lưu trữ/lấy dữ liệu và cách trình bày dữ liệu. Do vậy tính phức tạp của quy trình lấy dữ liệu, xử lý dữ liệu cũng như (sự thay đổi của chúng theo thời gian) trước khi trả về sẽ không làm ảnh hưởng đến việc trình bày dữ liệu. Do vậy sự khác biệt về công nghệ lấy dữ liệu và công nghệ render không gây ảnh hưởng đến ứng dụng. Điều này khá quan trọng trong việc tích hợp các ứng dụng.

Ngoài ra, cách làm này thực sự đảm bảo việc tách biệt vai trò của người thiết kế giao diện với vai trò của lập trình viên thiên về dữ liệu. Như vậy khi làm việc theo nhóm, PM có thể tổ chức nhóm phát triển thành các nhóm kĩ năng và phát triển ứng dụng song song với nhau

+ Page designer
+ Application flow developer
+ Business Process and Data developer

Tuy nhiên, View của thế giới hiện tại đã khác đi nhiều. Có một lớp lập trình viên thiên về tầng presentation đã ra đời. Do vậy, nhóm kĩ năng mới sẽ là

+ Page designer: những người hiểu template file và cách design nó sao cho đẹp
+ Presentation Developer: những người hiểu template, hiểu template cần dữ liệu từ nguồn nào và còn hiểu cả cách cấu trúc template cần thay đổi như thế nào với dữ liệu và sự kiện từ Action Controller gửi xuống. Họ còn quan tâm đến việc View đó được sử dụng và sử dụng lại như thế nào trong các application flows khác nhau (ví dụ bối cảnh ajax). Đặc biệt họ quan tâm đến các ứng dụng mashup.
+ Application flow developer: người hướng đến việc render toàn bộ trang, page navigation và để trách nhiệm render từng khối cụ thể của trang vào Presentation Developer
+ Business Process and Data developer: người chỉ quan tâm đến việc kiểm tra tính hợp lệ của user input, business workflows, tính tích hợp của quy trình và dữ liệu nhưng không quan tâm đến dữ liệu đó được sử dụng ở đâu và theo cách render nào.

Vai trò của View cần thay đổi đặc biệt là các ứng dụng web thiên về View phức tạp khi vai trò của Model đã trở nên ổn định.

----------------------------------------------------------------
FAT CONTROLLER, THIN CONTROLLER VÀ GOD CLASS
----------------------------------------------------------------

Trong cộng đồng CakePHP, Zend Framework và Rails từ 1 - 2 năm trở lại đây bắt đầu xuất hiện lời ca thán về fat controller hay thin controller. Theo họ, việc chuyển một số công việc của Controller vào Model là hợp lý hơn. Phải chăng đó là dấu hiệu của God Class? Trong lập trình hướng đối tượng với MVC, việc tạo là một God Class là điều nên tránh. Fat Controller có thể là hiện tượng rời rạc của cái gọi là God Class. Tuy nhiên nó có thể chỉ là cách quan sát và nhận thức về tính thủ tục và labour-extensive của Controller hay View và tính tự động hóa do framework-backed của Model. Nhu cầu điều phối lại chức năng của Model, Controller và View rõ ràng là dấu hiệu của Code Smells.

Ví dụ: việc thiết kế Model thiếu trách nhiệm khiến cho công việc lọc và xử lý dữ liệu trả lại trên Controller và View trở nên labour-extensive hơn: http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model

Theo quan điểm của tôi, nếu bạn thấy Controller của bạn hay View làm nhiều hơn logic của nó cần có trong khi Model lại hơi ít việc quá thì hay xem lại cách thức giao tiếp giữa 3 thành phần này. Giao diện giữa chúng càng compact thì mô hình của bạn càng hiệu quả.

----------------------------------------------------------------
KHI CONTROLLER TRỞ THÀNH GOD CLASS
----------------------------------------------------------------

Controller có lẽ thành phần bị phê phán nhiều nhất trong MVC. Như đã nói ở trên rất nhiều những người code Rails sau khi đã định nghĩa Model dựa trên ActiveRecords để làm các công việc như extract data, update data và validate dữ liệu thì họ bỏ hết trách nhiệm xử lý business logic sang cho Controller. Controller cũng đóng vai trò là thành phần quản lý việc cung cấp dữ liệu cho View nên View thực sự là Passive. Thậm chí Controller còn biết cả cấu trúc tên biến dữ liệu sẽ dùng trên View. Lúc đó View giảm tính Logic của nó xuống chỉ là còn là điều khiển việc render trên 1 cấu trúc có sẵn. Vì thế ta thấy có công thức View = ViewRenderer.

Các khái niệm như partial hay slot chỉ là một cách tăng cường tính sử dụng lại view template và các view helper cũng chỉ làm 1 số logic xử lý dữ liệu trên View trước khi nó được render trên 1 cấu trúc template. Dữ liệu hoàn toàn là do Controller cung cấp. Theo cách này DRY biến mất vì cùng một thao tác cung cấp dữ liệu cho View có thể được duplicate trên nhiều Controller. Trên thực tế việc sử dụng lại View chẳng qua chỉ là sử dụng lại cấu trúc HTML và cách render dữ liệu trên trang HTML đó. Muốn dùng lại dữ liệu, bạn có thể cần pass cả đối tượng Model xuống View. http://mentalized.net/journal/2006/12/08/simplifying_my_rails_views/ Tôi gọi đây là một bad practice.

Cái mà View template cần chính là một thứ DTO (VOs) hoặc BO không phải là cả model vì chúng ta cần tránh phô trương quá nhiều logic trên template. Chúng ta nên tập trung các thao tác trên dữ liệu trên 1 hay 1 số node chính (đặc biệt là các node điều phối) của mô hình MVC thay vì trên các nhánh phụ để tổ chức và quản lý tài nguyên và nghiệp vụ cho dễ hơn.

Nếu như Controller xử lý quá nhiều (ví dụ như edit hay add 1 multi-step form là trường hợp tôi thấy khó chịu nhất) thì đó thường là liên quan đến xử lý user input thành dạng được chuẩn hóa trước khi phân tích nó thành 1 lời gọi trên Model. Thường thì khi đến Model, user input đã phải khá là fine grained. Tuy nhiên đối với các form phức tạp với nhiều checkbox có tính phân nhánh thì việc để Controller thực hiện việc validate dữ liệu là rất nặng nề. Như thôi đã nói ở trên Controller chỉ thực hiện các basic validation (ví dụ diễn giải URL thành các module, controller class và action method). Nhưng đối mặt với các form phức tạp với 20 - 30 input có phân nhánh mà để xử lý Controller có thể phải phân tích đến 10+ trường hợp và mỗi trường hợp có thể có đến nhiều hơn 1 trường hợp phụ thì Controller đã có nguy cơ phình to. Khi đó nhu cầu phân tách Controller đã xuất hiện.

Thông thường Controller được tách thành 3 lớp chính
+ Dispatcher
+ Filter
+ Event Handler: lớp Action trên Struts hay Zend hoặc Controller trên CakePHP, chính là nơi sẽ làm việc với user input và các quyết định trên View

Khi Event Handler Controller bị phình thì rõ ràng có lý do để xét đến
+ User Input Validation
+ Multistep View Handler
+ Changes Committer
+ View Selection

Theo cách làm của tôi, User Input Validation Logic nên được chuyển về cho Model và xác nhận rõ việc đánh giá user input theo các rule của application là một vấn đề business logic thay vì application flow logic. Điều này có tính hợp lý riêng. Ví dụ: trên trang contact, input có tên là job position không cần phải validate nhưng trên trang sign up thì lại cần. Lý do của sự khác biệt: do yêu cầu của nghiệp vụ. Rõ ràng là cách quy định này có thể thay đổi từ app này sang app khác mà không phụ thuộc vào software architect.

Khi đó thay vì dùng if/else, lớp thực hiện User Input Validation sẽ cài đặt các rule có sẵn hoặc custom rule hoàn toàn cách khỏi lớp Event Handler. Controller phụ trách event handler sẽ gọi đến Model chuyên biệt về xử lý user input này và yêu cầu validate hoặc không. Trong các trường hợp đặc biệt một form validation như vậy có thể re-use lại ở nhiều Controller khác nhau và hỗ trợ tính kế thừa.

Ví dụ:
+ Controller A sử dụng PasswordChangeForm để validate dữ liệu với các input pass1, pass2 và email
+ Controller B sử dụng PasswordChangeForm2 extends từ PasswordChangeForm với thêm input là username

Như vậy việc tách user input ở mức form ra khỏi Controller sẽ giúp

+ Reuse code thông qua re-use cả class hoặc extend
+ Reuse rule checking thông qua việc định nghĩa rule thành các chuẩn riêng
+ Reuse tính gắn kết rule vào form và do đó đơn giản hóa việc apply quy trình nghiệp vụ trên form.

Bằng cách này bạn sẽ thấy Event Handler Controller đã đơn giản đi rất nhiều. Trong phần tiếp theo tôi sẽ trình bày cách thiết kế MVC Pull của tôi để tiếp tục giảm vai trò điều phối của Controller và tăng tính chủ động của View

(còn tiếp)

----------------------------------------------------------------
Phụ lục
----------------------------------------------------------------

Code demo về việc tách form ra khỏi Controller. Các đoạn code dưới đây là các code thực sự chạy vận hành trên PONE framework để cung cấp 1 số dịch vụ tại World'Vest Base Inc. Tuy nhiên, đây là các code ở mức application developer. Do vậy, code này chỉ có thể test nếu có PONE framework. PONE cung cấp mô hình Observer pattern để các lớp dưới đây vận hành được.

File Home_PagesController: file Controller. Xem method contactAction()

_layout->attachCss('home');

// Attach file: javascript
$this->_layout->attachScript('home');

// Attach file: meta
$this->_layout->attachMeta('home');
}

/**
* When use comes to this page by a mistake, redirect them to the about-us page
*
* @link http://www.wvbresearch.com/home/pages
* @name index
* @access public
*/
public function indexAction()
{
$this->forward('home', 'pages', 'about');
}

/**
* Show the introduction page about the website and company behind it
*
* @link http://www.wvbresearch.com/home/pages/about
* @name about
* @access public
*/
public function aboutAction()
{
// Attach placeholder: the name of ElementGroup
$this->_layout->registerBody('homeAbout');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}

/**
* Show the contact page
*
* @link http://www.wvbresearch.com/home/pages/contact
* @name contact
* @access public
*/
public function contactAction()
{
// Instantiate form object
$this->initForm('contact');
// Create action state object
$this->initState();

try
{
// Check if the form is submitted and/or is submitted correctly
if (false === $this->_form->isPost() || false === $this->_form->validate())
{
throw new Exception();
}

// Initialize the model object wih an appropriate database access object
$model = new ContactModel($this->getDatabaseConnection('oracleweb', true));

// Persist the form data into data storage medium (database, file system, messaging server, email server, file-backed memory server)
if (false === $model->save($this->_form))
{
throw new Exception();
}
}
catch (Exception $ex)
{
// the form input is not complete. User need to fill it (if the form is rendered at the first time)
// or user need to correct the data and submit again
$this->_state->setState(Pone_Action_State::FORM_INCOMPLETE);
}

// Render the body part that contains contact form
$this->_layout->registerBody('homeContact');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}

/**
* Show the faqs page
*
* @link http://www.wvbresearch.com/home/pages/faq
* @name faq
* @access public
*/
public function faqAction()
{
// Attach placeholder: the name of ElementGroup
$this->_layout->registerBody('homeFaq');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}

/**
* Show the WVB global offices page
*
* @see Group_HomeGlobalOffices
* @see index.tpl.php
* @link http://www.wvbresearch.com/home/pages/offices
* @name WVB Global Offices
* @access public
*/
public function officesAction()
{
// Attach placeholder: the name of ElementGroup
$this->_layout->registerBody('homeGlobalOffices');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}

/**
* Show the sitemap page
*
* @link http://www.wvbresearch.com/home/pages/sitemap
* @name faq
* @access public
*/
public function sitemapAction()
{
// Attach placeholder: the name of ElementGroup
$this->_layout->registerBody('homeSitemap');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}


/**
* Show the terms and conditions page
*
* @link http://www.wvbresearch.com/home/pages/termsandconditions
* @name termsandconditions
* @access public
*/
public function termsandconditionsAction()
{
// Attach placeholder: the name of ElementGroup
$this->_layout->registerBody('homeTerms');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}

/**
* Show the terms and conditions page
*
* @link http://www.wvbresearch.com/home/pages/termsandconditions
* @name termsandconditions
* @access public
*/
public function privacyAction()
{
// Attach placeholder: the name of ElementGroup
$this->_layout->registerBody('homePrivacy');

// Set content for the response
$this->_response->setContent($this->_layout->render());
}
}

?>


File Form_Contact đúng vai trò như là Form Model, một model đặc biệt phục vụ cho việc xử lý form validation dựa trên business rules dành cho form.

setFormKey('contact');

$this->setFormFeedbackHeader(_t('common.error.form.false'));

$titleRules = array(
Pone_Form_Rule::NOT_EMPTY => array('feedback' => _t('common.error.title.empty'))
);
$this->setValidationRule('title', $titleRules);

$nameRules = array(
Pone_Form_Rule::NOT_EMPTY => array('feedback' => _t('common.error.name.empty'))
);
$this->setValidationRule('name', $nameRules);

$emailRules = array(
Pone_Form_Rule::EMAIL => array('feedback' => _t('common.error.email.notvalid'))
);
$this->setValidationRule('email', $emailRules);

$contentRules = array(
Pone_Form_Rule::NOT_EMPTY => array('feedback' => _t('common.error.content.empty'))
);
$this->setValidationRule('content', $contentRules);
}
}
?>


File Group_HomeContact: Vùng View sẽ tương tác trực tiếp với Form trên

getFront()->getActionController();
$this->form = $action->getDataForm();

if (null === $this->form)
{
throw new Pone_Exception('This element group is form-based so the action controller needs to initialize a form object for being re-used in this object');
}

$message = $action->getActionState();

if (Pone_Action_State::OK === $message->getState())
{
$this->_templateFile = 'homeContactCompletion';
}
}
}
?>

is_dir hay file_exists


Share/Bookmark
Khi làm việc với file thường coder php sẽ kiểm tra file có tồn tại hay không bằng hàm file_exists, tôi cũng không tránh khỏi trường hợp này.

Nhưng có trường hợp dùng file_exists kiểm tra, mặc dầu kiểm tra thì file vẫn nằm lù lù đấy :|
Lý do là vì cái warning của php manual:

Warning

This function returns FALSE for files inaccessible due to safe mode restrictions. However these files still can be included if they are located in safe_mode_include_dir.


Bạn thấy đấy, nó không phải lúc nào cũng chạy tốt, nhất là với trường hợp cấu hình safe_mode hơi khó khăn chút, đặc biệt ở các hosting Việt nam hay sợ bị local attack.

Giải quyết vấn đề này, hãy dùng thử is_dir. Hãy yên tâm là hàm này có thể làm việc được cả với file và folder.
Bạn chỉ cần lưu ý một điều ở note của php manual:

Note: The results of this function are cached. See clearstatcache() for more details.

Wednesday, June 10, 2009

SamSung Laser Printer ML-1640


Share/Bookmark
Em này vừa được chính thức rước về làm tình nhân, hi vọng em mày sẽ chạy tốt cho 2 cái hồ sơ hoàn công sắp tới của anh em , kể cũng tội, vừa về đã chuẩn bị vài trăm nhát rồi thì khó đỡ đấy

























Bao giờ mới tới em khổ lớn cỡ A0 nhở

Tuesday, June 9, 2009

CakePHP, CodeIgniter, Solar và Zend Framework


Share/Bookmark
Slide giới thiệu về các framework thông dụng hiện nay, bạn có thể dựa vào đây để tự chọn một framework cho bản thân.

Monday, June 8, 2009

Web Security Demo


Share/Bookmark
File powerpoint

Slide, code ví dụ và cơ sở dữ liệu MySQL

Sunday, June 7, 2009

Javascript confirm alert


Share/Bookmark
Tiện dương làm cái nút confirm


<script type="text/javascript">
<!--
function confirm() {
var answer = confirm("Bạn có chắc muốn dời trang?")
if (answer){
alert("Tạm biệt!")
window.location = "http://www.google.com/";
}
else{
alert("Không làm gì cả :D")
}
}
//-->
</script>
</head>
<form>
<input type="button" onclick="confirm()" value="Chuyển tới google">
</form>

Nhà mới


Share/Bookmark
Trước cũng chả mấy khi đụng đến blog, nhưng mà cũng hóng được tí thông tin yahoo 360 sắp đóng cửa nên ăn mừng bằng cái nhà mới :D