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.

Advertisements

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ì.

Kiến trúc sư phần mềm

Chỉ là một vài thứ tôi mong chờ ở một kiến trúc sư phần mềm (KTSPM).

KTSPM, trước hết, phải thấy xa hơn những gì mà một kĩ sư bình thường thấy và thực sự hiểu rõ về hệ thống. Có một chuyện khá là kì cục là các dự án hay bắt đầu bằng cách cho KTSPM viết ngày viết đêm ra một cái gọi là framework (framework ở đâu ra mà lắm thế), sau đó lui ra, và các kĩ sư bình thường sẽ nhào vô viết thêm tính năng, và chúng ta có một phần mềm. Sau đó có thể có chút trục trặc, chậm chạp thì các KSTPM này lại quay trở lại để dọn rác.

Nhưng hãy để tôi kể câu chuyện về dự án mà tôi đang làm đã. Đầu tiên chúng tôi có một KTSPM. Người này chuẩn bị mọi thứ, từ hệ thống build, database, Spring, Hibernate này kia, và cũng viết một ít làm mẫu. Và vì chỉ là làm giúp nên rời dự án nhanh chóng. Sau đó chúng tôi bỏ một thời gian dài loay hoay vừa muốn giữ cái nền này vừa muốn đập bỏ. Khi yêu cầu phần mềm thay đổi và vấn đề nảy sinh thì cái nền rõ ràng là không phù hợp. Nhưng cái nền là do KTS viết ra mà. Sự thiếu dứt khoát khiến cho mọi thứ trong hệ thống mà chúng tôi xây dựng vẫn còn khá là vá víu và không linh hoạt. Trong giai đoạn này có hai người nữa, một người là KTS và một người gần được KTS. Nhưng họ cũng chỉ viết mã cho một vài phần. Có thể là những phần khó hơn, nhưng nó chỉ là một phần nhỏ của toàn bộ bức tranh. Và nó cũng chứa những sai lầm tiềm ẩn như những nhiều phần khác. Và nó cũng có thể được hoàn thành bởi những kĩ sư khác trong dự án, mặc dù có thể là phải có một chút hướng dẫn. Nói tóm lại, những KTSPM đang làm những việc mà kĩ sư làm, chỉ là (có thể) ở một trình độ tốt hơn.

Vậy những sai lầm mà dự án tôi gặp phải và mắc kẹt là gì. Có thể kể ra những thứ khá cơ bản, như bỏ qua các bước an ninh cơ bản (chống XSS, CSRF), không xây dựng một dạng protocol (hay interface) thống nhất cho các request, bỏ lơ vấn đề cache và performance (cache phía server, cache phía client), không có hệ thống build tự động, không có phương pháp chung để xử lí vấn đề cross-browser, v.v. Đây là những vấn đề có tác động quan trọng tới thiết kế của phần mềm, nên không thể giải quyết một sớm một chiều được. Dĩ nhiên, phần mềm là một hệ thống phức tạp mà khi đã đầy đủ các bộ phận thì việc thay đổi sẽ tốn kém. Vì vậy, không thể ngày hôm nay nghĩ về vấn đề này thì xây dựng nó một kiểu, rồi mai gặp hay chợt nghĩ về vấn đề khác thì sửa đối nó theo kiểu khác.

Tất nhiên KTS vẫn nên là người viết những thành phần quan trọng, để góp phần tạo ra một phần mềm có chất lượng tốt. Nhưng kĩ sư giỏi thì cũng có thể viết được những phần khó, họ cũng có thể đọc sách, tìm hiểu, suy nghĩ. Vậy thì giá trị đặc biệt của KTSPM nằm ở chỗ nào, tại sao họ đứng trên một cấp, và lương cao hơn? Theo tôi nghĩ đấy là vì kĩ sư giỏi là những người chỉ giải quyết được những vấn đề cục bộ, riêng rẽ, chứ không thể quan sát hệ thống một cách tổng thể. KTSPM phải là người định hướng. Họ phải liệt kê ra được những yêu cầu, vấn đề, hoặc thử thách mà dự án sẽ đối mặt, trước mắt và tương lai. Họ phải xây dựng được những quy tắc chung để kĩ sư có thể tuân theo nhằm hạn chế sai sót. Họ phải biết phân bổ nhân lực cho hợp lí với từng phần việc. Và họ phải nắm tình trạng phát triển hiện tại của phần mềm để nhận ra những bài toán hay cải tiến cần được thực hiện một cách thực sự đúng đắn và dứt khoát.

