Có nhiều LTV tỏ ra rất chuyên nghiệp trong buổi phỏng vấn, song tính chuyên nghiệp này không được duy trì những ngày sau đó khi họ làm việc trong tổ chức. Điều đó là không nên, hãy chuyên nghiệp trong mọi việc, kể cả sau khi chia tay.

Nếu bạn đã đến đúng giờ trong buổi phỏng vấn, tại sao không đúng giờ trong các hoạt động khác của công ty?

Nếu bạn đã ăn mặc rất chỉnh chu trong buổi phỏng vấn, tại sao không ăn mặc chỉnh chu trong các hoạt động quan trọng khác của công ty?

Nếu bạn đã tỏ ra mình là người thông minh, nhạy bén và chủ động trong buổi phỏng vấn, tại sao không thông minh, nhạy bén và chủ động trong từng công việc hàng ngày?

Nếu bạn gửi một thư cảm ơn sau buổi phỏng vấn, sao không tiếp tục gửi thư hay nói lời cảm ơn với đồng nghiệp mỗi khi họ giúp đỡ mình một công việc?

Nếu bạn thể hiện sự yêu mến tổ chức cũ, liên tục nhắc đến họ với sự biết ơn, sao không thể hiện sự yêu mến với tổ chức hiện tại?

Nếu bạn liên tục nói về tổ chức cũ với những điều không hay, sao không nhắc đến và tìm cách giải quyết những vấn đề trong tổ chức hiện tại?

Hàng loạt những điều nhỏ nhặt như trên mà tôi không thể kể hết. Nhỏ thôi, nhưng những hành động nhỏ thể hiện tính chuyên nghiệp của một LTV. Sau cùng, tổ chức nào cũng muốn thấy sự gắn kết của nhân viên vào tổ chức và tương lai của tổ chức. Bởi khi đội ngũ cho thấy sự gắn kết, các lãnh đạo dễ hơn trong việc vẽ ra và thực thi chiến lược phát triển.

Tôi quan sát thấy nhiều LTV, sau khi bắt đầu công việc ở tổ chức mới được một thời gian, vẫn mắc 2 sai lầm sau thông qua lời nói. Thứ nhất, vẫn sử dụng cụm từ “công ty em” để chỉ tổ chức cũ. Đây là điều thực sự tệ hại. Thứ hai, liên tục sử dụng câu “công ty cũ của em làm… (thế này)”. Bạn à, nếu công ty cũ của bạn thật sự vượt trội như vậy, tại sao bạn lại ở đây? Kể cả khi bạn nhắc về công ty cũ với những điểm đáng chê, đó là điều không hay. Bạn đã bao giờ hình dung việc mình liên tục nhắc về người yêu cũ trước mặt người yêu hiện tại? Điều đó không tốt chút nào, cho thấy mối quan hệ hiện tại cũng không có tương lai lâu dài.

Hãy thể hiện sự gắn kết với tổ chức hiện tại, ngay từ ngày đầu tiên tới những giờ phút cuối cùng. Chỉ đơn giản là sống hết mình cho từng công việc nhỏ hiện tại, không quan tâm tới quá khứ hay tương lai.

Tới đây, tôi muốn dành một phần để nói về sự chia tay – điều mà theo tôi quan sát, là rất không ổn trong giới CNTT. Nói chung, nếu sự việc kết thúc một mối quan hệ không xảy ra ổn thoả, trách nhiệm đến từ 2 phía. Song trong khuôn khổ của cuốn sách này, tôi muốn LTV làm tốt nhất về phía mình.

Có 3 kịch bản để mối quan hệ giữa LTV và tổ chức đi đến hồi kết.

Thứ nhất, LTV tìm được công việc mới. Đây là kịch bản hay xảy ra nhất, và kết quả của việc chia tay phụ thuộc nhiều vào LTV. Ngay sau khi nhận được thư mời làm việc từ công ty mới, LTV thông báo việc nghỉ với tổ chức hiện tại; thường là thông báo với quản lý trực tiếp. Quản lý trực tiếp sẽ tổ chức một buổi nói chuyện, tìm hiểu nguyên nhân và tìm cách giữ LTV ở lại nếu muốn – song điều này, theo kinh nghiệm của tôi, ít có khả năng thành công. Trong buổi nói chuyện này, LTV cũng đưa ra ngày mong muốn được chấm dứt hợp đồng – đây thường là ngày ngay trước ngày nhận công việc mới theo thư mời làm việc. Một điều rất kỳ lạ là các LTV luôn đưa ra mong muốn là “cuối tuần” hoặc “cuối tháng” với không một chút cân nhắc về các điều khoản trong hợp đồng (thường là thông báo trước 45 ngày) hay tình hình công việc hay dự án họ đang tham gia. Điều này đã được tôi đề cập tới trong phần Phỏng vấn; các tổ chức luôn muốn các LTV bắt đầu sớm. Nhưng tôi cho rằng, đây là trách nhiệm của các LTV, khi họ quá dễ dàng nhận lời khi con số về lương thưởng được đưa ra, phớt lờ những gì đang cam kết với tổ chức hiện tại. Điều này đẩy các tổ chức vào vòng xoáy tuyển dụng gấp nhân sự thay thế. Tự mình đưa ra con số “cuối tuần” hoặc “cuối tháng” thể hiện sự thiếu chuyên nghiệp của LTV, sự thiếu tôn trọng với tổ chức hiện tại. Điều đáng tiếc là việc này xảy ra quá thường xuyên, gần như tất cả những LTV nói chuyện với tôi về việc chấm dứt hợp đồng đều rơi vào mô-tuýp này. Một số LTV được tôi yêu cầu thực hiện đúng cam kết, không được rời đi trước 45 ngày; họ thể hiện thái độ không hợp tác – đây là điều không nên.

