Đây là vấn đề cốt lõi cần được giải quyết của việc chuyển đổi sang môi trường Agile.

Push system (hệ thống đẩy) là mô thức quản lý phổ biến hiện nay, sử dụng một quy trình được đinh nghĩa trước cùng các vai trò và mô tả công việc tương ứng. Mọi công việc được chỉ định tới một thành viên cụ thể, quy định từng mức trách nhiệm và khả năng quyết định. Trong một hệ thống phân cấp, mọi công việc đều:

  • cần phối hợp và báo cáo cho người quản lý trực tiếp;
  • thực hiện bởi người ở mức thấp hơn trong phân cấp quản lý.

Thông qua việc định nghĩa rõ ràng sự phân cấp trong mô hình tổ chức, mọi công việc đều được định nghĩa cụ thể về mục tiêu, thời điểm hoàn thành, tiến độ… giúp người quản lý thực hiện việc push công việc xuống những nhân viên như commandcontrol được những gì đang xảy ra; chất lượng công việc phụ thuộc lớn vào tài năng của những nhà quản lý. Push system dựa trên giả định rằng những nhân sự không có động lực làm việc và luôn cần được giao việc và giám sát để hoàn thành.

Cuối thế kỷ 20, Peter Drucker lần đầu nói về thời đại của những lao động tri thức, những công việc trở nên phức tạp hơn, và cần nhiều kỹ năng để hoàn thành hơn. Hệ quả là sự bất hợp lý trong việc phân chia và giao từng công việc cụ thể tới một cá nhân; mô hình làm việc nhóm với những thành viên có đầy đủ kỹ năng trở nên thắng thế. Và bước phát triển tiếp theo là nhóm tự quản.

Pull system (hệ thống kéo) là mô thức quản lý được điều hướng bởi giá trị và kết quả; những công việc được xây dựng thành một danh sách cần hoàn thành theo một thứ tự nhất định và không được giao cho một thành viên cụ thể; những thành viên trong nhóm sẽ chủ động thực hiện pull công việc và thực hiện. Pull system được xây dựng trên giả định rằng những nhân sự luôn có động lực làm việc và không cần nhiều sự quản lý.

Hiểu được sự khác biệt giữa push systempull system là vấn đề lớn nhất với những tổ chức muốn chuyển đổi sang môi trường Agile. Điều cốt lõi nằm ở:

Cách thức định nghĩa quy trình. Trong push system, quy trình được định nghĩa trước, và thông thường được định nghĩa bởi những người không trực tiếp thực hiện công việc cụ thể, và đặt trọng tâm vào giá trị quản lý. Bộ phận quản lý quy trình định nghĩa ra cách thức thực hiện một chiến lược marketing, những bước thực hiện, tài liệu trao đổi giữa các phòng ban từ việc thiết lập chi phí đến thiết kế hình ảnh, nội dung… song chính họ lại có rất ít kiến thức về cách tạo ra một chiến lược marketing hiệu quả. Quy trình được định nghĩa chủ yếu hướng tới việc giúp những nhà quản lý có cái nhìn toàn cảnh và kiểm soát công việc thông qua chỉ định công việc tới từng cá nhân cụ thể; cho mọi dự án. Nhưng sự cứng ngắc của những quy trình được định nghĩa sẵn làm hạn chế sự sáng tạo, tạo ra rào cản làm chậm quá trình tạo ra giá trị thực sự. Push system và Agile hướng tới thực nghiệm. Thông qua việc thực hành và đo đạc hiệu quả, nhóm tự tổ chức biết cách thực hiện nào là phù hợp cho nhóm trong từng hoàn cảnh cụ thể, và hình thành quy trình riêng cho nhóm; từ đó loại bỏ rào cản và tối ưu giá trị tạo ra.

Trách nhiệm hoàn thành công việc. Điều khiến mọi người phân vân là trách nhiệm cá nhân trong pull system: nếu một công việc không được chỉ định cho một cá nhân cụ thể, điều gì khiến công việc đó được hoàn thành? Đây là một câu hỏi hợp lý; song suy nghĩ theo một cách khác, nếu mọi công việc được chỉ định theo cá nhân cùng KPI tương ứng, những cá nhân này có thể vì tập trung nỗi lực hoàn thành một phần việc cụ thể mà bỏ qua việc cộng tác trong bức tranh toàn cảnh và tạo ra giá trị lớn hơn. Một tester được giao nhiệm vụ cụ thể sẽ cố gắng tìm ra thật nhiều bug thay vì cộng tác với developer trong nhóm nhằm tìm cách hạn chế chúng. Pull system và Agile hướng trọng tâm vào xây dựng nhóm có động lực làm việc – tập trung vào con người. Nhưng đó là cách làm phù hợp với thị trường lao động tri thức ngày nay khi nhu cầu người lao động đi dần lên phía đỉnh của tháp Maslow.

Chất lượng công việc. Công việc được nâng cao khi người thực hiện hiểu được giá trị và có cái nhìn thổng thể. Push system thường chỉ tập trung vào từng công việc cụ thể và bỏ qua góc nhìn về toàn cảnh hệ thống và giá trị, mức độ quan trọng cụ thể của một thành phần công việc tạo ra giá trị chung. Pull system cung cấp góc nhìn toàn cảnh, những giá trị đóng góp của từng công việc cụ thể tạo thành giá trị chung, hỗ trợ việc ra quyết định chính xác hơn. Cách vận hành kiểu thực nghiệm của pull system cũng giúp nhóm tìm ra quy trình cho chính mình, giúp loại bỏ trở ngại, tăng năng suất và chất lượng công việc.

Về cơ bản, push systempull system khác nhau về hệ quy chiếu đo lường và đánh giá. Push system đo lường và đánh giá số lượng và khối lượng những công việc được hoàn thành; song cả số lượng và khối lượng công việc được hoàn thành không đại diện cho giá trị được tạo ra. Ngược lại, pull system đo lường và đánh gía dựa trên giá trị được tạo ra.

2,177 total views, 2 views today

Scrum of Scrums là một phương pháp mở rộng rất tự nhiên của Scrum. Thay vì mở rộng nhóm Scrum thành một nhóm lớn hơn; tổ chức duy trì nhóm Scrum vật lý như một thành phần đơn vị và tạo ra sự liên kết giữa những thành phần này thông qua một nhóm Scrum logic.

Hình minh hoạ cho thấy quy mô dự án với 243 nhân sự. Thay vì mở rộng nhóm Scrum thành 243 thành viên (scale out); những nhân sự được tổ chức thành nhiều nhóm Scrum với 9 thành viên mỗi nhóm. Mỗi nhóm Scrum A có 1 thành viên tham gia vào nhóm Scrum ở mức cao hơn để kết nối, đồng bộ, cộng tác công việc giữa các nhóm và hình thành Scrum of Scrums AScrum B; mỗi thành viên trong nhóm Scrum B có 1 thành viên tham gia vào nhóm Scrum C ở mức cao hơn để kết nối, đồng bộ, cộng tác công việc giữa các nhóm.