(Bạn nghỉ ngơi một xíu trả lời câu này xem. Nếu bối rối thì chắc chưa phải KSTPM rồi.)

Không chỉ nhìn xa hơn những kĩ sư, KTSPM còn phải cố gắng nhìn xa hơn những gì ông chủ nghĩ. Không phải là về kinh doanh, mà là về chức năng của phần mềm. Họ phải biết trừu tượng hóa các yêu cầu cụ thể để có cái nhìn bao quát cho chức năng mà trong đó yêu cầu của những người phân tích nghiệp vụ chỉ là một lựa chọn, một hướng hiện thực cụ thể. Ý định của con người luôn thay đổi rất nhanh, và yêu cầu cũng vậy, nên không có lí do gì lập trình viên đặt niềm tin là những thứ họ phải làm hiện tại sẽ giống vậy mãi mãi. Chuẩn bị tốt cho những lựa chọn chưa xảy ra sẽ giúp phần mềm linh động với những nhu cầu, đòi hỏi từ thị trường. Và điều quan trọng là thấy trước thay đổi của hệ thống là nhiệm vụ của KSTPM, không cần ai khác phải nói ra, và họ sẽ không thể đổ lỗi đi đâu đó như người phân tích nghiệp vụ, hay người dùng nếu không thực hiện tốt nhiệm vụ này.

Chẳng hạn, hãy nói việc hỗ trợ bookmark cho những web application dùng AJAX nhiều. Nếu một trang web mà trạng thái của nó, như đang mở tab nào, đang hiện nội dung gì, không được thể hiện trên địa chỉ thì người dùng sẽ không thể bookmark để quay lại trạng thái đó một cách nhanh chóng được. Tuy nhiên, yêu cầu phần mềm thường quên mất chuyện này, trong khi nếu không được thiết kế ngay từ đầu thì việc chỉnh sửa thiết kế của ứng dụng để hỗ trợ chức năng này sẽ khá rắc rối. Do nên KTSPM phải biết tự thấy trước và đáp ứng chức năng ngay khi chưa có yêu cầu.

Có thể tóm lại là KSTPM trước hết phải biết nhìn xa, nhìn trừu tượng, không chỉ xây nên framework mà còn những tiêu chuẩn, quy định, và đường lối cho dự án.

Điều thứ ba, liên quan đến cách mà một KTSPM làm việc với nhân viên (và sẽ không viết ở đây).

(Nhưng bạn có thể đọc bài này để tìm kiếm một vài ý tưởng.)

UX cho người không chuyên

Tôi thấy UX là một vấn đề vừa bị xem nhẹ vừa bị thổi phồng. Xem nhẹ ở chỗ dường như ai cũng hiểu và lí luận về UX mà không cần tham khảo ý kiến xung quanh, ngay cả khi chưa từng biết hay tìm hiểu về những kiến thức liên quan. Thổi phồng là ở chỗ người ta quá coi trọng nó, chăm chút nó, tới nỗi tiêu tốn một phần không nhỏ thời gian cho những cuộc họp dài lê thê hay sửa đi sửa lại một chức năng nhỏ. Nếu dự án thiếu đi một người thực sự giỏi về UX để cầm trịch, thì những điều nói trên sẽ càng trầm trọng và đe dọa sự thành công của phần mềm.