Thứ hai, cắt giảm hoặc sa thải. Cắt giảm là tình huống không hay nhưng dù sao cũng tốt hơn sa thải vì khi có nhiều cộng sự cùng cảnh ngộ, LTV thấy ít bị tổn thương hơn. Có nhiều lý do để một tổ chức đi đến quyết định cắt giảm nhân sự: thay đổi định hướng, tình hình tài chính,… Nhưng dù tình huống nào xảy ra, bạn cũng nên biết rằng tổ chức của mình đã làm việc rất chăm chỉ để đi tới quyết định; và những quản lý của bạn đã trải qua những thời khắc khó khăn khi quyết định ai đi ai ở. Tôi không thể nói đây là một trải nghiệm thú vị, song là một trải nghiệm hữu ích với mọi nhà quản lý; và có vẻ COVID-19 đã mang lại điều kiện tuyệt vời để nhiều nhà quản lý có trải nghiệm này. Là một LTV, bạn nên thông cảm và giúp đỡ họ. Thông cảm không có nghĩa là bạn chịu mọi thiệt thòi về bản thân mình. Mọi tổ chức “tử tế” khi thực hiện việc cắt giảm đều có ngân sách cho việc cắt giảm bao gồm: đền bù, hỗ trợ, đào tạo, trợ giúp, … Ở mức tối thiểu, bạn xứng đáng nhận được thông báo sớm trước 45 ngày hoặc khoản hỗ trợ tương đương 45 ngày lương. Nokia khi thực hiện đóng cửa một văn phòng, ngoài việc thông báo và hỗ trợ, họ còn tổ chức các khoá đào tạo cùng việc đôn đáo tìm kiếm những công việc mới giúp nhân viên. Ở Việt Nam, cũng có nhiều công ty như vậy. Tôi cho rằng, đây là cách làm tử tế và mọi doanh nghiệp đều nên như vậy. Nếu bạn không may mắn để có sự hỗ trợ này, đừng ngần ngại đòi hỏi sự minh bạch từ tổ chức về hiện trạng và kế hoạch cắt giảm; điều này không chỉ tốt cho bạn, mà còn tốt cho những người ở lại. Khi mọi thứ được minh bạch và tình hình của tổ chức không đủ tốt để có những khoản hỗ trợ này, hãy thông cảm cho tổ chức và tự tìm con đường khác. Sa thải (một cá nhân) thì phức tạp hơn, điều này thường đến từ việc LTV không đáp ứng được kỳ vọng của tổ chức. Theo luật lao động, tổ chức muốn sa thải một nhân viên phải chứng minh được nhân viên không đạt được hiệu quả làm việc như hai bên đã thống nhất. Khi tình huống này xảy ra, tôi mong bạn hiểu rằng chiếu theo luật lao động và xử lý vấn đề bằng kiện tụng là điều không nên. Nếu hiệu quả làm việc của bạn không tốt, hãy coi đó là một bài học và tiến lên; ngược lại, hãy coi rằng tổ chức không còn xứng đáng để bạn làm việc cùng và tìm một hướng đi mới.

Thứ ba, LTV nghỉ đơn giản vì họ … muốn nghỉ. Điều này cũng hay xảy ra. LTV chỉ đơn giản là không tìm thấy con đường của họ ở tổ chức hiện tại; hoặc họ cảm thấy mệt mỏi và muốn nghỉ ngơi một thời gian. Không sao cả, bạn hãy cởi mở và nói đúng những cảm nghĩ của mình. Tôi đánh giá cao những LTV như vậy, ít nhất họ không đẩy tổ chức vào tình thế khó xử như trường hợp đầu tiên.

Dù tình huống nào xảy ra, tôi cũng mong các LTV lưu tâm tới một số gợi ý sau để việc chia tay diễn ra êm đẹp:

  1. Tuyệt đối không được chỉ dùng email cho việc chấm dứt hợp đồng. Bạn có thể thông báo việc chấm dứt hợp đồng qua email nhưng nên có buổi nói chuyện với quản lý trực tiếp, sau đó, email về quyết định của mình. Đừng sử dụng email cho việc trao đổi qua lại hoặc thông tin theo kiểu “đã quyết định rồi… không còn gì để thảo luận…” khi quản lý trực tiếp muốn nói chuyện. 
  2. Nên rõ ràng về lý do bạn muốn ra đi, cũng như nơi bạn muốn tới. Đừng ngần ngại, đôi khi việc đó giúp ích cho tổ chức để có những thay đổi phù hợp hơn với những nhân sự ở lại; đôi khi quản lý trực tiếp cũng giúp bạn giải đáp những thắc mắc và giúp đỡ bạn trong việc định hướng tương lai.
  3. Hãy để người quản lý thông báo với tổ chức về quyết định của bạn, hoặc bạn tự thông báo vào một thời điểm người quản lý cho là phù hợp. Đừng tự quyết định và hành động mà không qua thảo luận.
  4. Trong quá trình làm việc còn lại, hãy chuyên nghiệp như bạn đã từng như vậy. Hãy làm việc như bình thường. Tuyệt đối không đề cập đến việc ra đi hay tổ chức mới, trừ khi việc đó có liên quan đến việc bàn giao.
  5. Hãy thu xếp công việc và bàn bạc với người quản lý trực tiếp về kế hoạch bàn giao công việc cho phù hợp. Đừng để người khác đánh giá rằng bạn đã để lại một “bãi rác”.
  6. Đến ngày chia tay, hãy nói lời chào qua email hoặc gặp mặt trực tiếp những cộng sự của mình. Ưu tiên gặp mặt trực tiếp và hãy nói lời cảm ơn. Các cộng sự của bạn chắc chắn sẽ hỏi chuyện nhiều về công việc sắp tới; hạn chế nói về nó, đừng để tổ chức hiểu nhầm rằng bạn sẽ lôi kéo những cộng sự của mình sang tổ chức mới.
  7. Bàn giao toàn bộ công việc cũng như tài khoản cá nhân. Dù không ai để ý, tự bạn phải xoá bỏ những thông tin này, không lưu trữ bất kỳ dữ liệu nào của tổ chức trừ khi được yêu cầu để hỗ trợ việc bàn giao.
  8. Từ đây, tổ chức hiện tại của bạn đã là “công ty cũ”. Tuyệt đối không nói xấu về công ty cũ.

Tôi luôn cho rằng có thể đánh giá một tổ chức là “tử tế” hay không thông qua cách họ chia tay nhân viên. Một LTV “tử tế” hay không cũng có thể được nhìn nhận theo cách này. Hãy chia tay trong êm đẹp bằng tất cả sự chân thành. Một ngày nào đó, có thể bạn sẽ muốn làm việc cùng tổ chức hiện tại. Hãy để lại những ấn tượng đẹp.

 302 total views,  7 views today

Đến đây, có một câu hỏi  cho mọi ngành nghề: làm vì đam mê hay vì tiền? Đây không phải là một câu hỏi riêng của nhân sự ngành CNTT, song ngành CNTT có những đặc trưng khiến câu hỏi này “hóc búa” hơn nhiều những ngành nghề khác. Bạn không khó để trả lời rằng anh bạn chạy Grab làm vì tiền hay vì đam mê – đa số người làm những công việc đó vì họ không có lựa chọn khác. Nhưng CNTT nói chung và lập trình nói riêng là câu chuyện khác: không ai lựa chọn làm LTV vì lập trình là lựa chọn duy nhất. Lập trình là nghề vất vả, có sự đòi hỏi và đào thải cao. Lập trình là nghề dễ gây “nghiện”. Lập trình là nghề, hiện nay, đang được chi trả cao. Ba yếu tố trên khiến câu hỏi làm vì đam mê hay vì tiền khó trả lời hơn nhiều với LTV. Tôi được hỏi câu này hàng chục lần khi tiếp xúc với các bạn sinh viên hoặc LTV mới vào nghề: theo anh, em nên làm vì đam mê hay vì tiền? Có quá nhiều sách báo và những người nổi tiếng khuyên các bạn theo đuổi đam mê; cũng có quá nhiều người nổi tiếng khác nói điều ngược lại.

