Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Tại sao phải quan tâm đến coding style?

Nicholas C. Zakas là một trong các đại tôn sư JavaScript và front end hiện nay. Anh từng làm ở một số công ty nhỏ trước khi đến Yahoo! vào năm 2006. Ở đó, anh đóng vai trò Senior Front End Engineer rồi Principal Front End Engineer. Có thể xem Nicholas như thế hệ đàn em xuất sắc của Douglas Crockford, một bậc thầy JavaScript vĩ đại khác. Cả hai đều hoạt động sôi nổi, có đóng góp rất lớn trong việc hình thành thế giới front-end sống động như ngày nay. Hiện anh đang làm ở Box.com trong vai trò Principal Architect. Ngoài ra anh cũng tham gia biên soạn đặc tả EcmaScript, viết phần mềm và sách, cuốn mới nhất của anh có tiêu đề "Understanding ECMAScript 6", đang là sách gối đầu giường của nhiều developers, trong đó có tôi.

Năm 2011, Yahoo! YUI share 1 seminar chủ đề "Scalable JavaScript Application Architecture" của Nicholas trên YouTube và đã tạo thành hiệu ứng dữ dội, hàng loạt JavaScript framework mới ra đời hoặc được kiến trúc lại, bao gồm cả Angular, Ember và Backbone. Sau đó, chính anh cũng xây dựng T3.js, một framework nhỏ gọn, dùng cho hệ thống ứng dụng ở Box.

Năm 2012, Nicholas viết "Why Coding Style Matters" trên Smashing Magazine. Bài viết nhấn mạnh tầm quan trọng của coding theo convension. Theo anh, coding style không chỉ thể hiện tính chuyên nghiệp và tăng cường khả năng debug, mà còn ẩn chứa 2 yếu tố rất nhân văn khác: sự quan tâm đến người khác và trân trọng tương lai của chính mình.

Nay tạm dịch lại, mời các bạn xem chơi :)



Tại sao coding style quan trọng?

Thời còn đi học, tôi có một ông thầy rất nghiêm khắc tên là Maxey. Ông dạy các môn phức tạp như cấu trúc dữ liệu và kiến trúc máy tính. Ông giảng hay, dễ hiểu, nhưng cũng đặc biệt khó tính. Ông không chỉ dò code xem chạy đúng không mà còn bắt lỗi trình bày code nữa.

Nếu bạn quên comment vào những chỗ cần thiết, thậm chí nếu bạn gõ sai một hai từ trong comment, ông sẽ trừ điểm. Nếu code của bạn "bẩn" - so với tiêu chuẩn của ông ấy - ông ấy cũng trừ điểm. Thông điệp rất rõ ràng: chất lượng code không chỉ nằm ở chỗ nó chạy ra sao, mà còn phụ thuộc cách bạn trình bày nó nữa. Đó là những trải nghiệm đầu tiên của tôi về coding style.


Thế tóm lại coding style là gì?

Hiểu đơn giản, coding style là nói đến việc code của bạn trông ra làm sao. Chữ "bạn" ở đây tôi muốn nhấn mạnh là chỉ chính bạn, người đang đọc bài viết này. Coding style là chuyện hết sức cá nhân và ai cũng có thói quen riêng của mình. Bạn có thể tự khám phá style của bạn bằng cách xem lại những đoạn code mà bạn đã viết trước đây khi chưa học theo bất cứ style guide nào. Mỗi người có phong cách khác nhau vì cách họ tiếp cận các môn lập trình không hề giống nhau. Nếu bạn dùng các IDEs như Visual Studio để học code, bạn sẽ viết theo đúng cách editor đó quy định. Nếu bạn dùng các trình soạn thảo thuần văn bản, cách viết của bạn có thể tiến bộ dần theo những gì bạn thấy là dễ đọc.

Bạn sẽ sớm nhận ra rằng, ở mỗi ngôn ngữ khác nhau, cách viết code của bạn cũng thay đổi theo những chiều hướng khác nhau. Bạn có thể làm với JavaScript một kiểu, làm với CSS một kiểu khác. Chẳng hạn, bạn cho rằng chuỗi trong JavaScript nên dùng nháy kép, trong khi chuỗi bên CSS bạn vẫn dùng nháy đơn. Đây không phải chuyện hiếm gặp vì chúng ta có xu hướng chuyển đổi ngữ cảnh khi nhảy từ ngôn ngữ ngày sang ngôn ngữ khác. Nó là một bài tập thú vị trong việc tự quan sát bản thân.

Coding style được hình thành từ những quyết định nhỏ trong từng ngôn ngữ bạn sử dụng:

- Khi nào cần comment và comment thế nào?
- Thụt đầu dòng bằng tabs hay spaces (và bao nhiêu spaces)
- Sử dụng white space hợp lý
- Đặt tên biến và hàm rõ ràng
- Tổ chức và gom nhóm code
- Các patterns nên dùng và nên tránh

Đấy cũng chưa phải là tất cả, vì coding style có thể rất chi tiết như Google JavaScript Style Guide hay cũng có thể tổng quát hơn như jQuery Core Style Guidelines.


Đó là chuyện cá nhân


Tính chất cá nhân của coding style là một thách thức khi làm việc nhóm. Nhiều khi để tránh phải tranh luận dài dòng, người ta cố gắng trì hoãn việc xây dựng style guides với lý do không muốn "ngăn cản sự sáng tạo và tự do biểu hiện." Một số người nghĩ rằng đưa ra style guide cho team là ép buộc tất cả các developers vào cùng khuôn khổ. Một số developers kịch liệt chống đối khi phải code theo style guide, họ tin rằng sẽ không làm được việc nếu có ai đó cứ chỉ bảo họ phải viết code như thế nào.


Tôi thấy giống với tình huống một ban nhạc mới thành lập. Mỗi thành viên đều tin rằng cách chơi của họ là tốt nhất và cố gắng chơi theo cách riêng của họ. Nhưng không thể có âm nhạc ra hồn được trừ khi các thành viên nhất trí với nhau về nhịp độ, phong cách và cử ra người dắt nhịp. Nghe các nhóm nhạc trong trường học biểu diễn thì biết. Khó có thể làm được gì nếu mọi người không vận hành theo cùng một cách thức.

Đó là lý do tại sao tôi rất khuyến khích áp dụng style guide trong các nhóm phát triển phần mềm. Nếu bạn thấy khó để mọi người nhìn vấn đề theo cùng một cách thì hãy bắt đầu từ style guide. Khi mà ai cũng trình bày code giống nhau, bạn sẽ tránh được rất nhiều rắc rối tiềm ẩn.


Thân thiện: nghĩ đến người khác


Giao tiếp là thứ quan trọng nhất khi làm việc nhóm. Để công việc trôi chảy thì phải tương tác với nhau thật tốt. Các developers giao tiếp chủ yếu qua source code. Chúng ta dùng code để nói chuyện với phần mềm cũng như với các developers khác.

