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 đề.

636 total views, no 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.

591 total views, no 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.

1,148 total views, 1 views today

Lập trình không dùng if-else, có được không?

If-else thật xấu xí

Đối diện với một bài toán, lập trình viên (LTV) thường phải trả lời câu hỏi: Đây là bài toán đặc thù hay phổ quát? Bài toán “số ít” hay “số nhiều”?  Và thông thường, câu trả lời sẽ quyết định thành quả tiếp theo. Ví dụ, con chó kêu gâu gâu?” là bài toán số ít. Ta có thể viết thế này:

Thật đơn giản. “Con chó kêu gâu gâu, con mèo kêu meo meo” thì sao? Vẫn là bài toán số ít thôi.

Thật đơn giản. “Con chó kêu gâu gâu, con mèo kêu meo meo, con vịt kêu quạc quạc” thì sao? Vẫn là bài toán số ít thôi.

Thật đơn giản. À từ từ, chuyển sang switch cho đẹp mắt.

Đẹp đẽ quá rồi. Tuyệt vời.

Bạn có thấy câu chuyện trên quen thuộc trong cuộc sống hàng ngày của LTV? Khi if-else bắt đầu phát huy sức mạnh, làm ơn đừng chuyển sang switch – chẳng hay ho gì đâu. Khi if-else bắt đầu phát huy sức mạnh, chính là khi nó bắt đầu trở nên xấu xí, chính là khi chúng ta cần phải xem lại cách đánh giá bài toán của mình. Đây không phải là bài toán số ít ngay từ đoạn code #2. Các LTV cần hiểu đúng đắn rằng đây là bài toán số nhiều ngay từ khi nó có dấu hiệu là bài toán số nhiều, thay vì cứ else-if và hy vọng giữ nó là bài toán số ít.

LTV có thể sống mà không cần if-else?

Có, dùng switch thôi. Không không, tiêu đề trên để cho vui thôi. Câu hỏi thực sự là “chúng ta có thể lập trình mà không sử dụng câu lệnh rẽ nhánh (conditional statement)?”.  Vâng, không dùng if-else, switch,…?

Từ thưở đầu học lập trình, ai trong chúng ta cũng biết những thứ căn bản nhất của một ngôn ngữ lập trình (NNLT): variable, array, conditional, loop statement. Lâu dần chúng ta coi đó là điều nghiễm nhiên của một NNLT. Nhưng bạn cần biết rằng, âu lệnh if-else còn nhiều điểm xấu xí khác, từ logic cho tới runtime speed, memory… nên một số NNLT hoàn toàn không có if-else.

Vậy thì sống làm sao? Làm sao để giải bài toán trên mà không dùng if-else? OOP – polymorphism là một giải pháp. Thử xem:

Không có gì huyền bí cả, bạn có thể tham khảo tại blog của Martin Fowler về pattern này.

Nếu bạn muốn thực hành nhiều hơn, có thể tìm đến Anti-IF pattern tại đây.

No if-else

Về lý thuyết, chúng ta hoàn toàn có thể lập trình mà không sử dụng if-else. Tại các buổi Code Retreat thường có 1 session mà LTV nhất định không sử dụng if-else khi lập trình ngay cả khi NNLT đó hỗ trợ. Mục tiêu là luyện tập khả năng ít phụ thuộc vào conditional statement để hình thành tư duy abstract. Như ví dụ trên, câu lệnh if-else thực sự quá mạnh mẽ, đến nỗi các LTV không thể tránh được cám dỗ, giải bài toán theo “số ít” và tạo ra những thiết kế sai lầm, vi phạm nguyên tắc open-closed cơ bản.

Nếu bạn chưa biết thực hành thế nào, hãy tới một buổi Code Retreat cho biết.

938 total views, no views today

Here is my presentation for the workshop at CodeGym today about Design patterns. One of the biggest issue in training design patterns is the trainees don’t know how to apply them together in a single real world problem. I tried to create a real world problem and introduced a simple way to get it solved by combining some design patterns.

KFC. Order system

KFC is very famous fastfood brand, they have many franchises in various places that share the same hotline, menu.

When users open the menu on KFC website, they see the single menu, choose and order food by calling to the single hotline. A order center (OC) receives the order and notifies to the appropriate store by a specific criteria (now is location and can be changed in the future). A store can answer their possibility to take this order (they need to cook and deliver it on time). If a store takes this order, the process ends; otherwise, the OC will find another one.

To process a order, a store has a recipient who receives the order from OC, forwards it to the kitchen, finds the right delivery man and updates the order basing on the information from delivery man such as payment, status (accepted or declined), customer feedback… to OC. So OC has real time data of every orders but doesn’t have order’s internal note that works within the store.

When OC gets the order information from customer, they may get the extra information in some categories like food change, delivery time, special notes… If customer calls to OC to cancel the order, OC can directly cancel it by updating the order status in taken store.

Design the system by design patterns.

943 total views, no views today

I will have a workshop at CodeGym at the end of this month about Design patterns. One of the biggest issue in training design patterns is the trainees don’t know how to apply them together in a single real world problem. Here is my example that will be used as the exercise for this workshop. Is it interesting enough? Try it out.

KFC. Order system

KFC is very famous fastfood brand, they have many franchises in various places that share the same hotline, menu.