Nếu có một lời khuyên rõ ràng cho LTV, tôi đã không đưa câu hỏi này vào phần Hiểu những thế lưỡng nan. Tôi chỉ có thể đưa ra một vài gợi ý.

Thứ nhất, nếu bạn thực sự yêu thích nghề lập trình, hãy yên tâm theo đuổi đam mê. Với nhu cầu lớn từ thị trường hiện nay, LTV có đam mê (và từ đó, dần hình thành kiến thức và kỹ năng tốt) luôn có cơ hội được trả lương cao và rất cao. Đây là điều thuận lợi mà gần như chỉ ngành CNTT có tại thời điểm này. Là một LTV có đam mê với nghề, bạn nên cảm thấy may mắn. Không một nghề nghiệp nào có sự đảm bảo chắc chắn về tiền bạc sẽ đi kèm đam mê nhưng CNTT thì có: LTV có đam mê được đảm bảo sống tốt thậm chí là sung túc, chỉ cần họ thực sự (là đắm chìm vào công việc bằng hành động) chứ không chỉ là thích (và không hành động gì).

Thứ hai, nếu bạn vẫn đang loay hoay với câu hỏi trên, hãy làm vì tiền. Tôi tin rằng những LTV có đủ đam mê đang được trả công xứng đáng, và họ không màng trả lời câu hỏi này. Tuy vậy, không có gì sai trái nếu bạn chọn nghề lập trình vì tiền. Tư duy làm vì tiền thậm chí cũng tốt vì giúp bạn chuyên nghiệp hơn: bạn lo sợ bị đào thải và vì thế, cập nhật công nghệ thường xuyên; bạn muốn được trả lương cao hơn và vì thế, hoàn thành công việc với chất lượng tốt hơn và nhanh hơn… Nỗi sợ hãi và mong muốn về vật chất nhiều khi là động lực tốt để con người phát triển. Phần lớn người Việt Nam, công dân của một nước nghèo đang phát triển, đang làm việc chăm chỉ vì sự ám ảnh nghèo đói từng đã trải qua. Điều đó không có gì sai trái, thậm chí đáng tự hào.

Tôi từng tổ chức một buổi họp nhóm, để từng thành viên chia sẻ thẳng thắn lý do họ gắn bó với công ty và làm việc trong nhóm. Có những LTV nói rằng, họ yêu thích công việc và sản phẩm này, họ học được rất nhiều, họ chấp nhận mức lương thấp hơn nhiều lời đề nghị từ những công ty khác. Có những LTV thể hiện rõ quan điểm rằng họ cần tiền để có khoản tích lũy cho mục đích xa hơn. Tôi đánh giá rất cao những LTV thẳng thắn và rõ ràng. Sau cùng, họ đều nhận được thành quả xứng đáng khi có hành xử chuyên nghiệp để đồng bộ được mục tiêu của cá nhân với mục tiêu của tổ chức.
Đáng ngại nhất là những LTV không rõ ràng trong câu trả lời cho câu hỏi làm vì đam mê hay vì tiền?. Họ không có đam mê và cũng không có nhu cầu có thêm tiền vì đang được xã hội trả công ở mức cao để có một cuộc sống “đủ tốt”. Họ ở đáy của kim tự tháp mà tôi đã đề cập, và cũng không có nhu cầu di chuyển dần lên đỉnh tháp. Không chỉ ảnh hưởng tới bản thân, họ cũng đẩy tổ chức của mình vào thế khó xử.

 272 total views,  26 views today

You have an idea. You already had a responsive web app, it works well for mobile. It leads you to the thought of having a MVP mobile app to engage users: an app is built by embedded web-view. You also know React Native can help you build a cross-platform app. Very good solution: a React Native app with few WebView screens that point to correct links. Life is so easy, right? Unfortunately, it’s not.

Problems

You are right. It’s a great solution until you need to implement the authentication. There are at least 2 problems if your app requires user login.

Firstly, “remember me” doesn’t work although it works well on web. You need to enter credential whenever the app opens (in cold start).

Secondly, 3rd party authenticators like Google, Facebook… doesn’t work. You tap on “Login by Facebook”, Facebook login page is opened inside the app. Although you already logged in on Facebook app or OS browser, you need to enter Facebook credential whenever the app opens.

The reason is that WebView doesn’t share any data with OS browser. Each time the app starts, a “fresh” browser is initiated. It means there is no cookies, token, history… are stored by default.

There is only one weird function on your app while the rest are working perfectly. Yes, only one. But it kills your whole app. Do you know anyone who is willing to type username & password anytime he opens the app? Yes, if the app relates to very sensitive personal data like personal finance. But your app doesn’t.

Solutions

There are many solutions. I will describe the simplest one with less code change in your existing web app.

Facebook login

Let’s firstly solve the problem with 3rd party authenticators. I use Facebook as an example, you could treat others in the same way. The steps could be:

  • Handle event in WebView to detect user tapping on Facebook login button
  • Open client Facebook login, get the access token
  • Pass token to server to authenticate user

First step is setting up the Facebook SDK, please follow here: https://github.com/facebook/react-native-fbsdk

Second step is handling user tapping on Facebook login link on app, onNavigationStateChange of WebView is the good function to work on. Passing the token to server could be simply made by GET calling from WebView.

The code looks like:

There are some notes:

  • Line 20: we should let WebView stop loading to avoid strange UI: a popup of Facebook login on app on the top of Facebook web login screen (on app). It also stops WebView being redirected from https://facebook.com to https://m.facebook.com that lets the popup show twice.
  • Line 24: Facebook LoginManager caches the access token, calling logOut() before logInWithReadPermissions() helps app detects if user logout the app from other Facebook areas (web etc).
  • Line 64: you need to implement FacebookNativeLogin on server side then setting cookies etc.

Now it works? Yes, but not really. User is still required to press Facebook login when he opens the app. If you want “auto login”, componentDidMount could be a simple solution.

Remember me

Now it’s time for “remember me” function. The common solution is using the cookies. If you already had it running for web, your hands wouldn’t be much dirty. There is a simple solution with CookieManager, you could find it here: https://github.com/joeferraro/react-native-cookies

Well, let’s combine it with componentDidMount above:

Some notes:

  • Line 3: replace it with your correct cookies
  • Line 5: I introduce loggedIn state because Facebook login is separated with your system username/password login. It lets you update uri in WebView of render() function above with a condition combined by loggedIn and facebookToken. But it’s not difficult, right? Hmm, loggedIn isn’t a good name.

Done? Almost. You could see it works really well on Android but not on iOS. In cold start, CookieManager.get() returns value on Android but doesn’t on iOS. Then storing and restoring cookies programmatically is a solution. AsyncStorage could help https://facebook.github.io/react-native/docs/asyncstorage.html. Just add the few lines of code to onNavigationStateChange to store the cookie and set it back on componentDidMount. Fortunately, CookieManager.set() only works on iOS.