Cách bạn trình bày code không quan trọng đối với máy tính, nhưng lại rất quan trọng đối với các developer khác. Code viết rõ ràng thì đọc dễ hiểu hơn. Đã bao lần bạn mở source code của người khác mà việc đầu tiên là sửa lại định dạng lại theo cách của bạn? Đó là vì cách trình bày khiến bạn không hiểu được code. Khi ai đó viết code nhìn khác lạ, mọi người sẽ ngay lập tức phải phân tích một cách trực quan trước khi có thể hiểu được code đó làm gì. Khi ai đó viết code giống bạn, bạn sẽ cảm thấy dễ chịu và hiểu được chương trình một cách nhanh chóng.


Khi bắt đầu nghĩ về code như một phương tiện giao tiếp với các developer khác, cũng là lúc bạn nhận ra rằng viết code chính là một nghệ thuật. Code nên thể hiện rõ ràng mục đích của nó. Luôn nhớ rằng code mà bạn viết ra rồi sẽ được những người khác dùng lại. Bạn không chỉ tương tác với các thành viên trong team ở thời điểm hiện tại, mà còn cả những developers sẽ gia nhập sau này.

Mới đây tôi có nhận email từ một người đang làm việc với code do tôi viết từ 10 năm trước. Tôi giật mình kinh ngạc: code của mình vẫn còn được dùng trong sản phẩm. Anh ta cảm thấy thôi thúc phải mail cho tôi để bày tỏ rằng anh rất vui khi được làm việc với code của tôi. Tôi mỉm cười. Người đồng đội tương lai này thực sự tán thưởng coding style mà tôi đã theo đuổi.


Thận trọng: nhìn xa phía trước

Trong cuộc sống, phải tự biết mình. Trong coding cũng vậy. Dẫu sao bạn sẽ không bao giờ biết mình đủ rõ để nhớ lại những gì bạn nghĩ khi viết ra mỗi dòng code. Hầu hết developers đều trải qua những lúc nhìn lại code cũ của mình mà không hiểu tại sao viết thế. Không phải do trí nhớ bạn kém, chỉ là bạn đã phải giải quyết quá nhiều chi tiết nhỏ và không thể nào ghi nhớ từng chút một.

Nhưng nếu bạn viết code dựa trên một style guide, các thông tin đó sẽ được gửi gắm vào trong bản thân mỗi đoạn code. Chỉ cần bạn biết rõ khi nào và ở đâu nên để comments, patterns nào nên/không nên sử dụng, bạn đã tạo ra ở đó một con đường mòn cho tương lai khi cần quay lại tìm kiếm ý nghĩa của code.

Không gì thú vị hơn khi mở ra một đoạn code xưa cũ mà vẫn thấy nó như vừa được viết hôm qua. Bạn sẽ bắt nhịp nhanh chóng chứ không phải mất hàng giờ nghiền ngẫm lại logic của những đoạn code ấy.

Chris Epstein từng khuyên: “Hãy ân cần với tương lai của chính bạn.”


Sáng suốt: nhận biết lỗi nhanh chóng


Một trong những lý do phải áp dụng style guide là nó khiến cho lỗi trở nên dễ thấy. Style guides giúp developers thích nghi với các patterns nào đó. Và khi bạn đã quen với những patterns ấy rồi thì chỉ cần nhìn qua code một cái, bạn sẽ phát hiện ngay ra các patterns khác lạ. Những patterns khác lạ này có thể không gây lỗi, nhưng chúng đòi hỏi phải xem xét thật kỹ để đảm bảo không có gì sai.

Chẳng hạn như với cấu trúc "switch" trong JavaScript. Có một lỗi khá phổ biến là cho phép thoát khỏi case để đi vào case khác, ví dụ:

switch(value) {
    case 1:
        doSomething();
    case 2:
        doSomethingElse();
        break;
    default:
        doDefaultThing();
}

Nếu value là 1 thì chương trình sẽ đi qua case thứ nhất rồi nhảy vào case thứ 2. Nghĩa là cả doSomething và doSomethingElse cùng được gọi.

Câu hỏi đặt ra ở đây là: có lỗi gì không? Rất có thể developer quên một câu lệnh "break" trong case thứ nhất, nhưng cũng có khả năng developer cố ý cho kịch bản chạy cả 2 cases nếu value bằng 1. Chưa thể khẳng định được điều gì qua đoạn code trên.

Bây giờ giả sử bạn có JavaScript style guide nói như sau:

“Tất cả các cases trong câu lệnh switch phải kết thúc bằng break, throw, return, hay một comments chỉ dẫn một fall-through”.

Với style guide như thế, chúng ta xác định đây là một lỗi trình bày, tức là có thể có lỗi logic. Nếu chủ ý bạn muốn chương trình đi qua case thứ nhất, thì nên code như sau:

switch(value) {
    case 1:
        doSomething();
        //falls through
    case 2:
        doSomethingElse();
        break;
    default:
        doDefaultThing();
}


Nếu bạn muốn thoát khỏi switch ở case đầu tiên, nó nên kết thúc bằng "break". Ngoài ra, code đầu tiên không đúng với style guide, nghĩa là bạn cần kiểm tra thật kỹ kịch bản. Với thói quen này, bug sẽ được ngăn chặn rất sớm. Cái

Style guide giúp chỉ ra những đoạn code viết bừa bãi. Chỗ lợi hại nhất của style guides là: bằng cách định nghĩa thế nào là trình bày code đúng, bạn sẽ dễ dàng hơn trong việc nhận diện code sai và do đó, cả những lỗi tiềm ẩn trước khi chúng xảy ra.


Càng tỉ mỉ càng tốt

Khi giúp khách hàng xây dựng style guide, tôi thường được hỏi những chi tiết vụn vặt có thực sự quan trọng không? Câu trả lời là đúng và không đúng. Đúng vì cách trình bày code không thực sự quan trọng với máy tính. Không đúng vì những chi tiết nhỏ ấy sẽ giúp ích rất nhiều cho các developer phải bảo trì code. Hãy nghĩ thế này: nếu trong sách có một ký tự lỗi, bạn vẫn hiểu và không mất đi hứng thú với câu chuyện. Nhưng nếu có quá nhiều lỗi, bạn sẽ nhanh chóng cảm thấy khó chịu khi cứ phải giải mã ý tứ của tác giả.

Coding style giống hệt như vậy. Các bạn đang định nghĩa cách phát âm, quy tắc ngữ pháp cho mọi người theo. Style guide của các bạn có thể khá dài và chi tiết, không sao cả. Theo kinh nghiệm của tôi, một khi các nhóm bắt đầu code theo style guides, họ có xu hướng đi vào chi tiết vì điều đó giúp họ hiểu code và tổ chức code ngăn nắp hơn.

