Eclipse tại eBay, Phần 1: Làm cho Eclipse thích ứng với kiến trúc của eBay

Một người trong cuộc giải thích cách eBay sử dụng Eclipse và các trình cắm thêm tùy chỉnh để xây dựng thế hệ kế tiếp của trang Web bán đấu giá khổng lồ như thế nào.

Điều đầu tiên tạo nên danh tiếng của Eclipse đó là Eclipse là một môi trường phát triển tích hợp (IDE) cho công nghệ Java™. Kiến trúc cắm thêm của Eclipse là lý do quan trọng cho thành công của sản phẩm này. Có nhiều trình cắm thêm phổ biến sẵn có và bạn cũng rất dễ dàng tạo ra chúng cho riêng mình. Hai đặc tính này làm cho Eclipse trở nên phù hợp một cách hoàn hảo với các hệ thống có các kiến trúc chuyên dụng, ví dụ như eBay. Trong bài viết này, phần đầu tiên của loạt bài báo gồm hai phần về cách eBay sử dụng Eclipse, chúng ta sẽ xem kiến trúc của eBay và cách eBay làm cho Eclipse phù hợp với kiến trúc của nó như thế nào. Bài báo này sẽ tập trung vào eBay, nhưng bạn có thể sử dụng các bài học ở đây để làm cho Eclipse phù hợp với kiến trúc của hệ thống của bạn.

Michael Galpin, Kiến trúc sư phần mềm, Ludi Labs

Michael Galpin đã phát triển phần mềm Java một cách chuyên nghiệp từ năm 1998. Ông hiện đang làm việc cho eBay. Ông đã có bằng về toán học của Viện Công nghệ California.



13 06 2009

Bài báo này giả thiết bạn đã có các hiểu biết sơ bộ về Eclipse. Chúng ta sẽ nói về Môi trường phát triển eBay (EDE), được dựa trên nền Eclipse V3.2 và yêu cầu phải có JDK phiên bản V5.0 hay mới hơn (xem mục Tài nguyên để lấy đường kết nối). Nếu bạn có hiểu biết nhất định về phát triển Web, bao gồm HTML, JavaScript và CSS thì tốt, nhưng không bắt buộc.

Eclipse được biết đến vì nó là một IDE cho Java với một hệ thống plug-in lớn. Bản phát hành Eclipse V3.3 (Europa) của Eclipse mang theo một số bản phân phối chuyên dùng của Eclipse. Chúng bao gồm Eclipse dành cho các nhà phát triển Java và Eclipse dành cho các nhà phát triển Java EE. Ngoài ra, bạn có thể sử dụng bộ công cụ phát triển C/C++ (CDT) của Eclipse và bộ công cụ phát triển PHP (PDT) của Eclipse.

Tất cả những bản phân phối này chỉ đơn giản là nền tảng cơ sở của Eclipse cộng với một tổ hợp nào đó của các trình cắm thêm. Đó chính là vẻ đẹp của Eclipse. Thậm chí tất cả những công cụ phát triển Java thông thường mà đa số mọi người cho là một bộ phận không thể tách rời của Eclipse thực sự chỉ là các trình cắm thêm. Nếu bạn đang phát triển PHP, thì rốt cuộc bạn không cần phải bận tâm tới trình xây dựng Java. Java, C++, và PHP đều là các ngôn ngữ lập trình và như vậy bản thân chúng là các đề tài khá rộng. Tuy nhiên, hệ thống của bạn bị ràng buộc phải có một số nhu cầu chuyên biệt, khác với hệ thống khác nào đó, sử dụng cùng ngôn ngữ lập trình.

Phải chăng IDE của bạn cũng nên chuyên dùng giống như hệ thống của bạn? Đây là triết lý nằm đằng sau Eclipse, và đây chính là nguyên lý được dùng ở eBay để tạo ra EDE trên nền Eclipse. Chúng ta hãy xem kiến trúc của eBay để chúng ta có thể hiểu các nhu cầu đặc biệt của nó và cách eBay sử dụng Eclipse như thế nào để thỏa mãn các nhu cầu đó.

Kiến trúc của eBay

Có thể viết nguyên một cuốn sách chỉ để mô tả các khía cạnh của kiến trúc và lịch sử của eBay. Bài báo này sẽ tập trung vào kiến trúc trình bày của eBay, nó đã phát triển như thế nào và các nhu cầu đặc biệt mà eBay đã giải quyết khi sử dụng nền tảng Eclipse. Chúng ta sẽ lướt nhanh lịch sử về kiến trúc của eBay để hiểu được các thách thức mà kiến trúc hiện tại đã phải giải quyết.

Lịch sử

Đầu tiên eBay được khai trương với tên là AuctionWeb vào 1995. Trang web đầu tiên được viết bằng Perl. Vì rằng trang Web lớn lên, nên nó được viết lại bằng C++ ở mặt sau (back end) còn mặt trước (front end) thì sử dụng XSL. Việc sử dụng XSL để sinh ra HTML là rất hiện đại vào cuối những năm 1990. eBay được cổ phần hóa vào năm 1998 và tiếp tục phát triển mạnh với sự tăng trưởng theo hàm mũ.

Sức ép tăng lên liên tục của lưu lượng truyền thông bắt buộc phải viết lại trên quy mô lớn phần mặt sau của eBay bằng ngôn ngữ lập trình Java, bắt đầu vào năm 2001. Kiến trúc mặt trước không thay đổi. Kiến trúc Java + XSL được nói đến trong nội bộ như là kiến trúc V3, Perl là V1 và C++/XSL là V2. Kiến trúc V3 tỏ ra có khả năng co dãn trên quy mô rộng, cho phép eBay lớn lên tới kích thước hiện thời của nó, trở thành một trang web có nhiều người xem nhất thế giới. Nó không chỉ là một trang Web có lưu lượng truyền thông cao mà còn là trang web có số lượng giao dịch cao với hàng triệu người chào hàng, đặt giá và mua các mục hàng trên nhiều nước trên khắp thế giới. Tất nhiên, không có giải pháp nào là hoàn hảo, và đây là điều đặc biệt đúng đối với một hệ thống đang liên tục phát triển như là eBay.