Know issues

I hope it help you overcome the common issue of web-view app. I don’t want to put the setting cookies into existing functions because they are too long now. You should refactor it after getting it run.

Is the solution simple? Yes. Is it perfect? No. There are some small issues:

  • We call GET to FacebookNativeLogin with accessToken. Might POST be a bit better?
  • What if the cookies is expired? Is it good to still keep user login? A solution is storing username/password by AsyncStorage and injecting Javascript to auto fill username/password text fields. But I don’t prefer storing any data like that.

But if you are interested in those topics, I will go into the example next post.

 5,044 total views,  4 views today

Ngày nghỉ cafe thảo luận, tôi cho rằng thế giới Agile đang ngày càng phức tạp. Phạm Anh Đới cũng đồng ý rằng, Agile đang bị bias – thành kiến: kẻ thích trở nên cuồng, người không thích trở thành căm ghét.

Bài viết dài, là tập hợp của các ý tưởng lộn xộn. Vì thế bạn có thể nhảy vào bất cứ đoạn nào cũng nhận được các thông tin riêng lẻ; thấy hay thì đọc tiếp, không nhất thiết phải đọc từ đầu.

Agile là gì (và không là gì)?

Tại chính thời điểm này, định nghĩa về Agile hoàn toàn không rõ ràng. Quay lại lịch sử, thuật ngữ này lần đầu tiên được giới thiệu là “Agile Software Development”, sau một cuộc hội thảo giữa 17 người là tác giả của một số phương pháp phát triển phần mềm hiện đại (có tên và không tên), 2001. Họ chia sẻ chung một số phương pháp, nguyên lý… và Manifesto for “Agile Software Development” ra đời với 4 điều trong Tuyên ngôn và 12 nguyên lý.

Vậy là Agile Software Development có định nghĩa từ hời điểm đó, nhưng không bị giới hạn. Sau này có một số phương pháp nữa ra đời, dựa trên những nguyên lý trên, đồng thời khái niệm Agile cũng dần được thay thế cho Agile Software Development và lan dần sang một số lĩnh vực khác. Định nghĩa này chưa bao giờ được “nâng cấp version” một cách chính thức bởi những tác giả cũ cũng như mới nên nó trở nên không rõ ràng.

Agile thế nào (và không thế nào)?

Nhìn lại 4 điều trong Tuyên ngôn và 12 nguyên lý, dễ nhận thấy là chúng khá chung và đúng. Điều này dễ hiểu vì tìm kiếm điểm chung của nhiều phương pháp cũng như đồng thuận của 17 người, đại diện cho 17 tư duy, quan điểm thì khó mà cụ thể được.

Thời điểm đó, Agile là tập hợp của các phương pháp phát triển phần mềm dựa trên sự kết hợp của phương pháp lặp và tăng trưởng. Lưu ý, tôi đang nói về phần “thể hiện” của các phương pháp, không phải “tư duy” (nguyên lý) phía sau.

Nhưng sau này, dựa trên nguyên lý, nhiều thứ khác được coi là Agile với nhưng thể hiện không giống như ban đầu. Người ta bắt đầu nói về no planning, no estimation, no Sprint,… đủ thứ. Một ví dụ là Kanban, nó chỉ có thể hiện phần tăng trưởng, không rõ ràng đề cập tới lặp nhưng vẫn nằm trong Agile.

Agile có gì (và không có gì)?

Lưu ý rằng Agile Software Development cũng phải dựa trên một số nguyên tắc về quản lý, cách tổ chức nói chung nhưng những thứ này không được định nghĩa rõ ràng. Điều này dẫn đến một số hiểu lầm khá tệ. Ví dụ như “self-organized team”“cross-functional team”, Agile sử dụng mà không sở hữu; vậy nên không thể hiểu chỉ Agile mới xây dựng những team như vậy. Hay như mô hình về team stage của Tuckman cũng không thuộc về Agile. Kỹ thuật 5Whys, Kaizen… cũng vậy. Đó là những công cụ để nhóm hay người quản lý nhóm thực hiện tiến hoá quy trình.

Tương tự, DevOps ra đời sau, và “có liên quan” tới Agile. Nhưng ngày nay, cách hiểu Agile quá lớn nên DevOps được hiểu như là “nằm trong”. Holacracy?

Trách nhiệm có lẽ thuộc về những nhà tư vấn, đào tạo không phân biệt rõ, gây ra những hiểu nhầm rằng “Agile là con đường duy nhất để đạt được những điều này”.

Agile hướng tới gì (và không hướng tới gì)?

Agile hướng tới giá trị (value oriented), không hướng quy trình (process oriented). Quy trình trong Agile cũng buộc phải thể hiện được giá trị mới có lý do để tồn tại. Để tìm được giá trị, bắt buộc phải trả lời câu hỏi “tại sao (why)?”. Để tìm được quy trình, câu hỏi là “thế nào (how)?”. Câu hỏi why khó hơn rất, rất nhiều câu hỏi how. Và thông thường, để trả lời được câu hỏi why, chúng ta cần dựa trên how đang tồn tại.

Rắc rối ở đây, các nhà tư vấn, huấn luyện hoặc quản lý mong muốn đưa how vào trước; và kỳ vọng thời gian sau tổ chức sẽ tự trả lời được câu hỏi why. Công bằng mà nói, cách làm này không sai, nhưng nếu why không dần được tổ chức nhận ra, họ vẫn cứ loay hoay trong how. Và vô tình, Agile trở thành process oriented. Dù vậy, các “process” trong các phương pháp Agile vẫn khá tinh giản (so với các mô hình phát triển phần mềm khác), nên các team đã có quy trình trước đó khi chuyển sang Agile vẫn thấy bình thường. Điều tệ hại là, hầu hết các team ngày nay đều không áp dụng một phương pháp nào trước đó cho tới khi thực hành Agile, họ bỗng thấy Agile “cồng kềnh” và trở nên căm ghét.

(Ví dụ, team trong Scrum là self-organized, thật khó tin là đưa 5, 7 con người vào một team và hy vọng self-organized được nên vẫn cần có một số quy tắc, quy trình cơ bản ban đầu; nếu team không có sự tiến hoá, sẽ trở thành process oriented).

Sau không trào “doing Agile”, giờ là phong trào “being Agile” – dù không dễ, tôi vẫn thấy nó thiết thực. Nhưng “go Agile” thì không. Tôi chẳng biết trông nó sẽ thế nào.

Agile phù hợp với gì (và không phù hợp với gì)?

Nên nhớ, Agile ra đời với “Agile Software Development” tức là để giải quyết bài toán của phát triển phần mềm. Scrum nói rõ nó phù hợp với các dự án / sản phẩm nằm trong miền “phức hợp và phức tạp tương đối” về yêu cầu và kỹ thuật – tức là các dự án / sản phẩm đơn giản (đã rõ ràng) hoặc quá phức tạp (VD: R&D, công nghệ quá cao…) cần được xem xét. Thế nào là đơn giản, phức tạp… phụ thuộc nhiều yếu tố: con người, trình độ, công cụ,… nên (ví dụ) Scrum có thể phù hợp với team này ở sản phẩm này nhưng không phù hợp với team khác ở chính sản phẩm đó.