Tôi chưa từng thấy style guide nào quá mức chi tiết, nhưng tôi đã thấy một số được làm quá sơ sài. Cho nên điều quan trọng là nhóm phát triển style guide phải phối hợp chặt chẽ, thảo luận kỹ càng xem cái gì cần nhất, để đưa ra một nền tảng tốt cho style guide. Đừng quên rằng style guide là tư liệu sống. Nó sẽ tiếp tục được nâng cấp trong quá trình làm việc tập thể mọi người ngày càng hiểu nhau hơn và nắm rõ công việc hơn.


Công cụ hỗ trợ

Đừng ngại dùng các tools bắt bạn phải tuân thủ coding style. Web developers có rất nhiều tools hỗ trợ kiểm tra coding style, từ command line chạy khi build, đến các plugins gắn vào text editors. Đây là vài công cụ bạn có thể tham khảo:

Eclipse Code Formatter
Eclipse IDE có một tool tích hợp sẵn hỗ trợ định dạng code.
JSHint
Công cụ kiểm tra chất lượng code và trình bày code JavaScript.
CSS Lint
Công cụ kiểm tra chất lượng và trình bày CSS do Nicole Sullivan và tôi xây dựng.
Checkstyle
Một công cụ kiểm tra style guidelines trong Java code, dùng được cho nhiều ngôn ngữ khác.

Bạn có thể chia sẻ trong team các files cấu hình kiểm tra style guide. Ngoài ra, làm các công cụ tích hợp vào hệ thống continuous integration của bạn cũng là ý tưởng tốt.



Kết luận

Style guides là phần quan trọng khi viết code chuyên nghiệp. Dù bạn viết JavaScript hay CSS hay ngôn ngữ nào cũng vậy, cách trình bày code là phần không thể thiếu khi đánh giá chất lượng code. Nếu team hay dự án của bạn chưa có style guide, hãy bắt đầu ngay đi. Đây là một số style guides để các bạn tham khảo:

Tất cả mọi người trong team đều nên tham gia xây dựng style guide để tránh hiểu không đúng. Vả lại, có bỏ công sức vào mới thấy trân trọng. Hãy bắt đầu bằng cách để mọi người cùng đóng góp cho sự sáng tạo chung đó.


by Nicholas C. Zakas, October 25th, 2012, Smashsing Margazine



* Một năm sau bài viết này, Nicholas quyết định viết ESLint, và cũng có chia sẻ tại đây: ESLint: The Next-Generation JavaScript Linter

Two-ways data binding với Object.observe

Các framework Javascript thường nhấn mạnh vào tính năng data binding như một ưu thế nổi bật của chúng. Nhưng thực ra bạn có thể thêm data binding vào ứng dụng Javascript của bạn một cách nhanh chóng và không có gì khó khăn cả.

Data binding về bản chất chỉ là việc đồng bộ thông tin một cách tự động giữa phần thể hiện ra ngoài trang web (DOM element, thường liên quan đến View) và phần dữ liệu được kiểm soát bên trong code Javascript (properties, thường liên quan đến Model). Vì thế, trong mô hình MVC, người ta thường hiểu data binding như là cơ chế tự cập nhật View khi Model thay đổi, và/hoặc tự cập nhật Model khi View thay đổi. Nếu sự đồng bộ diễn ra theo cả 2 chiều thì đó là two-ways binding.

Nguyên lý của data binding là theo dõi sự thay đổi của DOM và đối tượng Javascript liên quan, một khi có thay đổi ở phía bên này thì phát tín hiệu để cập nhật ở đầu kia của mối quan hệ.

Ảnh minh họa data binding, codeproject.com

Một trường hợp cụ thể

Giả sử chúng ta có 1 object:

var people = {
  firstName: "Dong",
  lastName: "Nguyen"
}

và chúng ta output thông tin này ra ngoài giao diện bằng đoạn HTML sau:

<input type="text" id="txtFirstName" value="">
<input type="text" id="txtLastName" value="">

Để hiển thị, chúng ta có script sau:

var people = {
  firstName: "Dong",
  lastName: "Nguyen"
}

var element = function(id){
  return document.getElementById(id);   
}

var $firstName = element('txtFirstName');
var $lastName = element('txtLastName');

var render = function(){
  $firstName.value = people.firstName;
  $lastName.value = people.lastName;
}

render();

Nhìn nó như thế này:

https://jsfiddle.net/ndaidong/76eadzth/1/

Ở đây nói về data binding tức là chúng ta muốn :
  • Khi user thay đổi giá trị của các input thì thuộc tính của people cũng thay đổi theo. Đây là chiều từ DOM tới Object.
  • Khi kịch bản làm cho thuộc tính của people thay đổi thì giá trị của các input cũng được thay đổi. Đây là chiều từ Object tới DOM.

Chiều thứ nhất: từ DOM tới Object

Để giải quyết việc đồng bộ từ DOM tới Object thì rất dễ vì có thể gắn event listener vào bất kỳ HTML element nào để lắng nghe. Chúng ta xử lý đoạn này trước bằng hàm domToObject như sau:

function domToObject(source, target, attribute){
  source.onchange = function(){
    var v = String(source.value);
    target[attribute] = v;
  }
}

Hàm này nhận vào 3 tham số, phần tử DOM đóng vai trò nguồn phát tín hiệu, đối tượng Javascript đóng vai trò tiếp nhận tín hiệu, và thuộc tính mà chúng ta muốn theo dõi. Bây giờ hãy thử cho kịch bản tự cập nhật các giá trị của đối tượng people khi bên ngoài input thay đổi:

 domToObject($firstName, people, 'firstName');
 domToObject($lastName, people, 'lastName');

Kết quả như thế này:

https://jsfiddle.net/ndaidong/76eadzth/15/

Các bạn thử thay đổi các giá trị trong inputs và nhấn button bên dưới để kiểm tra xem các thuộc tính của people đã được đồng bộ ra sao.

Chiều thứ 2: từ Object tới DOM

Bây giờ, chúng ta xét theo chiều ngược lại, từ Object tới DOM. Thời “xa xưa”, mọi thứ rất phức tạp. Hãy xem bài viết của Luca Ongaro cách đây 2 năm:

Easy Two-Way Data Binding in JavaScript

Nhưng bây giờ, với Object.observe, câu chuyện trở nên đơn giản hơn nhiều.

Đây là cách tôi xử lý, với một hàm objectToDom như sau:

function objectToDom(source, target, property){
  Object.observe(source, function(changes){
    changes.forEach(function(change){
      if(change.name === property){
        target.value = change.object[property];
      }
    });
  });
}

Hàm này cũng nhận vào 3 tham số, nhưng bắt đầu với source là một đối tượng Javascript, kế đó - target - là phần tử DOM móc nối với nó, và cuối cùng là property - tên thuộc tính mà chúng ta muốn nắm bắt sự thay đổi.

Kết quả như sau:

https://jsfiddle.net/ndaidong/76eadzth/16/

Trong demo, tôi để people tự thay đổi giá trị các thuộc tính firstNamelastName thành “Altonio” và “Vivaldi” sau vài giây. Các bạn có thể nhấn button để thay đổi chúng một cách ngẫu nhiên thành tên các tổng thống Mỹ ;)

