Best Selenium automation testing tools review: Robot Framework vs Katalon Studio

Recently I had a chance to work with several software testing teams to help them get started with their test automation endeavors. The teams consist of mostly manual testers, and some who had experience with test automation before, but none of them were familiar with programming like developers. The applications are mostly web based, with companion mobile apps. We made a short list of several testing tools, including free and non-free ones, and then came up with the two best ones – Robot Framework and Katalon Studio. They are quite good choices in general, so I think it would be interesting to make a side by side comparison and see how they will perform in the future.

Technology

Both are built on top of Selenium — the automation framework that is currently backed by top web browser developers (Google, Microsoft, Apple, Mozilla). It is safe to say Selenium is the best way to automate your web browser for now.

Selenium can also be used to automate mobile apps via Appium. Granted that Google and Apple both come up with their own way to do automation, using Selenium and Appium means that we can reuse source code and knowledge in multiple platforms — learn once, write everywhere.

So for technology, it’s a tie. Robot Framework – Katalon Studio : 1 – 1.

Price

Both are free with no obligation. Running outdated “enterprise” software like UFT is just cost-prohibitive for us.

Robot Framework – Katalon Studio : 1 – 1.

Installation & Components

Robot Framework comes with two separate components: the test runner and the IDE. It is a little complicated to install these components, but once things are done, you are good to go. First, you need to install Python on your computer. Then run some command lines. If you use Windows, you might encounter issues because this OS is not Python’s first-class citizen, but they rarely happen, and solutions can be googled easily.

There is actually a third “unofficial” component, which I will mention later.

For Katalon Studio, from my opinion, this is one of the best installation experience. If you have installed Eclipse, then you would know it. For Windows, you will have to download a ZIP file and extract. For macOS, there is a DMG file ready for you. Pretty neat.

Robot Framework – Katalon Studio : 0.5 – 1.

Test Design

Recording (codeless test automation)

Honestly, as a programmer, I am not a big fan of record and playback. It feels easier and quicker for me to just type the code. However, for those who have little experience with coding, the ability to record their actions and generate test cases is a huge productivity win.

Unfortunately, Robot Framework does not provide a recorder — and this is where the third component shows up. The Selenium project includes an infamous Firefox add-on called Selenium IDE, which is essentially a test record & playback tool. Selenium IDE can have add-ons (it is add-on on add-on!), and someone had kindly written an add-on that helps Selenium IDE generate Robot Framework code. Some more installation works to be done, but it works.

The downside of this is that Selenium IDE development has been inactive for a while, and it is based on Firefox’s old add-on framework, which they have decided to unplug at the end of 2017. Yes, Selenium IDE will stop working at that time for newer Firefox versions.

Katalon Studio comes with its own add-ons for Chrome, Firefox, and even Internet Explorer. Installation is as easy as going to corresponding web browser add-on stores and click install.

Katalon Studio extends its lead here. Robot Framework – Katalon Studio : 0.5 – 1.

Coding (Scripting)

Robot Framework has its own domain specific language (DSL). Custom keywords can be written in Python and Java, but when it comes to test cases content, you have to speak that DSL. Why it mimics human languages for simple test cases, complex ones are quite robotic. I personally find it less descriptive than common programming languages:

*** Settings ***
Library String

*** Test Cases ***
For-Loop-In-Range
 : FOR ${INDEX} IN RANGE 1 3
 \ Log ${INDEX}
 \ ${RANDOM_STRING}= Generate Random String ${INDEX}
 \ Log ${RANDOM_STRING}

For-Loop-Elements
 @{ITEMS} Create List Star Trek Star Wars Perry Rhodan
 :FOR ${ELEMENT} IN @{ITEMS}
 \ Log ${ELEMENT}
 \ ${ELEMENT} Replace String ${ELEMENT} ${SPACE} ${EMPTY}
 \ Log ${ELEMENT}

For-Loop-Exiting
 @{ITEMS} Create List Good Element 1 Break On Me Good Element 2
 :FOR ${ELEMENT} IN @{ITEMS}
 \ Log ${ELEMENT}
 \ Run Keyword If '${ELEMENT}' == 'Break On Me' Exit For Loop
 \ Log Do more actions here ...

Repeat-Action
 Repeat Keyword 2 Log Repeating this ...