Những nhóm Scrum A chính là một nhóm Scrum tiêu chuẩn với những thành viên luôn làm việc cùng nhau và gắn kết với nhau; tôi gọi là nhóm Scrum vật lý.

Những nhóm Scrum B, Scrum C bao gồm những thành viên không cố định; tôi gọi là nhóm Scrum logic.

Nhóm Scrum vật lý được tổ chức là một nhóm Scrum tiêu chuẩn, tuân theo những vai trò, sự kiện, artifact được định nghĩa trong Scrum guide. Nhóm Scrum logic thì khác và cần một chút lưu ý.

Thứ nhất, nhóm Scrum logic chỉ xác định số thành viên, không xác định thành viên cụ thể. Bởi trong nhóm Scrum tiêu chuẩn, mọi thành viên trong nhóm đều biết điều gì đang xảy ra trong nhóm, những gì đang được thực hiện, những khó khăn gặp phải và tiến độ hiện tại. Do đó, bất kỳ thành viên nào trong nhóm Scrum vật lý đều có thể tham gia nhóm Scrum logic và cung cấp những thông tin như nhau. Nhóm Scrum A thường sẽ không chỉ định An hay Bình sẽ là người tham gia nhóm Scrum B; bởi bất kỳ ai cũng có thể giam gia với hiệu quả như nhau; chế độ quay vòng là một ví dụ. Ngược lại, việc này cũng giúp mọi thành viên trong nhóm có trách nhiệm trong việc quản lý chung công việc của nhóm Scrum A. Tương tự như vậy với nhóm Scrum B.

Thứ hai, nhóm Scrum logic không có nhiều lý do để thực hiện mọi vai trò, sự kiện như nhóm Scrum tiêu chuẩn. Nhóm sẽ chỉ thực hiện nhanh Sprint Planning cũng như Daily Scrum để đồng bộ công việc với nhau, cũng như tìm ra những công việc đang bị block (tắc) khiến lộ trình có thể bị thay đổi. Việc xử lý những khó khăn gặp phải nói chung vẫn là trách nhiệm của nhóm Scrum vật lý.

Để Scrum of Scrums hoạt động hiệu quả, việc giảm sự ràng buộc giữa các nhóm rất quan trọng. Scrum of Scrums không giới hạn việc cộng tác, trao đổi trực tiếp giữa những thành viên khác nhóm; song nếu việc này xảy ra với tần suất cao, hiệu suất cùng khả năng hướng tới Sprint Goal của nhóm Scrum giảm sút do có quá nhiều ràng buộc. Điều này nói thì dễ, song trong một hệ thống lớn cùng một phần cutting edge phức tạp thì không đơn giản. Khi đó vai trò của việc thiết kế cũng như phân rã chức năng trở nên quan trọng.

Để tăng sự độc lập, những nhóm Scrum A được thiết kế là feature team, làm việc trên một sản phẩm hoặc một nhóm chức năng cụ thể. Tôi không rõ nhóm thực hiện Firebase của Google được tổ chức theo phương pháp nào, song dù chia sẻ một tầm nhìn chung về sản phẩm, Firebase Database, Firebase Testlab… vẫn có sự phân mảnh lớn trong cách cấu hình, sử dụng (console hoặc API…) bởi họ được tổ chức theo feature team. Về mặt kiến trúc bạn có thể không hài lòng bởi việc tích hợp giữa những thành phần này không thực sự tự nhiên và nhất quán; song dưới góc độ phát triển sản phẩm, việc này cho hiệu quả cao bởi Google chỉ mất 12 tháng để cho ra đời một tập lớn dịch vụ hữu ích.

Scrum of Scrums cũng vậy, đây là cách mở rộng rất tự nhiên để tổ chức việc phát triển sản phẩm với quy mô lớn theo phương pháp scale up thay vì scale out. Những phương pháp khác hầu như cũng chia sẻ chung tầm nhìn này, nhưng có sự trưởng thành cao hơn (và đương nhiên, phức tạp hơn).

860 total views, no views today

Month ago, my colleagues complained that our project was slow to build: it normally took 5 minutes, especially in branch switching it took about 10 minutes. Then I found that it doesn’t belong to only our project, it’s the common issue. And here are somethings I have done in our Android project to get its build faster.

Profiling

How long it takes to get your build done? Let’s add the –profile param to have the exact number. In Android Studio, go to Preferences -> Build, Execution, Deployment -> Compiler and set:

Let build. You could file a HTML file in [project_dir]/build/reports/profile/ generated with the detail time spent for each build task, like that:

I recommend you see the report for any optimisation we do in this article to see how good of each param.

Reasons

There are 2 common reasons of the slow build:

Repositories and dependencies

What does Android Studio do when you click on “Sync Gradle” (if build.gradle file is changed) or build a project? Gradle collect all the dependencies. The good news is Gradle uses cache, a folder to store all dependencies to stop going online. The bad news is if Gradle cannot find any specific dependency, it always goes online to scan the repositories (normally is mavenCenter or jcenter); so it’s really slow if your network isn’t good enough.

There are 2 reasons for Gradle cache cannot be used:

  • Dependency version isn’t fixed.

You could use + signal to let Gradle check for the latest version of a dependency, it always get Gradle online

 

  • Gradle version isn’t fixed.

Each Gradle organises the cache itself, no shared the dependency cache. If your team has some Gradle versions, it takes time to switch and download all the dependencies when you switch Gradle version.

Gradle isn’t optimised

Gradle provides some parameters to allow us optimise but they aren’t normally set in Android Studio.

Gradle is slow itself

Gradle is official used and supported by Android Team but it’s not a fastest build tool.

Solutions

The solutions to solves these issues are:

Setup the fixed Gradle and dependency versions

  • Use same Gradle version as your team settings. The good way is using Gradle wrapper instead of local Gradle by creating the gradlew, checkin the source code repository, go to Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle

  • Specific all the dependency version

Use correct Gradle params

There are some Gradle params you could miss:

  • –offline: Force Gradle using cache
  • –configure-on-demand: Let Gradle only builds the relevant projects instead of all projects
  • –daemon: Let Gradle use in-process build and cut down the initial and warm-up state
  • –parallel: Let Gradle builds your projects in parallel if it’s possible
  • –max-workers: Going with –parallel param to let Gradle know how may threads it could use

So normally command line call could be:

Mapping to Android Studio config, they could be:

Go to Preferences -> Build, Execution, Deployment -> Compiler

Go to Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle

Other settings