Và đây là vấn đề chính: trong hàm objectToDom, tôi sử dụng Object.observe để theo dõi các biến đổi trên đối tượng Javascript.

Syntax của Object.observe như sau:

Object.observe(ob, callback);

Khi 1 hay một số thuộc tính của ob thay đổi, hàm callback sẽ được gọi cùng với tham số là một mảng chứa các thuộc tính đã thay đổi. Trên website của Mozilla có giải thích rất rõ về Object.observe.

Các ví dụ trong bài dùng để minh họa cách áp dụng data binding theo từng chiều ở mức độ cơ bản. Khi đưa vào thực tế, các bạn có thể cần bổ sung thêm các phương thức khác để testing, validating…

Now, hãy thử ghép chúng lại…

Đồng bộ 2 chiều

Dưới đây tôi sẽ xử lý cả 2 chiều cùng lúc bằng cách định nghĩa 1 đối tượng DataBinder như sau:

var DataBinder = (function(){

  var domToObject = function(source, target, attribute){
    source.onchange = function(){
      var v = String(source.value);
      target[attribute] = v;
    }
  }

  var objectToDom = function(source, target, property){
    Object.observe(source, function(changes){
      changes.forEach(function(change){
        if(change.name === property){
          target.value = change.object[property];
        }
      });
    });
  }

  var isElement = function(v){
    if(!!v && typeof v === 'object'){
      var ots = Object.prototype.toString;
      if(ots.call(v).indexOf('HTML') !== -1 && ots.call(v).indexOf('Element') !== -1){
        return true;
      }
    }
    return false;
  }     

  var start = function(source, target, attr){
    if(isElement(source)){
      domToObject(source, target, attr);
      objectToDom(target, source, attr);
    }
    else{
      objectToDom(source, target, attr);
      domToObject(target, source, attr);
    }
  }

  return {
    domToObject: domToObject,
    objectToDom: objectToDom,
    start: start
  }
})();

Như các bạn thấy, DataBinder có 3 public methods: domToObject, objectToDomstart dùng để tự động bind theo 2 chiều. Nhờ đó tôi chỉ việc gọi:

DataBinder.start(people, $firstName, 'firstName');
DataBinder.start(people, $lastName, 'lastName');

Hoặc có thể đảo thứ tự 2 tham số đầu tiên:

DataBinder.start($firstName, people, 'firstName');
DataBinder.start($lastName, people, 'lastName');

Dù thế nào, kết quả thu được vẫn như sau:

https://jsfiddle.net/ndaidong/76eadzth/17/

Cần nhắc lại, DataBinder như trên vẫn thiếu một vài thứ như exception handling, validation… Trong bài này, tôi chỉ muốn share concept của Object.observe và việc áp dụng nó trong two-ways data binding mà thôi.

Lời kết

Object.observe được mô tả trong ES7, hiện nay mới chỉ có trình duyệt Chrome hỗ trợ (33+). Nhưng polyfills của Jeremy Darling hoặc MaxArt2501 viết sẽ giúp bạn đem nó vào các trình duyệt khác. Chỉ việc load script từ CDN của Polyfills.io như cách tôi load vào JSFiddle.

Mong rằng qua những gì tôi đề cập trên đây, các fan mới của Javascript có thể hiểu được bản chất vấn đề data binding và có khả năng ứng dụng Object.observe vào thực tiễn.

Cảm ơn các bạn đã theo dõi bài viết này.

Những skills mới cho web developer 2015



Thế giới web năm 2015 sẽ có nhiều thay đổi mang tính cách mạng, dưới đây tôi điểm qua một số nét chính. Bên cạnh mỗi cái tên sẽ là chỉ số đánh giá mức độ cần kíp của skill đó - theo quan điểm cá nhân thôi :)


1. Web Components: 10/10


Web Components là một trong những thuật ngữ quan trọng nhất hiện nay. Nó bao gồm 4 khái niệm chính yếu: Custom Elements, HTML Imports, HTML TemplatesShadow DOM.

Với Web Components, khả năng của HTML và trình duyệt sẽ được mở rộng ra vô hạn. Đó là một thế giới web hoàn toàn mới, tràn đầy sức mạnh sáng tạo. Theo đó, web developers sẽ phải thay đổi quan niệm về cấu trúc hồ sơ DOM truyền thống, cấu trúc trang web, cũng như cấu trúc files/folders của hệ thống web. Có thể cách làm cũ ( viết trang HTML, nhúng các files CSS và JS vào) sẽ trở nên không còn hợp lý nữa. Thay vào đó, người ta cần tách ra nhiều components và phối hợp chúng lại thành trang web. Giống như cách chúng ta chia 1 mặt bằng ra nhiều mảnh cho nhiều nhà thầu đến xây dựng vậy. Quy trình làm web vì thế tất yếu cũng sẽ thay đổi theo. Mỗi component là 1 tổ hợp hoàn chỉnh của HTML, CSS và JavaScript được đóng gói trong 1 scope riêng biệt, có thể tương tác lẫn nhau nhưng không ảnh hưởng lẫn nhau. Hiện nay, nếu bạn nhúng cả jQuery 2.1 và jQuery 1.2 vào cùng trang web, sẽ chỉ có 1 thư viện chạy, và thế nào cũng có lỗi xuất hiện đâu đó. Nhưng với Web Components, bạn có thể dùng nhiều version của cùng library/framwork trên cùng trang web. No problem.

Trong tưởng tượng của tôi, tương lai có thể sẽ ra đời 1 dạng Web Components Market nơi các developers làm và bán components như là người ta đang bán Widgets và jQuery Plugins hiện nay vậy.

Angular 2 sẽ tận dụng khả năng của Web Components để xử lý lại một số vấn đề chưa tốt trong Angular 1.x như databinding, templating… Đặc biệt Tranclusion trong Angular 1 sẽ bị loại bỏ, thay vào đó Angular 2 sử dụng Shadow DOM.

Hiện có nhiều cách tiếp cận Web Components, như Polymer của Google, X-tags của Mozilla, và Bosonic. Hy vọng rằng tất cả rồi sẽ hợp lại trong 1 ecosystem thay vì cứ phân tán như vậy.

Theo đánh giá của tôi, Web Components là kiến thức bắt buộc phải có đối với front-end developer hiện nay.

2. ES6: 9/10


Đặc tả ECMA-262 biến JavaScript mà chúng ta đang dùng trở thành một thứ gì đó hoàn toàn mới lạ. Có lẽ không nhiều hơn 10% javascripter trên thế giới hiện nay đủ khả năng chơi với nó. Nhưng tôi tin rằng cho đến cuối năm, con số đó sẽ tăng lên hơn 50%. Hiện đã thấy nhiều framework cho Node.js và browser được viết trên đặc tả ES6, như WaigoJS, AureliaIO.js đã hỗ trợ ES6 ngay từ khi ra mắt.