Thách thức

Từ một phối cảnh mặt sau, kiến trúc V3 khắc phục một số vấn đề hóc búa nhất mà một ứng dụng Web có thể đặt ra. Từ một phối cảnh dữ liệu thuần túy, eBay có thể được mô tả như một hệ thống có một số lượng khổng lồ các thao tác viết cũng như các thao tác đọc xảy ra liên tục với một dung sai cho lỗi hay cho sự không nhất quán vô cùng thấp. Sau hết, ở đây chúng ta đang nói về tiền của mọi người. Không quá nhiều người sẽ chú ý hay tức giận vì những thiếu sót trong các chỉ mục tìm kiếm hay bộ kết tập tin tức, nhưng đa số mọi người sẽ chú ý ngay lập tức đến một lỗi khi nó xảy ra cho món tiền mà họ đã đặt giá trong một vụ bán đấu giá. Tương tự như vậy, có thể chấp nhận được nếu lượng thời gian cần để nhận được một thư điện tử hay tin nhắn tức thời là khó dự đoán, nhưng người ta muốn biết ngay lập tức liệu họ đã trả giá cao hơn trong một vụ bán đấu giá. Kiến trúc V3 giải quyết các vấn đề cực kỳ hóc búa này, nhưng có nhiều vấn đề mặt trước rất khó mà bạn cũng phải đối mặt khi bạn thành công như eBay.

Lấy ví dụ, khi bạn có một trang Web lớn, đang phát triển rộng ra, thì điều bình thường như việc quản lý tất cả những ảnh trên trang web đó có thể trở nên khá phức tạp. Giả sử bạn muốn “dọn dẹp nhà cửa” và xóa một ảnh. Làm sao bạn có thể biết được nó có vẫn đang còn được sử dụng hay không? Trong một hệ thống dựa trên nền XSL, toàn bộ cái mà bạn có thể làm là tìm kiếm trong hàng triệu dòng XSL (hàng triệu dòng văn bản). Thậm chí làm như vậy có thể vẫn chưa đầy đủ vì XSL có thể dễ dàng nối các chuỗi với nhau, vì vậy chuỗi cuối cùng biểu diễn ảnh có thể không còn nguyên một khối nữa. Điều này không chỉ đúng với XSL mà còn đúng với bất kỳ kiến trúc mặt trước nào dựa trên nền văn bản hay kịch bản lệnh.

Hình ảnh chỉ là đỉnh của núi băng trôi. Vì eBay đã hiện đại hóa, nó đã sử dụng ngày càng nhiều hơn các phiếu định kiểu xếp chồng nhau (Cascading Style Sheets - CSS). Thông thường sẽ hiệu quả hơn khi tách các CSS ra thành một tệp tin ngoài riêng của nó, hơn là điền trực tiếp thành các dòng (in-line) trong một trang web, vì các bộ duyệt có thể ghi nhớ sẵn (cache) nó. Thậm chí còn tốt hơn nữa nếu bạn có thể sử dụng lại các tệp tin CSS này chung cho nhiều trang, vì một lần nữa bạn được lợi từ việc ghi nhớ sẵn (caching) của trình duyệt. Nhưng giả sử bạn cần thay đổi một kiểu trình bày của một trang. Bạn sẽ nói gì nếu thay đổi này sẽ tác động đến trang khác? Kịch bản trên đây cũng có thể xảy ra với JavaScript.

Đã bao giờ bạn từng di chuyển một trang trong một điểm web ? Bạn cần phải chắc chắn rằng bạn đã sửa đổi tất cả đường liên kết tới trang đó. Bây giờ bạn hãy tưởng tượng đang làm điều đó với một điểm web có kích thước như eBay. Một lần nữa, bạn bị mắc kẹt khi phải khởi chạy việc tìm kiếm văn bản trên quy mô lớn để tìm tất cả các thể hiện của các chuỗi ký tự biểu diễn các mối liên kết này.

Bạn có nhớ khi nào các cổng Web (portal) bắt đầu trở nên phổ biến? Theo nhiều khía cạnh, chúng là tiền thân của các mớ hỗn độn hiện đại — một loại hỗn độn cục bộ. Các trang web theo kiểu cổng web bao gồm nhiều phần tử từ các trang khác, và thông thường đó là các CSS và JavaScript. Bây giờ bạn bước vào vùng có khả năng xung đột: cùng một tiêu đề giống như tên kiểu dáng, có thể được dùng tại nhiều chỗ, nhưng với những giá trị khác nhau. Tương tự như thế, các hàm hay các biến JavaScript giống nhau có thể được định nghĩa tại nhiều chỗ khác nhau. Thậm chí dù không có xung đột, bạn vẫn còn có thể gặp sự sao đúp, khi mà đúng dữ liệu đó (CSS hay JavaScript) xuất hiện hai, ba lần hoặc nhiều hơn trên một trang. Các loại vấn đề này không dễ dàng được giải quyết bằng cách sử dụng kiến trúc mặt trước dựa trên nền tảng XSL cũ của eBay. Bạn phải dựa vào các tìm kiếm văn bản.

Sau cùng, có lẽ vấn đề lớn nhất đó là sự địa phương hóa. Một trang Web toàn cầu như eBay được dịch ra hơn 30 ngôn ngữ. Thậm chí chỉ trên mặt bề ngoài, một hệ thống dựa trên nền XSL yêu cầu mọi tệp tin XSL phải được địa phương hóa. Có lẽ bạn đã cười tự mãn khi nghĩ rằng: "Chỉ cần sử dụng các tệp tin thuộc tính như ResourceBundles của Java." Bạn nghĩ lại đi. Bạn tính như thế nào đối với các văn bản trong một số ngôn ngữ có phân biệt danh từ giống đực-giống cái (gender-specific)? Hay thậm chí là biến đổi số ít sang số nhiều, ví dụ như số ít "Có 1 người bỏ thầu” (There is …) sang số nhiều "Có 2 người bỏ thầu” (There are …). Các hình ảnh phải được địa phương hóa như thế nào ? Làm thế nào khi bản địa hóa mà cần đến các thẻ đánh dấu khác nhau (chẳng hạn như vị trí đặt một mối liên kết bên trong một câu) cho các địa phương khác nhau ?