But the Robot Framework IDE with syntax highlighting is good, so I guess I can get used to it quickly anyway.

Katalon Studio, on the other hand, supports Groovy and of course Java (Groovy is based on Java). Why it is not as popular as mainstream programming languages such as Java, C#, or JavaScript – it bears similar productive structures as in Ruby, Python, or JavaScript. Another good thing is that there are tons of free Java libraries to do just everything, so we did not have to rewrite “everything”.

But the coolest thing in Katalon Studio is that we can switch between Manual mode (with Recorder and point-and-click GUI) and Script mode (with Groovy editor) at any time. We took advantage of this to educate manual testers to write code. They at first design their test cases by point-and-click actions and elements, then switch to Script mode to see the equivalent Groovy code. Very nice feature.

Robot Framework – Katalon Studio : 0.5 – 1.

Test Data

Both are good. Data for test cases can be fed from Excel files, databases etc. We got what we need, so nothing to complain by now.

Robot Framework – Katalon Studio : 1 – 1.

Keyword extensibility

You can write custom keywords in both Robot Framework and Katalon Studio. They required some repeatedly ceremonial syntax, but testers can write their own keywords without the help from programmers. The documentation and tutorials are good enough, so I will leave this as a tie. Robot Framework – Katalon Studio : 1 – 1.

Execution, Reporting, and Integration

We expect modern test automation tools to be able to execute test cases via command line and in CI like Jenkins. We also need to have reports in-app to make it easy to investigate failures. The reports should also be prepared in archivable format (HTML, CSV, PDF) so that they can be looked up later.

It seems that Katalon Studio is experimenting with a more native JIRA integration, which sounds good to me since we also use JIRA, but let me see how well it will work out.

One thing missing in both is an image to cut down the time for CI deployment and configuration, but maybe it is just my laziness.

Another tie for me. Robot Framework – Katalon Studio : 1 – 1.

Community and support

Both products are in active development and are well supported by their owners as well as the community. The questions are answered in very short time. Moreover, since Robot Framework and Katalon Studio are Selenium-based, we can pretty much resort to vanilla Selenium and WebDriver for complex scenarios.

It seems that Katalon Studio is built by a company doing software testing services, which means they know what features are practical and necessary. Robot Framework is a popular open source project on GitHub so I expect the same thing.

The last tie here. Robot Framework – Katalon Studio : 1 – 1.

Conclusion

Robot Framework: 7.5/9 – Katalon Studio: 9/9.

Both tools are great choices for test automation teams, with Katalon Studio has an upper hand on user experience and therefore is better than Robot Framework for tester-based test automation team. Competition is always good for consumers, and I look forward to seeing more advancements from the players in the future.

Testing Dojo web applications with Selenium

I jot down here some findings about testing Dojo web applications (with a lot of Dijit Widget!) using Selenium, just in case someone will need them.

The first thing that you should never ever try to do is simulating events using JavaScript. Some libraries like jQuery provide convenient ways to click, focus, or type on HTML elements. But these “synthetic” events have two important limitations:

  • You have to find the right element to send an event. The DOM trees generated by Widgets are huge, with layers under layers. Sometimes it is necessary to read the code and decide which element is used by Dojo to receive which kind of event. Moreover, synthetic events are bad as it will not be able to consistently updating the focused elements the way human interactions do, while Widgets heavily rely on this behavior. Some Widgets even refuse to react upon faux clicks.
  • They can be sent to invisible elements, while human obviously cannot manipulate with such things. Dijit Widgets consist of many HTML elements that are carefully arranged in different positions. Any wrongly placed element can render the Widget unusable, while JavaScript does not care about (and understand) position. Therefore, synthetic events are not reliable at all, which would render your tests useless.

Without JavaScript, we have two more effective ways to trigger actions on Widget. They both simulate human interactions in the most native way.

The first one is to utilize native events implemented by all major web browsers. This approach should work well unless you encounter a bug in their implementation, or you are testing against an unpopular browser. It is quite straightforward to enable native events:

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(“nativeEvents”, true);

The second one, which will work for edge cases, is to use a robot. A robot can simulate human action as Operating System level. This means if the robot is trying to move the mouse, you will see on your screen that the pointer is moving. The drawback is that the executing machine needs to have a display device regardless of being a physical machine or a virtual one (in another word, a headless machine will not work). Another disadvantage is that you have to convert coordinates from window-relative into device-relative. To overcome this limitation, just run the browser in full-screen mode. For example, with Chrome, we use “kiosk” command switch for full-screen mode:

ChromeOptions options = new ChromeOptions();
options.addArguments(“—kiosk”);

And we control the robot like this:

Point location = input.getLocation();
int x = location.getX();
int y = location.getY();
Robot r = new Robot();
r.mouseMove(x + 10, y + 10);

Finally, Dijit Widget has a bug with touch event (Dojo manipulate browser’s events a lot, it even managing it own focusing behavior so it is really prone to bugs and browser’s compatibility. Make sure you have latest fixes and if things still happen, disable touch events in Chrome.

  1. From Google Chrome, type chrome://flags in the address bar, then press Enter.
  2. Scroll down to the “Enable Touch Events”.
  3. Select the drop-down menu and select Disabled.
  4. Restart and enjoy Chrome!

Autocomplete plugin for TinyMCE 3

I’ve made a fork at https://github.com/minhhai2209/TinyMCE-Autocomplete-Plugin from https://github.com/abrimo/TinyMCE-Autocomplete-Plugin.

This fork improves the method to calculate the caret’s current position so that the suggestion list can work as expected on Internet Explorer, Firefox, and Chrome. Also the suggested options as well as their labels are retrieved via callback functions in order to increase the flexibility.

Untitled

Example code:

$(document).ready(function() {

  var autocomplete_options = [
    {
      homepage: 'http://google.com',
      fullname: 'Google Inc.',
      description: 'Google'
    },
    {
      homepage: 'http://google.com',
      fullname: ' GitHub Inc.',
      description: 'GitHub'
    },
    {
      homepage: 'http://yahoo.com',
      fullname: 'Yahoo Inc.',
      description: 'Yahoo'
    },
    {
      homepage: 'http://yelp.com',
      fullname: 'Yelp Inc.',
      description: 'Yelp'
    },
    {
      homepage: 'http://microsoft.com',
      fullname: 'Microsoft Inc.',
      description: 'Microsoft'
    }
  ];

  var matchingOptions = function(currentWord) {
    var matches = [];
    for (var i in autocomplete_options) {
      var option = autocomplete_options[i];
      if (currentWord.length == 0 || beginningOfWordMatches(currentWord, option.description)) {
        matches.push(option);
      }
    }
    return matches;
  };

  var beginningOfWordMatches = function(beginning, option) {
    var test = new RegExp("^" + beginning, "i");
    return (option.match(test));
  };

  var asString = function(value) {
    var a = $('<a/>', { href: value.homepage }).text(value.fullname);
    return $('<div/>').append(a).html();
  };

  $('.tinymce').tinymce({
    theme : 'advanced',
    plugins : 'autocomplete',

    theme_advanced_buttons1 : '',
    theme_advanced_toolbar_location : 'top',
    theme_advanced_toolbar_align : 'left',
    theme_advanced_statusbar_location : 'none',

    autocomplete_matching_options: matchingOptions,
    autocomplete_as_string: asString
  });
});

Thing

Tôi vẫn loanh quanh với cái ý này nên phải tiếp tục.

Các hệ thống thông tin thường định nghĩa các loại đối tượng mang nội dung, với một số thuộc tính.Chẳng hạn một hệ thống quản lí dự án (tôi đang làm một cái đại loại vậy, nên các ví dụ sẽ dính tới nó) có thể có các đối tượng test case, requirement. Với một số hệ thống người dùng có thể thêm các thuộc tính mới vào. Điều này giúp tăng cường khả năng thích nghi của hệ thống với những yêu cầu khác nhau. Các hệ thống dạng này có những điểm chung và riêng, nhưng bất kể là chung hay riêng thì khi phát triển chúng ta cứ phải làm đi làm lại, và giải quyết những vấn đề giống nhau. Tôi muốn tìm kiếm một cách nhìn cho những điểm chung và riêng như vậy, theo một hướng khác, biết đâu sẽ giúp ích cho những dự án sau này.

Thường thì các hệ thống sẽ đi từ loại đối tượng (từ giờ tôi sẽ gọi ngắn gọn là type, như test case, requirement, bug, note, …). Hệ thống hoặc người dùng sẽ định nghĩa các type, và khi tạo một đối tượng người ta phải chọn type trước. Tôi muốn thử đi ngược lại, đối tượng có trước, type có sau (lí do sẽ được trình bày dần). Chúng ta sẽ gọi các đối tượng mang nội dung trong hệ thống là thing (tiếng Anh cho dễ viết mã). Mỗi thing thì gồm nhiều tính chất (gọi là property). Điều này ứng với thực tế là khi nhìn một đồ vật người ta sẽ ghi nhận tính chất của chúng. Property là một bộ gồm tên (key) và giá trị (value), key thì phải là dạng chuỗi, còn value thì có thể là chữ, số, ngày, hay một dạng phức tạp hơn, tương tự như mỗi tính chất của đồ vật thì có rất nhiều từ để mô tả nó.

Khi người dùng tạo thing thì họ có thể tạo và điền các property của nó theo ý của mình. Đôi khi chúng ta muốn thing tạo ra có sẵn các property và value nhất định. Cách tiếp cận thông thường là các hệ thống cho người dùng tạo một type mới, định nghĩa các property và value mặc định của chúng. Tuy nhiên, khi làm như vậy, các value mặc định sẽ đứng đơn lẻ chứ không phải hợp với nhau để thể hiện một thing. Chẳng hạn những ràng buộc như “ngày bắt đầu” phải nhỏ hơn “ngày kết thúc” sẽ không thể được định nghĩa hay kiểm tra khi tách riêng hai property này. Nói cách khác, cái chúng ta cần không phải là giá trị mặc định của một property, mà là một thing mặc định. Một hạn chế nhỏ nữa là với thiết kế dạng này, chúng ta không thể tạo sẵn nhiều hơn một khuôn mẫu (những bộ value mặc định) cho thing. Để giải quyết vấn đề này chúng ta sẽ đưa ra khái niệm sao chép (clone) và khuôn mẫu (template).

Với các thing đã tạo, người dùng có thể clone để tạo ra các thing mới. Tất nhiên, thing tạo ra bởi clone sẽ có property và value giống như thing được clone. Chúng ta sẽ gọi thing được clone là template. Template chỉ là một cách gọi, còn về bản chất chúng cũng là thing. Như vậy chúng ta có thể đưa ra định nghĩa type mới. Type chính là template của một thing. Ví dụ, thing C và thing D được clone từ template thing B thì chúng cùng có type A. Type ở đây không cần là khái niệm chính thức, mà chỉ để giúp chúng ta đối chiếu với các hệ thống đã có. Type có thể thành một chuỗi, ví dụ template thing B có thể được tạo từ template thing A. Có thể chúng ta sẽ có một thing gốc, ví dụ như THING. Từ THING chúng ta sẽ tạo ra các thing và các thing này có thể được dùng làm template để tạo ra các thing khác.

Có thể xét một ví dụ để làm rõ ý này. Cho một hệ thống quản lí dự án. Chúng ta sẽ tạo một thing là Artifact với một property là name. Dùng Artifact làm template chúng ta clone ra Test Case, Requirement và thêm những property khác. Khi đấy việc hiện thực chứng năng tìm kiếm sẽ được đơn giản hóa, vì tìm kiếm trên Test Case, Requirement, hay toàn bộ Artifact thì cũng chỉ là tìm kiếm trên thing mà thôi. Hơn nữa, nếu sau này tất cả các đối tượng trong dự án phải có thêm property mới như ID chẳng hạn, chúng ta chỉ cần cập nhật thing Artifact.

Tôi đã mượn từ clone trong JavaScript rồi, tôi sẽ mượn thêm ý tưởng duck typing (“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck”). Bởi vì chúng ta không có type, mọi chức năng sẽ khá mềm dẻo. Những chức năng nghiệp vụ giờ đây không cần quan tâm đến type của thing, mà chỉ cần biết chúng thỏa mãn một tập điều kiện cho trước. Chẳng hạn, chức năng report chỉ cần quan tâm là tập thing có property status hay không, và status có giá trị gì, v.v là có thể đưa ra thống kê cho tập thing này rồi. Việc giới hạn chức năng hoạt động theo type (hay chính xác hơn là template mà một thing được clone từ đó) vẫn có thể thực hiện được, nhưng nó chỉ là một tham số mà thôi. Cách tiếp cận này sẽ giúp chúng ta xây dựng nhanh chóng những chức năng giống nhau cho các type khác nhau.

Về mặt hiện thực, cần chú ý là các thing có thể hoàn toàn khác nhau về số lượng hay kiểu property, nên cấu trúc database phải loại bỏ hoàn toàn khái niệm về type như thông thường. Về việc thiết kế kiến trúc, có lẽ phải tìm cách để module hóa càng nhiều càng tốt, khi đó các khái niệm xung quanh thing có thể được hiện thực thêm mà ít gây ảnh hưởng cho toàn hệ thống. Có thể là thing sẽ được thể hiện trong database hay mã dưới dạng associate array, gồm các cặp key và value. Các cặp key và value này không nhất thiết phản ánh 1:1 các property. Chẳng hạn cho một property dạng tag với value “new, unfinished”, chúng ta sẽ có trong thing các cặp (key, value) là (p_count, 2), (p_tag_1, “new”), (p_tag_2, “value”). Cách thể hiện này ít nhất sẽ giúp việc đọc ghi với database được thống nhất, và các module sẽ không cần tạo ra những cấu trúc dữ liệu phức tạp. Tôi sẽ quay lại chuyện này nếu tôi thực sự bắt đầu hiện thực :D.

Hiện tại chỉ có thế. Còn nhiều vấn đề nữa mà tôi sẽ phải suy nghĩ, trước mắt là:

  • Xem xét khái niệm actor dựa trên thing. Actor là một dạng thing đặc biệt có khả năng kích thích một hành động của hệ thống. Actor có thể là người dùng, một hệ thống khác, hoặc chính bản thân hệ thống này.
  • Xem xét một cơ chế để chia vùng cho thing (zone). Chẳng hạn hệ thống có thể phân cấp theo công ty (company), dự án (project), và nhân viên (user). Một hệ thống khác lại muốn phân chia theo nhóm (group) và thành viên (member/user). Có lẽ các cấp này sẽ được quy về zone, với company, project, user, group, v.v là các property của zone.
  • Xây dựng một cơ chế nào đó cho chức năng security. Mục tiêu là có thể tắt bật “bức tường” security này tùy ý mà hệ thống vẫn hoạt động bình thường.
  • Và mở rộng hơn, là một cơ chế module phù hợp để xây dựng các chức năng dựa trên nền cơ bản này.

Tôi nghĩ xây dựng khái niệm là điều quan trọng khi bắt đầu xây dựng hệ thống. Cho dù cấu trúc của nó có thế nào, thì việc đầu tiên có lẽ là phải gọi tên được một cách chính xác và ngắn gọn các khái niệm sẽ xuất hiện trong mã nguồn của bạn.

Linh tinh về datagrid

Table, datagrid (không biết từ này có trong từ điển không, tránh nhầm với data grid), bảng dữ liệu, v.v là thứ không thể tránh khỏi khi làm mấy thứ hệ thống thông tin :(. Trên thị trường hiện nay có rất nhiều loại datagrid cho web. Hàng bán cả nghìn USD cũng có, hàng trôi nổi cũng không thiếu, mẫu mã đẹp, chức năng đa dạng, nhưng đã dùng là phải hối hận. Chúng ta sẽ xem xét một vài tiêu chí để chọn hoặc xây dựng datagrid.

Nhưng mà trước khi bắt đầu có lẽ tôi phải nói điều này. Nếu bạn định dùng DataGrid của Dojo, hay đang cố gắng chỉnh sửa nói, hay đang cố gắng khắc phục lỗi của nó, thì bạn nên cân nhắc việc bỏ hẳn nó để dùng một thứ khác, có thể là HTML table, có thể là bạn tự viết, SlickGrid, jqGrid, v.v. Nói rộng hơn, nếu bạn đang định dùng hay mới dùng Dojo thì hãy cố gắng tránh xa nó ra trước khi quá muộn.

Quay lại bài.

Quan hệ giữa dữ liệu và việc hiển thị

Các datagrid nói chung thường hay cố gắng quá mức trong việc quản lí data, như xây dựng các Store hay Model để lấy dữ liệu từ server, phân trang, tìm kiếm, cập nhật động, v.v mà trong khi đó xem nhẹ các method để giao tiếp trực tiếp với việc hiển thị. Hệ quả là việc tổ chức dữ liệu cho datagrid sẽ bị couple một cách cứng nhắc, gây khó khăn trong việc tùy chỉnh datagrid hay chuyển đổi sang một loại datagrid mới. Ở mức tối thiểu, datagrid phải cho chúng ta thực hiện những hành động như:

  • thay đổi giá trị được hiển thị (chứ không phải giá trị của dữ liệu) trong một ô
  • render lại một ô, một dòng, hay một khu vực nào đó (chứ không phải cập nhật dữ liệu của datagrid)
  • thay đổi thứ tự các dòng (chứ không phải sắp xếp bản thân dữ liệu của datagrid)
  • v.v

Trong trường hợp tự viết datagrid, tôi nghĩ chúng ta sẽ có ba thành phần:

  • Thành phần hiển thị, đây chính là datagrid. Thành phần này chỉ yêu cầu dữ liệu với cấu trúc tối thiểu, không cần hiểu những chức năng như sắp xếp, tìm kiếm, v.v. Đối với nó, dữ liệu chỉ là để  hiển thị.
  • Thành phần quản lí dữ liệu, như Store hay Model tùy theo framework hay cách bạn viết. Thành phần này ngược lại, không cần biết và không nên biết rằng dữ liệu sẽ được hiển thị với datagrid hay bất kì cái gì.
  • Một datagrid builder để xây dựng cầu nối giữa hai thành phần trên.

Không may là nhiều datagrid có sẵn lại được cung cấp ở dạng datagrid builder, với hai thành phần đầu tiên trộn lẫn rất chặt với nhau.

Markup được sinh ra

Tùy vào mức độ phức tạp của bảng dữ liệu, datagrid có thể dùng thẻ table của HTML, hay dùng thẻ table cho mỗi một dòng, hoặc dùng div và CSS để xếp thành bảng. Riêng table có một ưu điểm là cấu trúc bảng sẽ luôn được bảo đảm bởi ngữ nghĩa của markup, sẽ không bao giờ có chuyện ô trên rộng, ô dưới hẹp, mất ô, v.v. Nói chung, mỗi kiểu có ưu nhược điểm khác nhau, tuy nhiên tốt hơn cả là việc render có thể thay đổi được, dựa vào chẳng hạn những hàm callback. Datagrid sẽ không cần biết dữ liệu được hiển ở dạng bảng hay dạng gì, chúng chỉ cần biết là phải render ô, một nhóm các ô (ví dụ gọi là dòng), và một nhóm các dòng (ví dụ gọi là trang), v.v. Khi đó với dạng đơn giản chúng ta có thể render bảng dùng thẻ table, với dạng phức tạp chúng ta dùng div, v.v. Nếu không thì ít nhất việc thay đổi style như chiều rộng, chiều cao có thể được thực hiện dễ dàng bởi một người chỉ biết CSS. Đồng thời chiều cao của datagrid không được phụ thuộc nhiều vào sự tính toán của JavaScript (như DataGrid của Dojo), mà phải phụ thuộc vào việc reflow của trình duyệt.

Cơ chế plugin

Datagrid nào cũng cho bạn tự viết các hàm callback để tạo giá trị hiển thị trong một ô, hay tạo các thành phần giao diện để người dùng có thể nhập dữ liệu. Tuy nhiên, một datagrid tốt thì nên để cho người dùng có thể tùy ý thay đổi markup. Lí do là việc hiển thị dữ liệu hay thay đổi theo yêu cầu của phần mềm, như tô màu, ẩn, nhập ô, v.v và đều khó đoán trước. Trong khi đó datagrid là một thành phần giao diện phức tạp và việc đọc hiểu cũng như sửa đổi từ bên trong sẽ đòi hỏi nhiều thời gian và công sức. Tốt nhất là datagrid nên cung cấp những hàm callback với tham số là bản thân DOM node của các thành phần trên datagrid. Các callback này có thể được thể hiện như những filter method nhằm cho phép các module khác nhau có thể chỉnh sửa cùng một bộ phận trong markup.

Bốn câu hỏi

Và những tuần qua tôi gặp rất nhiều rắc rối với việc làm theo cảm giác và sự mơ hồ.

Từ việc làm cái gì…

Có một vấn đề (tôi nghĩ là dự án nào cũng sẽ có thôi) là cấp dưới thì không biết rõ là làm một chức năng nào đó để làm gì, còn cấp trên thì không truyền đạt được một cách cố định là cấp dưới cần làm cái gì để làm gì. Trong trường hợp với dự án tôi tham gia, chúng tôi bỏ thời gian thảo luận những chi tiết nhỏ nhặt, tỉ mí hóa những thứ mà dù thế nào cũng có thể không ảnh hưởng tới mục tiêu cuối cùng. Và những lí do như “làm cho người dùng tiện dụng”, “Agile” được tung ra như những vũ khí nhằm bảo vệ một ý tưởng nào đó. Những cuộc tranh luận cứ đi xa dần, xa dần và kết quả là chúng tôi có nguy cơ làm một thứ lớn hơn rất nhiều thứ chúng tôi thực sự cần cho chức năng đó. Và những thứ thực sự cần thì có khi lại chưa hề nghĩ tới. (May mắn là tôi vẫn có một người cấp trên nhạy bén để ra những quyết định đúng đắn và nhanh chóng, nhưng không phải lúc nào chúng ta cũng may mắn như vậy phải không?)

…tới việc làm thế nào

Một trong những ưu điểm trong việc gói những công nghệ vào những từ ngữ đơn giản là nó giúp chúng ta tưởng tượng ra vấn đề rất nhanh, và nhược điểm là chúng ta tưởng tượng nó rập khuôn thay vì thực sự nghĩ về giải pháp hay lí do bên dưới. Chẳng hạn những từ như cloud, AOP, SOA, v.v vừa có vẻ rõ ràng vừa có vẻ mơ hồ. Sự mơ hồ sẽ khiến những suy luận có lí bị lấn át bởi cảm giác. Có lẽ tôi sẽ lấy luôn ví dụ mà tôi đã gặp. Pull và push bạn nghĩ cái nào tốt hơn? Tôi sẽ nói là không có cái nào. Pull khiến chúng ta liên tưởng tới poll. Và poll thì thường bị cho là dở. Nên pull là dở. Vậy cơ chế tự cập nhật phần mềm của Windows là pull hay push? Có thể nói là pull, vì máy tính luôn quyết định việc có tải xuống gói cập nhật hay không. Vậy là pull không hẳn là dở. Sự nhập nhằng là do chúng ta thực tế không bao giờ phải xem pull hay push cái nào tốt hơn, mà là những giải pháp cụ thể cái nào tốt hơn. Khi bạn gói những giải pháp vào những từ mơ hồ như pull và push là bạn đã bóp méo quá trình ra quyết định.

“Tôi thấy như vậy không hợp lí”

Và khi những lập luận mơ hồ như vậy được đưa ra để lấn át quá trình ra quyết định dựa vào những dữ kiện thực tế, thì mọi cuộc thảo luận xem như đã kết thúc. Những lập luận mà trong đó không có một lí do sẽ rất khó bị phản bác, vì thực sự là nó không cung cấp điều gì để mà phản bác. “Tôi thấy không hợp lí”, “làm sao cho tốt nhất”, “Agile”, “tôi thấy kì”, v.v sẽ là vũ khí bí mật của bạn. Và không, quan hệ không giải quyết vấn đề. Đi chơi, hội hè có thể giúp mọi người thân mật và hiểu nhau, nhưng nhiều nhất nó chỉ giúp mọi người thảo luận một cách hòa bình. Nếu không có một cơ chế thực sự khoa học và chặt chẽ để ra quyết định, thì từng cá nhân có cố gắng tới đâu cũng sẽ không thể đưa các quyết định đi theo con đường đúng đắn.

Bốn câu hỏi

Đây là bốn câu hỏi mà mấy hôm trước tôi học được của một người bạn để ra các quyết định. Không biết nó là của ai.

  1. Thực tế hiện tại là gì?
  2. Thực tế đó gây ra vấn đề gì?
  3. Lời giải của tôi là gì?
  4. Khi làm như vậy thì điều gì xảy ra?

Nếu câu 1 bị bỏ qua, chúng ta sẽ không thấy được nguồn gốc sâu xa của vấn đề. Nếu câu 2 bị bỏ qua, thì chúng ta sẽ đi tìm những câu trả lời cho những câu hỏi mà chúng ta thực ra không định hỏi. Nếu câu 4 bị bỏ qua, khả năng lời giải ở câu 3 không phải để trả lời cho câu 2. Và chúng ta tiến vào thế giới của sự mơ hồ.

Bốn câu hỏi có thể chỉ ra sự mơ hồ, nhưng có lẽ chúng ta cần thêm một cái gì đó.

Tag

Chỉ là một suy nghĩ chơi, có thể trùng với chỗ nào đó rồi.

Liệu chúng ta có nên nhìn một số kiểu input và property dưới dạng tag. Hãy lấy một ví dụ cụ thể. Tôi có một hệ thống quản lí test case và feature với những thuộc tính như:

  • Mỗi test case có một status, như new, abandoned, finished.
  • Mỗi test case có thể ứng (liên kết) với nhiều feature.
  • Mỗi test case có thể có nhiều tập tin đính kèm.
  • Mỗi feature có thể ứng (liên kết) với nhiều test case
  • v.v

Để ý rằng những tính chất này khá là động, theo nghĩa nó có thể thêm vào bớt đi tùy nhu cầu của người dùng hay người phát triển, và mỗi người dùng lại muốn một cách thiết lập khác nhau.

Chúng ta có thể nhìn các khái niệm trên như sau:

  • Mỗi test case hay feature đều là một sự vật, và đều được mô tả bởi các tính chất.
  • Mỗi property của test case hay feature, như status hay tập tin đính kèm, đều là những tính chất.
  • Các property đều có giá trị, tập giá trị có loại là vô hạn (như text), có loại là cố định (như một tập các check box). Những giá trị này là những “tính từ” mô tả tính chất.
  • Mỗi người dùng hay nhóm người dùng có thể tạo các tập property khác nhau. Ta sẽ coi như đây là các ngôn ngữ khác nhau. Mỗi ngôn ngữ có một bộ từ vựng riêng.

Trước hết, cần hiểu rằng mỗi sự vật đều có tính chất. Nhưng mối quan tâm và cách mô tả sự vật của mọi người đều khác nhau, nên phải tách tính chất chủ quan ra khỏi bản thân sự vật. Trong trường hợp này, chúng ta phải thiết kế để test case hay feature giữ những thuộc tính tối thiểu, và những tính chất cũng test case hay feature sẽ được giữ ở một nơi hay module khác.

Lúc này ta có thể tìm cách xây dựng một cấu trúc chung cho tất cả các property với tập giá trị hữu hạn (vô hạn cũng có thể, nhưng tạm lấy hữu hạn cho dễ nói). Những giá trị này giống như tag (nên tôi đặt tên bài viết là tag). Trong đó mấu chốt là xây dựng tính từ sao cho nó có thể đại diện cho mọi loại đối tượng, cụ thể như:

  • Những tính từ mà người dùng thoải mái thêm vào, như status của test case (new, abandoned, v.v).
  • Những tính từ ứng với đối tượng trong hệ thống. Ví dụ như property thể hiện các feature được liên kết với test case. Mỗi feature chính là một tính từ, cho nên tính từ được sinh ra theo đối tượng.

Khi ta xây dựng được một loại tính từ có thể đại diện cho mọi loại đối tượng, thì việc viết các input cho giao diện cũng sẽ được quy về những loại chung, chẳng hạn:

  • Input cho tối đa n giá trị, n từ 1 tới vô cùng.
  • Input dạng check box, radio, drop down list. Nói chung là dạng mà mọi giá trị được liệt kê.
  • Input dạng search, người dùng sẽ tìm kiếm tại chỗ các tính từ mà họ muốn, đặc biệt là những tính từ ứng với đối tượng trong hệ thống.

Điều này cũng sẽ giúp ta đơn giản hóa việc xây dựng một engine cho việc query dữ liệu. Ví dụ ta có thể đưa ra một cú pháp chung là “<property> has value <adjective>”. Việc query chỉ thực hiện trên tập tính chất và tính từ, nên ta sẽ không phải viết code để xử lí cho từng thuộc tính riêng.

Cuối cùng, chúng ta cần khả năng tách biệt giữa các loại ngôn ngữ và từ vựng, để đảm báo người dùng sẽ có được sự tự do khi làm việc với hệ thống, và người phát triển sẽ không phải nghĩ nhiều về việc người dùng cần gì.