Như vậy nên làm thế nào nhỉ? Tôi không biết, vì những gì tôi gặp phải chỉ là những kinh nghiệm rời rạc trong từng tình huống cụ thể, chưa đủ để tạo thành một tư tưởng gì đó thật đúng đắn. Bạn mà làm lập trình viên thì bạn cũng sẽ phải làm đi làm lại một chức năng cho UX nó tốt hơn thôi. Tuy nhiên, dưới con mắt lập trình viên, tôi nghĩ rằng với những nhóm nhỏ không chuyên về UX, thì điều quan trọng là làm cho phần mềm ổn định, logic, và linh động (hay nói cách khác là dẹp UX qua một bên).

Để có UX tốt thì trước hết phải chạy được đã, tức là phần mềm phải ổn định. Để phần mềm ổn định thì nhất định không được làm những thứ quá khó, đặc biệt là những thành phần trên giao diện web trong thời đại mà JavaScript là tất cả. Tôi biết là lập trình viên ham thử thách, và không có gì là không thể khi ta quyết tâm, v.v nhưng mà đôi khi phải nhìn nhận thực tế là chúng ta không đủ trình độ để làm mọi thứ, và nhìn ra thứ gì khó làm, không làm được, hoặc dễ gây lỗi cũng là một cách thể hiện trình độ. Với người viết yêu cầu cho phần mềm, cần nhìn ra bản chất của một yêu cầu để tìm ra cách thể hiện phù hợp và khả thi, nhất là tránh bị cuốn vào những hành vi tủn mủn trên giao diện mà quên mất chính flow bên dưới mới là thứ quyết định UX tốt hay không.

(Đấy là chưa kể thời gian cho việc phát triển một phần mềm luôn là có hạn, cho nên hệ quả là thời gian cho nhiều thứ quan trọng không kém như kiến trúc, unit test, build, deploy, v.v sẽ bị ăn bớt. Kiến trúc là thứ cần ổn định, mà một khi phần mềm đã cho dùng đại trà thì việc thay đổi nó sẽ khó khăn hơn. Còn yêu cầu về chức năng, UX, v.v thì luôn cần thử nghiệm và đổi mới, cho nên sẽ không hợp lí nếu tập trung công sức và thời gian vào nó trong giai đoạn đầu.)

(Nhưng ổn định không phải là không có gì. Bạn có nhận thấy vào buổi đầu của những ứng dụng web, người ta cố gắng nhái theo những phần mềm trên desktop, điển hình là các web mail. Kết quả là chúng ta có những ứng dụng đầy đủ chức năng, nhưng cồng kềnh, chậm chạp, nhiều lỗi. Về sau này, người ta lại có xu hướng tạo ra những ứng dụng cực kì đơn giản, rồi bổ sung dần tính năng song song với việc đảm bảo tính ổn định. Mọi chức năng đều cần được đưa vào đúng thời điểm.)

Nếu chúng ta không đủ trình độ hay dữ kiện để hiểu được người dùng mong đợi gì, thì hãy cố gắng làm do mọi chức năng logic nhất có thể. Việc không làm người dùng bất ngờ thì sách báo hay nói rồi, tôi cũng không dám ý kiến gì nhiều. Nhưng ít nhất yêu cầu chức năng không được làm lập trình viên bất ngờ. Tính logic sẽ giúp lập trình viên giữ code "ngăn nắp" và ít lỗi. Không nên để lập trình viên phải xoay sở với những sơ đồ trạng thái lòng vòng đầy những kịch bản tủn mủn và khó xảy ra. Chẳng hạn, những thứ mà lập trình viên có thể đoán đúng mà chưa cần đọc yêu cầu, hay người kiểm tra có thể nhớ được dễ dàng thì thường có logic tốt.