Các chức năng nổi bật trong ES6 gồm arrow function, subclassable built-ins, và collections (Maps, Sets…) Những chức năng khác như classes, modules, module loaders, promises, proxies… thì những developers xông xáo chắc cũng đã làm quen trên Node.js hoặc thông qua các polyfills rồi. Bên cạnh đó, ES6 cũng thêm vào không ít methods cho các đối tượng dựng sẵn.

Angular 2 sẽ dùng ES6 Modules thay cho Angular Modules ở v1. Nếu bạn muốn tiếp tục theo đuổi Angular, bạn sẽ cần phải nghiên cứu sâu hơn về ES6.

3. TypeScript: 6/10


Lâu nay JavaScript vẫn bị các lập trình viên khó tính xem là ngôn ngữ không mạnh, và nguyên nhân chính là do nó thiếu những ràng buộc chặt chẽ về kiểu (type). TypeScript là JavaScript được mở rộng thêm khả năng định kiểu, modules, classes, interfaces, namespaces… vô cùng phức tạp chẳng kém gì các ngôn ngữ hệ thống. Tôi chưa thực sự dùng cái này nhưng nhìn code khá đẹp mắt, ở mức sơ đẳng thì cũng giống như khai báo schema trong Mongoose thôi!

Thoạt tiên tôi có ý nghĩ rằng những thứ này có thể làm hỏng tính đơn giản, linh hoạt của JavaScript. Nhưng nhìn sang PHP, phải chăng nó cũng đang đi cùng một hướng. Cả PHP và JavaScript đều bắt đầu như những ngôn ngữ scripting thuần túy, dần hoàn thiện theo thời gian để trở thành những ngôn ngữ lập trình chặt chẽ, powerful. Đặc biệt là khi JavaScript ngày nay không chỉ quanh quẩn trên browsers mà đã tràn lên cả servers và handset devices. Nó cần phải mạnh mẽ hơn, chắc chắn hơn để có thể làm chủ các vùng đất nhạy cảm đó.

TypeScript là 1 đóng góp đáng giá của Microsoft cho thế giới web. Các tác giả của Angular đã tạo ra AtScript cho Angular 2 nhưng sau cùng vẫn phải loại bỏ để dùng TypeScript. Tuy nhiên bạn không cần quá đặt nặng TypeScript lúc này. Nó chỉ đơn giản là syntax, dùng nhiều sẽ quen.

4. SystemJS: 10/10


Trong vài năm trở lại đây, module pattern trở thành khái niệm phổ biến nhất trong kiến trúc nền tảng JavaScript. Từ module pattern mới nảy sinh ra 2 khái niệm khác là AMD (Asynchronous Module Definition) và DI (Dependencies Injection). Đã có nhiều giải pháp cho vấn đề AMD như CommonJS, RequireJS, curl.js… Nhưng có vẻ đã đến lúc kết thúc cuộc đua, và tôi đoán rằngSystemJS sẽ thay thế tất cả, vì nó đi cùng ES6; làm việc với mọi compiler; tương thích mọi phương thức module loading cũ; hỗ trợ map, path, bundles… Thậm chí nó có thể thay thế cả lệnh require quen thuộc trên Node.js server.

AMD là khái niệm mà web developer phải nắm vững từ ít nhất 1 năm trước, bằng không bạn sẽ chỉ mơ hồ đứng sau các framworks mà không hiểu tại sao nó phải viết như thế, cái gì khiến nó phải tổ chức như thế… Nếu bây giờ bạn vẫn chưa vận dụng AMD được một cách tự nhiên thì phải lập tức khắc phục hạn chế này.

5. jspm: 10/10


Không phải bower, browserify… mà là jspm sẽ chấm dứt thời kỳ cát cứ phân tranh của các package management tools trên browsers. Tôi tin chắc điều đó vì jspm được thiết kế cho SystemJS, hỗ trợ mọi định dạng module từ RequireJS, CommonJS đến ES Harmony. Nếu các bạn để ý rằng bower chỉ làm 1 việc duy nhất là chạy lệnh ngầm tải repositories từ GitHub về thư mục bower_components ở local, thì jspm làm việc với cả GitHub và NPM, cho khả năng xử lý trùng lặp, version index, và tìm kiếm tốt hơn rất nhiều.

Tuy ít được biết đến như bower, nhưng jspm với sự tương thích SystemJS/ES6 chắc chắn sẽ trở thành giải pháp hoàn chỉnh cho vấn đề quản lý packages và dependencies trên front-end.

Trên đây là những kiến thức dành cho front-end developers mà tôi tin rằng sẽ vô cùng hot vào nửa cuối năm 2015. Sẽ rất tuyệt nếu các bạn để mắt đến chúng và thử trải nghiệm ngay từ bây giờ.



Links tham khảo:

Cài đặt NodeJS trên WebFaction server


NodeJS gần như là tùy chọn mặc định cho các web application hoạt động trên thời gian thực. Cài đặt và sử dụng NodeJS không khó, nhưng cài đặt lên các đám mây như AWS, Cloud9 IDE,  WebFaction, ModolusIO...  lại là những câu chuyện hoàn toàn khác. Mỗi hệ thống này được thiết kế một kiểu, cấu hình và platform của chúng khác nhau, phiên bản ứng dụng, ngôn ngữ cũng rất khác biệt.

Cái tôi cần là một server chạy NodeJS và có Forever để giữ nó chạy liên tục. Phải mất tới 3 tiếng mày mò, install và uninstall vài lần, tôi mới tạo được NodeJS server như ý muốn trên WebFaction. Lần đầu tiên, tôi clone thẳng repository của NodeJS từ GitHub về WebFaction, gói này đã có sẵn NPM nhưng khi cài đặt Forever bằng lệnh install của npm thì nhận được thông báo lỗi "shasum check failed" mà khá nhiều người gặp phải. Gỡ bỏ NPM và cài lại bằng gói chính thức cũng không ăn thua. Cài lại NodeJS bằng bản tar.gz, sau đó cài thêm NPM cũng gặp một số vấn đề khác. Sau cùng, tôi uninstall toàn bộ những gì đã cài đặt và thực hiện lại quá trình 4 bước rất đơn giản như sau :


1. Tạo application có port riêng

Từ WebFaction dashboard, tôi tạo 1 application mới để chạy dịch vụ NodeJS.

Ở đây tôi thiết lập app là Custom app (listening on port) để WebFaction mở ra một cổng cho NodeJS về sau.


Kết quả, tôi có một application mới với tên node. Chú ý cổng được cấp phát là 13166. NodeJS server sẽ nói chuyện với các clients qua cổng này.



2. Cài đặt NodeJS

Bây giờ, tôi mở command line và đăng nhập tài khoản WebFaction qua SSH, đưa con trỏ vào webapps/node, tạo thêm thư mục src để lấy source về cài đặt :