Agile dựa trên giả định về việc “chào đón sự thay đổi” (welcome change, Scrum: adapt to change, XP: embrace change); tức là, mọi cá nhân trong tổ chức đều thống nhất rằng “thay đổi là điều được chấp nhận”. Tổ chức không đồng tình với sự thay đổi, không “chào đón” mà áp dụng Agile là sai từ gốc.

Hầu hết các phương pháp Agile đều dựa trên gỉa định “cá nhân có động lực làm việc” nên các tổ chức còn loay hoay trong việc này cũng nên cẩn trọng.

Nếu nhìn lại các câu hỏi đã được trả lời trên, Agile có thể giải quyết rất nhiều bài toán khác, không chỉ với việc phát triển phần mềm (trong Agile Y tôi còn nói tới cá nhân). Cùng với sự thống trị của các công ty công nghệ (mà lõi là sản phẩm phần mềm), Agile lan rộng sang những lĩnh vực khác, “nuốt chửng cả thế giới”. Cần lưu ý:

– Vì vậy Agile càng không rõ ràng.
– Các lĩnh vực khác không có chỉ dấu rõ ràng về hiệu quả vượt trội của Agile như trong phát triển phần mềm – nơi Agile ra đời do trải qua sự khủng hoảng về phương pháp.

hãy cẩn trọng.

Agile trở thành “thuốc chữa bách bệnh”.

Agile thực sử trở nên không rõ ràng. Cách hiểu gần nhất (của tôi) có thể là “Agile là công cụ (mindset, toolset) để tăng tính linh hoạt (agility) của tổ chức, qua đó thích ứng tốt với thay đổi (hoặc dẫn dắt thay đổi)”.

Và cho đến giờ này, đây có vẻ là “bệnh” rõ nhất của các doanh nghiệp; và với hổ lốn những thứ được gắn tag Agile, Agile có vẻ được kỳ vọng quá lớn để chữa bách bệnh.

Và khi không chữa được, đương nhiên Agile bị đổ lỗi.

Như trên, tôi cho rằng trách nhiệm nằm ở những nhà tư vấn, đào tạo Agile trong việc rạch ròi Agile là gì, và Agile trong phạm vi anh cung cấp dịch vụ là gì, nó thế nào, hướng tới đâu. Bằng cách vơ vét tất cả mọi thứ vào Agile cùng sự quảng cáo quá đà, gây ra sự ảo tưởng về sức mạnh từ tổ chức.

Agile trở thành “đạo”.

Agile dự trên pull-system, giả định “cá nhân có động lực làm việc”, điều này đi ngược với phần lớn cách tư duy về quản lý hiện có. Dù có hệ thống lý thuyết chặt chẽ đứng sau, Agile vẫn cần niềm tin để thực hiện trong tổ chức. Khi phương pháp cần tới “niềm tin” là điểm xuất phát thì nó không khác gì “đạo” – sẽ có kẻ sùng đạo và phản đạo.

Có fan và anti-fan là điều dễ hiểu.

Scrum đã làm tốt gì (và không làm tốt gì)?

Scrum thực sự tuyệt vời. Nó là một mô hình tuyệt vời với đủ sự tinh gọn, hiệu quả cho phép tổ chức “nhận diện vấn đề”. Đây là điều siêu quan trọng để phát triển sản phẩm cũng như phát triển tổ chức.

Scrum không làm việc giải quyết vấn đề. Vậy nên nếu nhóm không giải quyết những vấn đề được nhận diện, Scrum là đống rác cạnh hàng ăn. Nhưng có phương pháp nào giải quyết vấn đề không?

Scrum làm tốt trong việc ghi chú “Scrum dễ hiểu, khó làm chủ”.

Scrum (đúng hơn là các tổ chức cấp chứng chỉ Scrum (Master, Developer, PO)) làm không tốt trong việc đào tạo. Khá dễ dãi. Có 2 lỗ hổng lớn, khiến các ScrumMaster cầm chứng chỉ và nếu không chịu học hỏi thêm sẽ mắc phải:

1. Không trả lời được rõ ràng các câu hỏi trên. Cái gì thuộc Scrum, cái gì không? Dẫn đến ngộ nhận trong lỹ thuyết lẫn thực hành.

2. ScrumMaster không yêu cầu kiến thức về phát triển phần mềm. Về lý thuyết, điều này không sai; song thực tế thật khó để tham gia vào nhóm phát triển phần mềm mà không hiểu gì về cách nhóm thực hiện.

Từ đây dẫn tới những hệ luỵ vô cùng phức tạp. Chuyển giao cái gì? Technical debt là gì? Simple design là gì? Xử lý thế nào? Tài liệu thế nào là đủ?…

ScrumMaster yếu về chuyên môn (ngành) và non tay dẫn dắt nhóm có trình độ cao hơn mình sẽ là thảm hoạ. Đội bóng cần HLV tương xứng. Vấn đề là, tốc độ phát triển của thành viên Nhóm phát triển thường nhanh hơn (và khởi đầu tốt hơn) những ScrumMaster. Vậy nên nhiều nhóm phát triển bắt đầu chán ghét Scrum.

Trách nhiệm này thuộc một phần vào các tổ chức cấp chứng chỉ Scrum, phần lớn thuộc về các ScrumMaster khi không thể hiện được vai trò tương ứng, và cả các nhà đào tạo – không trang bị đủ hệ thống lý thuyết và thực hành.

Trách nhiệm của những nhà đào tạo, tư vấn?

Đừng trách sự tồn tại của những nhà đào tạo, tư vấn. Đừng trách những quảng cáo, khóa học. Đó là nhu cầu tất yếu, và thiết thực, bởi họ giúp rút ngắn con đường tổ chức tiếp cận Agile (nếu muốn). Nếu họ làm việc trên nguyên tắc cung cấp đúng giá trị và đạo đức.

Nhưng, đến lúc này, tôi cho rằng những nhà đào tạo, tư vấn cần phải có câu trả lời rõ ràng cho mình, cho khách hàng rằng với anh, Agile là gì (và không là gì), Agile (trong phạm vi đó) mang lại giá trị gì và lấy đi gì…?

Giống như bác sỹ, cần rõ ràng rằng những thành phần này là gì, tổ hợp lại được gọi tên gì, chữa bệnh gì, chống chỉ định gì, tác dụng phụ gì…?

Tuyệt nhiên không thể mông lung như Agile làm nhóm hạnh phúc hơn, Agile giúp tăng năng suất, Agile giúp tăng tốc độ hoàn thành dự án… – những điều Agile nguyên thuỷ không hề đề cập.

Những chuyện “nhỏ nhặt” khác:

Còn một mớ trao đổi khác. Cơ chán rồi. Có phản hồi mà rảnh thì viết tiếp, thế cho nó Agile.

 2,012 total views,  4 views today

Nhân chuyện được thanh niên đam mê khởi nghiệp chia sẻ về ý tưởng làm sản phẩm, viết qua về câu hỏi: khi nào bắt đầu? Hay là, khi nào thì có thể quyết định bắt tay vào làm một sản phẩm thương mại?

Làm sản phẩm thương mại là quá trình để kiểm chứng 3 giả định:

  1. Bài toán là có thật
  2. Khách hàng là có thật
  3. Thị trường là có thật

Sản phẩm phải xuất phát từ bài toán thực tế. Giả định đầu tiên cần kiểm chứng là “bài toán này có tồn tại thật không?” hay chỉ là cách diễn tả của một bài toán khác, hay đã được giải bằng một phương pháp khác…? Ví dụ, chúng ta có ý tưởng về sản phẩm thu thập câu hỏi trong các buổi hội thảo, thì cần phải trả lời: bài toán đó của ai, người tổ chức sự kiện hay người tham dự…? vấn đề họ gặp phải là gì, số lượng hay chất lượng câu hỏi…? Cần nhớ, người dùng cuối không luôn đồng nghĩa với người có bài toán cần giải; cần tìm đúng người để interview về bài toán của họ.

Sản phẩm thương mại phải có khách hàng. Giả định tiếp theo cần kiểm chứng là “khách hàng có tồn tại thật không?”. Có ai sẵn sàng bỏ tiền (hoặc có thể chuyển đổi ra tiền) để sử dụng sản phẩm như một giải pháp giải quyết bài toán của họ không? Mà tốt nhất là bỏ từ “sẵn sàng” đi, thấy tiền vào tài khoản rồi mới kiểm chứng được giả định này. Có thể bài toán của khách hàng là có thật, song nó không đủ lớn để họ đổi tiền lấy sản phẩm; hay nói cách khác, ROI không đủ tốt thì cũng hỏng. Đặc tính của sản phẩm thương mại là phải có khách hàng chịu trả tiền nên kiểm chứng giả định này phải qua bán hàng. Bán hàng có bao giờ dễ?

Sản phẩm thương mại phải sống được. Giả định tiếp theo cần kiểm chứng là “thị trường có tồn tại thật không” hay chỉ một vài bài toán riêng rẽ của khách hàng đơn lẻ…? Có bao nhiêu khách hàng tiềm năng? Dung lượng thị trường ra sao? Sản phẩm muốn sống lâu dài đương nhiên ROI phải dương; chi phí phát triển, marketing, bán hàng… tựu chung là invest đã xác định, dung lượng thị trường có đủ mang lại return để ROI dương không? Có thể bài toán của khách hàng là có thật, có khách hàng chịu trả tiền thật, song số lượng quá bé để có ROI dương thì cũng hỏng. Kiểm chứng giả định này rất khó, có tới 42% trong số các startup fail là do thị trường không tồn tại hoặc 29% do không đủ tiền để hình thành thị trường.

Vậy khi nào thì nên bắt tay vào làm sản phẩm thương mại?

Là khi đã trả lời thật cẩn thận câu hỏi “tại sao không nên làm (sản phẩm này)?”. Thường thì chúng ta quá dễ dàng tìm được lý do để làm một sản phẩm: interview vài người, thấy một vài bài toán… Nhưng như trên, họ có thực sự chịu trả tiền cho sản phẩm không? Có nhiều người sẽ trả tiền giống họ không?

Đấy là lý do chúng ta phải trả lời câu hỏi “tại sao sản phẩm này không nên tồn tại?”, “tại sao sản phẩm này không cần tồn tại?”, “tại sao không ai làm sản phẩm này?”, “tại sao mình không nên làm sản phẩm này?”… Cứ sau mỗi lý do được đưa ra, là một lần thì trường bị bóp nhỏ lại. Khi tất cả các lý do được đưa ra, rất cẩn trọng, mà thị trường vẫn còn đủ lớn (ROI), thì đấy là lúc sớm nhất để có thể nói “yes, bắt đầu thôi.”

 1,660 total views,  5 views today

Nhân tiện mọi người có vẻ hào hứng về chủ đề nho nhỏ này và đang viết được, viết nôt kẻo ít hôm lại lười.

Trả lời ngắn gọn là dùng. Dùng chứ. Nhưng dùng thế nào cho đúng thì phải hiểu rõ một chút. Bài viết này cố gắng cung cấp nhiều góc nhìn để cân nhắc.

Vì sao ra đời?

Trong GoF, Singleton được đưa ra với mục đích sau: “Ensure a class only has one instance, and provide a global point of access to it.”“Đảm bảo một class chỉ có duy nhất một instance, và cung cấp một điểm truy cập duy nhất trên toàn cục tới instance.”

Cái gì hay?

Hay thì rõ rồi, nó cung cấp ý tưởng của việc một instance duy nhất, điều mà chúng ta gặp trong nhiều bài toán thực tế: một ứng dụng được khởi tạo, một cấu hình hệ thống, một logger… Tôi cá là nhiều người không biết tới Singleton thì không biết giải quyết bài toán này thế nào.

  • Runtime:
    • Không giống như static trong class, object và các giá trị trong đó chỉ được khởi tạo khi cần thiết. Memory và cả CPU đều được tiết kiệm.
    • Cho phép chủ động quản lý life cycle, giải phóng khi cần thiết.
  • Design:
    • Abstract hơn sử dụng static trong class;
    • Có khả năng thừa kế;
    • Có thể kếp hợp với những design pattern khác.

Cái gì dở?

Dở thì cũng có, bởi vậy mới có nhiều tranh luận.

  • Tư tưởng: Singleton trong GoF dở cơ bản về tư tưởng bởi nó giải quyết 2 bài toán khác nhau (dù có vẻ liên quan): “Ensure a class only has one instance, and provide a global point of access to it.”
    • Một class có duy nhất một instance;
    • Cung cấp một điểm truy cập duy nhất trên toàn cục tới instance.
    • Tác giả đã vô tình kèm cả lời giải trong bài toán với giả định: để có một điểm truy cập toàn cục duy nhất thì chỉ có duy nhất một instance được tạo ra từ một class. Bài toán “một điểm truy cập” có thể được giải quyết bởi Facade, Wrapper… không nhất thiết phải là Singleton.
  • Design:
    • Coupling: Vì là global state nên các thành phần bị gắn chặt với nhau;
    • Khó / không thể viết test;
    • Viết dễ sai sót, để lại lỗ hổng (xem bài trước Singleton có thực sự dễ?).
  • Runtime:
    • Không “thân thiện” với theading.

Nên dùng thế nào?