Tất cả những nhân tố này bắt buộc eBay phải địa phương hóa từng tệp tin XSL. Bạn đừng quên rằng XSL là mã, vì vậy một điều bình thường như việc thay đổi cách dùng một từ trên một trang yêu cầu một phiên bản mã mới để được chuyển tới hàng nghìn máy chủ.

Ít trang Web gặp phải những vấn đề này. Và vì thế không ngạc nhiên rằng không có một khung công tác mã nguồn mở nào giải quyết tất cả những vấn đề ấy. eBay cần phải xây dựng một công cụ rất thông minh, rất chuyên dụng. Và đó chính xác là cái mà nó đã làm.

V4

Vì eBay đã giải quyết một số vấn đề phức tạp về quy mô với kiến trúc V3, nó xúc tiến giải quyết bài toán khó về tính co giãn quy mô thuộc mặt trước với một kiến trúc mặt trước mới có tên là V4. Kiến trúc V4 sử dụng cách tiếp cận biểu diễn mọi thứ sẽ được sử dụng tại mặt trước bằng những đối tượng Java được định kiểu mạnh ở mặt sau. Trang web của bạn có sử dụng một hình ảnh? Thế thì có một đối tượng Java dành cho hình ảnh này. Nếu bạn muốn xóa hình ảnh này, thì điều này cũng đơn giản như (hay cũng phức tạp như) xóa mọi lớp Java khác. Có thể nói hoàn toàn tương tự đối với các mối liên kết, CSS và JavaScript. V4 không sử dụng servlets hay JSPs để tạo ra HTML. Thay vào đó, HTML DOM thực tế được biểu diễn trong ngôn ngữ Java, vì vậy bạn có thể buộc CSS và JavaScript cùng nhau trên một máy chủ.

Vấn đề hóc búa nhất là gì: nội dung ư? Hệ thống nội dung của V4 là duy nhất và mạnh. Nó sử dụng ngôn ngữ dựa trên nền tảng XML của riêng mình để tạo ra những giao kèo (contract) về nội dung. Việc lựa chọn dùng từ giao kèo là có chủ ý. Các giao kèo xác định loại dữ liệu cần có để tạo ra bất kỳ biến đổi nào của một mẩu (đơn vị) nội dung. Ta lấy ví dụ, một đơn vị nội dung cụ thể có thể cần một số nguyên và một chuỗi ký tự trong tiếng Anh (Ví dụ như "Raymond có 4 ô tô "), nhưng nó lại cần hai số nguyên và một chuỗi ký tự trong ngôn ngữ khác. Cũng có thể có nhiều biến thể dành cho giống (đực/cái) và số (ít/nhiều). Các giao kèo định nghĩa tất cả những thứ này bằng XML. Rồi sau đó các giao kèo được thực hiện trong mỗi ngôn ngữ được hỗ trợ bởi một ứng dụng/ trang/ thành phần cụ thể. Và tất nhiên nó phải được biểu diễn như một đối tượng được định kiểu mạnh trong Java, đối tượng này yêu cầu tất cả là dữ liệu động (ví dụ như "Raymond" và "4" ở trên) phải được cung cấp theo trật tự mà nó được sử dụng. Vì rằng mọi thứ liên quan là các đối tượng Java được định kiểu mạnh, mọi thứ đều bị bắt buộc tuân thủ tại thời gian biên dịch. Nếu một nhà phát triển ứng dụng không cung cấp hai tham số đó trong mã Java của mình, thì mã sẽ không biên dịch được.

Tất cả các biểu diễn của Java về tất cả mọi thứ nghe có vẻ hay trên giấy. Tuy nhiên, bạn có thể hình dung rằng chúng có thể tạo ra một gánh nặng nếu bạn phải viết một lớp Java mới mỗi khi bạn muốn sử dụng một hình ảnh hay JavaScript nào đó trên một trang. Đây là chỗ mà Eclipse can thiệp vào.


Eclipse và V4

Bây giờ chúng ta hiểu được không gian vấn đề và giải pháp ta mong muốn, chúng ta có thể thấy Eclipse đã giúp đỡ eBay thực hiện giải pháp như thế nào. Nhiều mã được mô tả ở trên — mã để biểu diễn các hình ảnh, các mối liên kết, các kiểu dáng và JavaScript — có thể được cho là mã bản mẫu (boilerplate), hay ít nhất từng phần là mã bản mẫu. Đây là bài toán chung của các khung công tác. Chúng yêu cầu một số kiểu mã mà chủ yếu là các khung công tác cần đến. Một số khung công tác sử dụng các đối tượng uỷ nhiệm (proxy) hay thao tác mã byte để làm điều này. Điều này có thể làm cho các thao tác gỡ rối gặp khó khăn hay hiệu năng thực thi kém. Khung công tác V4 sử dụng một kỹ thuật khác đó là các công cụ tạo mã. Nếu bạn cần một đối tượng Java để biểu diễn JavaScript của mình, thì tốt hơn là bạn thực sự có đối tượng đó ở đâu đó, thậm chí còn tốt hơn nữa nếu bạn không phải viết mã cho nó. Thay vào đó, bạn để một trình cắm thêm của Eclipse viết mã đó cho bạn.

Sử dụng các trình tạo mã