$ cd webapps/node/
mkdir src
cd src
curl http://nodejs.org/dist/node-latest.tar.gz | tar xz --strip-components=1
./configure --prefix=$HOME
make install

Note :

- Tham số --prefix=$HOME chỉ định hệ thống sao chép chương trình Node vào ~/bin/
- Cài đặt NodeJS yêu cầu phải có Python 2.6 trở lên. Gói account WebFaction của tôi được cấp phát máy chủ chạy Python 2.7, do đó không cần quan tâm đến vấn đề này. Một số tài khoản WebFaction khác chạy phiên bản Python cũ hơn yêu cầu sẽ phải dùng lệnh alias để fake thông số phiên bản Python. Các bạn có thể tham khảo chi tiết trong hướng dẫn của Akseli Palén trên StackOverflow.

Tiến trình cài đặt NodeJS của tôi chỉ diễn ra trong vài phút. Sau khi hoàn tất, tôi gõ lệnh node -v để kiểm tra lại phiên bản NodeJS. Mọi thứ suôn sẻ.


3. Cài đặt NPM

NPM là chương trình được thiết kế để quản lý các modules chạy trên server NodeJS. Đó là thứ không thể thiếu được. Tôi dùng dòng lệnh sau để cài đặt :

curl https://npmjs.org/install.sh | sh

Isaac hay ai đó ở Joyent đã thay đổi giao thức HTTP cũ bằng  HTTPS. Một số hướng dẫn trên mạng dùng đường dẫn trước đây sẽ không chạy.


4. Cài đặt Forever

Với NodeJS, chúng ta thường chạy nó qua command line, nhưng khi đóng cửa sổ command line, server sẽ tắt. Để giữ NodeJS server chạy suốt, người ta thường sử dụng một daemon tool nào đó hỗ trợ tự động kiểm tra và kích hoạt lại NodeJS server khi bị tắt ngoài ý muốn. Forever được tạo ra để duy trì trạng thái running của server NodeJS. Đã có NPM, việc cài đặt Forever rất đơn giản :

npm install -g forever


Kết quả cuối cùng như hình dưới. Không có error nào cả :D



Vậy là xong, mọi thứ đã sẵn sàng để tôi build các ứng dụng NodeJS trên WebFaction server của tôi.


Lập trình dựa trên nguyên mẫu

Thừa kế (inheritance) là khái niệm chủ đạo trong lập trình hướng đối tượng (OOP). Đây cũng là thứ để lại nhiều câu chuyện thú vị nhất trong bộ môn "Javascript học".

Thoạt tiên, người ta cho rằng Javascript không phải là một ngôn ngữ hướng đối tượng, mặc dù trong lõi của Javascript có sẵn một đối tượng tên là Đối tượng (Object). Tại sao? Vì khi nhìn bằng quan điểm OOP truyền thống, người ta không thấy trong Javascript những đặc tính của một ngôn ngữ hướng đối tượng, như : đa hình (polymorphism), đóng gói (encapsulation ) và thừa kế (inheritance). Nhìn vào những phiên bản Javascript đầu tiên, có thể nói rằng Javascript không phải là một ngôn ngữ OOP "bẩm sinh".

May mắn thay, các nhà Javascript học tiên phong đã bước vào thế kỷ XXI với một loạt những khảo sát giá trị về ngôn ngữ này. Cho đến giữa thập kỷ trước, hàng loạt sản phẩm mới ra đời tận dụng một cách triệt để các thế mạnh của Javascript phía client như GMail, GMap... và bên cạnh đó là Firefox, mở đầu cho một thế hệ trình duyệt mới, mạnh mẽ và thông minh. Cộng đồng Mozilla, cũng như các nhà phát triển của AOL, Google, Yahoo!... từ lúc đó, đã nhìn thấy nơi Javascript bóng dáng một ngôn ngữ  lập trình của tương lai. Netscape vứt bỏ hẳn khái niệm applet/embed để tập trung vào nâng cấp Javascript engine. Hai tổ chức về chuẩn web và ngôn ngữ lập trình là  W3C và ECMA giữ vai trò cầm cân nẩy mực phía sau việc chuẩn hóa Javascript. Với sự hậu thuẫn từ rất nhiều thế lực Internet như vậy, Javascript đã ngày càng trở nên hoàn thiện.

Qua loạt bài dịch này, tôi sẽ kể lại câu chuyện về thừa kế trong Javascript, những phương pháp khắc phục hạn chế OOP mà những người yêu thích Javascript thời trước sáng tạo ra, và phương thức hỗ trợ thừa kế trong Javascript sẽ xuất hiện thời gian tới...

Nhưng trước hết, chúng ta hãy cùng tìm hiểu thế nào là lập trình dựa trên nguyên mẫu (prototype-based programming) qua một topic trên Wikipedia.


Lập trình dựa trên nguyên mẫu


Lập trình dựa trên nguyên mẫu (prototype) là phương pháp lập trình hướng đối tượng mà ở đó người ta không sử dụng các class (lớp). Thay vì thừa kế thuộc tính và phương thức của lớp cha như trong các ngôn ngữ dựa trên class, việc dùng lại phương thức và thuộc tính trong lập trình prototype được xử lý bằng cách sao chép một đối tượng có sẵn đóng vai trò nguyên mẫu. Mô hình này cũng được gọi bằng những cái tên khác như lập trình khử class, lập trình hướng nguyên mẫu, lập trình dựa trên hiện thể, hoặc lập trình thừa kế theo phương ngang (1). Ủy quyền (delegation) là điểm đặc trưng của các ngôn ngữ hỗ trợ lập trình prototype.