Other settings could help is increasing the heap size for

  • JVM

  • multiDex

Use another build tool

OK, it’s time to build your project, open the HTML report file to see how much time you saved.

During the study, I found out that there are some faster build tool than Gradle, especially Buck that is using by Facebook. On my demo, it’s super fast. But of course, it isn’t supported by Android Team and its community is very small. The idea of keeping Gradle and Buck builds in parallel is really nice to get it stable by Gradle but also fast by Buck. I will try to get back to it later.

1,198 total views, no views today

Today I had an accident chance to join an interesting meetup about Craftsmanship in Copenhagen when I visited my company’s office. This event was hosted by NNIT that’s a one of the biggest companies in Denmark and spoken by Mark Seemann, a professional programmer, .NET fan and also a consultant.

It’s the first time I join a meetup in Copenhagen so cannot talk much about that but generally it’s quite good today: very professional and nice place, good speaker, great content, good participants, good free foods and drinks – one reason to attract about 200 people (?) 🙂

This talk was dived into 2 parts. In the first one, about 1 hours, Mark was talking about Software Craftsmanship in his viewpoint: making the good code in humance way by activating System 2 (you could find it, System 1 and System 2 in a great book Thinking, Fast and Slow of Daniel Kahneman). It also shows that a good developers need more soft skills such as psychology, communication… in the top of the toolset. After break, he came back to demo session of how to deal with legacy code by refactoring and adding tests. This example is mostly based on the last post on his blog with some update in the model technology like Entity Framework, DataContext, ApiController… instead of ADO.NET,… but the ideas are still there. Of course, his talk was leaded by some well-known books like Refactoring: Improve the Design of Existing Code of Martin Follower, Working Effectively with Legacy Code of Michael C. Feathers, Clean Code: A Handbook of Agile Software Craftsmanship of Uncle Bob… and Code Katas.

Ok, stop taking about him, do about me 🙂

What makes me happy is these content isn’t new for me compared to the content that we have delivered in annual events of Agile Vietnam. Of course, we always learn something from any meetup but if these things are predictable and doesn’t make our brain work hard, it wouldn’t be new. By comparing the topic quality of a developed country like Denmark, I’m proud of and believe on what Agile Vietnam is delivering to community. It stays up-to-date and world-class. At least, Michael C. Feathers has never talk in Denmark but he had in Vietnam 🙂

But I also feel a bit upset. Mark said “Yes, you are too young and don’t know” after he got laughs by talking a story “There are a lot of company have reference architecture design and they might apply C# style to iOS and Android app project”. It sounds funny, of course. But it’s true: “Yes, you are too young and don’t know”. If you ask a young developers about Agile, TDD, CI… they will tell you as it is only way to build the software today. But why don’t we stop talking about it? There are still the “old” men need to know and need to change. So one of our target is the experienced developers who was tight with the old way and might use C# style for iOS project just because it appears in the reference design. But I’m disappointed that it seems experienced developers don’t want to learn more in Vietnam – there are just few old guys in ours meetups.

But where will we go without learning?

1,063 total views, no views today

In my opinion, iterating through a collection is very basic and simple thing because it appears in any developer’s code everyday (of course in the languages support collection).

It’s normally my simplest question to start the interview to warmup and make the candidate more confident. But I’m wrong. I’m so surprised that 90% of our candidates, who have been (senior) developers for 2-3 years, cannot give the right answer:

Let say I have a collection LinkedList<int> list. What are differences between 2 types of iterating through list:

and

Most of answer I got is “we can have the index by #1 code that we cannot have in #2 code. The performance are the same.”. But it’s incorrect, #1 is really bad code in performance wise.

The performance are the same in the index-based collection, like array or ArrayList. But #1 code is very slow in other collection like LinkedList. The reason is for getting the item at index i (by calling get(i) method), LinkedList needs to iterate from the first item with the counter set to 0, increase it in each step and stop when the counter reach to i. So while the notation of #1 code is O(N2), the notation of #2 code is O(N).

#2 code actually works as

#3 code is exactly the way #2 code works before Java introduced for each syntax.

The best solution is always use #2 code for iterating through any collection. If you are worry about the index, another code would be:

Java is just a used language here but I believe this way works in any language today. Whatever the technology you are chasing, let start from the basic things, language and data structure.

1,116 total views, no views today

Hôm rồi thấy anh bạn share document về RESTful APIs của Shoptify, tự dưng nghĩ đến hình như chưa có bài viết nào bằng tiếng Việt về cách xây dựng RESTful APIs mặc dù vấn đề này đã khá phổ biến. Vậy nên tôi viết bài này, chia sẻ một số best practices mà chúng tôi đã thảo luận và áp dụng khi thiết kế và xây dựng APIs cho sản phẩm của mình.

Tại sao API lại quan trọng trong mỗi sản phẩm? Để hiểu đơn giản, bạn có thể tham khảo bài viết này, dù không mới nhưng có một tiêu đề và nội dung rất hay. “Trong thế giới kết nối như bây giờ, một sản phẩm không thể đứng độc lập, và sản phẩm nào không có APIs, giống như máy tính không được kết nối Internet vậy”.

RESTful

Tôi không phân tích tại sao lại là RESTful, vì chủ đề này có lẽ cần một bài viết khác, nhưng nếu có cũng thành thừa vì gần như chúng ta đều đồng ý với nhau rằng APIs trong thời đại ngày nay sử dụng tiêu chuẩn RESTful.

Nhưng nếu chúng ta đã quyết định sử dụng RESTful cho APIs, thì nên hiểu đúng và làm đúng. RESTful có thể tóm lược như sau:

  • URI như tên gọi (Uniform Resource Identifier), chỉ định địa chỉ của mỗi tài nguyên (resource). VD: api.shop.me/customer hoặc api.shop.me/order
  • Các method của HTTP được sử dụng tương ứng với những hành động CRUD trên resource tương ứng. Thông thường: Create – POST, Read – GET, Update – PUT / PATCH, Delete – DELETE

Hầu hết những webservice cũ chỉ sử dụng 2 phương thức GET và POST và để đơn giản với người sử dụng; nhưng lại sử dụng URI cho cả entity lẫn function. Đừng mang tư tưởng đó khi thiết kế RESTful.

Tại sao là entity?

Webservice theo chuẩn cũ coi resource gồm business entity và method / function nhưng thực sự thì method / function không nên là resource, chỉ business entity là resource như RESTful định nghĩa mà thôi. Nhưng tại sao lại “quy hoạch” theo business entity? Vì dễ hơn. Mọi lập trình viên đều dễ làm việc với entity hơn. Chẳng phải ai cũng bắt đầu với một nghiệp vụ với CRUD một entity đó sao? Trong một hệ thống thông thường, các entity có số lượng ít và “đơn giản”, dễ hiểu hơn các nghiệp vụ (method / function). Cung cấp danh sách các entity cùng ít hoạt động CRUD nhằm ẩn đi những nghiệp vụ phức tạp (thường là lời gọi tới hàng chục method), giúp các lập trình viên sử dụng đơn giản hơn.