(Tôi định viết một vài ví dụ trong dự án tôi làm, nhưng có vẻ dài dòng không cần thiết. Có vẻ các dự án mới thường hay có xu hướng phức tạp hóa mọi flow vì sợ người dùng không hiểu, người dùng "ngu si", v.v. Cho nên người ta hay bỏ thời gian vào việc suy đoán và lựa chọn giùm đường đi cho người dùng, chặn cái này cái kia, thậm chí tìm cách bỏ bớt các thông báo cần thiết. Khi đã cho dùng thử và bắt đầu cảm thấy tự tin thì họ lại bắt đầu đơn giản hóa nhiều thứ. Tuy không có thẩm quyền can thiệp vào chuyện này,  lập trình viên nên sẵn sàng cho những thay đổi tới lui như vậy.)

Có một cách giúp phần mềm ổn định và logic là xây dựng một hệ thống tổng quát cho mọi tình huống, linh động, để người dùng muốn làm gì thì làm. Thay vì bắt người dùng hạnh phúc theo một cách nào đó, thì tốt nhất để họ tự "mưu cầu hạnh phúc". Chẳng hạn, chúng ta có custom fields hay custom flows trong các phần mềm như Jira, tùy chọn màu trong những phần mềm của Microsoft, add on trong các trình duyệt. Bên cạnh đó, undo (như trong Remember the milk) là một công cụ tuyệt vời để người dùng có thể yên tâm khám phá. Tất nhiên, nhìn ra những điều như vậy trong những ngày đầu xây dựng một phần mềm thực sự không dễ. Thường thì những ý tưởng khái quát sẽ nằm sau những giới hạn bí ẩn, không rõ lí do kiểu như người dùng chỉ được tạo một cái gì đó, liên kết một đối tượng kiểu này với đối tượng kiểu khác, không được nhập quá bao nhiêu đó thông tin. Cả người viết yêu cầu và lập trình viên phải nhìn ra các giới hạn ẩn trong yêu cầu của phần mềm để tìm kiếm những bản chất và khái niệm khái quát hơn đằng sau những yêu cầu đó.

(Tôi có nhớ đã đọc ở ít nhất một cuốn sách toán là khi không thể tìm lời giải cho một bài toán, hãy tìm lời giải cho bài toán tổng quát của nó. Nếu bạn vẫn nhớ những bài toán phổ thông thì sẽ thấy sự khái quát trước hết đến từ việc loại bỏ đi những giới hạn cụ thể, chẳng hạn từ (x+1)2 >= 4x ta có (x+y)2 >= 4xy, rồi (x+y)n >= (tôi quên rồi), hay (x1+…+xn)2 >= (tôi cũng quên rồi). Dĩ nhiên là đi xa hơn để nhìn ra giới hạn từ số n (lũy thừa n), hay phép cộng (+) thì phức tạp hơn từ 2 (bình phương), và cần những bộ óc siêu việt hơn.)

Cuối cùng, phải nhắc lại là UX là một thứ rất khó, và quyết định nhầm là chuyện hoàn toàn có thể xảy ra. Nhiệm vụ của lập trình viên là lập trình và lập trình thật tốt, vì vậy trong bất cứ tình huống nào, cũng cần đảm bảo phần mềm ở trong trạng thái vận hành được, và việc thay đổi yêu cầu chức năng, dù nhỏ hay lớn, đều có thể thực hiên trong một khoảng thời gian xác định được, và sẽ không làm mất đi khả năng vận hành của phần mềm.

qTrace—món ngon, bổ, rẻ cho tester

qTrace là một phần mềm miễn phí cho phép bạn chụp lại màn hình và các thao tác của tester trong quá trình kiểm tra, bao gồm các phím được bấm, các nút được click, v.v. Mục tiêu của qTrace là giúp giảm thiểu tối đa thời gian cho các hoạt động “thủ tục” của tester khi phát hiện defect như chụp màn hình, chú thích, nghĩ và viết mô tả các bước làm để reproduce defect. Ngoài ra, với khả năng ghi lại khá chính xác những thao tác mà tester đã thực hiện, qTrace giúp cho tester nhanh chóng tìm ra cách reproduce những defect ít xảy ra mà tester vô tình bắt gặp.