Các ấn bản Java và Java EE của Eclipse sử dụng rất nhiều trình tạo mã. Điển hình, chúng xuất hiện dưới dạng các trình thủ thuật, sinh ra nhiều tạo phẩm cho bạn. Ví dụ, nếu bạn có sử dụng Java EE, thì bạn có thể đã sử dụng thủ thuật Ứng dụng Web động mới (New Dynamic Web Application). Thủ thuật này tạo ra các cấu trúc thư mục và tệp tin web.xml cho ứng dụng web của bạn, sao cho nó có thể dễ dàng được nén thành tệp tin WAR và được phân phối tới một thùng chứa WEB. Các trình tạo mã được eBay tạo ra phục vụ cùng một mục đích: Chúng tạo ra mã bản mẫu cho bạn, vì vậy bạn có thể tập trung vào mã ứng dụng của mình, thường được gọi là "lôgic nghiệp vụ" của ứng dụng của bạn.

Chúng ta hãy xem một vài trình cắm thêm tạo mã của Eclipse mà eBay đã tạo ra như là một phần của các công cụ cho khung công tác V4.

JavaScript

JavaScript là ngôn ngữ của Web, và nó rất quan trọng trong khung công tác V4. Khung công tác V4 cho phép JavaScript sẽ được mã hóa theo cách thông thường, nhưng với một số cấu trúc đặc biệt. Nó sử dụng cú pháp hướng đối tượng bản ngữ của JavaScript, tuy nhiên, điều này không bắt buộc. Nó cũng sử dụng cú pháp chú thích mã từ dự án nguồn mở JsDoc để định rõ các siêu dữ liệu bổ sung thêm về các lớp JavaScript. Hai thứ này làm việc cùng nhau để cho phép tạo ra một lớp tham chiếu JavaScript (JsRef) ứng với từng lớp JavaScript. Đây là một lớp Java, có thể được tham chiếu bên trong bất kỳ cây DOM V4 nào. Chúng ta hãy xem một ví dụ.

Liệt kê 1. Một lớp JavaScript của eBay
vjo.needs("vjo.samples.classes.Person");
vjo.type("vjo.samples.classes.HelloPerson")
.props({
     /**       
       * @return boolean
       * @access public
      */
     helloPerson:function(){
          var person1 = new vjo.samples.classes.Person();
          person1.setName("John");
          alert("Hello " + person1.getName());
          return false;
     }
});

Nhiều cấu trúc vjo.* bắt chước các cấu trúc trong các khai báo của tệp tin lớp Java. Các chú giải JsDoc cung cấp các định kiểu mạnh mà JavaScript không thể cung cấp. Nó cho phép một trình cắm thêm của Eclipse tạo ra một JsRef cho lớp JavaScript như hình ở dưới.

Liệt kê 2. JsRef tương ứng
package vjo.samples.classes;

import com.ebay.dsf.resource.pattern.js.JsType;
import com.ebay.dsf.spec.component.BaseComponentSpec;
import com.ebay.dsf.aggregator.jsref.internals.JsCmpMeta;
import com.ebay.dsf.spec.component.IComponentSpec;
import vjo.bootstrap.VjBootstrap;
import com.ebay.dsf.resource.pattern.js.JsResource;
import com.ebay.dsf.aggregator.jsref.JsObj;
import com.ebay.dsf.aggregator.jsref.JsFunc;
import com.ebay.dsf.jstojava.codegen.JsRefGenerator23;
import com.ebay.dsf.resource.pattern.js.IJsResourceRef;
import com.ebay.kernel.CodeGenerated;
/*
 Generator: JsRefGenerator23 version: 2.3
 Generated: Mon Jan 28 11:01:13 PST 2008
 Source URL: file:/D:/Views/v4flash/v4samplecode/VjoSample/src/vjo/samples/
                                                     classes/HelloPerson.js
*/

/** 

 * <pre>vjo.needs("vjo.samples.classes.Person");
 * vjo.type("vjo.samples.classes.HelloPerson")
 * .props({
 *      //*       
 *        * @return boolean
 *        * @access public
 *       //
 *      helloPerson:function(){
 *           var person1 = new vjo.samples.classes.Person();
 *           person1.setName("John");
 *           alert("Hello " + person1.getName());
 *           return false;
 *      }
 * });
 * </pre>
*/


@com.ebay.dsf.resource.utils.CodeGen(JsRefGenerator23.class)


@com.ebay.dsf.jstojava.codegen.JsRefGeneratorVersion(2.3)

public class HelloPersonJsr extends JsObj  implements CodeGenerated{
private static final long serialVersionUID = 1L;

public static final JsResource RESOURCE = JsResource.viaName("HelloPerson");
public static class ResourceSpec extends BaseComponentSpec{
     public static final IJsResourceRef REF = jsRef(RESOURCE, JsType.DefOnly);
     private static volatile IComponentSpec s_instance;
     public static IComponentSpec getInstance() {
     if (s_instance != null) {
               return s_instance;
     }
     synchronized (
     ResourceSpec.class) {
               if (s_instance == null) {
                         s_instance = new ResourceSpec();
               }
     }
     return s_instance;
     }
     
     private 
     ResourceSpec() {
          addJsRef(jsRef(RESOURCE, JsType.DefOnly));
          addDependentComponent(VjBootstrap.ResourceSpec.getInstance());
          addDependentComponent(vjo.samples.classes.PersonJsr.ResourceSpec.
		                                                    getInstance());
     }
}

protected HelloPersonJsr(JsCmpMeta cmpMeta, boolean isProto) {
     super(cmpMeta, isProto);
}

/** 

 * @return boolean
@access public
 * @jsfunc helloPerson
 * 
 * function () {
 *     var person1 = new vjo.samples.classes.Person();
 *     person1.setName("John");
 *     alert("Hello " + person1.getName());
 *     return false;
 * }
*/


public static final  JsFunc<Boolean> helloPerson(){
JsFunc<Boolean>  func = new JsFunc<Boolean> (getInstance(), 
                                              "helloPerson",true,true);
return func;
}
public static final JsCmpMeta META = new JsCmpMeta("vjo.samples.classes.HelloPerson", 
                                          "HelloPerson", ResourceSpec.getInstance());
     private static volatile HelloPersonJsr s_instance;

private static HelloPersonJsr getInstance(){
     addResourceSpec(ResourceSpec.getInstance());if (s_instance !=null){
          return s_instance;
     }
     synchronized (HelloPersonJsr.class){
          if (s_instance == null) {
               s_instance = new HelloPersonJsr(META,false);}return s_instance;}
}
}