Ví dụ, để cập nhật một đơn hàng, chúng ta chỉ đơn giản gọi tới API http://api.shop.me/orders/10 với method PUT kèm theo những thông tin mới, thay vì phải đắn đo giữa một loạt những API như http://api.shop.me/updateOrder, http://api.shop.me/replaceOrder… với hàng loạt những ràng buộc về nghiệp vụ.

JSON only?

Hầu hết những nhóm viết RESTful API giờ đây đều chọn JSON là format chính thức nhưng rất nhiều nhóm vẫn phân vân với câu hỏi “chỉ JSON hay hỗ trợ thêm XML?”. Tất nhiên, có hàng tá lý do để chúng ta hỗ trợ thêm những format khác, đặc biệt là XML. Nhưng theo tôi, chỉ cần JSON là đủ. Tôi không tin rằng ngày nay có lập trình viên hay nền tảng nào không biết hoặc không hỗ trợ JSON. Hỗ trợ nhiều định dạng chỉ làm cho việc kiểm thử API thêm phức tạp.

gzip và binary format?

Có chăng chúng ta nên nghĩ tới việc sử dụng những format dạng binary để tiết kiệm dữ liệu khi truyền tải qua mạng như BSON, MessagePack… Tuy vậy, hãy để chúng là optional, và người dùng có thể định nghĩa format nhận thông qua HTTP Header.

Tương tự là câu hỏi “formatted hay compressed JSON? Có nên enable gzip?” (formatted (hay pretty) JSON là JSON được thể hiện ở định dạng “đẹp”, được format bởi tab…; ngược lại compressed JSON loại bỏ hết các dấu tab, space, enter.. nhằm giảm dung lượng). Compressed JSON và gzip rất tuyệt vời vì có thểm giảm từ 30-70% dung lượng truyền tải. Đồng nghĩa với server sẽ tốn tài nguyên và thời gian để xử lý việc nén. Và với tốc độ mạng ngày càng được cải thiện như hiện nay, có lẽ đặt formatted JSON là mặc định thì tốt hơn. Tuỳ vào điều kiện network (VD trên mobile…), client chỉ định định dạng muốn nhận về thông qua HTTP Header (Content-Type hoặc Accept).

snake_case hay camelCase?

Well, câu trả lời muôn thủa, kiểu như “thế giới có 2 loại người…”. Việc sử dụng snake case hay camel case chủ yếu do sở thích của lập trình viên thôi, không có lý do gì để phân định được. Camel case tiết kiệm hơn snake case (1 ký tự, orderName so với order_name) là lý do không đủ thuyết phục.

Tôi thích snake_case. Vì có vẻ snake_case dễ đọc hơn.

dash hay underscore (- hay_)?

Hmm, tương tự như trên. Theo bạn thì http://api.shop.me/orders/last-updated hay http://api.shop.me/orders/last_updated sẽ tốt hơn? Tất nhiên, http://api.shop.me/orders/lastUpdated thì quá tệ, đừng đưa nó vào danh sách lựa chọn của bạn.

Số ít hay số nhiều?

Tương tự như trên. Để liệt kê các đơn đặt hàng, chúng ta sẽ đặt URI là http://api.shop.me/order hay http://api.shop.me/orders?

Chuyện này giống như chúng ta cãi nhau về cách đặt tên bảng trong CSDL quan hệ vậy, Order hay Orders? Best practice cho việc đặt tên bảng trong CSDL quan hệ là sử dụng số ít: Order; nhưng trong api là số nhiều: /orders. Lý do là nó tường minh và gợi nhớ hơn cho người dùng rằng đây là “danh sách đơn hàng”. Rõ ràng, nó tường minh hơn /order (danh sách đơn hàng) và /profile (thông tin người dùng); cùng là dạng số ít nhưng cấu trúc dữ liệu trả về lại khác nhau.

Câu chuyện phức tạp hơn một chút với /persons hay /people :). Hãy sử dụng /persons.

Quan hệ

Đây là vấn đề đau đầu nhất. Bài toán thế này: Một đơn hàng thuộc về một khách hàng và có nhiều sản phẩm. Vậy thông tin đơn hàng trả về sẽ có những gì? Nếu bạn sử dụng CSDL quan hệ thì chắc chắn là bạn đang lưu những thông tin này trong 3 bảng: Order, CustomerProduct. Trả về một entity có những thông tin giống hệt như bảng Order là điều ngu ngốc. Trả về một entity có  những thông tin được JOIN từ 3 bảng trên còn ngu ngốc hơn. Tại sao? Bởi vì nếu thể hiện đúng data model thì chúng ta cần API để làm gì? Thử tưởng tượng dạng đơn giản nhất của entity Order thế này:

Và để hiển thị thông tin đơn hàng có tên và địa chỉ khách hàng, tên sản phẩm, client (APIs consumer) cần gọi thêm hàng chục API nữa. Bạn cũng hiểu tại sao không nên trả về thông tin đơn hàng được JOIN từ 3 bảng: có hàng trăm thông tin không cần thiết. Việc cân bằng, tìm ra những thông tin nào nên được trả về trong tình huống này không thực sự đơn giản. Ý tưởng ở đây là API nên trả về thông tin “thiết yếu, liên quan trực tiếp tới nghiệp vụ”. Ví dụ trong tình huống này là:

http://api.shop.me/orders/10

Nếu client cần thêm thông tin về khách hàng, gọi tới API http://api.shop.me/customers/105

Nếu client cần thêm thông tin về sản phẩm cho order này, gọi tới API http://api.shop.me/orders/10/products

Và theo trí tưởng tượng phong phú, bạn có thể nghĩ tới việc để client gọi tới API http://api.shop.me/orders/10/products/101 để lấy thông tin chi tiết của sản phẩm có mã 101. Câu trả lời là không. Nếu cần thông tin đầy đủ, client hãy gọi tới API http://api.shop.me/products/101.

Ở đây tôi chỉ dám đưa ra ý tưởng và ví dụ cơ bản, bởi “thông tin bổ sung” trong quan hệ của những entity là vấn đề thực sự không đơn giản và phụ thuộc rất nhiều vào từng nghiệp vụ cụ thể.

Pagination

Hãy luôn sử dụng pagination. Trả về đầy đủ danh sách khách hàng qua API http://api.shop.me/customers là việc tốn kém tài nguyên, đồng thời không hữu dụng. Bởi client cũng sẽ giới hạn lại danh sách này nhằm đáp ứng một giao diện dễ nhìn cho người dùng.