Như vậy, ta thấy rằng đa phần những thứ dở của design pattern này là ở tư tưởng global state. Vậy nên những ai yêu thích functional programming thì sẽ rất anti-pattern này. Cũng đúng thôi, GoF sinh ra cho OOP, không phải FP. Và thời đại của GoF (1994) cũng không quan tâm nhiều tới concurrency – bài toán trở thành rất cơ bản trong thời đại này. Bởi vậy, việc sử dụng Singleton có chút thay đổi. Có 3 điều cần chú ý:

  1. Concurrency: Global state là điều tệ hại cho concurrency. Hãy giảm thiểu tối đa nếu có thể. Global state bẻ cong cách suy nghĩ về luồng và gây mệt mỏi cho việc debug trong concurrency. Nếu bạn muốn thiết kế hệ thống tối ưu hiệu năng và concurrency thì không sử dụng Singleton cũng là một ý hay.
  2. Memory:
    1. Lưu cái gì? Global state cũng là một ý hay vì khiến việc thiết kế và lập trình dễ dàng hơn, nó chỉ không hay khi bạn không cân nhắc tới nên lưu gì. Rất nhiều thứ có thể nhìn dưới góc độ một instance nếu chúng ta không có khả năng khái quát hoá. Logger là Singleton không? Hay có errorlog, accesslog? Database là single thì lưu cả database? Hay chỉ connection? Hay chỉ connectionString? Lưu ít nhất có thể. 
    2. Lưu khi nào? Nhiều người hay gắn Singleton với life cycle của cả ứng dụng, kèm theo việc lưu trữ nhiều, hoặc giữ strong reference dẫn đến GC không thể hoạt động; sớm muộn gì cũng gây ra memory leak. Khởi tạo muộn nhất có thể, giải phóng sớm nhất có thể. 
  3. Language: Cần lưu ý cách sử dụng trong từng ngôn ngữ (xem bài trước Singleton có thực sự dễ?Singleton:threading() in Java), mỗi ngôn ngữ khác nhau sẽ có vấn đề khác nhau. Dù design pattern là mức thiết kế song đừng mang nguyên cách cài đặt từ ngôn ngữ này sang ngôn ngữ khác, hãy nhìn vào diagram và đặc trưng ngôn ngữ.

Trên đây là một số góc nhìn, gợi ý để bạn dùng Singleton đúng hơn. Không có đúng hay sai khi dùng Singleton, dùng đúng hay không mới là vấn đề.

 3,622 total views,  1 views today

Bài trước về Singleton có thực sự dễ, tôi nhận được vài comment rất chuẩn về cách cài đặt xử lý với theading. Vì bài trước tập trung nói về Singleton và các vấn đề có thể gặp phải với reflection, threading, serializable… nên tất cả những giải pháp đưa ra chỉ dừng ở mức ý tưởng không làm bạn đọc phân tâm. Bài này nói rõ hơn về xử lý theading khi cài đặt Singleton.

Tôi sẽ đi vào cài đặt “chuẩn” đã đưa cuối bài Singleton có thực sự dễ trước:

Khi phân tích về threading trong bài trước bạn thấy tôi viết “Vậy nên cần phải synchronized việc tạo object.”. Nếu để ý kỹ, có 2 phần thay đổi:

  • synchronized được thêm vào method getInstance()
  • volatile được thêm vào self (phần này được tôi lờ đi)

Có mấy vấn đề ở đây liên quan tới threading bạn nên biết.

synchronized cần phải tối thiểu

Cần phải khẳng định ngay rằng cách viết trên cho hiệu năng rất thấp. synchronized sẽ thực hiện việc lock method khiến các thread không thể invoke method song song, chúng buộc phải invoke tuần tự. Nếu có 100 thread gọi getInstance(), thread thứ 100 sẽ nhận được object AppConfig sau khi 99 thread trước đã hoàn thành. Sẽ tốt hơn nếu object AppConfig được tạo ra bởi thread đầu tiên, 99 thread còn lại có thể đồng thời được nhận lại object AppConfig.

Double check locking nên được sử dụng trong trường hợp này. Double check locking là một design pattern phổ biến trong bài toán về threading, kiểm tra lock trước khi thực sự lock method (theo nguyên lý return as soon as possible).

if (self == null) được thực hiện 2 lần, nên pattern này được gọi là double check. Đừng bỏ câu lệnh thứ 2 nếu bạn không muốn một hệ quả tai hại (100 object được tạo ra… tuần tự, tại sao?). Đấy là lý do tôi muốn synchronized cả method để ai đọc cũng hiểu.

Chỉ lock những statement thực sự cần thiết và không nhiều hơn mức cần thiết là nguyên lý cơ bản của threading.

synchronized vẫn chưa đủ

Ngay cả khi bạn không bỏ đi câu lệnh if (self == null) nào, vẫn có thể có hàng chục object AppConfig được tạo ra.