Tất cả những điều này làm đơn giản và dễ dàng cho các nhà phát triển khi sử dụng các công cụ của Eclipse. Bạn có thể chỉ cần nhấn chuột phải vào tệp JavaScript và tạo ra các mã Java bạn cần, như hình ở dưới.

Hình 1. Sử dụng Eclipse để tạo ra JsRef
Using Eclipse to generate the JsRef

Các JsRef sau đó có thể được sử dụng để viết chương trình trong mã Java. Điều này làm cho việc buộc nối JavaScript vào trong mã Java trở nên dễ dàng. Ví dụ, có thể bạn muốn gọi JavaScript ở trên để xác nhận tính hợp lệ của một biểu mẫu (form) khi một người dùng nhấn nút đệ trình.

Liệt kê 3. Buộc nối các sự kiện phía khách hàng tại máy chủ
DButton button = new DButton("Hello Person - click me");
button.add(EventType.CLICK, HelloPersonJsr.helloPerson());

Các chú giải của JsDoc cũng làm cho việc lần theo vết các phụ thuộc trở nên dễ dàng, vì nó thực hiện công việc chính là bằng cách sử dụng một cấu trúc nhập khẩu của Java. Bạn không phải nhớ để nhập các thư viện JavaScript khác mà mã JavaScript của bạn dựa trên chúng. Bạn chỉ cần khai báo các phụ thuộc trong mã lệnh. Nếu bạn thay đổi mã JavaScript — ví dụ, thêm một tham số vào một hàm — điều này sẽ gây ra lỗi biên dịch trên mã đang sử dụng hàm, trừ khi bạn cấu trúc lại mã đó. Cú pháp gói cũng cung cấp một không gian tên rõ ràng cho các mã JavaScript để ngăn cản các xung đột. Bạn nhận được tất cả các lợi ích từ việc có một lớp Java đại diện cho mã JavaScript, nhưng với sự giúp đỡ của các trình cắm thêm của Eclipse, chỉ thêm một số tối thiểu công việc cần làm để có được các lợi ích này.

JavaScript chỉ là một phần của ứng dụng web mà đã được xử lý một cách độc đáo trong khung công tác V4 của eBay và các trình cắm thêm của Eclipse, trao thêm sức mạnh cho các nhà phát triển web để sử dụng V4. Một ví dụ quan trọng khác đó là CSS.

CSS

Cách tiếp cận của V4 tới JavaScript là giữ JavaScript nguyên gốc và chỉ ủy quyền nó thông qua mã Java. Cách tiếp cận đối với CSS thì khác một chút. JavaScript tự thân nó là một ngôn ngữ lập trình phức tạp. CSS có thể cũng phức tạp, nhưng chắc chắn không phải cùng mức phức tạp như JavaScript. Đối với CSS, các tệp tin CSS chỉ được sử dụng như là một điểm bắt đầu. Chúng được sử dụng để tạo ra một lớp Java mà sẽ được dùng trong môi trường chạy (runtime) để tạo ra CSS. Tập tin CSS ban đầu có thể bị bỏ đi. Chính lớp Java sẽ trở thành một phần của kiểm soát nguồn, trong khi đó, tệp JavaScript thực tế sẽ được đăng ký và JsRef được Eclipse tạo ra trên hệ thống của nhà phát triển hoặc được tạo ra bởi hệ thống xây dựng cho mã nguồn sẽ được chuyển ra để chạy sản xuất thực sự. Tuy nhiên, thường là tự nhiên hơn khi bắt đầu với CSS, có thể là từ một mô hình trực quan nào đó.

Vì vậy, eBay đã xây dựng các trình cắm thêm của Eclipse để làm việc với các CSS và “tự mồi” (bootstraping) việc tạo ra Java-CSS (JCSS). Trong liệt kê 4, chúng ta thấy một tập tin CSS điển hình.

Liệt kê 4. Một tệp tin CSS
* {
     margin: 0;
     padding: 0;
}

body {
     font-size: 100.01%;
     font-family: Verdana,sans-serif;
     padding: 10px;
     text-align: center;
}

h1, h2, h3, h4, h5 {
     font-family: Georgia,serif;
}

h1 {
     color: #9A351D;
     background-color: transparent;
     margin: 1em 0;
}

h3 {
     font-size: .9em;
}

div h3 {
     color: #58B;
     text-transform: uppercase;
     font-size: .7em;
}

div h3:before {
     content: "by";
     font-style: italic;
     text-transform: none;
     color: #000;
     display: block;
     margin-bottom: 1em;
}

h4 {
     text-align: center;
     font-style: italic;
     color: #666;
     margin: 2em 0 0 0;
     font-size: .7em;
     font-weight: normal;
}

.footer {
     color: #999;
     font-size: .5em;
     font-family: Verdana,sans-serif;
     font-weight: normal;
}

Một lần nữa, chúng ta có thể nhấn chuột phải trên Eclipse để truy cập vào trình cắm thêm JCSS và tạo ra lớp JCSS.

Hình 2. Sử dụng trình cắm thêm JCSS
Using the JCSS plug-in

Thao tác này sẽ sinh ra một lớp Java.

Liệt kê 5. Lớp JCSS tương ứng
package com.ebay.css.example;

import com.ebay.dsf.css.CssClassConstant;
import com.ebay.dsf.javatocss.JCssDef;
import com.ebay.dsf.javatocss.JCssStyleRule;
import com.ebay.dsf.javatocss.prop.BackgroundColor;
import com.ebay.dsf.javatocss.prop.Display;
import com.ebay.dsf.javatocss.prop.FontStyle;
import com.ebay.dsf.javatocss.prop.FontWeight;
import com.ebay.dsf.javatocss.prop.TextAlign;
import com.ebay.dsf.javatocss.prop.TextTransform;
import com.ebay.kernel.CodeGenerated;