When users open the menu on KFC website, they see the single menu, choose and order food by calling to the single hotline. A order center (OC) receives the order and notifies to the appropriate store by a specific criteria (now is location and can be changed in the future). A store can answer their possibility to take this order (they need to cook and deliver it on time). If a store takes this order, the process ends; otherwise, the OC will find another one.

To process a order, a store has a recipient who receives the order from OC, forwards it to the kitchen, finds the right delivery man and updates the order basing on the information from delivery man such as payment, status (accepted or declined), customer feedback… to OC. So OC has real time data of every orders but doesn’t have order’s internal note that works within the store.

When OC gets the order information from customer, they may get the extra information in some categories like food change, delivery time, special notes… If customer calls to OC to cancel the order, OC can directly cancel it by updating the order status in taken store.

Design the system by design patterns.

—————————————————————-

The solution will be updated later.

893 total views, no views today

Hôm nay đồng nghiệp hỏi câu này: Tại sao nên viết như #a thay vì #b?

Tôi mở rộng câu hỏi thành: Sắp xếp các cách viết sau theo thứ tự “tốt dần”.

Khá khó để nói #3 và #4, cách nào tốt hơn; nhưng có thể dễ dàng khẳng định #1 và #2 không tốt bằng #3, #4. Tại sao?

Nguyên tắc chung của lập trình hướng đối tượng là trừu tượng hoá và cố gắng tối đa việc trừu tượng hoá. Trừu tượng (không phải là giải pháp toàn vẹn nhưng) là một phần trong cách tư duy về Open / Closed principle. #1 rất trực quan và dễ hiểu: tạo một danh sách lưu trữ sách dưới dạng ArrayList. Nhưng những thứ cụ thể rất khó để sửa đổi và thay thế. Ví dụ, sau khi implement, chúng ta phát hiện ra đoạn code phía sau sử dụng rất nhiều thao tác thêm phần tử vào list thay vì lấy phần tử ra; do đó lưu trữ dưới dạng Stack cho hiệu suất tốt hơn; chúng ta phải sửa đổi các đoạn code phía dưới với implement cụ thể của Stack (thay cho ArrayList). Một thời gian sau, nhu cầu lấy phần tử từ list đủ nhiều để sử dụng ArrayList cho hiệu suất tốt hơn, chúng ta phải sửa lại đoạn code phía dưới với implement cụ thể của ArrayList. (Tham khảo: hiệu suất các implement của List). Khổ chưa?

Một cách thông minh hơn là sử dụng #3, khi đó, đoạn code phía dưới chỉ sử dụng những method được định nghĩa cho interface List. Khi cần thay đổi implement cụ thể thành Stack, LinkedList…, chúng ta chỉ đơn giản thay new List<Book>() bởi new Stack<Book>() hay new LinkedList<Book>(). 

Và theo cách tư duy đó, #4 tốt hơn #3? Không hẳn, nếu chúng ta đã xác định list chỉ chứa Book, việc khai báo list chứa Object khiến chúng ta có thể mất công cast những object này trong trường hợp sử dụng những method cụ thể của Book (và thường là vậy). Nên dùng #4 thường là bất lợi hơn #3 (trừ trường hợp list chữa những object khác ngoài Book).

Do đó, sử dụng #3 (khai báo interface và khởi tạo bằng class (đương nhiên)) thường là cách viết nên được “quen tay”.

Thật ra #3 còn nên viết theo 1 cách khác tốt hơn như sau. Tại sao nhỉ?

915 total views, 1 views today

Don’t wanna get your wife angry just because of let her wait so long for a dinner? This program is for you. It’s a guide to build the simple application that automatically sends SMS to your wife at a specific time if you need to stay longer at the office.

Get Twilio account

Register an account at: https://www.twilio.com, the service lets you send the SMS via REST API. During trial period, you could get 10$ – enough free messages; then you get charged with low fare later (~0.01 – 0.05$ for each SMS).

Setup Twilio

  1. Buy a number at: https://www.twilio.com/console/phone-numbers/incoming. It costs 1$, Twilio uses this number to send SMS. Call it SENDER.
  2. Verify your wife’s phone number (with country code like +84 988 999 888) at: https://www.twilio.com/console/phone-numbers/verified (to make sure you don’t spam anyone). Call it RECEIVER.
  3. Create API key at: https://www.twilio.com/console/dev-tools/api-keys. You can get API key and secret key here. Call them KSID and KSECRET.
  4. Go to https://www.twilio.com/console and get your account SID. Call it ASID. 

Now replace this command with your information above, replace + in the phone number with %2B.

Then run.

Got it? We are almost done.

Setup a cronjob

You can send SMS to your wife by only 1 command; now get it automated.

1. Create a file sweet_sms_to_darling.sh, put the command above.

2. Get it executable, and run at 18:30 every day.

Add this line, correct your file path, 18, 30 is the hour and minute triggers this bash script.

3. Save this file and add to cronjob. That’s all.

OK, now when your computer is up on 18:30, it automatically send the SMS to your wife.

Don’t worry about she get angry. Now work. 

Please don’t put this job on server – it’s always up 😉

It’s general idea of building the application, you could do it in others platform like Windows with BAT file and scheduled task. Another simpler and specific version for Mac is coming soon 😉

1,062 total views, 3 views today