(http://tutorials.jenkov.com/images/java-concurrency/java-volatile-1.png)

Hãy nhớ, máy tính có đến mấy loại bộ nhớ, nên việc đảm bảo dữ liệu đồng nhất không dễ. Lan man 1 chút về kiến trúc máy tính qua hình trên:

  • Main memory là RAM.
  • CPU xử lý dữ liệu được nạp vào bộ nhớ của CPU, không phải RAM. Bởi vậy dữ liệu được sao chép theo trình tự RAM -> Lx ->… -> L2 -> L1 cache. Trong lúc đấy hàng triệu thứ đã xảy ra.
  • Tưởng tượng, counter là self, khi 2 thread bắt đầu, self = null, được copy vào cache. Sau đó dù có synchronized thì 2 CPU vẫn lấy giá trị trên 2 cache độc lập để ra quyết định. Kể cả sau khi xử lý xong, giá trị vẫn được giữ trên cache đến khi thực sự cần đưa xuống RAM.

Vậy là ta phải dùng volatile để giá trị của biến luôn được tham chiếu tới RAM khi thay đổi. Vậy đây là giá trị duy nhất.

Còn cách nào khác không?

Nếu để ý, bạn thấy volatile trở nên vô dụng khi ta lock toàn bộ method. Tức là cách cài đặt của tôi ở cuối bài trước là rất ngớ ngẩn. Thật ra tôi cố tình viết vậy, ai không hiểu về threading thì vẫn có giải pháp chạy đúng; người hiểu biết về threading thì có hint đi tiếp.

Tôi không muốn đi sâu vào threading vì vấn đề này phụ thuộc ngôn ngữ, nền tảng. Hy vọng bạn hiểu rằng một design pattern đơn giản như Singleton cũng cần cài đặt cẩn thận và hiểu biết sâu sắc.

Kết

Có 2 vấn đề muôn thưở của lập trình: performance và memory. Bài này đề cập tới performance. Một số comment khác về việc không quản lý tốt life cycle khi sử dụng Singleton gây ra memory leak. Tôi sẽ cố gắng viết sau.

Và đừng hỏi tại sao lập trình lại phải biết kiến trúc máy tính. Bởi vì code không chạy trên máy tính thì chạy ở đâu? Nền tảng quan trọng lắm.

 2,267 total views,  1 views today

Khi nói về Design Patterns, gần 100% những người tôi tiếp xúc đều thực hành Singleton như một design pattern phổ biến và dễ nhất (nhiều người chỉ biết/nhớ mỗi Singleton trong GoF). Tôi thường có 2 câu hỏi:

  1. Sử dụng Singleton và static trong class có gì khác nhau?
  2. Có tự tin cài đặt đúng Singleton?

Thường thì mọi người gặp khó khăn ở câu hỏi #1, và rất chắc chắn ở câu hỏi #2. Tôi thấy, #2 khó hơn #1 nhiều, và nếu bạn không tự tin trả lời #2 thì tôi khuyên bạn nên sử dụng static trong class thay vì Singleton. Tại sao? Đọc tiếp nhé.

Sử dụng Singleton và static trong class có gì khác nhau?

Nếu bạn chưa rõ về câu hỏi thì tôi giải thích thêm một chút: Mục đích của Singleton là tạo ra một object duy nhất trên toàn ứng dụng, kéo theo các thuộc tính của nó cũng là duy nhất; điều này hoàn toàn giống / có thể thực hiện bởi thuộc tính static của class – là nơi duy nhất lưu trữ dữ liệu. Ví dụ:

Cả 2 cách cài đặt trên, appId đều chỉ có một nơi duy nhất để lưu trữ và truy xuất giá trị. Sử dụng static theo #2 gọn và tường minh hơn, vậy cần gì Singleton?

Để ý một chút, một cách cài đặt sử dụng class, một cách sử dụng object. Có 2 sự khác nhau giữa class và object trong trường hợp này:

  1. Life-time: Life cycle của class gắn với ứng dụng, life cycle của object gắn với việc sử dụng. Sử dụng static trong class, những thuộc tính này sẽ được load theo class khi chạy ứng dụng; sử dụng Singleton, những thuộc tính này sẽ được load chỉ khi object được khởi tạo. Trong cả 2 trường hợp, thuộc tính không được tự động giải phóng cho tới khi ứng dụng kết thúc. (do object vẫn có reference được giữ bởi self, tồn tại theo class).
  2. Abstraction: Sử dụng static trong class là concrete implement, sử dụng object cho một tầng abstraction nữa nên dễ thay đổi hơn. Ví dụ, chúng ta cần thay đổi AppConfig sang WindowsAppConfig, theo #2, tất cả mọi nơi truy cập tới appId đều phải sửa đổi; theo #1, nơi duy nhất cần thay đổi là AppConfig.getInstance() (có thể không cần thay đổi nếu áp dụng với những design pattern khác như Factory, DI).

Chẳng có gì đặc biệt, lý thuyết thôi. Chính xác, và vì thế bạn vẫn cài đặt Singleton như đã học? Nhưng thử tìm hiểu thêm nhé.

Có tự tin cài đặt đúng Singleton?

Cài đặt Singleton thế nào?

Dễ ợt, có 2 việc:

  1. Đặt constructor là private để object không thể khởi tạo được từ bên ngoài. 
  2. Cung cấp 1 method duy nhất trả về giá trị static 

Code thường được cài đặt như sau:

Có một vài câu hỏi phía dưới.

Chỉ có đúng 1 object được tạo ra?

Bạn có chắc rằng với cách cài đặt trên chỉ có đúng 1 object có thể được tạo ra? Còn cách nào có thể tạo ra object không?

Reflection là một trong những thứ rất hay ho của một số ngôn ngữ (những ngôn ngữ khác nhau có thể có những tên gọi khác nhau: runtime reference…), và cũng là một thứ khó bởi nó nâng abstraction lên mức runtime. Những pattern như Object Mapper hay DI… không dễ cài đặt nếu không có reflection. Thử đoạn code sau nhé.

Output của đoạn code trên thường sẽ là 2 số nguyên khác nhau, chính là appId. Về lý thuyết, appId chỉ được gán giá trị một lần duy nhất khi khởi tạo object. Như vậy đã có 2 object configappConfig được tạo ra. Điều chúng ta mong muốn là configappConfig là 2 biến cùng tham chiếu tới 1 object trong bất cứ trường hợp nào. Vậy nên giải pháp là kiểm soát constructor.

Chỉ có đúng 1 object được tạo ra?

Bạn có chắc rằng với cách cài đặt trên chỉ có đúng 1 object có thể được tạo ra? Còn cách nào có thể tạo ra object không?

Threading là một trong những thứ rất hay ho nhưng cũng làm đau đầu developer vì nó không đi theo flow thông thường. Thử đoạn code sau nhé.

Hãy thử chạy một vài lần vì cơ hội gặp trường hợp hai số khác nhau được in ra thấp hơn ví dụ trên. Tương tự ví dụ trên, ta có thể khẳng định: có 2 object đã được tạo ra. Sai lầm ở đâu? Hãy để ý method getInstance(), điều gì xảy ra nếu câu lệnh if (self == null) được thực thi đồng thời ở cả threadDownloadthreadUpload? Chúng đều đúng, và câu lệnh tạo object và return vẫn được tiếp tục trên 2 thread độc lập, và trả ra 2 object độc lập. Vậy nên cần phải synchronized việc tạo object.

Chỉ có đúng 1 object được tạo ra?

Bạn có chắc rằng với cách cài đặt trên chỉ có đúng 1 object có thể được tạo ra? Còn cách nào có thể tạo ra object không?

Serializable có thể là một vấn đề. Chúng ta muốn lưu lại cấu hình AppConfig xuống file sau đó load lại khi cần. Thử đoạn code sau nhé.

Bạn sẽ thấy output có dạng này:

Tức là giá trị của object (các properties như appId) được giữ nguyên song object thực chất đã được tạo mới (tìm hiểu thêm về method toString()). Như vậy không đảm bảo 1 object được tạo ra duy nhất trên toàn bộ life cycle của ứng dụng. Vì cơ chế deserialize sẽ tạo mới object. Chúng ta cần sửa thành:

Chỉ có đúng 1 object được tạo ra?

Bạn có chắc rằng với cách cài đặt trên chỉ có đúng 1 object có thể được tạo ra? Còn cách nào có thể tạo ra object không?

Đáng tiếc là vẫn còn, clone thì sao?

Kết

Singleton “chuẩn” nên được cài đặt như sau:

  • Bài viết này tôi lấy cảm hứng từ: https://medium.com/exploring-code/how-to-make-the-perfect-singleton-de6b951dfdb0, viết lại theo cách dễ đọc hơn.
  • Đến đây chắc bạn đã hiểu tại sao tôi khuyến nghị dùng static trong class nếu bạn không thực sự rõ về Singleton. Với class bạn không có vấn đề với serializable và reflection… Điều bạn gặp phải về threading có thể được IDE warning.
  • Hãy nhớ nhé, Singleton không dễ đâu.

 5,568 total views,  6 views today