/*
 Generator: class com.ebay.dsf.csscodegen.generator.def.JCssDefGenerator 
                                                            version: 1.0
 Generated: Mon Jan 28 17:37:36 PST 2008
 Source: com.ebay.css.example cover.css
*/

/**
 * <pre>
* {margin:0; padding:0}
body {font-size:100.01%; font-family:Verdana, sans-serif; padding:10px; 
                                                     text-align:center}
h1, h2, h3, h4, h5 {font-family:Georgia, serif}
h1 {color:#9a351d; background-color:transparent; margin:1em 0}
h3 {font-size:0.9em}
div h3 {color:#58b; text-transform:uppercase; font-size:0.7em}
div h3:before {content:"by"; font-style:italic; text-transform:none; 
                        color:#000; display:block; margin-bottom:1em}
h4 {text-align:center; font-style:italic; color:#666; margin:2em 0 0 0; 
                                   font-size:0.7em; font-weight:normal}
.footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
                                                   font-weight:normal}
 * </pre>
 */
public class CoverJCssDef extends JCssDef implements CodeGenerated {

  private static final String SCOPE_NAME = "";
  public interface Clz {
       /**
        * <pre>
        * .footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif;
                                                       font-weight:normal}
        * </pre>
        */
       CssClassConstant footer_ = new CssClassConstant(SCOPE_NAME, "footer");
  }

  private static CoverJCssDef s_instance= new CoverJCssDef();

  public static CoverJCssDef getInstance(){
       return s_instance;
  }


  public static interface DEFAULT {

       public static final JCssStyleRule STYLE_RULE_1 = s_instance.rule()
            .select(any)
            .set( properties()
                 .margin("0")
                 .padding("0"));

       public static final JCssStyleRule STYLE_RULE_2 = s_instance.rule()
            .select(body)
            .set( properties()
                 .fontSize("100.01%")
                 .fontFamily("Verdana, sans-serif")
                 .padding("10px")
                 .textAlign(TextAlign.CENTER));

       public static final JCssStyleRule STYLE_RULE_3 = s_instance.rule()
            .select(h1)
            .select(h2)
            .select(h3)
            .select(h4)
            .select(h5)
            .set( properties()
                 .fontFamily("Georgia, serif"));

       public static final JCssStyleRule STYLE_RULE_4 = s_instance.rule()
            .select(h1)
            .set( properties()
                 .color("#9a351d")
                 .backgroundColor(BackgroundColor.TRANSPARENT)
                 .margin("1em 0"));

        public static final JCssStyleRule STYLE_RULE_5 = s_instance.rule()
            .select(h3)
            .set( properties()
                 .fontSize("0.9em"));

        public static final JCssStyleRule STYLE_RULE_6 = s_instance.rule()
            .select(div.desc(h3))
            .set( properties()
                 .color("#58b")
                 .textTransform(TextTransform.UPPERCASE)
                 .fontSize("0.7em"));

        public static final JCssStyleRule STYLE_RULE_7 = s_instance.rule()
            .select(div.desc(h3.pseudoBefore()))
            .set( properties()
                 .content("\"by\"")
                 .fontStyle(FontStyle.ITALIC)
                 .textTransform(TextTransform.NONE)
                 .color("#000")
                 .display(Display.BLOCK)
                 .marginBottom("1em"));

       public static final JCssStyleRule STYLE_RULE_8 = s_instance.rule()
            .select(h4)
            .set( properties()
                 .textAlign(TextAlign.CENTER)
                 .fontStyle(FontStyle.ITALIC)
                 .color("#666")
                 .margin("2em 0 0 0")
                 .fontSize("0.7em")
                 .fontWeight(FontWeight.NORMAL));

       public static final JCssStyleRule STYLE_RULE_9 = s_instance.rule()
            .select(any.with(Clz.footer_))
            .set( properties()
                 .color("#999")
                 .fontSize("0.5em")
                 .fontFamily("Verdana, sans-serif")
                 .fontWeight(FontWeight.NORMAL));
  }
}

Tệp tin này trình bày các định nghĩa kiểu dáng của chúng ta. Để tách biệt các mối quan tâm, một lớp riêng biệt được sử dụng để thực thi các CSS trong một tài liệu HTML. Tất nhiên, lớp này cũng được tạo ra bởi một trình cắm thêm của Eclipse.

Hình 3. Sử dụng trình cắm thêm để tạo lớp thực thi CSS
Using plug-in to generate CSS realizer

Bên dưới là một ví dụ về một lớp thực thi CSS mà trình cắm thêm tạo ra.

Liệt kê 6. Lớp thực thi CSS được tạo ra
package com.ebay.css.example;

import com.ebay.css.example.CoverJCssDef;
import com.ebay.dsf.css.CssClassConstant;
import com.ebay.dsf.csscodegen.generator.realizer.CssRealizerGenerator;
import com.ebay.dsf.csscommon.BaseCssRealizer;
import com.ebay.dsf.html.dom.BaseCoreHtmlElement;
import com.ebay.dsf.resource.pattern.css.CssResource;
import com.ebay.kernel.CodeGenerated;


/*
 Generator: class com.ebay.dsf.csscodegen.generator.realizer.CssRealizerGenerator 
                                                                     version: 2.0
 Generated: Tue Jan 29 15:20:08 PST 2008
 Source: com.ebay.css.example.CoverJCssDef
*/