Một điểm mạnh của qTrace chính là giao diện đơn giản, làm một việc duy nhất là ghi lại hoạt động của tester (và làm rất tốt), không có những chức năng linh tinh làm sao nhãng tester.

qTrace lúc chạy:

Untitled5

Và tự động mở rộng khi bạn hover chuột:

Untitled

Để minh họa cho khả năng của qTrace, tôi đã làm theo các bước để reproduce lỗi của Google Chrome Bookmark Manager. Khi kéo thả một bookmark folder vào một folder khác, bạn sẽ thấy cây bên trái không thể hiện cấu trúc folder mới ngay, bạn có thể refresh lại Bookmark Manager để đối chiếu. Đây là kết quả ghi lại của qTrace:

Untitled4

Mỗi bước bên trái sẽ được minh họa bằng hình chụp màn hình với chú thích cụ thể.

chrome bug.5

Nếu cần ghi chú thêm, tester có thể chỉnh sửa vào kết quả mà qTrace tạo ra như thêm chú thích, làm mờ thông tin nhạy cảm, cắt hình, v.v. Những công cụ này được thiết kế cho tester, nên việc sử dụng sẽ nhanh chóng và thuận tiện hơn Paint trong Windows.

Untitled2

Cuối cùng, sau khi đã bổ sung chỉnh sửa theo ý mình, tester có thể submit defect trực tiếp từ qTrace lên các hệ thống tracker phổ biến một cách nhanh gọn—không còn chuyện lưu hình, mở trình duyệt, attach hình, v.v.

Untitled3

Tất nhiên, đây chỉ là những tính năng đơn giản nhất của qTrace. Vẫn còn nhiều tiện ích khác giúp cho tester hoàn thành công việc nhanh chóng. Nếu bạn là tester, tại sao không thử ngay qTrace miễn phí và tự khám phá?

Nói không

Nói với quản lí rằng không có đủ thời gian để hoàn thành một công việc là một trong những kĩ năng tôi muốn có nhất sau gần một năm đi làm. Hoặc bạn phải lựa chọn giữa trễ hạn và sống trong lo lắng vì chất lượng của những thứ mình tạo ra.

Trong ngành này dường như làm kịp thời hạn là một cái gì đó xa xỉ. Tất nhiên mọi thứ cũng có giới hạn của nó, quản lí thì có quản lí ở cao hơn, quản lí ở cao hơn thì có khách hàng, khách hàng thì có thị trường, v.v. Cho nên không phải cứ cái gì cũng nói không kịp là được.

Công bằng mà nói, không cứ gì phát triển phần mềm, mà nói chung bạn không thể có đủ thời gian để làm tất cả mọi việc, nhưng bạn có thể có thời gian để làm những việc quan trọng nhất. Vì vậy làm không kịp cũng là một biểu hiện của tính yếu kém trong việc ước lượng thời gian và đánh giá kế hoạch.

Nói như thế có nghĩa là việc nói không với người quản lí không phải chỉ đơn giản là thu hết can đảm lại mà nói. Chính xác hơn can đảm không có vai trò gì ở đây cả. Bạn phải tính toán được và chấp nhận rằng bạn không có đủ thời gian, phải thấy được việc gì cần làm với chất lượng ở mức độ hợp lí, và phải chọn lấy những giải pháp thỏa hiệp nhất. Càng nhiều thông tin và lựa chọn thì người quản lí sẽ càng dễ tiếp thu ý kiến của bạn. Vậy là kĩ năng nói không phụ thuộc vào khả năng ước lượng, nắm vấn đề và kiến thức và các giải pháp.

Khi biết nói không rồi có lẽ tôi sẽ trở nên chuyên nghiệp hơn rất nhiều.