Hãy để thêm những param cố định trong mỗi API trả về một danh sách dữ liệu như /customers, /orders: page, page_size… để client có thể chỉ định http://api.shop.me/orders?page=4&page_size=10. Luôn sử dụng page_size mặc định để giới hạn dữ liệu trả về ngay cả khi người dùng không chỉ định rõ trong lời gọi API.

Tất nhiên, pagination thì có hàng chục cách, trên đây chỉ là một ví dụ.

Filter và dynamic field, dynamic query

Có một cách để giải quyết vấn đề trả về những dữ liệu quan hệ như trên là sử dụng dynamic field. Ví dụ http://api.shop.me/orders?fields=id,time,customer.fullname,product.id

Tương tự với dynamic query để thực hiện filter với những điều kiện truy vấn xác định. Trước đây, chúng tôi sử dụng OData và nó khá hiệu quả.

Ngoài ra, còn 1 khái niệm nữa, là embed: gắn thêm những thông tin liên quan. Ví dụ:

http://api.shop.me/order/10

http://api.shop.me/orders/10?embed=customer

Nhưng embed là một vấn đề khó, đừng chú tâm vào nó nếu không cần thiết.

Metadata

Luôn trả về metadata với dữ liệu dạng danh sách, dựa vào đó client cũng biết được các truy xuất vào những thông tin khác. Ví dụ: http://api.shop.me/orders

 

Partial update?

Một đơn hàng (entity Order) chứa 10 field, điều gì xảy ra nếu chúng ta chỉ muốn chỉnh sửa 2 field? Có 2 cách thông thường:

  1. Giữ nguyên dữ liệu được trả về từ API gọi qua GET, với 2 field được chỉnh sửa và gọi API qua PUT
  2. Set  dữ liệu đúng cho 2 field này, set các field còn lại thành null (hoặc zero, empty… – dấu hiệu nhận biết là field này không thay đổi) và gọi API qua PUT

Cả 2 cách này đều cần gửi lên đầy đủ format của entity. Một cách khác, chỉ cần gửi lên 1 object với đúng 2 field trên, gọi là partial update, thường sử dụng method PATCH.

Partial update rất hữu dụng, nhưng thường có 2 vấn đề:

  1. Việc deserialise ở phía server để ra đúng object không quá đơn giản
  2. Đôi khi gây bối rối cho người sử dụng API, đặc biệt với các required field.

Do đó, partial update nên được coi là phần advanced của API và nên xuất hiện ở version 2, 3.. Trước đây chúng tôi sử dụng OData khá tốt (nhưng không thực sự hoàn hảo) cho partial update. Quan tâm tới vấn đề này ngay từ ngày đầu thiết kế API khiến chúng tôi mất khá nhiều thời gian.

Status code

Luôn sử dụng HTTP code cho catched exception. Thay vì trả về message “Unauthorised” với HTTP code = 200, hãy trả về 401. Bạn có thể tìm hiểu thêm ở đây: http://www.restapitutorial.com/httpstatuscodes.html

Nói chung, RESTful APIs chỉ nên dùng những HTTP code 4xx cho những catched exception (unauthorised, validation…). Nếu những lỗi này là không đủ, hãy mở rộng chúng và đặt tham chiếu trong tài liệu API. Ví dụ, lỗi validation thường sử dụng HTTP code là 400 (bad request) hoặc 409 (conflict), cho lời gọi PUT http://api.shop.me/orders/10 trả về HTTP code = 409 cùng message (10xx dùng để validate order, tương tự 11xx cho customer, 24xx cho product…)

Authorization

Bởi RESTful là stateless HTTP nên đừng làm nóng server và client bởi session hay cookies. Cách đúng đắn nhất là sử dụng Authorization Header. OAuth 2 là chuẩn được khuyến nghị cho RESTful APIs.

Versioning

Vấn đề này với RESTful APIs phải nói là “hay dữ dội”. Sự phức tạp này đến từ việc khác nhau giữa client-side APIs và server-side APIs: khi sử dụng thư viện trên client, chúng ta hoàn toàn chủ động trong việc chọn version “gắn chặt” nó với chương trình, nhưng gọi qua RESTful thì không phải như vậy. Khi một version mới của RESTful API ra đời, version cũ sẽ sớm “chết”.