Ngôn ngữ lập trình dựa trên prototype đầu tiên xuất hiện là Self, được hai tác giả David Ungar và Randall Smith phát triển vào khoảng giữa những năm 1980 khi  nghiên cứu các chủ đề về thiết kế ngôn ngữ lập trình hướng đối tượng. Đến cuối những năm 1990, các mô hình khử class đã ngày càng mở rộng ra đại chúng. Một vài ngôn ngữ lập trình hướng prototype ngày nay là JavaScript (cùng với những bổ sung khác của ECMAScript, JScript và Flash's ActionScript 1.0), Cecil, NewtonScript, Io, MOO, REBOL, và Lisaac.

So sánh với các mô hình dựa trên class

Trong các ngôn ngữ dựa trên class, cấu trúc của các đối tượng được chỉ định theo những khuôn dạng do lập trình viên định nghĩa, gọi là các lớp (class). Trong khi class định nghĩa kiểu dữ liệu và chức năng mà đối tượng sẽ có, các hiện thể là những đối tượng "đem dùng được" (2) dựa trên bộ khung phương thức/thuộc tính của một class riêng biệt. Trong mô hình này, class có tác dụng như một tập hợp các ứng xử (phương thức) và cấu trúc đồng nhất cho mọi hiện thể, còn các hiện thể đem theo dữ liệu của đối tượng. Sự phân biệt vai trò do đó chủ yếu căn cứ vào một bên là sự phân biệt giữa cấu trúc và ứng xử, còn một bên là trạng thái.

Những người bênh vực lập trình dựa trên prototype thường lập luận rằng các ngôn ngữ dựa trên class khuyến khích một mô hình phát triển tập trung trước hết vào sự phân loại các quan hệ giữa những class với nhau, trong khi trái lại, lập trình dựa trên prototype có vẻ như khuyến khích lập trình viên tập trung vào ứng xử của một đối tượng nào đó và chỉ tính đến chuyện phân nhóm chúng khi các đối tượng sau đó dùng lại  theo cách thức giống như khi dùng class.  

Tương tự thế, nhiều ngôn ngữ dựa trên prototype khuyến khích việc sửa đổi nguyên mẫu khi đang thực thi chương trình, điều mà hiếm hệ thống hướng đối tượng dựa trên class nào cho phép, ngoại trừ Common Lisp, Dylan, Smalltalk, Objective-C, Python, Perl, hay Ruby. Hầu hết các ngôn ngữ lập trình dựa trên prototype đều là thông dịch và định kiểu động. Mặc dù về khía cạnh kỹ thuật, các ngôn ngữ định kiểu tĩnh cũng tiện dụng không kém.

Ngôn ngữ Omera được nhắc đến trong bài này là một ví dụ. Xem qua website của Omega thì nó không phải là ngôn ngữ định kiểu tĩnh hoàn toàn, bởi lẽ "trình biên dịch có thể chọn sử dụng ràng buộc tĩnh khi cần thiết sao cho tối ưu hiệu suất chương trình."

Xem phần "Phê bình" để thấy những so sánh khác nữa.

Sự kiến tạo đối tượng

Trong các ngôn ngữ dựa trên class, một hiện thể mới được sinh ra nhờ một hàm kiến tạo (3) của class. Hàm kiến tạo là một hàm đặc biệt có nhiệm vụ cấp phát một block bộ nhớ cho các thành viên của đối tượng (thuộc tính/phương thức) và trả về tham chiếu tới block đó. Khi gọi hàm kiến tạo, có thể  truyền vào một tập  tham số tùy chọn và dùng các thuộc tính để lưu giữ chúng. Hiện thể sinh ra sẽ thừa kế tất cả các phương thức và thuộc tính được định nghĩa trong lớp và hành xử giống như tất cả những hiện thể khác sản sinh ra từ cùng một lớp đó.

Trong các ngôn ngữ dựa trên prototype không có các lớp rõ ràng. Các đối tượng thừa kế trực tiếp từ đối tượng khác với những gì mà chúng liên kết với nhau thông qua một thuộc tính, thường gọi là prototype như trong trường hợp Javascript. Có hai cách để tạo đối tượng mới: đó là tạo mới hoàn toàn (4)  hoặc sao chép từ một đối tượng có sẵn.

Có một số hình thái của đối tượng theo nghĩa đen giúp tạo ra đối tượng mới hoàn toàn, những khai báo nơi mà đối tượng được định nghĩa vào lúc chương trình đang chạy, nhờ các cú pháp đặc biệt như {...} gán thẳng vào một biến. Trong khi hầu hết các ngôn ngữ đều hỗ trợ một cách sao chép, không có gì đáng nói về việc tạo ra một đối tượng mới từ rỗng.

Các ngôn ngữ hỗ trợ tạo đối tượng rỗng cho phép những đối tượng mới được tạo ra mà không cần sao chép từ nguyên mẫu sẵn có. Chúng cung cấp một cú pháp đặc biệt để chi định những thuộc tính và hành xử của đối tượng mới mà không cần tham chiếu đến những đối tượng có sẵn.
Trong nhiều ngôn ngữ prototype có một đối tượng trực thuộc đối tượng gốc thường gọi là Object, Đối tượng này được cài đặt như nguyên mẫu mặc định cho mọi đối tượng sinh ra khi chương trình đang chạy và mang theo những phương thức phổ dụng cần thiết như toString để trả về chuỗi mô tả của đối tượng. Một khía cạnh hữu ích của việc tạo ra đối tượng rỗng là để đảm bảo rằng tên của các đối tượng mới tạo ra không bị đụng chạm với đối tượng Object ở tầng cao nhất. (Trong bản sửa đổi Javascript của Mozilla, người ta có thể làm điều này bằng cách thiết lập giá trị null cho thuộc tính  __proto__ của đối tượng mới tạo ra).

Bản sao của đối tượng tham chiếu tới tiến trình nơi mà qua đó nó được kiến tạo bằng cách sao chép các phương thức của một đối tượng sẵn có (nguyên mẫu của nó). Đối tượng mới mang theo mọi đặc tính của đối tượng gốc. Từ điểm này, đối tượng mới có thể được hiệu chỉnh. Trong một vài ngôn ngữ, đối tượng phái sinh duy trì một kết nối trực tiếp với nguyên mẫu của nó và những thay đổi trong nguyên mẫu sẽ kéo theo những thay đổi tại bản sao. Những ngôn ngữ khác, như Kevo, một ngôn ngữ lập trình Forth-like, không ánh xạ những thay đổi từ nguyên mẫu sang bản sao theo cách này mà hướng đến một mô hình liên thông tự nhiên hơn nơi mà những thay đổi trong đối tượng được sao chép không tự động ánh xạ tới các thế hệ bản sao kế tiếp của chúng.

// Example of true prototypal inheritance style
// in JavaScript.

// "ex nihilo" object creation using the literal
// object notation {}.
var foo = {name: "foo", one: 1, two: 2};
// Another "ex nihilo" object.
var bar = {two: "two", three: 3};

// Gecko and Webkit JavaScript engines can directly
// manipulate the internal prototype link.

// For the sake of simplicity, let us pretend
// that the following line works regardless of the

// engine used:
bar.__proto__ = foo; // foo is now the prototype of bar.

// If we try to access foo's properties from bar
// from now on, we'll succeed.
bar.one // Resolves to 1.

// The child object's properties are also accessible.
bar.three // Resolves to 3.

// Own properties shadow prototype properties
bar.two; // Resolves to "two"

foo.name; // unaffected, resolves to "foo"
bar.name; // Resolves to "foo"

Ví dụ sau viết với Javascript 1.8.5 + (xem thêm : http://kangax.github.io/es5-compat-table/)

var foo = {one: 1, two: 2};
// bar.[[ prototype ]] = foo
var bar = Object.create( foo );
bar.three = 3;
bar.one; // 1
bar.two; // 2
bar.three; // 3

Sự ủy quyền (Delegation)

Các ngôn ngữ dựa trên prototype luôn sử dụng cơ chế ủy quyền. Chương trình khi thực thi có thể gửi đi phương thức chính xác hóa hoặc tìm kiếm phần dữ liệu cần thiết theo một loạt các con trỏ ủy quyền (từ đối tượng tới nguyên mẫu của nó) cho tới khi tìm thấy so khớp. Điều này yêu cầu thiếp lập chia sẻ phương thức giữa các đối tượng với con trỏ ủy quyền. Không giống quan hệ giữa lớp với hiện thể trong các ngôn ngữ OOP dựa trên lớp, quan hệ giữa nguyên mẫu với mỗi nhánh của nó không yêu cầu đối tượng phải đồng nhất về cấu trúc hoặc vùng bộ nhớ, ngoại trừ liên kết ủy quyền nói trên. Như vậy, đối tượng phái sinh có thể tiếp tục được hiệu chỉnh và sửa đổi qua thời gian mà không cần sắp xếp lại cấu trúc nguyên mẫu liên đới như trong các ngôn ngữ dựa trên class. Cũng cần chỉ ra rằng không chỉ dữ liệu mà cả các phương thức cũng có thể thêm vào hoặc thay đổi được. Vì lý do này, một vài ngôn ngữ hướng prototype coi dữ liệu và phương thức như các "slots" hoặc "members".

Sự liên thông (Concatenation)

Nhìn vào mô hình lập trình dựa trên prototype thuần túy, cũng như các tham khảo về mô hình prototype liên thông và ví dụ đưa ra trong ngôn ngữ Kevo, không có con trỏ hoặc liên kết tới nguyên mẫu gốc từ một đối tượng được sao chép. Đối tượng nguyên mẫu (cha) thiên về một bản sao hơn là một liên kết tham chiếu. Kết quả là sự thay đổi trong nguyên mẫu sẽ không tác động gì đến các bản sao.

Khác biệt chính mang tính khái niệm dưới trật tự này là các thay đổi được thực hiện trên đối tượng nguyên mẫu không bị đem sang các bản sao. Có thể nhìn nhận điều này như ưu điểm hoặc hạn chế. (Dù sao Kevo cung cấp các bản gốc thêm vào để cho phép mang những thay đổi sang các tập đối tượng dựa vào sự giống nhau của chúng - do đó gọi là "family resemblances" (tương đồng quyến thuộc) - hơn là thông qua sự phân loại nguồn gốc, như đặc thù trong mô hình ủy nhiệm. Đôi khi người ta cũng cho rằng mô hình nguyên mẫu dựa trên ủy quyền có một bất lợi ở chỗ các thay đổi trên đối tượng con có thể ảnh hưởng đến sự hoạt động của đối tượng cha sau đó. Dù vấn đề này không phải là cố hữu đối với mô hình nguyên mẫu dựa trên ủy quyền và không tồn tại trong các ngôn ngữ dựa trên ủy quyền, như Javascript, có sự đảm bảo các thay đổi ở đối tượng con luôn được lưu lại trong chính nó và không bao giờ ảnh hưởng tới đối tượng cha (ví dụ giá trị của đối tượng con làm nhạt giá trị của đối tượng cha hơn là thay đổi nó).

Trong các bổ sung chú trọng tính đơn giản, mô hình prototype liên thông dò tìm thành viên nhanh hơn mô hình ủy nhiệm (vì không cần đi theo chain của đối tượng cha), nhưng ngược lại nó cũng tốn bộ nhớ hơn vì tất cả các thành viên đều được copy ra thay vị hiện diện như một đơn thể tham chiếu tới đối tượng cha. Các bản bổ sung phức tạp hơn có thể không bị những vấn đề này nhưng nhìn chung vẫn là một cuộc đổi chác giữa tốc độ và lượng bộ nhớ cần sử dụng. Ví dụ, các ngôn ngữ nguyên mẫu ràng buộc có thể sử dụng một bổ sung copy-on-write (5) để cho phép chia sẻ dữ liệu ở hậu cảnh - đây cũng là hướng tiếp cận của Kevo.  Ngược lại, các ngôn ngữ với nguyên mẫu dựa trên cơ chế ủy quyền có thể sử dụng cache để tăng tốc truy vấn dữ liệu.

Lời bình

Có thể thấy rằng những người ủng hộ mô hình class thường có xu hướng phê bình các ngôn ngữ prototype trên một số điểm tương tự như những gì mà phe chủ chương định kiểu tĩnh phê bình các ngôn ngữ định kiểu động. Thông thường là về tính chính xác, sự chắc chắn, khả năng tiên liệu, hiệu quả chương trình và mức độ thân thiện đối với lập trình viên.

Ở ba điểm đầu tiên, các class thường được xem như giống nhau về kiểu (chúng đáp ứng vai trò đó trong hầu hết các ngôn ngữ lập trình hướng đối tượng định kiểu tĩnh) và được đề xuất đề cung cấp một cách chính xác cho các hiện thể của chúng cũng như để người dùng các hiện thể này khu xử chúng theo một vài kiểu cách cho trước.

Liên quan đến tính hiệu quả, khai báo các lớp đơn giản hóa sự tối ưu  trình biên dịch mà cho phép phát triển khả năng tìm kiếm phương thức và thuộc tính của hiện thể hiệu quả. Như Self, phần lớn thời gian phát triển dùng vào các kỹ thuật phát triển, biên dịch và thông dịch để tăng cường hiệu suất cho các ngôn ngữ prototype trên cơ sở so sánh với các ngôn ngữ dựa trên class.

Một chỉ trích phổ biến nhằm vào các ngôn ngữ dựa trên prototype là thiếu tính thân thiện đối với cộng đồng phát triển phần mềm, bất chấp tính đại chúng và sức lan tỏa sâu rộng của Javascript.

Cấp độ hiểu biết về các ngôn ngữ prototype xem ra đang có chiều hướng thay đổi nhờ vào sự tăng trưởng của các framework Javascript và đang nâng cao hơn nữa theo sự ứng dụng Javascript phức tạp trong giai đoạn chín muồi của Web 2.0.


Nguồn : Prototype-based programming, Wikipedia.
___________________________________________


Chú thích :


1. Horizontal inheritance programming : khái niệm này không được nhắc đến trong bài gốc, người dịch bổ sung thêm cho đủ ý.
2. Nguyên văn : "usable" objects. Sở dĩ nói như vậy vì trong các ngôn ngữ dựa trên class, người ta thường phải gọi phương thức của class một cách gián tiếp qua hiện thể thay vì gọi trực tiếp đến class. Ngược lại, trong các ngôn ngữ lập trình dựa trên prototype, nguyên mẫu hay đối tượng gốc  cũng chỉ là đối tượng.
3. Nguyên văn : constructor function. Các tác giả Việt Nam thời trước thường dịch là "hàm dựng". Ngày nay nghe hai chữ "hàm dựng" có vẻ hơi tối nghĩa.
4. Nguyên văn : ex nihilo object creation. Ý là việc tạo ra đối tượng từ chỗ không có gì cả. Cụm từ Latin "ex nihilo" có nghĩa là từ trong cái trống rỗng, từ hư không. Xem chi tiết.
5. Copy-on-write : viết tắt COW, một biện pháp tối ưu hóa sử dụng trong lập trình. Xem chi tiết.