/**
 * <pre>
* {margin:0; padding:0}
body {font-size:100.01%; font-family:Verdana, sans-serif; padding:10px; 
                                                      text-align:center}
h1, h2, h3, h4, h5 {font-family:Georgia, serif}
h1 {color:#9a351d; background-color:transparent; margin:1em 0}
h3 {font-size:0.9em}
div h3 {color:#58b; text-transform:uppercase; font-size:0.7em}
div h3:before {content:"by"; font-style:italic; text-transform:none; 
                       color:#000; display:block; margin-bottom:1em}
h4 {text-align:center; font-style:italic; color:#666; margin:2em 0 0 0; 
                                    font-size:0.7em; font-weight:normal}
.footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
                                                     font-weight:normal}
 * </pre>
 */
@com.ebay.dsf.resource.utils.CodeGen(CssRealizerGenerator.class)
public class CoverCssr extends BaseCssRealizer implements CodeGenerated {

    /** Answers the actual text this realizer was genned from */
    public static final String gentext = 
"* {margin:0; padding:0}\n"
+ "body {font-size:100.01%; font-family:Verdana, sans-serif; padding:10px; 
                                                     text-align:center}\n"
+ "h1, h2, h3, h4, h5 {font-family:Georgia, serif}\n"
+ "h1 {color:#9a351d; background-color:transparent; margin:1em 0}\n"
+ "h3 {font-size:0.9em}\n"
+ "div h3 {color:#58b; text-transform:uppercase; font-size:0.7em}\n"
+ "div h3:before {content:\"by\"; font-style:italic; text-transform:none; 
                           color:#000; display:block; margin-bottom:1em}\n"
+ "h4 {text-align:center; font-style:italic; color:#666; margin:2em 0 0 0; 
                                   font-size:0.7em; font-weight:normal}\n"
+ ".footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
                                                   font-weight:normal}\n"
;
    public static final CssResource src = CssResource.viaDef(
	                                CoverJCssDef.getInstance());
    public static final Classes classes = new Classes() ;
    public static final Utils utils = new Utils() ;

    /**
     * <pre>
     * .footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
	                                                      font-weight:normal}
     * </pre>
     */
    public static final class Classes {
        private Classes() { /* prevent instantiation */ }
        private static final CssClassConstant s_footer = new CssClassConstant("footer");
        /**
         * <pre>
         * .footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
		                                                      font-weight:normal}
         * </pre>
         */
        public final CssClassConstant footer = s_footer;
    }

    public static final class Utils {
        private Utils() { /* prevent instantiation */ }
        /**
         * <pre>
         * .footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
		                                                      font-weight:normal}
         * </pre>
         */
        public Utils addClass_footer(final BaseCoreHtmlElement element) {
            addCssClass(element, Classes.s_footer);
            return this;
        }

        /**
         * <pre>
         * .footer {color:#999; font-size:0.5em; font-family:Verdana, sans-serif; 
		                                                      font-weight:normal}
         * </pre>
         */
        public Utils setClass_footer(final BaseCoreHtmlElement element) {
            setCssClass(element, Classes.s_footer);
            return this;
        }

    }

}

Lớp thực thi giúp bạn dễ dàng gắn các kiểu dáng vào bất kỳ phần tử trực quan nào. Ngoài ra, bạn có thể đăng ký một hoặc nhiều định nghĩa JCSS trên một trang để xác định các kiểu dáng mặc định. Bên dưới là ví dụ về cả hai kỹ thuật này.

Liệt kê 7. Sử dụng JCSS
// Create a div, attach a style to it
DDiv footer = new DDiv();
CoverCssr.utils.addClass_footer(footer);
// create DOM, register the CSS for it
HtmlDisplayer2 doc = new HtmlDisplayer2(footer);
doc.registerCss(CoverJCssDef.getInstance());

Một lần nữa chúng ta lại có được những lợi ích của việc có một không gian tên (gói JCSS), do đó trong chế độ chạy runtime, CSS của chúng ta sẽ không xung đột với CSS của bất kỳ ai khác. Chúng ta có được lợi thế này trong khi vẫn có thể tận dụng lợi thế của các CSS "nguyên gốc". Bí quyết là là sử dụng trình cắm thêm của Eclipse để lấp khoảng trống giữa các CSS và các JCSS.

Ngay bây giờ bạn sẽ thấy các mẫu hình. V4 cần tất cả các cấu kiện được định kiểu mạnh ấy, và Eclipse làm cho việc cung cấp và làm việc với tất cả các mẫu hình này dễ dàng hơn. Chúng ta đã đề cập đến kiểu tài nguyên có nhiều thách thức nhất trong V4: Đó là nội dung. Chúng ta hãy xem Eclipse giúp đỡ giải quyết vấn đề này như thế nào.

Nội dung

Hệ thống nội dung của V4 dựa vào các giao kèo về nội dung. Các giao kèo này có ngôn ngữ XML riêng của chúng, nhưng một lần nữa việc sử dụng trình cắm thêm của Eclipse cho phép nhận được một bộ biên tập trực quan hơn cho các giao kèo này.

Hình 4. Bộ biên tập nội dung có cấu trúc của V4
V4 content structured editor

Chúng ta cần tạo ra mã Java để trình bày các giao kèo nội dung, và một lần nữa chúng ta đã có Eclipse sẵn sàng để tạo ra các mã này.

Hình 5. Tạo ra các mã Java cho giao kèo nội dung
Generating Java code for content contract

Các giao kèo về nội dung có một cú pháp mạnh, cho phép chúng mô tả các cấu trúc phức tạp được tìm thấy trong các ứng dụng của eBay. Điều này dẫn đến một API diễn cảm, dễ sử dụng, nhưng viết bằng tay sẽ rất mệt mỏi. Các trình cắm thêm làm cho chúng không còn là vấn đề nữa.

Như bạn đã thấy, eBay tận dụng các trình cắm thêm của Eclipse để tạo ra mã cho các nhà phát triển trong nhiều kịch bản. Đây là không là loại trình cắm thêm duy nhất do eBay viết ra. Ta hãy xem một số loại trình cắm thêm khác mà eBay sử dụng và chúng giải quyết những nhu cầu nào.

Các trình cắm thêm khác của V4