Có 3 cách thường dùng để versioning RESTful API: 2 trong số đó là versioning qua URI: qua sub-domain (http://v1.api.shop.me/orders) hoặc resource path (http://api.shop.me/orders/v1). Cả 2 cách đều dở như nhau vì nó khiến phía client bị hard-code. Cách versioning qua resource path tệ hơn, vì /v1 vốn không phải là 1 property của /orders. Còn nếu bạn dùng http://api.shop.me/v1/orders thì hãy dùng sub-domain, nó còn tuyệt hơn.

Cách thứ 3 là versioning thông qua HTTP Header (VD: API-Version=v1.1) sẽ tốt hơn nhưng ít người sử dụng, chỉ bởi việc phải đặt thêm HTTP header khiến người dùng không dễ copy-paste URI vào web browser để test.

Một cách tiếp cận khác là “không sử dụng versioning”, nghĩa là cố gắng hỗ trợ việc tương thích ngược hoặc xác định rõ thời điểm cung cấp API mới và yêu cầu người dùng phải migrate lên version mới trong một khoảng thời gian xác định. Đây là cách Google, Facebook.. đang làm. Nhưng phải nói thật là, chỉ khi nào “chúng ta lớn” hoặc có sản phẩm cùng RESTful APIs là trung tâm cuộc chơi về kết nối, tích hợp thì mới dễ thực hiện theo phương pháp này.

Tuy nhiên cũng chẳng có vấn đề gì nếu bạn bỏ qua việc versioning từ phiên bản APIs đầu tiên, hoặc versioning thông qua HTTP Header (nếu API-Version không được chỉ định, sử dụng version mới nhất). Nếu chúng ta không làm tốt version đầu tiên thì chắc gì đã cần tới v2, v3… thậm chí là v1.1 🙂

HATEOAS

HATEOAS là một trong những chuẩn được khuyến nghị cho RESTful APIs và bạn nên tận dụng. Ví dụ một bài toán: Khi lấy thông tin chi tiết của 1 đơn hàng (entity Order), người dùng hiện tại (nhận biết qua Access Token) chỉ được xem và cập nhật, không được xoá; làm sao client nhận biết được những action này? Cách đơn giản là sử dụng HATEOAS, gắn những hyperlink trong giá trị trả về tương ứng với những hành động có thể thực hiện trên entity.

http://api.shop.me/orders/10

HATEOAS rất hữu dụng nhưng như bạn thấy, bandwidth dành cho nó cũng không dễ chịu chút nào; tương tự với việc xử lý để tính toán ra những hành động, hyperlink tương ứng. Nếu không cần thiết, hãy hỗ trợ HATEOAS là optional thông qua header.

Overriding

Đừng ngần ngại overriding nếu cần thiết. HATEOAS không được liệt kê trong default HTTP header, hãy tự định nghĩa. Tương tự với HTTP method nếu thấy cần thiết. Nhưng hãy nhớ là cần thiết, đừng override Authorization thành shop.me-Authorization nếu bạn không biết mình đang làm gì.

Tài liệu

RESTful APIs phải có khả năng self-described hay self-documented; nghĩa là người dùng nhìn vào là biết cách dùng ngay. Tuy vậy, vẫn có những thứ bạn cần viết ra thành tài liệu như: authorization, HTTP header, filter, pagination… và nếu gói gọn trong Getting Started là tốt nhất. Đẹp nhất là người dùng có thể gọi thành công 1 API trong dưới 15 phút thông qua những công cụ đơn giản như curl, Fiddler, REST Console… ngay khi đọc xong Getting Started.

Có những ngôn ngữ / công cụ rất hay như Swagger để viết APIs document, thậm chí là generate document từ code và cho phép người dùng hand-on với APIs. Nhưng hãy cẩn thận, có lẽ bạn cần sandbox environment để tránh người dùng quá “hứng thú” trong việc khám phá APIs của mình.

Cuối cùng

Trên đây tôi chỉ điểm qua một số best practices bạn nên lưu ý khi thiết kế RESTful APIs. Bạn có thể đọc thêm cuốn sách này, không quá hay đâu nhưng có nhiều góc nhìn hơn.

Tuy vậy, trên tất cả, hãy nhớ rằng “Với một lập trình viên backend, thiết kế APIs chính là thiết kế giao diện. Đừng đi ngược xu thế UX, hãy thiết kế chúng thật đơn giản, hữu dụng và mạnh mẽ”. Những lập trình viên có thể kiên trì hơn người dùng cuối, nhưng bạn cũng chỉ có không quá 30 phút để cho họ hiểu cách sử dụng APIs của mình.

8,747 total views, 5 views today

Theo tôi quan sát, database versioning (DB versioning – phiên bản hoá cơ sở dữ liệu – CSDL) thường là vấn đề khó khăn nhất đối với các nhóm triển khai Agile trong việc thực hành CI và CD; thậm chí nhiều nhóm phát triển không nhận ra vấn đề này.

Mọi lập trình viên ngày nay đều hiểu sự quan trọng của những công cụ quản lý source code và có thể sử dụng thành thạo SVN, Git…, tuy nhiên ít người nhận biết được tầm quan trọng và biết cách quản lý những thay đổi trên CSDL. Tại sao lại như vậy? Bởi theo phương pháp phát triển phần mềm truyền thống, CSDL thường được coi như một phần đặc biệt quan trọng và được thiết kế rất chi tiết trong giai đoạn thiết kế phần mềm; và gần như không được phép thay đổi trong quá trình phát triển. Việc thiết kế CSDL cũng thường được thực hiện bởi những người đặc biệt quan trọng nhằm đảm bảo thiết kế tối ưu và đáp ứng tầm nhìn lâu dài của ứng dụng.

Tuy nhiên, phương pháp phát triển phần mềm mới đã thay đổi hoàn toàn cách suy nghĩ và sử dụng CSDL; phương pháp phát triển hướng CSDL (DB oriented programming) đã không còn được sử dụng. Có nghĩa là, CSDL giờ đây chỉ là một thành phần trong phần mềm đơn thuần, không phải là một phần “bất khả xâm phạm”, càng không phải là thành phần đầu tiên được nghĩ tới khi thiết kế kế hệ thống. Dữ liệu vẫn luôn đặc biệt quan trọng, nhưng cấu trúc của dữ liệu (thiết kế CSDL) thì không hẳn. Trong phương pháp phát triển phần mềm Agile, mọi thành viên trong nhóm phát triển đều có thể thay đổi thiết kế DB bất cứ lúc nào nhằm phục vụ cho chức năng mình đang phát triển. Điều này dẫn đến tần suất thay đổi thiết kế CSDL lớn hơn; và vấn đề quản lý thiết kế CSDL cũng phát sinh.

Thứ nhất, khi một lập trình viên thay đổi CSDL, những thành viên khác trong nhóm phát triển không nhận biết được thay đổi này. Vấn đề này được thực hiện rất tốt với source code version control như SVN hay Git; những thành viên trong nhóm chỉ cần check-out là nhận được những thay đổi trên source code. Thứ hai, khi những thay đổi này gây ra xung đột (conflict), nhóm sẽ giải quyết như thế nào? Vấn đề này phức tạp hơn rất nhiều; vì mỗi thay đổi trên CSDL sau khi được áp dụng sẽ không thể roll-back; không đơn giản như cách chúng ta giải quyết xung đột trên source code.

Theo tôi quan sát, những nhóm phát triển thường áp dụng những phương pháp sau:

  • Sử dụng môi trường chia sẻ. Cách dễ nhất (và đôi khi là cách tốt nhất) là sử dụng môi trường phát triển chia sẻ (shared environment); mỗi lập trình viên làm việc trên máy tính của mình với source code được check-out và phát triển hoàn toàn độc lập, nhưng sử dụng chung một DB server. Phương pháp này có rất nhiều điểm lợi, đặc biệt là đảm bảo một môi trường chung với mọi sự thay đổi được cập nhật kịp thời tới mọi lập trình viên. Tuy nhiên, vẫn có ít nhất 2 vấn đề gặp phải:
    • Hiệu năng. Trong phần nhiều dự án (không xử lý dữ liệu lớn), hiệu năng từ việc sử dụng môi trường chia sẻ thấp hơn nhiều hiệu năng xử lý trên máy tính cá nhân (vấn đề đường truyền, phân chia module…); gây ảnh hưởng tới năng suất làm việc.
    • Quản lý revision. Đây là vấn đề không có giải pháp toàn diện. Chúng ta sẽ xử lý thế nào với trường hợp sau: Sau một vài thay đổi, nhóm phát hiện ra rằng một số thay đổi gần đây không đúng và muốn roll-back? Vấn đề này thường xuyên xảy ra giống như việc chúng ta phải revert những commit lỗi khi sử dụng source code version control. Nhưng chúng ta không thể làm vậy với CSDL.
  • Tạo những script tương ứng với từng thay đổi. Ý tưởng ở đây là, nhóm lưu trữ một CSDL ổn định và tương ứng với mỗi thay đổi, từng script sẽ được tạo ra. Trong trường hợp cần revert commit, nhóm sẽ restore CSDL này và áp dụng từng script tương theo tuần tự tới trước commit cần revert. Vấn đề khác có thể nảy sinh, bằng cách nào những lập trình viên biết cách tạo những script theo thứ tự hợp lý khi việc phát triển, commit của họ được thực hiện song song trong khi sự thay đổi trên CSDL cần thực hiện tuần tự? Bằng cách nào nhóm có thể phát hiện ra những xung đột trên CSDL?

Tuy vậy, ý tưởng về việc scripting DB (kịch bản hoá CSDL) là một ý tưởng hay, và được phát triển thành DB versioning. Cơ bản có thể được mô tả như sau:

  • Mọi thay đổi trên CSDL phải được tạo bằng script. Thay vì thực hiện tạo một bảng mới qua công cụ có giao diện người sử dụng, chúng ta viết thành câu lệnh CREATE TABLE và lưu trong file SQL.
  • CSDL cũng được quản lý bởi source code version control. Khi mọi thay đổi trên CSDL là script, chúng ta hiểu rằng CSDL cũng là source code và những file này được quản lý bởi source code version control là điều hợp lý.
  • Mọi script thay đổi trên CSDL gắn với từng phần phát triển phải được commit đồng thời. Ví dụ, lập trình viên thực hiện user story “quản lý khách hàng” cần check-in source code và script tạo ra bảng KhachHang trong một commit. Điều này giúp cho việc quản lý (đặc biệt là revert) trở nên đơn giản hơn.
  • Mọi thay đổi trên CSDL được kiểm tra trong quá trình build hoặc start-up của ứng dụng. Theo tôi, việc kiểm tra nên được thực hiện sớm nhất có thể (tốt nhất là trong quá trình build) nhằm giảm thiểu thời gian lập trình viên nhận biết những thay đổi trên CSDL. Nếu việc áp dụng những script này không thành công, quá trình build hoặc khởi chạy ứng dụng sẽ thất bại; qua đó lập trình viên nhận biết được sự thay đổi và những xung đột đang xảy ra trên CSDL.
  • Các version của sự thay đổi được lưu trữ tại chính CSDL đó. Một cách tiếp cận đơn giản là tạo ra một bảng lưu trữ lịch sử những script đã được áp dụng trên chính CSDL đó.

Kỹ thuật trên sẽ khiến CSDL và những thay đổi trên CSDL (script) được coi là source code; giúp lập trình viên dễ dàng quản lý hơn rất nhiều, cả về tư tưởng lẫn kỹ thuật.

Hiện nay, thị trường cung cấp rất nhiều công cụ hoặc thư viện hỗ trợ việc versioning DB như dbUp, RoundhousE, các sản phẩm của Red Gate…, hầu hết đều có chung tư tưởng trên, và có thể có thêm một số chức năng khác như:

  • Restore DB. Khởi tạo hoàn toàn một CSDL từ các scripts là điều tuyệt vời khi chúng ta có bộ lịch sử đầy đủ; tuy nhiên, quá trình này thường tốn khá nhiều thời gian thực hiện. Cách làm tốt hơn là nhóm phát triển “chốt” một CSDL ổn định, được coi là điểm bắt đầu và chỉ quản lý những thay đổi bắt đầu từ phiên bản này. Sau một khoảng thời gian, một phiên bản ổn định khác có thể được thay thế. Tính năng này nhằm giảm bớt thời gian khởi tạo CSDL nguyên thuỷ.
  • Có thể roll-back khi gặp lỗi. Khi tạo một script cho sự thay đổi, lập trình viên cũng tạo một “roll-back” script. Khi gặp lỗi, công cụ này sẽ thực hiện những roll-back script này theo thứ tự ngược lại giúp CSDL quay lại trạng thái trước khi bị thay đổi. VD: script ALTER TABLE ADD COLUMN Address NVARCHAR(50); có roll-back script là ALTER TABLE Customer DROP COLUMN Address;
  • Sử dụng chính CSDL hiện có lưu trữ sự thay đổi.
  • Tích hợp với những công cụ CI, CD. Đây là một chức năng tuyệt vời khiến việc tích hợp, triển khai chỉ với một nút nhấn; cũng như đảm bảo không gây sai sót bởi con người (rất dễ xảy ra) ảnh hưởng tới môi trường thật.

DB versioning là vấn đề đặc biệt quan trọng và khá nhức đầu trong việc triển khai CD. Tôi sẽ trở lại vấn đề này với một hướng dẫn cụ thể trong bài viết sau.

2,001 total views, 1 views today

Đây là chủ đề nhận được khá nhiều sự quan tâm thời gian gần đây, đặc biệt qua hai sự kiện gần nhất của ITLC. Tuy rằng có nhiều người quan tâm và biết đến DevOps nhưng qua hai sự kiện này, theo đánh giá cá nhân, lượng người “thực sự hiểu biết” không nhiều, đa phần mọi người đánh đồng DevOps và CD; bài viết này mong cung cấp một số thông tin giúp hiểu đúng về DevOps và CD.

CD: Continuous Delivery hay Continuous Deployment?

Những nhóm phát triển phần mềm theo phương pháp Agile thường quen thuộc với kỹ thuật / công cụ tích hợp liên tục (Continuos Integration – CI) nhằm liên tục tích hợp phần tăng trưởng được tạo ra vào sản phẩm giúp kiểm soát tình hình thông qua thực hiện kiểm thử (đặc biệt là integration test, regession test) khiến sản phẩm đạt sự ổn định. Đây là một kỹ thuật / công cụ được thực hiện trong giai đoạn phát triển (development).

Bên cạnh CI, mọi người hay nói đến CD, nhưng lại không thực sự hiểu CD từ viết tắt của Continuous Delivery hay Continuous Deployment và cũng thường cho rằng hai khái niệm này là giống nhau. Thực tế là:

Continuous Delivery, giống như CI là một tập hợp những kỹ thuật / công cụ đảm bảo việc triển khai (deployment) được thành công bằng việc liên tục chuyển giao (delivery) những phần tích hợp lên môi trường staging (thường là rất giống với môi trường production). Bằng việc liên tục kiểm thử trong môi trường staging, phần mềm đảm bảo đủ chất lượng để deploy qua production; những deployable artifact này vẫn chỉ tồn tại trên staging và không được deploy tự động qua production.

Continuous Deployment, đúng như tên gọi, là một tập hợp những kỹ thuật / công cụ đảm bảo việc tự động hoá toàn bộ quá trình từ development đến production. Continuous Deployment được coi là bước phát triển của Continuous Delivery, hoàn tất giai đoạn chuyển giao đến người dùng cuối.

Có thể so sánh CI, CD đơn giản thế này:

  • Continuous Integration: Tập trung vào source code, tạo sự “tự tin” về source code qua unit test, integration test, tạo ra staging-ready-artifact.
  • Continuous Delivery: Tập trung vào artifact và môi trường (environment), tạo sự “tự tin” về deployable-artifact qua acception test, tạo ra production-ready-artifact.
  • Continuous Deployment: Tập trung vào người dùng cuối, tạo ra production-deployed.

Continuous_Delivery_Continuous_Deployment

Vậy: Continuous Delivery hay Continuous Deployment?

Nhưng tóm lại là Continuous Delivery và Continuous Deployment khác gì nhau? Rất nhiều người vẫn bị nhập nhằng giữa 2 nguyên tắc này. Lý do là: nếu staging là môi trường giống với production, thì khi đã làm được Continuous Delivery thì đương nhiên chúng ta cũng làm được Continuous Deployment (đều là deploy qua 1 môi trường, vậy thôi). Đúng. Về mặt kỹ thuật là như vậy. Vì vậy, những công cụ như Pupet, Octopus, Ansible… đều được sử dụng cho CD (còn ai hiểu CD là gì thì tuỳ ngữ cảnh, deploy tới staging thì là Delivery; deploy tới production thì là Deployment). Nhưng công cụ không phải thứ quan trọng nhất.

Thứ nhất, staging không phải production. Dù chỉ cần 1 cấu hình đơn giản là artifact được deploy qua bất cứ đâu. Nhưng chúng ta có đủ “tự tin” để việc deploy qua production được thực hiện tự động?

Thứ hai, staging vẫn không phải là production. Production luôn cần ổn định và mong muốn zero-down-time, staging thì không cần thiết.

Với những single-user-app như ứng dụng chạy trên PC, mobile… thì khá đơn giản, tôi không bàn tới. Với web app, các tổ chức thường dè dặt trong việc triển khai Continuous Deployment vì những lý do trên.

Về lý do thứ nhất, tổ chức chỉ có thể thực hiện Continuous Deployment khi hệ thống QA được thực hiện tự động hoặc “gần như tự động” với phần tích hợp để chắc chắn rằng sản phẩm đủ chất lượng và triển khai đúng thời điểm một cách tự động – đây là vấn đề tương đối phức tạp.

Về lý do thứ hai, cách làm phổ biến là sử dụng kỹ thuật “blue-green deployment”, deploy lần lượt từng phần hệ thống với HAproxy đứng trước nhằm đảm bảo traffic được route tới những phần đã được deploy thành công (green, version mới); trước đó traffic được route tới những thành đã chạy ổn định (blue, version cũ). Vấn đề sẽ trở nên phức tạp khi phần green và blue có nhiều sai khác về business logic dẫn đến không toàn vẹn dữ liệu. Đây là một trong những cản trở lớn nhất khiến tổ chức không “tự tin” với việc deploy tự động (tôi sẽ trình bày trong một bài viết khác).

blue_green_deployments

DevOps

Như bạn thấy, CD dù là Continous Delivery hay Continuous Deployment thì vấn đề phức tạp không phải là kỹ thuật hay công nghệ. Và DevOps cũng vậy.

Việc liên tục triển khai dẫn đến nhu cầu cộng tác chặt chẽ giữa nhóm phát triển (development) và nhóm vận hành (operation) và cách phân chia tổ chức theo nhóm chức năng (functional team) trở nên lỗi thời; cách làm việc liên chức năng (cross-functional) sẽ hiệu quả hơn rất nhiều. Và đó là DevOps. DevOps = Development + QA + Operation.

Như vậy DevOps thực sự là sự chuyển đổi trong tổ chức về cách làm, văn hoá (trong cách tổ chức nhóm, cộng tác…) và kỹ thuật, công nghệ nhằm linh hoạt hơn và nhanh chóng phản ứng với sự thay đổi xuyên suốt quá trình từ phát triển tới triển khai đến tay người dùng cuối với chất lượng đảm bảo một cách nhanh nhất.

Tại sao DevOps phức tạp? Vì DevOps thực sự tạo ra một văn hoá cộng tác để chuyển giao sản phẩm theo cách mới. Theo quy trình phát triển phần mềm cổ điển, các nhóm development, QA, operation hoạt động rất riêng biệt với những kỹ năng, văn hoá khác nhau. Giờ đây họ đứng cùng nhau với một mục tiêu chung và một văn hoá chung. Điều này không thể có trong một thời gian ngắn.

Tại sao DevOps thông thường nhanh thành công hơn trong môi trường Linux? Tôi lưu ý là thông thường. Vì thông thường, nhóm opeartion sử dụng Linux quen thuộc hơn với việc sử dụng câu lệnh, lập trình (viết script…); so với Windows, nhóm sử dụng công cụ đồ hoạ để cấu hình. Và CI, CD nói chung làm việc nhiều với dòng lệnh.

Một nhóm toàn developer có thể thực hành DevOps? Hôm trước, anh Trịnh Minh Cường có nói rằng “nhóm của anh toàn dev, làm DevOps tốt”. Đúng, vì bản thân nhóm phát triển đã có thể build, run phần mềm trên môi trường local thì hoàn toàn có thể triển khai đến production và CD là điều nằm trong tầm tay. Nhưng đó mới chỉ là kỹ thuật. Developer thường không có kiến thức về hệ thống, vận hành như operator. Đơn giản như cấu hình quyền thư mục, chmod 777 giúp họ chạy, test hoàn toàn tuyệt vời trên local nhưng sẽ là thảm hoạ trên production. Chính vì vậy, tổ chức cần sự kết hợp kiến thức, kỹ năng của cả developer, QA, operator để triển khai DevOps thành công.

Và xu thế?

Trong bài nói chuyện của CTO Automic tại ITLC, có nói đến heuristic CD khiến tôi liên hệ tới 2 xu thế chính hiện nay.

Một là, tính agility được mở rộng theo bề ngang của tổ chức. Bắt đầu bởi Agile software development; tiếp đến là DevOps khiến Dev và Ops gắn kết hơn; tiếp đến là NetOps khiến Net và Ops (thậm chí là Dev-Ops-Net) gắn kết hơn.

Hai là, tính agility được nâng cao dần. Bắt đầu bởi manual delivery / deployment; tiếp đến là CD khiến việc delivery / deployment tự động; tiếp đến là heuristic CD khiến việc delivery / deployment tự động ở mức độ “thông minh” hơn, tự động nhưng đúng thời điểm và có “trí tuệ” như manual delivery / deployment.

Những vấn đề này hơi phức tạp một chút, hy vọng tôi có thể trở lại trong một bài viết gần. Ngoài ra, bạn có thể tham khảo những bài viết ở dưới:

http://martinfowler.com/bliki/ContinuousDelivery.html

http://martinfowler.com/bliki/BlueGreenDeployment.html

2,904 total views, 3 views today