Các hệ thống của V4 cũng cung cấp các cách duy nhất để chạy các ứng dụng và gỡ lỗi cho chúng bởi vì cách thức nó sử dụng Java để biểu diễn tất cả các phần tử của một trang web. Điều này có thể mang lại lợi ích lớn về năng suất cho bạn, làm cho dễ dàng phát triển các ứng dụng và gỡ rối chúng một khi được triển khai.


Chạy một ứng dụng web từ Eclipse

Bạn đã bao giờ mong muốn rằng bạn có thể chạy một trang web mà không cần phải triển khai, khởi động hoặc khởi động lại một máy chủ web chưa? Với các trình cắm thêm V4 của eBay cho Eclipse, bạn có thể làm được điều này.

Hình 6. Chạy một ứng dụng web như là một "dervlet"
Running a Web application as a dervlet

Có thể bạn đang tự hỏi: "Dervlet là gì ?". Đúng như tên của nó gợi ý, nó tương tự như một servlet. Khung công tác của V4 cho phép sử dụng các dervlet như là các lớp tự mồi (bootstrapping) để nhanh chóng tạo mẫu ban đầu (prototyping) và kiểm thử một ứng dụng web. Nó tương tự như có một lớp với một phương thức main được sử dụng để kiểm thử các lớp khác trong gói. Tất cả những gì bạn cần làm là nhấn chuột phải và chạy như một dervlet. Rõ ràng rằng, bạn cũng có thể gỡ lỗi như dervlet và đi từng bước trong mã của bạn như bất kỳ một chương trình thực thi nào khác. Đằng sau sân khấu, các trình cắm thêm của Eclipse khởi động một phiên bản nhúng của thùng chứa servlet Jetty, sau đó nó mở một trình duyệt Web tới một URL mà Jetty phục vụ.

Trình cắm thêm này của Eclipse làm cho việc gỡ lỗi một ứng dụng V4 trong quá trình phát triển trở nên dễ dàng hơn. Khung công tác của V4 và Eclipse thậm chí còn đi xa hơn, bằng cách cho phép dễ dàng gỡ lỗi một ứng dụng đang chạy sản xuất.


Gỡ lỗi một ứng dụng đang sản xuất từ Eclipse

Khung công tác V4 là một khung gồm nhiều thành phần. Khi bạn đã có tất cả mọi thứ, ví dụ như các lớp Java, thì bước kế tiếp, rất tự nhiên, theo hướng đối tượng là bao gói các lớp khác nhau ấy đang làm việc cùng nhau thành một hợp phần. Điều này cung cấp các thành phần có khả năng sử dụng lại rất cao và có thể tiếp tục tăng năng suất của các nhà phát triển. Nếu bạn nhìn vào một trang web của eBay, nhiều khả năng là bạn sẽ được xem một sưu tập các thành phần của V4. Điều này không chỉ là tuyệt vời để tạo các ứng dụng một cách nhanh chóng, mà còn giúp cho việc tự xem xét bên trong một ứng dụng đang chạy.

Hình 7. Một trang eBay với Spyglass
Figure 6. An eBay page with Spyglass

Bạn có nhận thấy tất cả các hộp màu đỏ không? Mỗi một hộp này là một thành phần V4. Lướt chuột qua bất cứ hộp nào bạn sẽ thấy tên đầy đủ của thành phần. Nếu có khiếm khuyết nào nhìn thấy trên trang web, thì bạn khá dễ dàng suy ra được đoạn mã nào (thành phần nào) đang gây ra lỗi. V4 tiến một bước xa hơn bằng cách giúp bạn có mã đó ngay lập tức. Bạn có nhận thấy các liên kết trong hộp màu xanh không? Các nhà phát triển eBay có thể đi trực tiếp vào Eclipse từ bất kỳ trang V4 của eBay đang sản xuất nào. Bạn hãy thử làm như vậy với XSL, JSPs, hoặc với bất cứ thứ gì khác. Điều này được thực hiện bằng cách chạy một trình máy chủ lắng nghe (listener server) từ Eclipse. Trình lắng nghe là một trình cắm thêm do eBay viết ra, vận dụng kiến trúc của eBay để giúp các nhà phát triển sử dụng Eclipse.


Tóm tắt

Chúng ta đã nói về những thách thức duy nhất mà eBay phải đối mặt. Chúng ta đã thấy eBay đã chọn một kiến trúc đòi hỏi khắt khe để giải quyết những vấn đề này như thế nào. Kiểu kiến trúc này chỉ có thể được sử dụng với các công cụ mạnh để giúp các nhà phát triển không phải viết các mã bản mẫu tẻ nhạt. Hệ thống trình cắm thêm của Eclipse là hoàn hảo để cung cấp các loại công cụ ấy, cũng như nhiều công cụ mạnh khác để phát triển và gỡ lỗi. Các vấn đề và các giải pháp được mô tả có thể là duy nhất đối với eBay trên một số phương diện nào đó, nhưng kỹ thuật được sử dụng không phải chỉ dành cho eBay. Nếu công ty của bạn cần kiến trúc chuyên dụng cao, bạn có thể vay mượn một trang web từ eBay và tạo ra trình cắm thêm của Eclipse để giải quyết vấn đề mà không gây thiệt hại đến năng suất của các nhà phát triển của bạn.

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

  • Các nhóm tin về nền Eclipse nên là điểm dừng đầu tiên của bạn để thảo luận về các vấn để liên quan đến Eclipse. (Việc chọn trang này sẽ khởi chạy ứng dụng bộ đọc tin Usenet mặc định của bạn và mở eclipse.platform.)
  • Các nhóm tin về Eclipse có rất nhiều tài nguyên cho những người quan tâm đến việc sử dụng và mở rộng Eclipse..
  • Tham gia vào developerWorks blogs và tham gia cộng đồng developerWorks.

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=396397
ArticleTitle=Eclipse tại eBay, Phần 1: Làm cho Eclipse thích ứng với kiến trúc của eBay
publish-date=06132009