Random() có thực sự ngẫu nhiên ?

Không, trên đời chẳng có gì là ngẫu nhiên cả!

Tất cả đều là những quy luật được ẩn giấu, chỉ là chúng ta có phát hiện hay hiểu được nó hay không mà thôi; bởi đôi khi nó đơn giản, đôi khi phức tạp, thậm chí siêu phức tạp.

Random() cũng vậy. Bản thân máy tính do con người tạo ra, nên những quy tắc hoạt động của nó đều dựa trên những gì mà con người thiết kế. Tuỳ vào các hệ thống khác nhau mà random sẽ được thiết kế với các thuật toán khác nhau, nhưng ít nhất cần đảm bảo được các tiêu chí sau:

  1. Tính ngẫu nhiên của kết quả tạo ra
  2. Tính bảo mật của thuật toán

Quá trình sinh ra random trong máy tính được gọi là Pseudo Random Number Generation (PRNG).

1. PRNG Concept

Ta sẽ có 3 khái niệm chung trong PRNG:

  • Seed: giá trị khởi tạo của PRNG.
  • Internal State: trạng thái của PRNG, lưu trữ các biến số để có thể dự đoán được giá trị và trạng thái tiếp theo của PRNG.
  • Period: chu kỳ của random, random sẽ lặp lại mỗi khi chu kỳ kết thúc.

2. Random Distribution Types

Tuỳ vào mục đích sử dụng, Random() trong các ngôn ngữ lập trình sẽ sinh ra các số ngẫu nhiên theo các phân phối khác nhau.

Thông thường nhất là phân phối đều (Uniform Distribution) với xác suất xuất hiện các số là gần như nhau, hoặc phân phối chuẩn (Normal Distribution) để sinh ra các giá trị xung quanh một giá trị nào đó.

Đó, rõ ràng Random() không phải là dùng tuỳ tiện được mà phải phụ thuộc vào việc vào chúng ta muốn dữ liệu như thế nào nữa.

3. PRNG Algorithms

Có rất nhiều thuật toán trong PRNG, các bạn có thể tham khảo thêm tại đây Trong bài này mình sẽ giới thiệu qua 3 thuật toán được sử dụng trong các ngôn ngữ lập trình.

3.1. Linear Congruential Generator (LCG)

Đây là thuật toán sinh ngẫu nhiên cổ điển nhất và phổ biến nhất được sử dụng trong PRNG. LCG là thuật toán built-in trong Pascal, C/C++, Java và C#.

LCG rất đơn giản, rất trực quan và dễ hiểu, sử dụng chỉ một hàm:

Trong đó:

Chu kỳ của LCG lớn nhất là m, và để LCG sinh ra tất cả các giá trị trong chu kỳ với mọi giá trị khởi tạo (full-period) thì sẽ cần những điều kiện ràng buộc như sau (các bạn hãy thử tự chứng minh bằng toán học xem sao

Về giá trị mặc định của các hằng số với các ngôn ngữ lập trình khác nhau, các bạn có thể tham khảo thêm tại đây.

Dưới đây là vài ví dụ về LCG:

Ưu điểm: Rất nhanh và tốn ít bộ nhớ (32 hoặc 64 bits).

Nhược điểm: Tính chất ngẫu nhiên chưa cao, và do đó với những hệ thống thực sự cần độ ngẫu nhiên rất cao, người ta không khuyến khích sử dụng LCG. Và thay vào đó là sử dụng Mersenne Twister (sẽ được nói tới trong phần sau).

3.2. Multiply with Carry (MWC)

Để tạo ra chu kỳ random lớn hơn, George Marsaglia đã đề xuất một thuật toán PRNG khác với tên gọi Multiply with Carry (MWC). Trong MWC thì ta sẽ dùng một set gồm từ hai cho tới hàng ngàn giá trị cho seed.

Trong MWC chúng ta sẽ có một giá trị r, gọi là lag của MWC. Và cũng giống như LCG, chúng ta cũng sẽ có mutiplier và mô đun, nhưng sẽ không còn increment, mà thay vào đó là một giá trị carry. Công thức sẽ như sau:

Trong đó, cũng giống như trên, a sẽ là mutiplier, và ở đây b sẽ là mô đun, thường là 2^32. Điểm khác biệt là giá trị carry c, giá trị này sẽ được dùng để tính toán giá trị x tiếp theo. Công thức của c là:

Các bạn có thể tham khảo bảng giá trị chu kì của MWC như dưới đây:

3.3 Mersenne Twister

Mersenne Twister là một thuật toán PRNG được Makoto Matsumoto và Takuji Nishimura phát triển vào năm 1997. Đây là một thuật toán thực sự tuyệt vời. Rất nhanh và tạo ra được dãy số với chất lượng ngẫu nhiên rất cao.

Mersenne Twister được sử dụng như là built-in PRNG cho Python, Ruby, PHP và R.

Cái tên Mersenne Twister được chọn vì chu kì của số ngẫu nhiên tạo ra bởi thuật toán này luôn là một số nguyên tố Mersenne

Số nguyên tố Mersenne thường được sử dụng trong thuật toán sinh random là 2^19937 −1, đó cũng là nguồn gốc của cái tên MT19937 – standard implement của Mersene Twister. Kết quả đưa ra số tự nhiên 32 bits.

Ưu điểm:

  • Đưa ra được dải số rất lớn 2^19937 −1
  • Pass rất nhiều các bài kiểm tra về tính ngẫu nhiên, có thể nói MT là một thuật toán vô cùng tốt.

Nhược điểm: MT có nhược điểm cơ bản về performance, có thể coi là chậm và tốn bộ nhớS

3.3a. Algorithm Overview

Một cách tổng quát, thuật toán Mersenne Twister được triển khai bằng đệ quy, biểu thức như sau:

Các bạn lưu ý là mình viết vector và ma trận bằng kí tự in đậm, còn số là ký tự in thường.

Biểu thức trên chính là biểu thức Twist trong MT, mình hay gọi nó là biểu thức xoắn quẩy =))

Ma trận A được chọn lựa sao cho phép nhân ma trận trở nên đơn giản và nhanh chóng:

Tương tự như trên, để đơn giản hóa cho việc tính toán, người ta chọn T sao cho kết quả có thể nhận được chỉ bằng các phép XOR, AND và dịch bit thông thường

 Vậy là ta có cái nhìn tổng quan về Mersenne Twister, hãy ngồi xuống, nghe một ca khúc và làm một ly cà phê trước khi đến với phần code 

3.3b. MT19937

MT19937 là standard implement của Mersene Twister, sử dụng với các tham số như sau:

MT19937 implement code:

def _int32(x):
  # Get the 32 least significant bits.
  return int(0xFFFFFFFF & x)

class MT19937:

  def __init__(self, seed):
    # Initialize the index to 0
    self.index = 624
    self.mt = [0] * 624
    self.mt[0] = seed  # Initialize the initial state to the seed
    for i in range(1, 624):
      self.mt[i] = _int32(
        1812433253 * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i)

  def extract_number(self):
    if self.index >= 624:
      self.twist()

    y = self.mt[self.index]

    # Right shift by 11 bits
    y = y ^ y >> 11
    # Shift y left by 7 and take the bitwise and of 2636928640
    y = y ^ y << 7 & 2636928640
    # Shift y left by 15 and take the bitwise and of y and 4022730752
    y = y ^ y << 15 & 4022730752
    # Right shift by 18 bits
    y = y ^ y >> 18

    self.index = self.index + 1

    return _int32(y)

  def twist(self):
    for i in range(624):
      # Get the most significant bit and add it to the less significant
      # bits of the next number
      y = _int32((self.mt[i] & 0x80000000) +
         (self.mt[(i + 1) % 624] & 0x7fffffff))
      self.mt[i] = self.mt[(i + 397) % 624] ^ y >> 1

      if y % 2 != 0:
        self.mt[i] = self.mt[i] ^ 0x9908b0df
    self.index = 0

a = MT19937(1000)
print a.extract_number()
print a.extract_number()
print a.extract_number()
print a.extract_number()

4. Conclusion

Vậy là rõ ràng random() không phải là ngẫu nhiên, đó đều là kết quả do máy tính (hay chính xác hơn là con người) tạo ra mà thôi.

Nếu biết được trạng thái hiện tại của thuật toán và seed, thì hoàn toàn chúng ta có thể tính toán được trạng thái tiếp theo, tức kết quả tiếp theo của random(). Tuy nhiên điều này đôi khi không dễ dàng và cần một số những điều kiện nhất định, đôi khi thấy xuất hiện trong các cuộc thi CTF.

Vậy nên, nếu bạn chưa có bạn gái, hay chưa giàu, hay chưa trúng Vietlot, hãy luôn tin rằng đó chỉ là do chưa tới lượt mà thôi, ngày ngày làm một tấm vé, dù sớm hay muộn thì may mắn cũng sẽ đến.

Good luck! 😂

5. References

9 cách xử lý ngoại lệ trong java

Hôm trước có ngồi uống nước với anh sếp, anh ý có hỏi mình một câu là “Đã biết cách Handle Exceptions trong java như nào chưa”.

Thực sự trước giờ làm mình cũng không để ý cái này cho lắm nên khi bị hỏi thì mình trả lời như này “là xử lý ngoại lệ khi bắt gặp một lỗi phát sinh”
“Xử lý như thế nào ?” anh ý hỏi tiếp, nhìn mặt mình chắc biết không trả lời được nên bảo về tìm hiểu.

Sau một hồi tra google, tìm hiểu tài liệu thì mình đúc kết được 9 cách sau đây. Có thể không đầy đủ nhưng đây là thành quả mình tìm hiểu được 😀

Xư lý ngoại lệ trong java không phải là 1 vấn đề dễ dàng, nhất là đối với những người còn thiếu kinh nghiệm và mới bước vào nghề như mình.
Theo mình tìm hiểu thì đa phần các nhóm phát triển đều có bộ quy tắc riêng và cách sử dụng chúng nên việc bài viết của mình có thể sẽ khác so với các quy tắc của các bạn đã làm trước đây. Tuy nhiên có một quy tắc được hầu hết các đội ngũ sử dụng, và bài viết này sẽ tổng hợp lại những cách mà bản thân mình đã tìm hiểu được.

Trước tiên đi sâu vào tìm hiểu thì hãy thử trả lời 2 câu hỏi bên dưới :
– Ngoại lệ là gì, và tại sao chúng ta cần xử lý ngoại lệ ?
– Tại sao chúng ta lại cần chúng ?
Sau khi trả lời thì chúng ta sẽ bắt đầu đi sâu vào việc nghiên cứu, tuy nhiên nếu các bạn không muốn trả lời 2 câu hỏi bên trên hoặc không biết câu trả lời thì các bạn có thể click here.

Ok, Bắt đầu thôi nào 😀

-Giới thiệu và tóm tắt :

Ngoại lệ là gì ? và xử lý ngoại lệ là gì ?
Trước tiên đi sâu vào tìm hiểu thì chúng ta cần biết nó là gì và tại sao chúng ta cần phải xử lý nó.

-Xác định ngoại lê :

Cùng trả lời câu hỏi, ngoại lệ là gì ?
– Hiểu một cách đơn giản ngoại lệ là tất cả các trường hợp bất thường trong quá trình thực thi chương trình.
Một ngoại lệ xảy ra khi có sự cố, ví dụ như bạn mở 1 tệp tin mà nó không tồn tại hay là lấy giá trị từ 1 biến null. Và boommmm, 1 ngoại lệ đã xảy ra.

Ngoại lệ là một thứ tồi tệ mà chúng ta phải giả định rằng nó sẽ xảy ra, nhưng trước khi nó xảy ra thì chúng ta cần phải xử lý nó. Xử lý ngoại lệ là một cơ chế xử lý lỗi, khi có lỗi xảy ra, một ngoại lệ sẽ được bắn ra. Và nếu chúng ta không xử lý nó một cách đúng đắn thì rất có thể chương trình của chúng ta sẽ bị lỗi và dẫn đến việc không thể tiếp tục hoạt động được nữa.

Hoặc bạn có thể chọn việc xử lý ngoại lệ, thực hiện các bước để ngăn chương trình bị lỗi và tìm cách khôi phục chúng. Hoặc bạn có thể mặc kệ và để chương trình của bạn “chết” một cách nhẹ nhàng 😀
Mình nghĩ đa phần các bạn đã đọc được đến đây rồi thì không ai chọn cách thứ 2 đâu nhỉ.
Ok tiếp tục nào…

-Xử lý lỗi như trước đây:

Như bạn đã đọc, xử lý ngoại lệ là một cơ chế xử lý lỗi, nhưng nó không phải là cơ chế duy nhất.
Ngày nay, đại đa số các ngôn ngữ lập trình cung cấp xử lý ngoại lệ như một tính năng, nhưng mọi thứ luôn luôn theo cách này.
Vậy làm như thế nào để các ngôn ngữ lập trình có thể đưa ra 1 quy tắc chung khi gặp lỗi.
Một cách tiếp cận phổ biến là trả về mã lỗi. Chẳng hạn, giả sử bạn có hàm X chứa mảng số nguyên và một số nguyên duy nhất rồi tìm kiếm và trả về thứ tự của giá trị đầu tiên trong mảng được tìm thấy.
Ví dụ: 1 mảng bao gồm 5 số nguyên {1,2,3,4,1} và bạn muốn tìm ra thứ tự của số 1. Trong mảng có 2 số 1 và đương nhiên thứ tự số 1 đầu tiên được tìm thấy sẽ là thự tự đầu tiên. Nhưng nếu bạn muốn tìm số 5 trong mảng trên, bạn sẽ làm gì khi không tìm được giá trị trong mảng trên, bạn sẽ trả về thứ tự là bao nhiều ? Một lựa chọn phổ biến sẽ là trả về -1

Cách tiếp cận này có ưu điểm là giữ cho các mã lỗi được thể hiện 1 cách rõ ràng, với mỗi lỗi sẽ có một mô tả lỗi khác nhau. Ví dụ như khi nhắc tới lỗi 404 là ai cũng sẽ biết là lỗi Not Found.
Nhưng một nhược điểm của việc này là sự thiếu rõ ràng, ví dụ như khi trả về mã -5. Điều này có ý nghĩa là một số tập tin đã được tìm thấy. Nhưng tập tin nào ? Một mã lỗi không thể mô tả được điều này.

Một cách khác thay cho việc trả về mã lỗi là bạn có thể trả về giá trị, điều này sẽ giúp việc mô tả lỗi được rõ ràng hơn.

– Giải quyết các ngoại lệ

Các trường hợp ngoại lệ xuất hiện để giải quyết các vấn đề mà bạn vừa đọc.
Khi một ngoại lệ được ném ra, luồng điều khiển của chương trình bị gián đoạn. Nếu không ai xử lý ngoại lệ, nó sẽ khiến chương trình bị sập.
Người dùng sẽ có thể nhìn thấy các ngoại lệ, và đương nhiên sẽ mang lại trải nghiệm không tốt cho người dùng. Không ai muốn việc đang lướt web mà tự nhiên một thông báo lỗi hiện ra che hết màn hình của họ cả.

Vì vậy bạn sẽ muốn xử lý các ngoại lệ đó mặc dù nó chỉ là các lỗi rất nhỏ.
Và để xử lý ngoại lệ thì chúng ta xử lý bằng cách bắt nó khi mà trương trình ném cho chúng ta 😀 Chúng ta làm việc này bằng sử dụng exception-handling block.

Khi chúng ta bắt được một ngoại lệ, chúng ta sẽ điều khiển luồng xử lý của chương trình đến chỗ xử lý ngoại lệ và xử lý nó. Đọc thì thấy khó hiểu đúng không =)) Hãy đọc tiếp và chúng ta sẽ thấy những ví dụ cụ thể hơn.

-Các ngoại lệ Java hoạt động như thế nào ?

hãy nhìn vào ví dụ dưới đây

package com.company;
import java.io.*;

public class Main { 
    public static void main(String[] args){ 
        System.out.println("First line");
        System.out.println("Second line");
        System.out.println("Third line");
        int[] myIntArray = new int[]{1, 2, 3};
        print4hItemInArray(myIntArray);
        System.out.println("Fourth line");
        System.out.println("Fith line");
    } 
    
    private static void print4thItemInArray(int[] arr) {
        System.out.println(arr[3]);
        System.out.println("Fourth element successfully displayed!");
    }
}

Đoạn mã trên in một số thông điệp vô thưởng vô phạt chỉ nói chúng thuộc dòng nào.
Sau khi in dòng thứ ba, mã khởi tạo một mảng với ba số nguyên và truyền nó dưới dạng đối số cho một phương thức riêng. Phương thức này cố gắng in mục thứ tư trong mảng, mục thứ tư này không tồn tại, điều này khiến một ngoại lệ đã xảy ra:
ArrayIndexOutOfBoundsException exception to be thrown.
Khi điều đó xảy ra, việc thực thi chương trình bị dừng lại và thông báo ngoại lệ được hiển thị và các lệnh in ra sau đó sẽ không bao giờ được thực thi.
đây là kết quả đầu ra

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
	at com.company.Main.print4hItemInArray(Main.java:26)
	at com.company.Main.main(Main.java:13)
First line
Second line
Third line

Bầy giờ chúng ta sẽ xử lý bằng việc thêm một số xử lý ngoại lệ vào.

package com.company;
import java.io.*;

public class Main {

    public static void main(String[] args) {
	// write your code here
	    System.out.println("First line");
	    System.out.println("Second line");
	    System.out.println("Third line");

	    try {
	        int[] myIntArray = new int[]{1, 2, 3};
	        print4thItemInArray(myIntArray);
	    } catch (ArrayIndexOutOfBoundsException e){
	        System.out.println("The array doesn't have four items!");
	    }

	    System.out.println("Fourth line");
	    System.out.println("Fith line");
    }

    private static void print4thItemInArray(int[] arr) {
        System.out.println(arr[3]);
    }
}

Bây giờ, sau khi chạy đoạn code, đây là đầu ra chúng ta nhận được:

First line
Second line
Third line
The array doesn't have four items!
Fourth line
Fith line

Lần này, ngoại lệ vẫn xảy ra, nhưng khác với bên trên. Chúng ta đã xử lý và chương trình không hề bị lỗi.
Khi nói đến việc xử lý các trường hợp ngoại lệ trong Java, có nhiều điều hơn thế so với phần giới thiệu ngắn gọn của mình. Vì vậy các bạn có thể lick vào đây để tìm hiểu chi tiết hơn.

Và không lan man nữa, dưới đây sẽ là 9 cách xử lý ngoại lệ mà mình sẽ giới thiệu với các bạn.
Một vài lưu ý là có những câu mình sẽ để nguyên tiếng anh vì khi nếu dịch qua tiếng việt thì có thể sẽ không thể hiện được chính xác và đẩy đủ nội dung, tiếng anh của mình có hạn nên mình sẽ cố gắng hết sức =))) chỗ nào k đúng mọi người bỏ qua nhé.

1. Clean Up Resources in a Finally Block or Use a Try-With-Resource Statement

Thì ý nghĩa câu trên hiểu đơn giản là bạn phải xử lý resource của bạn ở khối cuối cùng hoặc nên dùng với Try-With-Resource

Lấy ví dụ cho dễ hiểu nhé, cùng nhìn xuống đoạn code bên dưới.

public void doNotCloseResourceInTry() {
	FileInputStream inputStream = null;
	try {
		File file = new File("./tmp.txt");
		inputStream = new FileInputStream(file);
		
		// use the inputStream to read a file
		
		// do NOT do this
		inputStream.close();
	} catch (FileNotFoundException e) {
		log.error(e);
	} catch (IOException e) {
		log.error(e);
	}
}

Đây là cách đơn giản để bạn có thể mở một file với inputStream. Nếu các bạn chưa biết inputStream là gì thì có thể ấn vào đây để đọc.
Rồi sau khi mở file, thao tác với file thì điều tiếp theo là bạn phải đóng nó lại, điều này sẽ đúng và thực hiện ok một cách ngon lành nếu như không có bất kì 1 ngoại lệ nào được ném ra ngoài. Nhưng cuộc đời thì không phải lúc nào cũng dễ dàng như vậy. Chuyện gì sẽ xảy ra nếu như bạn mở 1 file mà file đó lại không tồn tại ? Và boom!!!, một ngoại lệ được ném ra và câu lệnh inputStream.close(); sẽ không được thực thi. Điều đó đồng nghĩa với việc luống của bạn sẽ không được đóng lại. Và đó là lý do vì sao bạn nên để câu lệnh inputStream.close(); ở khối cuối cùng và sử dụng try-with-resource để đảm bảo rằng kể cả file của bạn có không tồn tại đi nữa thì luồng của bạn chắc chắn vẫn sẽ được đóng lại.

Use a Finally Block

public void closeResourceInFinally() {
	FileInputStream inputStream = null;
	try {
		File file = new File("./tmp.txt");
		inputStream = new FileInputStream(file);
		
		// use the inputStream to read a file
		
	} catch (FileNotFoundException e) {
		log.error(e);
	} finally {
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				log.error(e);
			}
		}
	}
}

Như đoạn code bên trên, thì cho dù có bất kì ngoại lệ nào được ném ra thì đoạn code thực thi đóng steam sẽ luôn được thực thi.

The New Try-With-Resource Statement

Một tùy chọn khác là sử dụng try-with-resource, bạn có thể sử dụng chúng khi bạn implements AutoCloseable interface. Đây được coi là một tiêu chuẩn của java.
Khi bạn mở resource trong try clause , nó sẽ tự động bị đóng sau khi try block được thực thi hoặc một ngoại lệ được xử lý.

public void automaticallyCloseResource() {
	File file = new File("./tmp.txt");
	try (FileInputStream inputStream = new FileInputStream(file);) {
		// use the inputStream to read a file
		
	} catch (FileNotFoundException e) {
		log.error(e);
	} catch (IOException e) {
		log.error(e);
	}
}

2. Prefer Specific Exceptions

-Ở mục này thì mình sẽ nói rõ hơn về tầm quan trọng của việc mô tả ngoại lệ

-Việc mô tả ngoại lệ càng chi tiết càng tốt, vì đơn giản là không phải ai cũng biết được code của bạn hoặc có thể là bạn trong vài tháng nữa. Khi ai đó sử dụng hoặc gọi tới hàm của bạn thì việc mô tả chi tiết 1 ngoại lệ mà hàm đó xử lý sẽ giúp tiết kiệm thời gian đọc và tránh những lỗi gặp phải. Do đó hay đảm bảo là bạn đã cung cấp một mô tả chi tiết cho việc này.

  • Một lưu ý nữa là nên tìm 1 class phù hợp nhất cho việc xử lý ngoại lệ của bạn.
    Ví dụ : ném một NumberFormatException thay vì IllegalArgumentException. Và tránh ném một ngoại lệ Exception.
public void doNotDoThis() throws Exception { ... }
	
public void doThis() throws NumberFormatException { ... }

3. Document the Exceptions You Specify

-Một cách mô tả nữa là sử dụng java doc

Khi bạn xác định một ngoại lệ trong hàm của bạn, bạn cũng nên ghi lại nó trong Javadoc.
Điều nay cũng có mục đích như bên trên, là cung cấp một mô tả chi tiết nhất cho người dùng sau đó để anh ta có thể tránh hoặc xử lý chúng một cách hợp lý.
Vì vậy, hãy đảm bảo thêm một khai báo @throw vào Javadoc của bạn và để mô tả các tình huống có thể gây ra ngoại lệ.

/**
* This method does something extremely useful ...
*
* @param input
* @throws MyBusinessException if ... happens
*/
public void doSomething(String input) throws MyBusinessException { ... }

4. Throw Exceptions With Descriptive Messages

-Một cách để tăng thêm sự mô tả chi tiết nữa đó là trả về một message cho người dùng gọi hàm của bạn. Và đương nhiên message cũng phải dễ hiểu hoặc đã được mô tả trong tài liệu trước đó.
Ví dụ khi gọi 1 API do bạn thiết kế, người dùng truyền vào thiếu 1 param hoặc truyền sai định dạng. Thì việc bạn trả về một message nói rõ đó là param nào và phải truyền như nào cho đúng sẽ dễ dàng hơn cho người dùng khi phải ngồi đoán và tự tìm hiểu xem mình đang sai ở đâu. Nhưng cũng k nên để 1 message quá dài dòng, hay trả về 1 message ngắn gọn nhưng mang đủ ý nghĩa.
Không nhưng thế, nó còn làm cho bạn dễ dàng biết là bạn đang gặp phải vấn đề gì và nó nằm ở đâu trong toàn bộ hệ thống.

-Một lưu ý nữa là nếu bạn xử lý và đưa ra 1 ngoại lệ, thì tên của class nó đã mô tả rõ loại lội mà bạn đang gặp phải, vì vậy bạn không cần phải cung cấp thêm nhiều thông tin bôr xung.

Một ví dụ điển hình cho điều đó là NumberFormatException. Nó bị ném bởi hàm tạo của lớp java.lang.Long khi bạn cung cấp String ở định dạng sai.

try {
	new Long("xyz");
} catch (NumberFormatException e) {
	log.error(e);
}

Tên của class NumberFormatException đã mô tả loại lỗi mà bạn gặp phải, việc bây giờ bạn cần là đưa đầu vào khiến gây ra lỗi như dưới đây

ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz"

5. Catch the Most Specific Exception First

-Hầu hết các IDE bây giờ đều giúp bạn việc bắt một ngoại lệ cụ thể nhất.
Vấn đề là chỉ có catch block đầu tiên phù hợp với ngoại lệ được thực thi. Vì vậy, nếu bạn bắt gặp IllegalArgumentException trước tiên, bạn sẽ không bao giờ tiếp cận đượccatch block NumberFormatException cụ thể hơn vì nó là một lớp con của IllegalArgumentException.
Luôn luôn bắt lớp ngoại lệ cụ thể nhất trước tiên và thêm catch blocks ít cụ thể hơn vào cuối danh sách của bạn.

Bạn có thể thấy một ví dụ về câu lệnh try-Catch như vậy trong đoạn code sau. catch block đầu tiên xử lý tất cả các NumberFormatExceptions và catch block thứ hai xử lý tất cả IllegalArgumentExceptions không phải là NumberFormatException.

public void catchMostSpecificExceptionFirst() {
	try {
		doSomething("A message");
	} catch (NumberFormatException e) {
		log.error(e);
	} catch (IllegalArgumentException e) {
		log.error(e)
	}
}

6. Don’t Catch Throwable

Throwable là superclass của tất cả các ngoại lệ và lỗi. Bạn có thể sử dụng nó trong một catch clause, nhưng điều này là không khuyến khích.
Nếu bạn sử dụng throwable, nó sẽ không chỉ bắt được tất cả các ngoại lệ mà nó cũng sẽ bắt tất cả các lỗi. Các lỗi được JVM đưa ra để chỉ ra các vấn đề nghiêm trọng không được xử lý bởi một ứng dụng. Ví dụ điển hình cho điều đó là OutOfMemoryError hoặc StackOverflowError. Cả hai đều được gây ra bởi các tình huống nằm ngoài sự kiểm soát của ứng dụng và có thể xử lý được. Vì vậy, tốt hơn là không nên bắt một Throwable, trừ khi bạn hoàn toàn chắc chắn rằng bạn đã ở trong một tình huống đặc biệt mà bạn có thể hoặc yêu cầu xử lý lỗi.

public void doNotCatchThrowable() {
	try {
		// do something
	} catch (Throwable t) {
		// don't do this!
	}
}

7. Don’t Ignore Exceptions

Bạn đã bao giờ phân tích một báo cáo lỗi trong đó chỉ phần đầu tiên của trường hợp sử dụng được thực thi?
Điều đó thường gây ra bởi một ngoại lệ bị bỏ qua. Nhà phát triển có lẽ khá chắc chắn rằng nó sẽ không bao giờ bị ném và thêm một khối bắt mà không xử lý hay ghi nhật ký.

Và khi bạn tìm thấy block này, rất có thể bạn sẽ tìm thấy một trong những comment nổi tiếng : “This will never happen” 

public void doNotIgnoreExceptions() {
	try {
		// do something
	} catch (NumberFormatException e) {
		// this will never happen
	}
}

-Có phải bạn đang nghĩ là tại sao phải phân tích và xử lý một vấn đề mà nó sẽ không bao giờ xảy ra đúng không ? Nhưng mình xin nhấn mạnh lại là đừng bao giờ bỏ lơ một ngoại lệ. Bạn sẽ không thể chắc chắn rằng trong tương lai đoạn code của bạn sẽ không bị thay đổi, hoặc ai đó có thể làm phá vỡ sự ngăn chặn lỗi xuất hiện. Ít nhất bạn nên viết một thông điệp tường trình nói với mọi người rằng điều không thể tưởng tượng được đã xảy ra và ai đó cần phải kiểm tra nó.

public void logAnException() {
	try {
		// do something
	} catch (NumberFormatException e) {
		log.error("This should never happen: " + e);
	}
}

8. Don’t Log and Throw

Ghi log và throw có lẽ là thực tế tốt nhất thường bị bỏ qua trong danh sách này. Bạn có thể tìm thấy rất nhiều đoạn code và thậm chí các thư viện trong đó một ngoại lệ bị bắt, ghi nhật ký và truy xuất lại.

try {
	new Long("xyz");
} catch (NumberFormatException e) {
	log.error(e);
	throw e;
}

Nó có thể cảm thấy trực quan để ghi lại một ngoại lệ khi nó xảy ra và sau đó suy nghĩ lại để người gọi có thể xử lý nó một cách thích hợp. Nhưng nó sẽ viết nhiều thông báo lỗi cho cùng một ngoại lệ.

17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Long.parseLong(Long.java:589)
	at java.lang.Long.(Long.java:965)
	at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
	at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

9. Wrap the Exception Without Consuming It

Nó đôi khi tốt hơn để bắt một ngoại lệ tiêu chuẩn và bọc nó thành một tùy chỉnh.

Một ví dụ điển hình cho một ngoại lệ như vậy là một application hay framework specific business exception. Điều đó cho phép bạn thêm thông tin bổ sung và bạn cũng có thể thực hiện xử lý đặc biệt cho lớp ngoại lệ của mình. Khi bạn làm điều đó, đảm bảo đặt ngoại lệ ban đầu là nguyên nhân. Lớp Exception cung cấp các phương thức xây dựng cụ thể chấp nhận một throwable làm tham số.

Mặt khác, bạn mất stack trace and message của ngoại lệ ban đầu, điều này sẽ gây khó khăn cho việc phân tích sự kiện đặc biệt gây ra ngoại lệ của bạn.

public void wrapException(String input) throws MyBusinessException {
	try {
		// do something
	} catch (NumberFormatException e) {
		throw new MyBusinessException("A message that describes the error.", e);
	}
}

Tóm Lại

-Như bạn đã thấy, có rất nhiều điều khác nhau bạn nên xem xét khi bạn ném hoặc bắt một ngoại lệ. Hầu hết trong số chúng có mục tiêu cải thiện khả năng đọc code của bạn hoặc khả năng sử dụng API của bạn.
-Các ngoại lệ thường là một cơ chế xử lý lỗi và một phương tiện truyền thông tại một thời điểm.
-Do đó, bạn nên đảm bảo và thảo luận về các quy tắc tốt nhất về xử lý ngoại lệ Java mà bạn muốn áp dụng với đồng nghiệp để mọi người hiểu các khái niệm chung và sử dụng chúng theo cùng một cách.
-Khi sử dụng Retrace APM với code profiling bạn có thể thu thập các ngoại lệ trực tiếp từ Java mà không có bất kỳ thay đổi mã nào!

Bên trên là 9 cách mà mình đã tìm hiểu và tổng hợp lại, rất có thể nó sẽ không hoàn toàn đúng và đầy đủ. Vì vậy rất mong nhận được những lời đánh giá để các bài tiếp theo được hoàn thiện hơn. Cảm ơn mọi người ^^

Khác nhau giữa i++ và ++i

Mình nhớ hồi phỏng vấn vào cty, có một bài test code về vòng lặp, cái for nào mình cũng xài ++i. Sếp thắc mắc 2 3 lần sao không dùng i++ nhưng mình cứ vòng vo là “Vì nó nhanh hơn nhưng em không nhớ lý do vì sao”. May sao lão sếp hình như cũng chả biết câu trả lời nên tự ái mà cho mình pass 

😂

. Cơ mà mãi đến bây giờ ngồi hồi tưởng lại mà mình cũng chưa nhớ ra cái nguyên nhân đó, nên tối về hỏi lại gugo-sama ngay và viết bài này.

Điểm khác biệt

Khác biệt cơ bản này áp dụng cho hầu hết các ngôn ngữ và compiler hiện nay.

int a=0, b=0;
a++; // a = 1
++b; // b = 1
b = ++a; // b = a = 2
a = b++; // a = 2, b = 3

++i tăng giá trị của i lên 1 và trả về giá trị mới đó.
i++ cũng tương tự nhưng giá trị trả về là giá trị ban đầu của i trước khi được tăng lên 1.

Một điểm đáng lưu ý ở đây, không nên nhầm lẫn là i++ sẽ trả về giá trị i cho phép gán trước khi nó được tăng lên. Phép gán luôn thực hiện sau cùng, nên điều đó là không thể nhé.

Về bản chất chương trình sẽ tạo ra một biến tạm (temp) để lưu giá trị ban đầu của i và trả về giá trị đó cho phép gán sau khi phép toán i++ thực hiện xong.

int MePlusPlus(int me) 
{
    int temp = me;
    me = me + 1;
    return temp;
}

Performance

Tuy phải tốn công tạo một biến temp cho i++ nhưng thực tế sự khác biệt về performance là không lớn. Hầu như tất cả compiler hiện đại sẽ optimize phép toán đó. Bằng chứng là trong ví dụ này trên stackoverflow, gcc cho kết quả biên dịch là như nhau cho hai file code chứa vòng lặp xài ++i và i++.

Nhưng riêng với C++, sự chênh lệch có thể là đáng kể trong một số trường hợp. Cụ thể là với user-defined type, tức là class bạn tạo ra, vì operator++() là một hàm và compiler không biết làm cách nào để optimize việc tạo ra cái temp object trong đó cả. Sao nó biết được bạn define cái gì và sẽ bự cỡ nào trong class.

Vậy nên xài cái nào trong vòng for?

Riêng đối với mình thì ++i đã trở thành một convention bất thành văn rồi. Dù chiến project nào mình cũng xài nó mà chả quan tâm performance gì cho mệt óc. Rất nhiều guru trong giới coder đều đưa ra lời khuyên:

IN ANY CASE, FOLLOW THE GUIDELINE “PREFER ++I OVER I++” AND YOU WON’T GO WRONG

Vâng hôm nay vừa kết thúc dự án trên công ty, vui vì kiếm đc kha khá, buồn thì có và em sẽ định viết rewiev vào 1 ngày ko xa cho các thím nhưng. Sau 1 tuần quay lại voz bị xôn xao bởi cuộc tình 4 năm của bác caorauroi, ban sáng thớt còn chưa bị dell, em ngồi đọc hết từ đầu đến cuối, xem xong cờ lip và cười như 1 thằng điên, vâng và ở đâu đó em thấy mắt mình nhạt nhòa đi, 1 vị mặn đắng trên môi, đó là nước mắt các thím ạ. Em cười như 1 thằng điên rồi lại khóc như mưa.

Vâng, đ*t cụ đời các thím ạ, sao lại trùng hợp thế, cũng 4 năm, cũng sắp lấy nhau và cũng cắm sừng.

Tối nay vừa đi liên hoan với mấy xếp tổng, làm xong cái dự án thành công, hà nội chỗ em đang mưa các thím ạ.

Đ*t, em sẽ kể lại cho các thím nghe, nhưng tên nhân vật sẽ thay đổi và ko 1 info nào đc tiết lộ cả bởi nick này em lấy đc của 1 thằng cu trông quán nét canh nhà em, nó ko làm nữa thì phải

Vâng năm nay 28t, với 1 thằng sv tỉnh lẻ lập nghiệp tại HN, quả là ko dễ những cũng đủ để biết mình đúng sai, đủ chin chắn và trách nhiệm lo cho tương lai và gia đình. Em đã đã trải qua vài mối tình nhưng cũng ko hẳn bởi tất cả chỉ dừng lại ở việc tìm hiểu, ko hợp là em thôi luôn, bởi còn làm thằng đàn ông còn nhiều thứ phải làm hơn là theo đuổi 1 cô gái ko hợp với bản thân. Chính xác là yêu khi em tiến xa hơn với cô ấy.

Yêu cô ấy (tạm gọi là T) đc 4 năm, quen biết là 6 năm ạ. Cô ấy ngoan hiền, là 1 người vợ đảm đang, nhu mỳ, biết đối nhân xử thế mọi người 2 bên đều rất qúy cô ấy, cô ấy có nhiều vệ tinh theo đuổi, em biết nhưng em kệ, bởi tin cô ấy. Hiện đang làm kế toán ở 1 công ty nhỏ

Một chút về em: cao ráo sang sủa, nếu ko phải mói là đẹp zai, XH cũng ok (yêu nhau 4 năm, là 2 đứa tự nguyện và đều là lần đầu của nhau cả, cả 2 đều xác định lâu dài), thế nên ct vì lý do này là chắc chắn ko thể nhưng đời nó ko như ta mong muốn.

Chúng em tính tháng 8 sẽ cưới nhưng vì 2 mẹ tính toán thế nào bảo hoãn vì tuổi của T là kim lâu, kim la gì đó. Đợi đến thắng giêng năm sau cưới, em đi làm lương tháng tầm 20 củ, nếu tăng bo dự án thì nhiều hơn. Em thuê 1 cái nhà trên này rồi xin phép 2 gia đình cho cô ấy chuyển về ở cùng để ổn định dần, nếu cần thiết thì đăng kí trước rồi sau cưới cũng ko sao, bởi cả 2 đếu xác định sẽ là vợ chồng, 2 bên sẽ là thông gia, cho đến khi…

Vâng, đ*t cuộc đời chó má, nếu như em ko vì cái dự án đó thì mọi truyện có phải sẽ êm xuôi rồi em sẽ có gia đình yên ấm, và rồi lên voz cười khẩy các thím bị cắm sừng, và rồi bây giờ các thím lại cười em, cứ cưới đi, bây giờ với em nó ko còn quá quan trọng nữa

1 tuần trc sếp tổng huy động anh em chạy sô dự án, phải làm tối, em và sếp thường về muộn nhất vì chưa vợ con

Vâng thật hạnh phúc khi chồng đi làm và ngày ngày bữa tối ko về nhà có vợ mang cơm tận cơ quan, dưới ánh mắt GATO của cả phòng, vâng hạnh phúc lắm, nghĩ lại vẫn lâng lâng, hạnh phúc đôi khi nhỏ nhoi vậy thôi em à, với anh, anh chỉ cần thế thôi, liệu anh còn đc cảm giác này nữa sau cái đêm ấy.

Để rồi vào 1 buối tối mưa gió, lão sếp và em làm cố tầm 10h30 về, thế nào lão ý lại đòi đổi xe, lão ấy mượn con EX gp của mình, còn mình cưỡi con CBR 600 của lão ý, vì lý do “ăn đêm” với ghẹ sợ ồn ào vì tiếng pô xe (lão này gần 40 vẫn chưa vợ con). Cười nhạt đồng ý đổi xe cho lão sếp rồi phóng như bay về

Trời mưa lâm thâm, ghé vào quán bên đường mua tạm cái áo mưa khoác, có 1 giọng nói quen thuộc đằng sau, hy vọng mình nghe nhầm tiếng pô e át cả, đứng hình khi chiếc SH từ phía sau vọt lên trc, tay bật côn, con xe tắc tịt, ko có tiếng pô xe và đúng giọng nói ấy đang nhạt dần theo ánh sáng chiếc đèn hậu con SH, dáng người quen thế, áo ren vòng eo đó, nghĩ sao lại rút điện thoại gọi cho em ấy để hy vọng mình nghe nhầm nhìn nhầm

– Vợ à, chồng đang về này

Vẫn là giọng nói đó, nó đã quá đỗi quen thuộc trong từng giấc ngủ, từng hơi hở, từng câu giận hờn em à, sao hôm đó anh lại ko bảo vì lý do nào đấy nên giọng em khác có phải anh đã ko giật mình vì có giọng nói khác giống em đến như vậy

– Dạ vợ nghe nè ông xã

– Em đang ở đâu thế, sao anh nghe có tiếng xe

– Dạ vợ ở nhà 1 mình sợ ma quá nên ghé nhà cái N chơi, tý vợ về liền

– Có cần anh qua đón ko, trời đang mưa đấy

– Dạ thôi, mưa nhỏ ý mà, ông xã về trc tắm rửa đi nhá, em về liền

– Vậy em đi về cẩn thận

Lòng có chút hoài nghi lên xe rồ ga phóng theo sau chiếc SH đó, cố tình vượt lên trước, em ấy ko nhận ra mình bởi đi chiếc CBR và đội mũ bảo hiểm ôm kín đầu, qua tấm kính đen của chiếc mũ nhưng anh vẫn nhận ra khuôn mặt đó, nụ cười ấy. Và phía trước là tay làm cùng cơ quan em mà anh biết, em vòng tay ôm eo hắn như từng đi với anh, rồi em lại cười khúc khích mỗi khi bàn tay hắn lân la trên cái đùi trắng sau lớp váy ren mỏng manh mà anh nghĩ nó sẽ chỉ thuộc về riêng anh. “Bạn bè” thôi à, “anh ấy giúp em trong công việc nhiều lắm”, anh nghĩ lại sao nó nhạt nhòa như nước mưa cuốn trôi hết mọi thứ vậy em

Em có biết lúc đó anh sốc thế nào ko khi, níu tay lái, vít ga, bắn côn khiến chiếc xe chao đảo, đến hắn và em phải quay sang nhìn anh, lúc đó em có biết anh đã khóc ko, chính xác anh đã khóc sau lớp kính đen, anh thấy em, còn em liệu có thấy anh, chắc ko đâu nhỉ, bởi em tưởng sẽ giấu đc anh mà

Dừng xe, gọi điên cho cái N

– N à, cái T nhà anh có qua chỗ em ko

– Dạ có anh ạ, N qua rồi về lúc 9h rồi

Nhìn đồng hồ, gàn 11h, rồi hỏi tiếp

– N có bảo đi đâu ko

– Ủa em tưởng anh qua đón nó, cái N bảo anh qua đón nó mà

– Ừ, ok cám ơn em

Cup máy, lên xe, đuổi theo, đầu óc trống rỗng và hy vọng kịch bản trên Voz ko xảy ra với mình nhưng cuộc đời chó chết các thím à. Khi em đi vào ngõ thì chiếc xe SH đó đã yên vị trong bãi để xe của cái nhà nghỉ bên đường, em ko nhìn nhầm đc, em nhớ như in biển số đó

Em thẩn thờ, tắt máy xuống xe đứng trc nhà nghỉ, ko biết đi đâu làm gì vào lúc 11h đêm khuya thé này.

Lúc đó em có thể vít hết ga mà tông con CBR này vào con SH đó, để hả cơn giận, em có thể lao vào cho thằng kia 1 trận, nhưng em ko làm thế, phải nói rằng Voz dạy cho em rất nhiều điều, và bình tĩnh khi gặp gấu chó là điều mà em đang thực hiện bây giờ.

Rút bao thuốc, châm 1 điếu, rít 1 hơi dài, dắt xe vô nhà nghỉ, các thím nghĩ em làm gì, chạy lên và đấm vào mặt chúng nó ư, ko làm thế chỉ chứng tỏ mình càng bất lực thôi, các thím có thể chử em điên, cũng đc, trơ mắt nhìn gấu vào n2 với thằng khác ư, em có trơ đâu chẳng qua ko làm gì ddc thôi, em đến nơi có lẽ chúng nó đã bóc bánh nhau rồi, lao vào để thấy vợ mình đang ôm ấp, đang rên là trong vòng tay thằng khác ư, em ko đủ cam đảm để đối mặt với cảnh đấy

Dắt xe vào chính nhà nghỉ đó, gọi thằng ku giữ xe, cho nó 200k, rồi cho nó sđt, bảo nó bao giờ thằng đi con SH này ra thì nháy mình.

Sau khi đưa cho thằng ku 200k, chụp ảnh biển số xe và địa hỉ cái nhà nghỉ, em bước vô n2, đằng sau nụ cười nhạt cuả thằng ku trông xe, nhục nhã, ê chề chưa, theo bạn gái vào nhà nghỉ cùng với thằng khác mà hèn, mà yếu đuối ko đủ dung khí lao vào mà chứng kiến cảnh đó. Vâng, nhục lắm, nhưng có lẽ đau hơn các thím à

Lên phòng nằm phịch xuống giường, mệt mỏi, thất vong chán nản, ko muốn nghĩ gì nhưng đầu óc quay cuồng như muốn nổ tung lên. Ra ngoài ban công đốt thuốc, gọi là để đuổi muỗi, ngắm phố lên đèn, ban đếm yên tĩnh thật, nhưng vẫn có những người lao đầu vào trong bóng tối để bươn trải cuộc sống kiếm miếng cơm manh áo, cũng như đằng sau màn đêm, nếu ai ko thức thì ko biết người ta đã làm gì để rồi buổi sáng mọi thứ lại êm đệp như quy luật vốn có của nó

Một số bạn thắc mắc cô ấy bảo tý về rồi lại vô n2 với thằng kia, bởi tính mình yêu nhau tin tưởng là chính (có lẽ sau truyện này cũng đéo tin đc ai nữa), cả 2 đếu có không gian riêng tư của nhau cả mình tôn trọng cô ấy à cô ấy tôn trọng mình, 2 đứa mới chỉ dọn về ở cùng nhau đc vài tuần (cái này là do mình đề xuất với 2 gia đình và 2 bên cùng cô ấy đều vui vẻ cả), thế nên cô ấy vẫn hay qua chỗ cái N cùng 1 đứa bạn của cô ấy nữa (3 đứa ở cùng nhau) để tám, rủ nhau shoping hoặc ngồi xem phim hàn xẻng rồi khóc cùng nhau, có khi 11-12h đêm cô ấy mới ở bên ấy về là bình thường.

Ha ha ha, nghĩ lại vẫn thấy ấm long, những lúc đó, mình ngồi ôm cô ấy bên canh 2 đứa bạn cùng xem 1 bộ phim hàn xẻng, 3 đứa khóc thút thít còn mình thì cười sặc sụa, rồi ăn những cái cấu veo đâu điếng khi chê mấy anh oppa của em. Hạnh phúc lắm, rồi khi chia tay lại khổ sở thế này. Đ*t mẹ cuộc đời chó má

Đang suy nghĩ miên man thì có số lạ gọi, chắc là của thằng ku trông xe, nhìn đồng hồ 12h45p, nghe máy rồi đứng ngoài ban công hóng, cô ấy cùng thằng chó kia vừa trèo lên xe mình liền phi ngay xuống, trả tiền phòng rồi lôi con CBR phóng theo (công nhận theo dõi gấu chó mà đi con này phê thật, có khi sắm 1 con để dự phòng mới đc, thím nào mượn em cho thuê). Có thể mấy thím chửi mình ngu, sao ko bắt quả tang, đập cho chúng nó 1 trận, mình có thể, với sức 1 thằng tập gym 3 năm cùng với đai nâu karate mình có thể làm việc này.

Nhưng lúc đó mình bình thản đến mức ko ngờ, giờ nghĩ lại vẫn tháy phục mình vl, đơn giản mọi truyện đã xảy ra rồi, làm to truyện lên cũng ko giải quyết việc gì, làm tổn thương người con gái mình yêu để rồi sau lại có truyện gấu trả thù như mấy thím vozer em sợ lắm, làm lùm xùm lên chỉ khiên cô ấy mất mặt và xấu hổ, ê chề hơn thôi. Giải quyết mọi việc 1 cách đơn giản nhất đó là kinh nghiệm mình thu đc sau 5 năm vật lộn để giải quyết 1 vấn đề

Phóng con CBR vượt lên con SH, vê côn, con xe gầm 1 cái rồi phóng vụt qua, chắc nàng và thằng đểu kia đang thắc mắc sao lại có con xe theo cả buổi tối thế nhỉ. Đến đầu ngõ xịch xe lại, chấm nốt điếu thuốc cuối cùng còn trong bao. Kéo 1 hơi dài, 1 lúc sau cô ấy cùng thằng chó kia về, thấy mình cả 2 đứa chắc cũng hốt hoảng vì mình đang dựa vaò chiếc xe theo cả tối, cô ấy nhanh nhẹn xuống xe, có hơi ngập ngừng. Mình đứng yên xem 2 đứa định làm gì, nếu lại trèo lên xe đi tiếp với nhau thì 1 các thím biết em sẽ làm gì rồi đấy, nhưng cũng may điều đó ko xảy ra, em ấy lại nhí nhảnh, vui tươi bồng bềnh trong chiếc váy ren quen thuộc chạy đến ôm tay mình rồi chỉ ra chỗ thằng chó kia:

– Anh S đưa em về, trời hơi mưa nên bọn em đợi cho ngớt rồi về

Mình từ từ, lê đôi chân mệt mỏi, với khuôn mặt mình đã cố kìm nén hết mức để ko thể bật khóc và lao đến đập thằng kia 1 trận, đưa tay ra và ra dấu bắt tay, thằng kia cũng dơ tay ra bắt lại, mình nói

– Cám ơn chú đưa T về, muộn rồi về sơm đi kẻo có truyện gì đó

Nói câu này mình nhin thẳng mắt đối thủ (ai học karate chắc sẽ biết), bàn tay hơi siết chạt 1 chút rồi thả ra, chắc thằng ku cũng hơi đau, mặt có vẻ biến sắc rồi phóng xe đi ngay

Quay lại với em, đứng canh chiếc CBR sao em có vẻ nhỏ bé và mong manh thế, lòng lại cuồn cuộn những cơn tức giân, như muôn trút hết lên em ngay bây giờ.

Dắt xe vào nhà, ko đả động gì, rửa mặt cái cho tỉnh táo. Em vân vậy, rót 1 cốc nước và có mùi café thơm của em pha. Nhấp 1 ngụm café mà sao nó đắng ngắt, rồi nói

– 30F-XXXXX, nhà nghỉ ABC – 123 đường yyy. Vui chứ em ???

– Anh nói gì thế?? Cô ấy hơi giật mình và ấp úng hỏi lại (mình có đc học qua vè ngôn ngữ cơ thể nên rất chú ý tiểu tiết, khuyên các bạn nên biết 1 chút khi đi làm, ở trên bàn nhậu nếu có body language thì ta sẽ thu đc nhiều thứ hơn ngoài việc zô và 100% đấy)

– Anh biết mọi thứ rồi, em cứ nói thật đi, ko giấu anh mãi đc đâu

Cô ấy bắt đầu khóc, và nói

– Em xin lỗi, em xin lỗi !!!

– Sao em phải khóc người phải khóc là anh mới đúng. Đến đây thì mình bật khóc, ko thể kìm nén nối cảm xúc nữa

Tiếp sau đó là điệp khúc cô ấy xin lỗi, khóc lóc kể lể và mình thì ko nói gì, mình muốn nói lắm, muốn xỉ vả vào cái mặt mà mình yêu thương ngày nào cho hả giận, muốn làm nhiều thứ, nhưng cuộc sống dạy cho mình rằng ko bao giờ nói và hành động vào lúc tâm trí đang bất ổn, bấn loạn. Thế nên mình ko nói gì, mặc xác cô ấy, lấy cái gối rồi ngủ đất ở phòng khách, còn cô ấy cứ rên la, xụt xùi xin lỗi, mình muốn khóc lắm, muốn đánh, muốn chửi, 1 ôm cô ấy, muốn hôn, muốn được bế cô ấy nhưng tất cả mình ko làm, mình quát lớn

– Em ngủ đi, có gì mai ta bình tĩnh nói truyện, em khóc để chứng minh điều gì, em hối hận à, hay là em bị oan. Nếu giải quyết mọi việc bây giờ anh ko dám chắc sẽ làm gì em đâu, em biết rõ tính anh nhất. Để mai tính. Còn giờ thì ngậm mồm vào và ngủ đi

Cô ấy khóc to hơn, nhưng lại cố nén kiểu như dằn lòng cho đỡ khóc thì phải, chỉ thấy cô ấy nấc, tiếng khóc rít lên ở cô họng cô ấy. Nhắm mắt muốn ngủ, muốn quên đi mọi thứ, bên cạnh vẫn có tiếng nấc, tiếng thút thít của cô ấy. Chìm vào giấc ngủ lúc nào ko hay

Sáng dậy muộn làm, alô sếp xin nghỉ 1 buổi, bị ổng ý quát om sòm vì sợ chậm hồ sơ dự án

Em ý đang ngủ bên co ro cạnh mình, rúc vào nách mình như 1 thói quen thân thuộc, sao chỉ thấy long đầy hận thù và đâu đớn, yêu thương hạnh phúc nó tuột đâu mất. Đôi mắt sưng lên vì có lẽ tối qua khóc nhiều quá, bờ vai trần có vài vết xước cấu véo đỏ ửng, tới đây trong lòng chỉ muốn đạp phăng cô ấy ra xa để cô ấy biết mình là chồng cô ấy chứ ko phải là thằng chó đã qua vật lộn với cô ấy tối qua ở n2

Vùng dậy, cệ sinh cá nhân xong cô ấy cũng dậy, xách cặp lồng ra đầu ngõ mua 2 tô phở, về đổ ra 2 bát, có thể 1 số bạn chửi mình ngu, đi làm osin cho loại con gái ko ra gì, ừ cũng đc, mình có thể ko còn yêu cô ấy nhưng mình tôn trọng phụ nữ, muốn làm gì thì cũng cần phải no cái bụng đã

Ăn ngon lành xong tô phở, cô ấy ăn mấy gắp ngồi chống đữa rồi bắt đầu khóc. Ăn xong xuôi, kéo cô ấy ra phòng khách, vẫn thản nhiên và máu lạnh, đúng với bản chất mình đã đánh mất nó từ khi đi làm. Rót 2 côc nước, cùng với 1 hộp khăn giấy trên bàn (cho cô ấy khóc nếu cần thiết)

– Ok, bây giờ anh muốn nghe mọi truyện 1 cách rõ ràng chi tiết, em hãy chắc chắn những điều em nói ko phải dối trá thì anh sẽ nghe còn ko thì sẽ ko còn cơ hội cho cả 2 đâu

Vâng em ấy bắt đầu kể: mỗi câu em nói đều làm lòng mình cuồn cuộn, nhưng mình cố giữ bình tĩnh nhất có thể, quen thằng đó 1 năm khi em chuyển vào chỗ làm mới, nó hướng dẫn em trong công việc những ngày đầu, em có bảo với anh rằng thằng đó ko đc bằng anh, lời ăn tiếng nói cách đối nhân xử thế ko đc bằng mình (cái này mình công nhận, mình luôn tự hào vì mình tâm lý, biết ăn nói đối xử nên mọi ng rất quý) nhưng làm chung cơ quan, trưa trưa em cùng nó đi ăn, ròi trò truyện rồi thì n2, rồi thì xh (2 đứa đã xh với nhau từ 3 tháng trc). Đến đây mình điên tiết, đập bàn rồi nói thẳng

– Nếu theo nó vì truyện đó, vì sinh lý thì em cứ nói thẳng tính anh ko ngại những vấn đề này, nếu có gì trục trặc cùng nhau giải quyết, sao em phải chui lủi giấu diếm anh, lừa gạt anh

– Dạ ko phải, anh S (thằng chó đó tên S) . . . . . ko . . . ko bằng anh đc. Em nó nói trong ngập ngừng, có phần sợ sệt và tủi nhục (mình nghĩ đúng rồi bằng thế đéo nào đc mình, cao 1,78m, 70kg, chơi gym và học võ điều độ)

– Thế tại sao lại vậy????

– Em cũng ko biết nữa em xin lỗi, em xin lỗi. hu hu hu. Em nó gào khóc thảm thiết. Mình cũng muốn khóc lắm nhưng thù hận trong lòng mình có lẽ giờ nó nhiều hơn yêu thương nên chẳng thể rơi nước mắt đc

– Em biết rõ tính anh nhất, anh ko muốn mât thời gian vào những thứ kiểu này, cho anh số điện thoại thằng S, bảo nó tối anh muốn 3 ngừời gặp nhau nói truyện rõ ràng, anh ko muốn có thêm rắc rối nữa. Nếu ko đủ 3 người thì anh sẽ ko có gì để nói với em cả. Nói xong bay lên công ty, đâm đầu vào làm cho ổng sếp đỡ la, ko quên phone cho thằng S hẹn tối nay ra café nói truyện rõ ràng, vì mình đã biết mọi thứ

7h30p tối, ngồi 1 mình ở café quen thuộc cùng với em, chờ thằng chó kia đến

7h54p con SH biển số đó đã đến, thằng S kém mình 2 tuổi, người dây, ko đô con = mình, khuôn mặt có vẻ công tử, thư sinh hơn mình

Mình mở lời trc

– Anh đã biết mọi truyện, hôm nay muốn cả 3 nói truyện rõ ràng để đơn giản và đỡ mất thời gian của nhau sau này. Em yêu T chứ ??? Vừa nói câu này thì cô áy khóc

– Cũng không hẳn, có 1 chút, sau này có thể sẽ khác, mình ko muốn phá hoại 2 bạn nhưng đó là cảm xúc nhát thời của cả 2, ko kìn nén được. Thằng S cũng lịch sự trả lời

– Tính mình muốn mọi thứ phân bua, ko thể mập mờ nhất là truyên tc đc. Bạn biết bọn mình sắp cưới nhau, bọn mình đã chuyển về ở cùng nhau

– Đúng mình biết T đã kể. Mình liếc nhìn cô ấy, cô ấy tránh né cái nhìn đó

– Và bạn quan hệ với vợ mình rồi nói ko có y phá hoại. Mình trợn mắt nhìn nó theo đúng tinh thần của karate

– Thực sự mọi truyện đã rồi, mình và cô ấy sai, mình ko biết làm thế nào nữa, nhưng chắc chắn sẽ ko có truyện này nữa. Mong bạn bỏ qua và thông cảm cho T

– Bạn ko bỏ qua cho người đã có chồng thì sao tôi phải bỏ qua cho bạn. Là thằng đàn ông với nhau bạn biết rõ lời nói và hành động sẽ chẳng bao giờ đi liền với nhau. Bạn đã trưởng thành đi làm, vì thế hãy có 1 chút gọi là suy nghĩ về trách nhiệm của bản thân với cảm nhân của thằng bị bạn cắm sừng. Đừng có hèn mạt, chạy trốn trách nhiệm như vậy. Nói bỏ qua, nói thông cảm là hết trách nhiệm à

Thằng S đó im lặng ko nói gì, cũng may nó ko bật, chứ nếu nó bật thì nó ăn mấy cái sẹo kỉ niệm rồi. Quay sang hỏi em

– Còn em, em tính sao đây???

– Dạ em ko biết, em xin lỗi anh, tha thứ cho em!! Cô ấy khóc tô, nước mất dàn dụa, đầu lắc nguầy nguậy

– Đừng nói với anh là em ko biết, 3 người chỉ có anh là ko biết thôi, em và S biết rõ nhất đấy

– Đừng, em xin lỗi, em sai rồi, em xin lỗi, Em nó khóc kéo cái áo sơ mi của mình bật cả cúc, mọi ng trong quán nhìn, thàng S im lặng, toát mồ hôi

Mình nói:

– Ok vậy cả 2 nghe mình nói nhé. 2 đứa có yêu nhau, ko nhiều thì ít, 2 đứa có quan hệ với nhau, và cảm thấy hạnh hòa hợp (đ*t cụ thế mới xh đc 3 tháng rồi). Và bây giờ cần 1 lời chia tay của anh với T để cả 2 tiếp tục. thằng S với T ngẩng mặt nhìn mình ko nói gì

– Sao ko ai nó gì??? Mình tiếp tục

– Anh, em xin lỗi, để cho em suy nghĩ đc ko??? Cô ấy nói

Ha ha ha địt cụ cuộc đời chó má, suy nghĩ các thím ạ. Em ko nói gì để lại tờ 100k, rồi phóng xe lên công ty làm nốt

11h30 làm xong về đến nhà, thấy cô ấy đã ở nhà cùng với bộ đồ ngủ quen thuộc. Vào nhà cô ấy chạy ra, nhưng ko dám lại gần, chỉ đúng đó nhìn

Cô ấy theo sau mình, lại khóc, mắt sưng mọng lên mà vẫn khóc. Mình quay lại kéo cô ấy vào lòng, sao ấm thế, thân quen thế mà có lẽ sẽ chẳng bao giờ mình đc cảm nhân nó nữa, ôm hôn nhẹ lên trán rồi đẩy cô ấy ra

– Thực sự anh có thể tha thứ mọi việc làm của em trc đấy, nhưng khi anh cho em quyết định thì em lại “cho em suy nghĩ”. Thực sự tình yêu 4 năm với 3 tháng, em hối hận lắm, em xin lỗi anh, em biết lỗi rồi, mong anh tha thứ, ấy vậy khi anh cho em cơ hội quyết định thì sao ạ. Em bảo “cho em suy nghĩ”, suy nghĩ về điều gì hả. Hay là em có quyết định rối mà ko dám nói ra, em cứ nói anh chịu đc, em yên tâm a ko shock đến mức em tưởng đâu, nó nhẹ nhàng lắm em ạ

– Em yên tâm anh sẽ nói truyện với 2 nhà, anh giấu kín mọi truyện, và chia tay em, anh sẽ nhận lỗi vè anh, bảo đó là do anh muốn chia tay, anh có người khác, em chỉ là nạn nhân thôi, ko cần phải quá lo lắng đâu. Chỉ có 3 người biết truyện này thôi

– Em xin anh mà, em biết em sai rồi. Cô ấy gào to kinh khủng và khụy xuống sàn, quay lại nhìn muốn chạy đến đỡ cô ấy lắm nhưng chả hiểu sao đôi chân ko theo suy nghĩ của mình chạy ra cửa, dắt xe phóng đi trong đêm, qua chỗ thằng bạn ngủ nhờ, nó có hỏi nhưng trả lời qua loa rồi ngủ luôn

Lại vùi đầu vào đống côn việc ùn tắc mấy ngày, tắt điện thoại, ko onl để tập trung làm cho kịp tiến độ, cũng 1 phần vì quá mệt mỏi sau 2 ngày hôm nay. Sau 3 ngày ăn ngủ luôn ở công ty, chán ko muốn về nhà, xong cái dự án thì buổi chiều có thằng bạn chạy đến tận công ty tìm mình bảo có truyện gấp. Cũng chẳng nghĩ gì, vừa gặp nó đã kêu

– cái thằng chết tiệt mày biến đi đâu mấy ngày hôm nay mà ko ai liên lạc đc, vợ mày bị tai nạn nằm viện 2 hôm rồi mà đéo vào chăm, chồng con như sh*t

Kéo ngay nó bảo đưa vào viện, trên đường đi hỏi nó sau, thì ra cô ấy đi làm tránh nhau xe cộ thế nào và đâm vào dải phân cách, bị mất máu và tổn thương phần mềm chút ít. Vào viện nằm máy hôm là xong

Chạy đến thấy cả bố mẹ mình với bố mẹ cô ấy đã ở đó rồi (chạy từ quê lên mà nhanh v~), bố mẹ mình chửi mình vô tâm, ko để ý đến vợ, bố mẹ cô ấy cũng trách mình chút ít, ko có gì, xin lõi phụ huynh, cũng biết ý nên các bố các mẹ ra ngoài để mình với cô ấy trong phòng (chắc các cụ chưa biêt truyện), hình như là phòng vip hay gì đó mà chỉ có bệnh nhận và có 1 cái giường cho người nhà nằm cạnh.

Cô ấy nắm tay mình và rồi lại khóc

– Em xin lỗi, em xin lỗi, anh đừng bỏ em 1 mình, em sợ lắm

Thở dài, sao em ko nói những câu này khi mình cho em lựa chọn, khi mình quyết định rồi và nói cho cô ấy hiểu thì cô áy mới thốt ra dc

– Đừng khóc nữa, nghỉ đi cho khỏe, có gì khi nào em ra viện thì anh sẽ nói truyện

ở lại 1 lúc nữa rồi mình ra ngoài, nói truyện, này nọ với các phụ huynh, naoflaf sắp làm chồng rồi, sắp cưới nhau rồi thì phải thế này, thế nọ với vợ, rồi bắt đẻ mấy đứa cháu, đặt tên là gì. Hazz, các cụ lắm truyện, trong lòng thì ngổn ngang.

Tối đi nhậu chúc mừng xong dự án là tối qua, về say quá nên viết tâm sự cho nhẹ long, gió máy cũng đc, tin hay ko tùy, mình tôn trọng phụ nữ, và ko mong truyện này xảy ra vơi mình thế nên mình ko thừa thời gian chém gió sáng tác truyện để nói xấu, hạ thấp phụ nữ cả. Đây là những dòng tám sự thật cảu mình

Sang náy dậy, xin nghỉ làm vào viện với cô ấy, 1 số bạn bảo mình ngu, bảo mình sao vẫn làm osin cho con phò, con đĩ đấy. Cũng chẳng sao, tính mình thế, họ là con gái, người thua thiệt luôn là họ, minh là đàn ông, sao chẳng đc. Đã làm gì là làm hết sức, làm tới cùng, truyện cảu mình và cô ấy còn chưa xong, hiện tại cô ấy vẫn còn là vợ chưa cưới trong mắt họ hàng 2 bên thế nên ko muốn nhưng đó là trách nhiệm, đó cũng chính là nguyên tắc làm việc và sống mình, dã nhận việc là làm hết sức, ko nhận tthif từ chối luôn, mà đã nhận là phải ra ngô ra khoai, cô ấy bắt mình hứa đủ thứ nhưng mình rất ít khi nhận lơi, chỉ những thứ nào mình chắc chắn làm đc mình sẽ làm còn ko thì thôi, mất lòng trc dc long sau

Đó cũng chính là thứ giúp mình thành công trong công việc đến thế.

Tranh thủ cô ấy ngủ trưa ra hành lang ôm con lap check mail và gõ vài dòng cho mấy thím. Mà cái đù má nó, hoãn cưới tránh kim lâu, sợ mưa gió gì đó thì làm ăn thất bát, còn bây h lại toàn găp mưa. Hôm nào có truyện trời cũng mưa. Ngồi type mấy dòng mà cũng mưa đc.

Đ*t nó chứ

Chiều nay type cho mấy thím xong, ổng sếp lại gọi lên cty xem lại 1 số thứ ở dự án và chỉnh lại theo ý nhà đầu tư, nói chung ko quan tâm gì nữa, sếp bảo sao làm vậy. Đang làm thì có điện thoại mẹ gấu bảo, bao giờ về thì ghé qua viện, dọn đò rồi cùng mẹ làm thủ tục cho em nó ra viện, đưa về nhà cho tiện đi lại. Dạ vâng xong, mệt mỏi làm chút rồi xin sếp về sớm có việc, y như rằng lại bị ổng kêu ka. Đùa tý cho ổng xếp dịu dịu rồi chuồn về. Lượn vào viện thấy mẹ mình cùng mẹ em ấy đang thu dọn đồ đạc. Mình vào giúp 1 tay, rồi xuống làm thủ tục xuất viện. Gọi taxi rồi lên cõng ẻm xuống xe, mà cái đù má nó trời cứ mưa là sao, 2 mẹ xuống xe trước, mình cõng ẻm xuống sau, hình như cô ấy khóc, hay là nước mưa rơi vào vai áo mình nữa, long mình lại nhói lên, thương cô ấy quá, nhưng biết làm sao đc khi mọi truyện đã rồi.

Mọi người bảo mình ngu, mình lụy mình yếu đuối, ha ha ha. Yên tâm đi, vì trải qua bao nhiêu truyện mình biết thế nào là đúng, là sai và cần thiết làm gì vào những lúc thế này: Yêu thương vị tha nhưng ko nhu nhược, sẽ níu giữ hết sức nhưng sẽ từ bỏ đúng lúc, nâng niu săn sóc nhưng sẵn sàng đâp vỡ mọi thứ.

Cuộc sống mà, chẳng ai cho ko nhau thứ gì, hạnh phúc cũng vậy, đôi khi nó giản dị gần gũi nhưng có lúc laị là 1 thứ xa xỉ. Là 1 thằng đàn ông, cho dù bị nói thế nào đi chăng nữa, các bạn nói mình đàn bà cũng đc, tự ái, sỹ diện cũng đc, mình ko quan tâm, mình sẽ từ bỏ, đây là quyết định xuất hiện ngay trong đầu từ khi thấy cô ấy ở cái đêm đó rồi. Là thằng đàn ông, mình ko bao giờ hối hận vì quyết định cuả mình cả, ít nhất là từ bỏ cô ấy. Cám ơn 1 số thím đã vào chia sẻ cùng mình, 1 số thậm chí đáng tuổi cha chú mình, mình cám ơn vì đã quan tâm, mình ko đủ cao thượng để bỏ qua cho cô ấy tất cả mọi truyện đc, mình sợ 1 lúc nào đo sẽ lại lôi quá khứ ra để dày vò cô áy mà thôi (có thể bình thường thì sẽ ko bao giờ nhưng lúc say chẳng hạn, chẳng ai dám chắc mọi thứ, mà đã ko chắc chắn thì mình ko làm, mình ko dám phiêu lưu với hạnh phúc và hôn nhân, hơi hèn đúng ko các thím)

Thế nên tốt nhất là để cho nhau tự do, nếu có duyên phận thì hy vọng găp lại nhau, em chỉ muốn bình tĩnh, làm rõ mọi truyện để sau này chẳng may lúc 2 người có con bồng bế sẽ ko phải hối hận khi gặp lại nhau, sẽ ko phải nói những câu “giá như ngày đấy thế này thế nọ” đúng ko các thím. Cô ấy đang nằm viện gia đình 2 bên lo lắng cho cô ấy thế nên mình sẽ ko dả động gì cả, ít nhất là cho cô ấy tĩnh tâm lại, để tránh việc cô ấy suy nghĩ lung tung làm việc dại dột, lúc đó bỏ thì thương mà vương thì tội, khổ cho cả cô ấy và khó cả cho mình

Thôi lan man quá rồi, quay lại vậy, cô ấy có khóc nhẹ trên vai em, ra đến xe 2 mẹ đang cầm ô chờ sẵn, bế em vào xe, 2 mẹ còn trách, thằng này cõng T cẩn thận, nó đau quá khóc kia kìa, sắp vợ chồng rồi mà thế à, mình cười nhẹ, đúng là đau thật, nhưng mình mới là người đau. Xe taxi đi rồi vào bãi để xe lấy xe rồi phóng nhanh về nhà, ko quên ghé qua cửaa hang thể thao mua 1 cái đích đấm.

Về nhà, mặc xác cô ấy, ngồi trên ghế, và 2 mẹ đang vui vẻ trong bếp, vác cái đích đấm lên sân thượng (nhà riêng em thuê nên có sân thượng nhé), treo lên cái xà, và rồi em đấm như chưa bao giờ đc đấm, đấm đá, bao nhiêu đáng cay, tức giận em trút hết vào những quả đấm lên cái đích, em hình dung ra khuôn mặt thằng S khốn nạn đó mà đấm mà đá cho hả cơn tức, mình có thể xông vào cho cả 2 đứa 1 trận nhưng mình đã ko làm thế, các thím có thể chửi mình ngu nhưng làm thế để đc gì, hả giận hả, hay là nhận đc cái nhìn khinh bỉ từ mọi người, 1 thằng đàn ông bất lực nhìn ng yêu ngoại tình và xông và đấm đá à, nó chỉ càng khiến cho bản thân thêm bất lực về mọi thứ mà thôi, và có thể lại làm cho mình có them 1 kẻ thù là thằng S thôi, mình đánh nó, nó đánh mình, mình hèn vì ko dám đánh nó – các bạn nói thế cũng đc nhưng mình đã thực sự mệt mỏi về truyện này lắm rồi, ko muốn rắc rối thêm nữa.

Mình đấm điên cuồng cho đến khi 2 bàn tay tê dại và mẹ mình phải lên tận nơi gọi xuống tắm rủa ăn cơm mình mới chịu xuống, cũng thấy dễ chịu hơn, mình khuyên nếu các thím tức giận cứ làm thế này, trút bớt bực tức, bình tĩnh hơn và nhất là mệt thở ko nổi thì chẳng nghĩ đc gì cả

Tắm rủa xong, ra ăn cơm, và 2 mẹ lại để chỗ mình ngồi cạnh cô ấy, cố gắng vui vẻ cho qua bữa cơm, cô ấy thì mặt buồn rườu rượi, chống đũa rồi chẳng ăn gì, 2 mẹ lại vui vẻ, cười tưới như tết vậy bàn truyện nhà cửa, cháu chắt, đám cưới đám hỏi, rủ nhau đi xem bói thầy này , cô kia….. trong lòng ngổn ngang, nhai cơm mà như nhai rơm vậy, ngấu nghiếm xong bát cơm, xô ghế đứng dậy, vừa dứng dậy thì cô ấy bật khóc, thầm nghĩ lại mệt với phụ huynh quả này rồi, ko ý kiến gì định rút êm nhưng mẹ mình hỏi ngay

– H kìa xem sao cái T nó khóc thế kia, xem nó đau chỗ nào. Đành ngồi xuống, ko nói gì, chỉ ngồi im, và em ấy cũng chỉ khóc, có lẽ ko giấu đc nữa rồi, định vài hôm nữa rảnh thì về quê nc với 2 nhà mà lại thành ra thế này, đúng là nhân tính ko bằng trời tính

Mẹ cô ấy hỏi tiếp luôn theo sau

– Có phải 2 đứa có truyện gì rồi không, lớn rồi, sắp lấy nhau rồi mà chúng mày vẫn làm mẹ lo quá

Mình và cô ấy đều in lặng. Mẹ mình lại tiếp lời

– Cả 2 đứa lớn rồi, truyện riêng tư của 2 đứa mẹ ko can thiệp nhưng, 2 đứa sắp làm vợ chồng cả rồi, đừng làm gì ảnh hưởng đến việc quan trọng này

Lấy hết can đảm mình nói

– Con quyết định rồi ạ, chúng con ko cưới nhau nữa. Vừa nói đến đấy thì cô ấy khóc to hơn, 2 mẹ đều nhìn mình giận dữ rồi quát

– Mày nói gì đấy

– Dạ con suy nghĩ kĩ rồi à

– Có việc gì đến mức thế, nói rõ tao nghe xem nào. Mẹ mình quát lớn, chắc do ngại với mẹ cô ấy

– Lý do thì con sẽ nói qua cho mẹ hiểu, còn việc hoãn đám cưới con sẽ lo sắp xếp mọi truyện ổn thỏa, con không muốn nhắc lại truyện này nữa, dù sao thì con sẽ ko tổ chức đám cưới

– Mày bị điên rồi H à, mày nghĩ kĩ chưa mà nói thế hả?? – mẹ mình to tiếng

– T có việc gì nói mẹ nghe, ai sai ai đúng mẹ sẽ giúp, đừng trẻ con quá như vậy, 2 đứa sắp làm vợ chồng rồi đấy – Mẹ cô ấy nói với cô ấy

Cô ấy khóc, vâng chỉ khóc, long lại đau đớn, nước mắt trực trào ra, em cố kìm nén rồi đi lên sân thượng, châm điếu thuốc, kéo 1 hơi dài, rồi thở dài ngao ngán, chỉ ngồi 1 mình, đầu óc quay cuồng, châm hết điếu này đến điếu kia chỉ mong đầu óc nhẹ hơn chút ít, ngồi nhìn phố về đêm.

Tầm 30p sau 2 mẹ có lên, mặt cả 2 đều rất buồn, và thái độ khác hẳn ban nãy, có lẽ cô ấy đã kể phần nào câu truyện. Mẹ mình mở lời

– Con nói rõ ràng lại cho mẹ với bác nghe, nếu mọi truyện đúng như T nói thì mẹ ko can thiệp vào truyện của con nữa, mẹ tôn trọng quyết định của con, con lớn rồi, con đủ khả năng chịu trách nhiệm với bản thân mình và mọi người nên mẹ ko nói thêm nữa

Châm điếu thuốc hút tiếp rồi chậm rãi kể lại, mình biết mọi truyện ra sao, đã làm gì và nói gì với cô ấy. Kể xong mẹ cô ấy có khóc, nhưng rồi bác lại nén ngay những giọt nc mắt đó. Mặt bác buồn lắm, mình nghĩ cũng khổ thân bác ý và cả cô ấy nữa. Rồi bác nói, giọng hơi ngẹn

– Cháu cho bác và chú nhà xin lỗi cháu và cả bố mẹ cháu nữa, cái T nó là đứa con mất dạy, bác nuôi cho nó ăn học, nó yêu cháu, bác mong 2 đứa nên vợ chồng lắm mà nó đi làm cái trò mạt hạng lăng loài thế này, bác chẳng còn mặt mũi đâu mà nhìn bố mẹ cháu cả

Mình thấy buồn, ko biết nói sao nữa, thất vọng chán nản, im lặng 1 lúc rồi mình nói với mẹ cô ấy

– Cháu xin lỗi, có thể cháu nhỏ mọn nhưng cháu có thể làm khổ cô ấy nếu tiếp tục với nhau, cháu đã suy nghĩ rất nhiều về việc chia tay hay ko, cũng chẳng vui vẻ gì khi bỏ vợ sắp cưới của mình, cháu cũng có phần sai trong việc này, cho cháu xin lỗi T, xin lỗi bác và gia đình. Hy vọng hiểu và thông cảm cháu

– Bác hiểu, sống hơn nửa đời người, bác biết thế nào là đúng, là sai.

– À bác ơi, bác để ý T giúp cháu, cháu lo cô ấy làm điều gì dại dột thì cháu ko yên tâm đc

– Bác biết rồi, nó là con bác mà. Xin lỗi cháu. Đi ngủ đi khuya rồi

Vào phòng của 2 đứa, cái mùi quen thuộc, ko khí ấm cúng của nó đã thay bằng sự nậng nề của cả 2. Cô áy ngồi cuối giường, ôm mặt, mình vẫn nghe tiếng nấc trong cổ họng cô ấy. Lặng lẽ vào phòng rồi lại đi ra, dịnh nói câu gì đấy gọi là dấu chấm hết cho mọi truyện mà lại chả nói đc, nói có lẽ chẳng khác gì đay nghiến cô ấy

Vác con lap ra phòng khách ngồi, 2 mẹ chắc cũng đã ngủ, lượn voz đọc cmt 1 số thím mà cũng phải cười, có thím còn chủ động gọi điện chia tay gấu cho bớt lo mới hài hước chứ. Đọc hết các cmt ko xót 1 cái nào, chủ yếu chửi cô ấy là phò hay đĩ, các bạn đừng nói thế, mình ko còn tình cảm với cô ấy nhưng tình nghĩa thì dù là người lạ cũng phải có 1 chút, đúng ko mấy thím, có thể việc làm cô ấy là sai, hoặc mình sai nhưng ko ai là phò hay đĩ ở đây cả, mình vẫn tôn trọng cô ấy như những người bạn là con gái của mình, cuộc sống có lúc này lúc kia, là người trong cuộc mới hiểu rõ mọi truyện

Cám ơn cô bé mazy, nhưng anh phải làm em thật vọng rồi, đọc cmt của em làm anh thấy rất ấn tượng với suy nghĩ của 1 cô bé trong sáng, hồn nhiên, đầy mở mộng giống cô ấy hồi 2 người mới yêu nhau vậy, thề non hẹn bể, sẽ tha thứ, sẽ là vợ chồng, nghĩ lại thấy chạnh lòng, có vài ngày mà mọi thứ đi xa quá. Chẳng thể kiểm soát nổi mọi thứ, cô ấy lừa dối mình, xuất hiện kẻ thứ 3, cô áy bị tai nạn rồi 2 mẹ biết truyện, tất cả nằm ngoài dự tính của mình

Mệt quá rồi, mình cần phải ngủ, rảnh dỗi sẽ tâm sự cũng các thím

Có thể đây sẽ là review cuối cùng về câu truyện của mình, nếu bạn nào bảo mình dựng truyện hay bịa thì có thể bỏ qua cũng đc.

Thực sự có nhiều điều muốn nói mà mình ko biết nói từ đâu.

Có lẽ đầu tiên mình xin gửi lời cảm ơn các bạn đã chia sẻ những câu truyện của các bạn cùng với mình giúp mình nguôi ngoai bớt phần nào, thực sự từ trước đến nay mình ít khi kêu ka về mọi thứ, bởi đàn ông mà suốt ngày kêu ka thì có cô gái nào có thể chọn bạn làm chỗ dựa cho tương lai, và voz là nơi đầu tiên mình kêu ka cũng là nơi mình đã chia sẻ câu truyện của mình lên. Một số bạn inbox cho mình, xin lỗi vì mình ko rep đc (chưa đủ post), và đây là nick của thằng ku mình mượn nó mà thôi.

Có 1 bạn đồng đạo (cùng karate), đã gửi lời chia sẻ tới mình, thực sự lúc đó ngoài việc dày vò đôi bàn tay bằng cái đích đấm mình ko biết làm gì hơn cả, bấn loạn, chán nản, nhưng ko thể chìm đắm trong mem rượu được vì lúc đó mình cần tỉnh táo hơn bao giờ hết, trút tức giận lên cô ấy, thằng s hay cái cuộc đời chó má này là ko thể nên dày vò đôi bàn tay là cách khá nhất mà mình nghĩ đc. Thôi lan man quá rồi, quay về chủ đề chính vậy

Sau buổi tối ngày hôm kia, tức là sau buổi tối khi 2 mẹ biết truyện đó. Sáng hôm sau mình đi làm bình thường, chiều thì mẹ gọi điện bảo về sớm có việc. Lại xin phép sếp về sớm, lại bị kêu.

Về đến cổng thì thấy thằng em trai cô ấy, nhìn nó mặc cái áo BK nghĩ lại thời sinh viên, bây giờ nó đầy đủ, đồng phục ko như thời của mình, chỉ tối ngày ở tam giác vàng, mình quen cô ấy cũng từ nó mà ra, hình như nó đang năm cuối rồi thì phải, nó rất quý mình, vì mình dạy nó võ, dạy nó chơi Dota.

Nó thấy mình đã chạy đến, mặt hơi nghiêm trọng, mình ko hiểu dắt xe vào nhà thì thấy thằng S, bố mẹ mình, bố mẹ cô ấy, cô ấy cùng đứa em gái út hình như năm nay thì đại học. Hơi bất bất ngờ nhưng ko thái độ gì. Ngồi xuống, mọi người im lặng nhin mình, không khí nặng nề, ko ai nói câu gì, mình mở lời trước

– Đầy đủ mọi người ở đây, có việc gì ko ạ???

– Em đến đây để xin lỗi anh chị với các bác, mọi truyện tại em mà ra cả, em ko biết phải làm thế nào nữa nhưng mong anh tha thứ cho cô ấy. – thằng S bật dậy nói

Mình chưa nói gì cả, thằng em cô ấy đã lao vào

– thằng chó mày phá hoại anh chị tao rồi mày …. Nó chưa kịp nói hết câu thì bố cô ấy đã quát lên

– thằng K ra ngoài, truyện người lớn ko phải việc của mày. Nó lủi thủi ra ngoài cổng cùng với con em nó (gọi là T bé)

– Thực sự mình ko có gì để nói, và cũng ko quan tâm ai nói gì nữa. Mình muốn mọi thứ chấm dứt, mình quá mệt mỏi sau mấy ngày vừa rồi – Mình nói, bố mẹ cô ấy và bố mẹ mình thoáng nét giận trên khuôn mặt, nhưng mình kệ. Còn cô ấy lại khóc, thấy thương và tội nghiệp cho cô ấy quá

– Mọi người hiêu và tha thứ cho cô ấy được ko, thực sự mọi truyện ko như mọi người nghĩ và mối quan hệ giữa em và cô ấy chỉ là bột phát, 1 phút ko kiểm soát nối bản thân – thằng S vừa dứt lời thì… Choang !!! Bố cô ấy cầm cái ly trên tay ném suống sàn nhà, chỉ vào mặt thằng S rồi nói

– Cậu nói thế mà nghe cho được à, tôi ko biết cậu dụ dỗ làm gì con gái tôi, mối quan hệ giữa cậu và con gái tôi thế nào nhưng mọi truyện rành rành ra đấy, nếu cậu ko có bố mẹ thì tôi đã giết cậu rồi

– Tôi hỏi cậu và hỏi luôn con T, 2 đứa mày có yêu nhau ko hả hả, trả lời cho rõ ràng – bố cô ấy hỏi tiếp

Mình đứng như trời trồng, cô ấy chỉ khóc, ko nói gì, thằng S thì ấp úng

– Dạ… dạ…có

– Được thế mày có lấy con T thay cho thằng H ko hả??? – bố cô ấy hỏi còn mình và bố mẹ mình vẫn im lặng

– Dạ cái này, cái này cháu còn phải…phải xem bố mẹ cháu đã ạ.

– Gọi bố mẹ mày đến đây cho tao

– Cái này ko đc đâu ạ

– Thế là mày ko lấy con T được, mà mày có lấy con T được thì tao cũng ko để con T nhà tao lấy cái loại như mày làm chồng, dù nó ko ngoan như tao tưởng???

Cảm giác của mình, muốn làm gì đó, cô ấy thì đang khóc, bố cô ấy luôn tự hào vì có 1 đứa con gái cả ngoan nhất nhà thì hôm nay đã thốt ra bảo cô ấy ko ngoan nữa, chẳng biết làm gì, hay mình tha thứ cho cô ấy thì sẽ ko có gì nữa, thở dài rồi mình bảo

– Thôi bác ơi, bình tĩnh, có gì nói truyện sau. Rồi mình quay sang thằng S bảo

– Mày về đi, nếu muốn sống thì đừng có qua lại với cô ấy nữa, mày hết việc ở đây rồi. Nó ko nói gì, cúp đuôi, ra dắt con SH với cái biển số chó chết ấy mở cổng về.

Nhưng mọi truyện ko êm đẹp như thế. Vừa quay vào đinh nói thì nghe thấy… Rầm!!! Là tiếng xe máy đổ, chạy ra cổng thì ra thằng em cô ấy đang đấm đá thằng S cật lực, còn cái xe thì đè lên chân thằng S. Mình thấy thế quát nó

– K mày làm gì thế, thôi ngay. Cái ngu của mình là lại đi quát nó, thấy mình quát, nó cố túm tóc thằng S, định làm 1 cú tạt vào mặt thằng S, mình nhảy đến gạt tay nó ra nhưng ko kịp, chỉ chạm vào tay nó và cú tạt nó vào đúng thái dương thằng S. Thằng S ngất. Mình lối nó ra, chắc cũng chỉ bị choáng bình thường, tỉnh ngay thôi, nhưng cô ấy đã hốt hoảng gọi taxi, gọi xe cứu thương.

Vâng cảm giác khó tả đến khó chịu, nó đau đớn, quằn quại mà ko làm gì đc, nếu thằng S là bạn cô ấy hay bạn mình thì cô ấy lo lắng và gọi taxi, xe cứu thương thì mình sẽ tự hào lắm, vì có 1 người vợ hết lòng vì bạn bè như vậy, nhưng đó lại là thằng S, thằng đã qua lại, quan hệ với cô ấy thì mình ko thể nào mà vui nổi, có thể mình nhỏ nhen quá chăng, khi thù hận nó làm mất hết niềm tin và yêu thương dành cho con người cô ấy. Vậy mà trước đó mấy phút thôi mình từng có ý nghĩ sẽ tha thứ cho cô ấy, nhưng bây giờ có lẽ mình sẽ phải dùng lý trí để suy nghĩ chứ ko thể cuốn theo cảm xúc 1 lần nữa.

Thấy cô ây hốt hoảng qua mình cũng nói

– S nó ko sao đâu, chỉ bi choáng tý, tỉnh ngay bây giờ thôi

Cô ấy ko cuống cuồng như vừa rồi nữa, bố cô ấy lôi thằng K vào rồi quát

– mày làm cái gì đấy, hết chị mày làm loạn lại đến mày đấy à

Mình thấy thế, dìu thằng K vào ghế, rồi bảo

– Thôi bác ạ, K nó cũng nóng tính như bác vậy, bác đừng quát mắng nó nữa. Bó cô ấy ko nói gì nữa. Mình lôi thằng K ra ngoài bảo

– Đây là chuyện của anh, ko cần mày làm thế, năm cuối rồi, cẩn thận mà lo tấm bằng đi, đánh nhau ko giải quyết gì đâu. Nó cũng im. Nhìn nó lại nhớ lại thời sinh viên, cũng nóng tính, nghích ngợm, bất cần và phá phách, cô ấy yêu mình cũng vì lẽ đó, mà bây giờ thì …..

Mình vào nhà, em T bé đang dọn chõ thủy tinh lúc nãy , còn cô ấy đang rót cốc nước cho thằng S đang nằm khèo ở cái ghế, nhìn thấy cảnh đó nếu là ngày thường thì cũng ko có gì cả, nhưng vào lúc này thực sự nó ko khác gì sát muối vào lòng mình, cảm giác bất lực, khó chịu. Thằng K thấy thế nó chỉ tay vào cô ấy, mồm nó méo xệch đi vừa khóc vừa nói: “Em ghét chị”. Chứng kiến cảnh đó thực sự mình ko biết làm gì nữa, ko lẽ vì mình mà gia đình cô ấy, tình cảm chị em lại có vấn đề thì ko biết làm cách nào nữa. Bố cô ấy thấy thế nói:

– Thằng K ra ngoài. Nó xụt xịt khóc rồi lủi thủi ra ngoài cổng đứng

Mình cũng ko biết làm gì nữa, kệ mọi người và thằng S ở đó, lên sân thượng, và trút mọi thứ lên cái đích đấm, đấm cho quên đi cái cảnh cô ấy rót nước hay cái cảnh cô ấy lo lắng cho thằng S, ko nói với ai và cũng ko ai biết những gì đang diên ra trong đầu mình, chỉ có nói cùng anh em vozer, những người mà họ ko biết mình và mình ko biết họ, cũng thấy bớt phần nào. Lúc sau mẹ gọi xuống tắm rủa ăn cơm.

Thấy cả nhà cô ấy và thằng S dã về, ăn cơm xong, chả ai nói với ai câu nào, vác cai lap lên sân thượng ngồi đọc cmt của các bạn, lúc sau thấy 2 cái xe xịch trc cổng, là bố mẹ và 2 đứa em cô ấy, khoảng 15p sau thì bố cô ấy cùn bố mình lên sân thượng, mình cất lap.

Vừa ra đứng cùng phụ huynh, bố cô ấy rút bao thuốc đưa mình 1 điếu (còn châm lửa cho mình nữa), ngậm điếu thuốc, rít 1 hơi dài, rồi bố cô ấy nói.

– Mọi việc thành ra thế này, bác ko còn mặt mũi nào mà nhìn bố mẹ cháu nữa, mong ngày đc làm thông gia với ông mà bây giờ tôi phải xin lỗi ông rồi. Bác ấy nói rồi quay ra nhìn bố mình

– Thôi thì kệ cho bọn trẻ nó quyết định, lớn cả rồi, cũng mong chúng nó nên cơm cháo, rồi có cháu bế nữa.

Mình suy nghĩ 1 lúc rồi nói

– Cháu xin lỗi bác, con xin lỗi bì làm phật ý bố, nhưng mọi việc của T con biết hết, sau này lấy nhau có thể con ko quên đc, lôi truyện cũ ra làm khổ cô ấy thì càng khổ cô ấy hơn, 1 vài năm nữa mọi truyện qua đi, có thể bố và bác ko phải là thông gia nữa nhưng nó nhẹ nhàng với cả T và con, sẽ ko có những lúc con cái chúng con hay là cháu của bố và bác phải chứng kiến cảnh bố nó đay nghiến mẹ nó bằng những truyện xảy ra mấy ngày vừa rồi.

2 người ko nói gì, mình nói tiếp

– Cháu xin lỗi bác, cháu hơi nhỏ nhen và ích kỉ, cháu làm thế thì T là người chịu thiệt thòi, cháu biết tình cảm cô ấy dành cho cháu là thật, nhưng cháu ko đủ cao thượng để vùi truyện này đi mãi mãi, bây giờ cháu ko làm đc gì hơn ngoài việc mong cô ấy tìm dc 1 người tốt hơn cháu

Bố mình và bác ấy cũng ko nói gì , chỉ lặng lẽ đốt thuốc và trầm ngâm. 1 lúc sau bác ấy vỗ vai mình rồi bảo

– Không sao cháu ạ, đừng suy nghĩ nhiều quá, nghỉ sớm đi ko mệt, nói rồi 2 phụ huynh đi xuống, để mình ở lại

Suy nghĩ lung tung, có phải mình đang làm cả 2 bố mẹ khó xử ko, có phải trẻ con làm mất lòng người lớn ko, mình đã làm sai hay đúng, có nên làm gì với cô ấy ko, mọi thứ lẫn lộn, mình muốn phát điên lên vì mọi thứ, nó ập đến quá nhanh và mình cũng chẳng thể ngờ tới. Đang ngồi thì 2 đứa em cô ấy lên, thằng K và em T bé. Mình cũng chán ko muốn quay ra nữa

– Sao lúc chiều anh ko để em đánh thằng khốn nạn ấy đi – thằng K nói

Mình vẫn im lặng

– Em ko biết sao chị ấy lại làm thế nhưng sao anh để yên cho thằng S vậy được – nó nói tiếp

– Đánh nó giải quyết gì, mọi chuyện cũng đã thế rồi, ko muốn chị em khổ thì đừng gây sự cho mọi chuyện thêm rắc rối nữa, chuyện của anh và chị các em đừng lo lắng làm gì, mệt đầu ra

– Em xin phép thay chị ấy xin lỗi anh – em T bé nói

– Không có gì, vài năm nữa, lớn chút nữa, đi làm rồi các em sẽ hiểu và thông cảm cho chị ấy, đừng ghét chị ấy như thế, là người 1 nhà, cố giữ lấy tình chị em, đừng có làm chị ấy thêm áp lực – mình nói với 2 đứa

– Thôi 2 đứa về đi, muộn rồi, nhớ lời anh dặn đấy – mình nói tiếp. 2 đứa em cô ấy về nhà

Tối nằm mệt quá nên ngủ luôn cũng chẳng nhớ đc gì, sang hôm sau dậy (tức là sang hôm qua) lại đi làm cả ngày, cuối buổi chiều điện thoại rung, mở ra, vẫn đuôi số điện thoại quen thuộc, là cái số mà thời mới bắt đầu yêu 2 đứa đã mua cùng nhau, sim đôi, có lẽ sắp mất 1 đôi rồi, đúng là yêu càng nhiều kỉ niệm cùng nhau thì lúc chia tay càng thấy thấm thía và hối tiếc về lúc 2 đứa hạnh phúc, mệt mỏi mở ra đọc, cô ấy hẹn tối nay có việc muốn nói với mình ở quán cf cũ, con gái thường thế nhỉ, bao giờ cũng chọn những chỗ nhiều kỉ niệm nhất, những thứ gần gũi nhất, có lẽ cũng chỉ muốn con trai mềm lòng hay làm cái lý trí nó mất đi trong tức thời để con trai nói ra tình cảm thực sự những lúc này. Phù !!! định từ chối, nhưng thôi, nhắn 1 tin Ok, dù gì mình cũng cần biết 1 lý do cụ thể và thật sự chính đáng để cô ấy đánh đổi 4 năm yêu nhau và 1 cuộc hôn nhân sắp tiến hành

Xin sếp về sớm và lại bị la, về nhà thì thấy đồ đạc của cô ấy đã dọn đi hết, chỉ có mẹ đang ở trong bếp, bố thì đang ngồi xem tv, nhìn cảnh này tự nhiên thấy lòng ấm áp, lâu rồi mới đc chứng kiến cảnh này quen thuộc này từ lúc bé, đúng là khi mải chạy theo hạnh phúc, tình yêu hôn nhân tan vỡ thì con người mới nhận ra đc tình yêu, và hạnh phúc gần gũi nhất, ở sát bên minh là gia đình, chả cần chạy theo, chả cần tìm kiếm, nó ko nhìn thấy đc, ko ồn ã, ko rực cháy, đằm thắm mọi lúc như tình yêu, mà nó âm thầm, nhẹ nhàng và cũng sẵn sàng bùng lên bất cứ lúc nào

Tối ra quán cf ngày nào, lần này cô ấy đến sớm, đến chỗ cô ấy, kéo ghế ngồi, trên bàn đã có sẵn 1 ly đen đá, 1 ít đường và vài điếu thuốc. Là những thứ mà mỗi khi đi cf với cô ấy mình hay gọi, còn cô ấy, 1 ly sữa chua, những thói quen mà cả 2 ai cũng biết, chả cần nói, cũng ko biết ngươi kia để ý thói quen của mình từ khi nào nữa. Ngồi xuống đối diện cô ấy thay vì ngồi cạnh như mọi lần. Mình từ từ nhấp 1 ngụm cf, sao đắng thế này, có lẽ nào cô ấy bỏ ít đường, châm diếu thuốc, rít 1 hơi, quay sang nhìn cô ấy, cô ấy vẫn ngồi im, chỉ nhìn mình, đối mắt hoe hoe đỏ, khuôn mặt hốc hác, quả thực là xót xa, khi thấy cô ấy như vậy. Mình mở lời trước

– Em nói đi, anh sẽ ngồi nghe

– Em xin lỗi anh… Em muốn găp anh để.. thực sự thì em yêu anh… chính xác hôm nay em đến đây để cầu xin anh cho em thêm 1 lần thôi, 1 cơ hội thôi, dù là nhỏ nhất em cũng sẽ cố gắng.

Cô ấy nói và bật khóc, rồi cúi mặt nói tiếp

– Những việc em đã làm với anh, em sẽ chẳng có mặt mũi nào mà gặp anh, cầu xin sự tha thứ hay thương hại từ anh, nhưng em ko cần danh dự hay bất cứ thứ gì nữa, em cần anh. Anh cho em là loại con gái đĩ, loại cave hay gì cũng đc, em đã nói rồi, dù chỉ còn 1 chút cơ hội thôi, em sẽ làm, anh ko chấp nhận em, xỉ vả, nhục mạ cũng đc. Bây giờ em cũng đã ko còn là gì của anh nữa, nên em sẽ thử nếu anh ko tha thứ gì kết quả cũng ko thay đổi gì.

Nghe cô ấy nói những câu này, thực sự lòng mình cồn cào, khó chịu, mặt nóng bừng bừng, châm điếu thuốc khác, rít 1 hơi dài rồi nói

– Khi anh chia tay với em, nghĩa là chúng ta là người xa lạ, với anh em cũng như những cô gái xa lạ ngoài kia thôi, và cơ hội để đến với 1 người đàn ông như anh và những thằng đàn ông khác là chia đều cho mọi người con gái. Em rõ tính anh nhất, cơ hội luôn có, nhưng anh sẽ ko cho ai cơ hội nếu chỉ ngồi và nói, khóc lóc van xin cả, anh cần thấy hành động, việc làm, nó trực quan cụ thể và ít nhất là anh ko dễ bị lừa

Khi quyết định nói truyện với cô ấy mình đã có chuẩn bị, chia tay cô ấy nhưng sẽ hạn chế khủng hoảng cho cô ấy ở mức thấp nhất, và khi gặp nhau cô ấy lại nói thế, vậy nên đành làm thế, cơ hội hay ko ko biết, thành công hay thất bại cũng ko quan trọng, ít nhất là mình nói thế cũng giúp cô ấy tích cực hơn 1 chút

– Em sẽ chuyển chỗ làm, em sẽ ….. Cô ấy chưa kịp nói thì mình ngắt lời

– Em ko cần phải kể ra mọi thứ em sẽ làm đâu, bởi liệu em có làm đc tất cả mọi việc, hãy làm những gì em thích, em muốn, nếu em cho là đúng, đừng gò ép bản thân phải làm việc này việc kia bởi em có thể em sẽ bỏ cuộc đấy. Em sẽ hành động nhưng còn anh nữa, có thể 1 năm, 2 năm hoặc sẽ chẳng bao giờ, thậm chí sang năm anh có thể lấy vợ và có con. Tính anh ko thích hứa hẹn hay trêu đùa với tình cảm của người khác, thế nên anh sẽ nói luôn cho em biết.

Đừng vội vàng quá, hãy suy nghĩ cẩn thận và chắc chắn vì có thể cơ hội sẽ ko đến với em, và việc em cô gắng sẽ là vô ích, trong thời gian đó em có thể bỏ qua rất nhiều cơ hội của những người khác đến với em. Em và anh cũng ko còn trẻ nữa thế nên đừng làm việc mà ko suy nghĩ để rồi lúc nhìn lại sẽ hối hận

Cô ấy cũng đã ngừng khóc, chỉ xụt xịt, rồi nói

– Em biết, em học anh đấy. Tính anh cũng thế mà, bất cần, phá cách, và đôi khi mạo hiểm làm 1 vài việc điên rồ mà ko cần biết kết quả

Nói câu này cô ấy cười nhẹ, thực sự nhìn thấy nụ cười ấy sau mấy ngày hôm nay cô ấy chỉ khóc lóc, mình cũng vơi đi nặng nề trong lòng 1 nửa, nhẹ nhõm, ít ra là thấy dễ chịu hơn. Phù !!! Rồi mình nói tiếp

– Có lẽ ko nên nhắc lại nhưng anh muốn hỏi em 1 câu và em cần phải cho anh câu trả lời

Và mình ngồi nghe cô ấy kể truyện, chỉ ngồi nghe nghe và nghe, đoạn này mình xin phép ko kể vì nó dài và mình sẽ tóm tắt lại nội dung cho các bạn

Cố ấy nói, cô ấy yêu mình là mối tình đầu tiên của cô ấy, cô ấy đc yêu, hạnh phúc và luôn tự hào với bạn bè, trong 4 năm đó, mặc dù có 1 khoảng thời gian yêu nhưng cô ấy luôn yêu mình, có rất nhiều kẻ theo đuổi cô ấy, và những kẻ đó đều bị bật ko nhanh thì chậm ra vì mình luôn là người biết cách xử lý mọi việc, biết cách yêu và hàn gắn cảm xúc cho cả 2, cô ấy khi yêu mình còn quá non nớt, tất cả đều đc mình dẫn dắt, chủ động trong mọi truyện, đôi khi có cảm giác hơi sợ nhưng lâu dần thì ko còn nữa và thay vào đó là tình yêu cùng với niềm tin vào mình, nhưng tâm lý của con gái, đc nhiều người theo đuổi bao giờ chả thích, nhất là khi bạn bè cô ấy xung quanh luôn kể về anh này anh nọ, rất nhiều anh, những anh chàng đó coi các cô bạn là trung tâm và có thể cho những anh chàng đó leo cây nếu thích, và cô ấy muốn thử cảm giác ấy giống như những cô bạn đó.

Đó cũng chính là thời điểm cách đây 3 tháng khi 2 nhà dặm ngõ, bàn chuyện 2 đứa, kể từ khi đó mình đã chủ quan, ko còn quan tâm đến viêc phải đánh bật các vệ tinh ủa cô ấy nữa, mình đã đặt toàn bộ lòng tin vào 1 tình yêu an toàn, cũng là lúc thằng S kia cho cô ấy trở thành trung tâm, chiều chuộng cô ấy như người yêu thủa mới yêu, và cô ấy muốn thử cảm giác đó, cô ấy sợ mình biết, nhưng vẫn thử và ko biết rằng mọi truyện đi quá tầm kiểm soát lúc nào ko hay, rồi cho đến khi mình biết

Qua câu truyện này mình có đôi lời muốn nói với các bạn đang, sẽ và sắp yêu: Hãy cẩn thận, giữ cô ấy bên mình, đừng quá cung phụng cô ấy, làm osin cho con gái khi chưa là gì của nhau (nếu bạn ko phải nông dân), biết khen, biết chê con gái, con gái sẽ cảm thấy mình cần phải phấn đầu, cần phải làm gì đó để xứng với bạn, nếu chỉ khen mà ko chê, sẵn sàng làm bất cứ thứ gì vì con gái thì bạn đánh mất giá trị của mình trong mắt con gái họ sẽ nghĩ: “thằng này làm thế cũng chỉ để lấy lòng mình mà thôi”. Đó là lý do tại sao mấy thằng đểu thích thì nó làm mà ko thích thì thôi thì luôn đc con gái theo, còn các bạn chân thành lại ko có con gái yêu.

Đây chính là cách mình giữ cô ấy trong 4 năm thế mà 1 lúc ko cẩn thận đã đi xa quá, đúng là “khi cực thịnh cũng là lúc  khởi suy”

Không phải mình bảo các bạn ngoan quá nhưng: “Nam bất vô lại, nữ bất ái” thế nên ai có lành quá ngoan quá thì nên hư 1 chút sẽ hay hơn
Gửi tới các bạn trẻ đang kêu ka FA: Mình ko có ý dạy đời hay bảo các bạn phải thế này thế nọ, đừng lo, chúng nó yêu kệ chúng nó, hãy tự làm cho mình hoàn thiện hơn, hay nói cách khác là đắp vào bản thân mình thì con gái nó tự khác sẽ theo bạn, 1 công việc tốt, 1 thân hình đẹp, biết đàn hát, có nhiều tài lẻ, ăn nói lưu loát, năng động thay vì tối ngày ngồi cắm đầu vào cái máy tính, thì mình dám chắc rằng bạn tha hồ lựa chọn các cô gái cho chính bạn, 

Đừng lấy con gái, hay số lần lên giường với con gái làm mục tiêu theo đuổi, mình biết 1 số bạn căm thù ghét con gái bởi từng bị phản bội, nhưng hãy tôn trọng con gái như bạn tôn trọng mẹ bạn, chị bạn, em bạn thì sẽ có những cô gái như họ, và khi đó họ là phần thưởng cho bạn

Mình có đọc qua 1 threat về 1 bạn tâm sự đang là con số 0 khi làm việc ở vtc và 1 số chỗ bị đuổi việc, người mình để ý thì bị người khác cướp mất, bạn đừng buồn, mỗi người 1 số, có khi bây giờ bạn khổ nhưng đó chính là lợi thế cho bạn sau này, tự tin lên, đừng ủ rủ, cuộc sống dạy cho mỉn rằng, đem 1 bộ mặt ủ rủ, buồn chán chỉ làm cho người khác từ chối cơ hội dành cho bạn mà thôi, nó là đồng tiền chính đáng thì cứ làm, dù vất vả cũng đc, ko ai giàu 3 họ, ko ai khó 3 đời mà

Mình xin kể câu truyện lúc mới ra trg và đi làm của mình: 1 thằng sinh viên BK mới ra trường với tấm bằng trung bình và 2 bàn tay trắng, khi bảo bố mẹ vào Miền nam lập nghiệp thì sẽ ra sao rồi chứ, rất buồn nhưng mẹ dấm dúi cho mấy trăm nghìn (ở thời điểm đó là khá lớn), lên xe đò vô miền nam, ko người thân o bạn bè nên thời gian đầu đành làm việc với chức vụ 1 thằng sửa máy móc ở 1 xưởng cơ khí nhỏ, làm đến chiều tối lại chạy xe đạp từ Bình Thạnh sang Tân Phú đi làm rửa xe ôtô vì ở đó đc ăn cơm tối miễn phí, rồi đêm lại chạy về Bình Thạnh để sáng mai đi làm, 

Rửa xe ôtô ở Tân Phú 1 năm thì mình có quen đc 1 ông hay đến rửa xe và khi biết mình tốt nghiệp BK, ông bảo mình nộp hồ sơ vào công ty của ông, rồi có gì tính sau. Vui mừng vì đc làm việc tuy ko đúng ngành mình học, nhưng thôi kệ, vì miếng cơm manh áo. 

Trong thời gian thử việc 3 tháng mình đã làm cho ít nhất là 1/3 cái công ty của ông ấy choáng, mình làm việc điên cuồng, ko có gì là mình ko nhúng tay vào, chạy sô công việc bằng xe bus và trên chiếc xe đạp mà mình sơn và sửa lại lúc làm ở cái xưởng cơ khí kia (mới cách đây 4,5 năm thôi mà sao thấy ngày đấy mình lúa thế), về sau thì có xe công ty đưa đón và đi taxi, thêm với tính cách hiền lành và ăn nói khá tốt nên mọi người đều rất quý, cũng có những kẻ đâm bị thóc chọc bị gạo nhưng mình kệ, bơ đi mà sống. 

Khả năng nhậu nhẹt thì 5 năm ở cái đất BK đã rèn luyện cho mình 1 tửu lượng ko thua kém dân bợm nhậu chính hiệu, nên đi cùng sếp, uống hộ sếp mình ko ngán, bao giờ cũng đưa sếp về, mình thì ko hề gái gú vì thời gian đó mình đang yêu T và công việc làm cho mình ko cò thời gian về gái gú cộng thêm cái áp lực dành 1 thằng bán xứ đi lập nghiệp nữa, nên bà vợ sếp rất tin tưởng còn sắm cho mình 1 cái điên thoại để liên lạc và làm tay trong cho bả ý, cũng vì thế mà ông sếp luôn quý mình. Bây giờ thi thoảng ghe qua trường, thấy các em bây giờ hiền quá, lại nhiều con gái nữa, ko hoang dại và bụi bặm (chính xác hơn là bẩn) như xưa 

Viết dài quá rồi.
Ngồi 1 mình luôn có cái hay của riêng nó, nhẹ nhàng và bớt căng thẳng
Hà nội 26/07/2013. 
Một buổi sáng đẹp trời bên bờ hồ

Hiểu về HTTPS trong 5 phút

Mấy hôm nay có dịp ôn lại về HTTPS, mặc dù đã có nhiều tài liệu nói về giao thức này nhưng hầu hết chúng thường được mô tả bằng ngôn ngữ kĩ thuật tương đối phức tạp, vì vậy sẵn tiện mình viết một bản tóm tắt nhỏ về giao thức bảo mật này theo cách đơn giản nhất có thể.

Về cơ bản, HTTP hay HTTPS là những phương thức giao tiếp giữa 2 bên (giữa client và server), không cần đi quá sâu vào chi tiết, hãy hình dung việc giao tiếp này là một cuộc trao đổi thư từ giữa 2 người. Lấy ví dụ với chàng Romeo và người yêu là nàng Juliet. Như vậy, quá trình trao đổi gồm 3 đối tượng chính: 2 người cần trao đổi thư từ (Romeo & Juliet) + người giao thư (kênh kết nối).

Bắt đầu với cách đơn giản nhất

Nếu Romeo muốn gửi thư cho Juliet, rất đơn giản, anh ta chỉ cần viết nội dung vào một lá thư, sau đó nhờ người đưa thư giao cho Juliet. Khi Juliet nhận được thư, nàng đọc, và như vậy là quá trình liên lạc hoàn tất trọn vẹn.

(Trường hợp gửi thư thông thường – HTTP (Đơn giản nhưng dễ bị tấn công man-in-the-midle) )

Nhưng, sẽ thế nào nếu ông Capulet (cha của Juliet) chen ngang vào đoạn giữa – trước khi người đưa thư trao thư cho Juliet (Kiểu tấn công man-in-the-middle). Với HTTP, nội dung thư không được mã hoá, ông Capulet có thể sửa nội dung thư trước khi trao lại cho con gái mình, Juliet sẽ không thể biết được lá thư mình nhận đã bị sửa hay chưa. Như vậy, quá trình trao đổi có thể xuất hiện sai lệch không thể kiểm tra được (điều này thực sự nguy hiểm).

Đây chính là vấn đề mà HTTPS muốn giải quyết.

Romeo và Juliet phải mã hoá thông tin

Romeo và Juliet đã nghĩ ra 1 cách để che giấu đi thông điệp mà 2 người trao đổi, họ sẽ mã hoá lá thư trước khi gửi. Cách mã hoá như sau: dịch bảng chữ cái về phía sau 1 kí tự (mã hoá tức là biến đổi thông tin theo 1 cách nào đó để nó khác đi so với ban đầu). Như vậy, nếu thông điệp là “I love you”, thì Romeo sẽ viết thành “J mpwf zpv”.

Chỉ có Romeo và Juliet biết được cách để giải mã, và như vậy, ông Capulet sẽ bất lực khi muốn thay đổi nội dung lá thư, bất cứ sự thay đổi nào cũng sẽ bị cả 2 phát hiện. Với quy ước đã định (ta gọi cách giải mã là khoá – key), nàng Juliet chỉ cần dịch chuyển bảng chữ cái đi là sẽ giải mã ra được thông điệp ban đầu, là “I love you”.

Quá trình mã hoá này được gọi là “mã hoá đối xứng” (symmetric key cryptography), tức là: khi biết được cách mã hoá, sẽ biết được cách giải mã.

Vấn đề đã được giải quyết chưa? Vẫn chưa …

Làm thế nào để Romeo và Juliet thống nhất được khoá (key)?

Cách mã hoá đối xứng tương đối an toàn nếu khoá chỉ được giữ bởi 2 bên nhận và gửi. Vấn đề là: Bởi vì Romeo và Juliet không thể gặp trực tiếp nhau, làm sao họ nói cho nhau biết được cách họ sẽ mã hoá là gì (khoá là gì)?

Bởi vì vấn đề này, ta sẽ phải thay đổi hoàn toàn cách để gửi và nhận thư giữa 2 người: dùng chiếc hộp bí mật.

Chiếc hộp bí mật

Romeo và Juliet quyết định sẽ thực hiện việc trao đổi theo một cách hoàn toàn mới. Khi mà Romeo muốn gửi thư cho Juliet, họ sẽ thực hiện theo quy trình sau:

  • Romeo nói với người đưa thư rằng anh muốn gửi thư cho Juliet, và người đưa thư sẽ nói với Juliet điều đó (Lúc này, thông điệp riêng tư vẫn chưa được gửi). Tức là phát đi tín hiệu muốn gửi thư.
  • Juliet đưa cho người đưa thư một chiếc hộp với tình trạng mở khoá, chỉ có nàng nắm giữ chiếc khoá mở.
  • Người đưa thư quay trở lại với Romeo, và Romeo sẽ bỏ lá thư cần gửi vào chiếc hộp và khoá lại. Chiếc hộp với tình trạng khoá sẽ được người đưa thư chuyển ngược lại cho Juliet.
  • Cuối cùng, Juliet nhận được chiếc hộp, nàng dùng khoá riêng mở ra và đọc nội dung mà Romeo đã gửi.

Bằng cách này, ông Capulet (vai trò man-in-the-midle) dù có lấy được chiếc hộp cũng không thể mở ra để đọc nội dung lá thư bên trong. Juliet lúc này có thể yên tâm rằng nội dung thư trao đổi được bảo mật và an toàn.

(Kĩ thuật trao đổi có mã hoá bất đối xứng)

Một cách kĩ thuật, ta có thể gọi cách mã hoá này là “mã hoá bất đối xứng” (asymetric key cryptography), tức là người thực hiện mã hoá chưa chắc đã giải mã ngược lại được (Romeo khoá hộp lại được nhưng không thể mở ra lại, vì Juliet là người duy nhất giữ khoá). Có thể hình dung nôm na rằng, chiếc hộp là public key, và chìa khoá là private key.

Làm thế nào biết được chiếc hộp là của Juliet mà không phải giả mạo?

Nếu bạn tinh ý, thì có thể nhận ra rằng, cách giao tiếp ở trên vẫn tồn tại 1 vấn đề còn khúc mắc: bởi vì 2 người không có cơ hội gặp trực tiếp, làm thế nào Romeo biết được chiếc hộp kia là của Juliet mà không phải của một man-in-the-midle nào khác?

Câu trả lời là: Juliet sẽ tạo 1 chữ kí (signature) ở chiếc hộp, và Romeo sẽ kiểm tra xem chiếc hộp gửi đến có tồn tại chữ kí của nàng Juliet hay không. Lại một câu hỏi nữa: Làm thế nào biết được chữ kí là thật?

Thay đổi cách làm ở trên 1 chút, ta sẽ có cách giải quyết: thay vì Juliet sẽ kí tên, thì một người khác (có uy tín cao) sẽ kí tên xác nhận rằng chiếc hộp đúng là của Juliet kí tên. Người thực hiện kí tên thay mặt này phải là một người có uy tín cao và được mọi người công nhận, ta giả sử rằng trong trường hợp Romeo và Juliet, người cấp xác thực cho chiếc hộp chính là Cha sở nhà thờ (nếu bạn có đọc qua truyện Romeo & Juliet thì sẽ biết có một vị cha sở có uy tín trong vùng đã làm chứng cho 2 người kết hôn).

Khi cấp chứng chỉ xác thực, cha sở sẽ kiểm tra chiếc hộp đúng là của Juliet, và sẽ đánh dấu xác thực vào chiếc hộp này. Khi đó Romeo và Juliet sẽ biết chính xác rằng chiếc hộp là bí mật và hợp lệ giữa 2 người mà không cần phải gặp nhau trực tiếp để xác nhận.

(Mô hình xác thực khoá trong thực tế)

Trong thực tế kĩ thuật, người cha sở trong ví dụ này chính là các “đơn vị cung cấp chứng thực số” (certification authority), các chữ kí xác thực chính là các “chứng chỉ số” (certificate) mà nhà cung cấp dịch vụ xác thực cấp cho website của bạn. Bởi vì tính chất định danh, mỗi “chứng chỉ số” là riêng biệt và duy nhất.

Romeo trong thực tế chính là trình duyệt web của bạn, và Juliet chính là các trang web mà bạn truy cập đến. Khi bạn thực hiện truy vấn tới trang web nào đó, server sẽ trả về thông tin mã hoá và chứng chỉ số cho browser. Các browser có hỗ trợ HTTPS sẽ tự động kiểm chứng các certificate này.

Đến đây thì hẳn là bạn đã hình dung được tổng quan về HTTPS là gì rồi.

Chiếc hộp và vấn đề về hiệu suất

Nói thêm một chút, mặc dù việc gửi nhận các nội dung thư từ thông qua chiếc hộp bí mật đã giải quyết được vấn đề về độ bảo mật, nhưng cách này có vẻ như đã tăng số bước lên nhiều lần so với thông thường, có cách nào để hạn chế việc dùng hộp mà thông tin vẫn được đảm bảo hay không?

Câu trả lời là: Kết hợp cả 2 kiểu mã hoá đối xứng (gửi thông điệp trực tiếp đã được mã hoá) và bất đối xứng (gửi thông điệp thông qua chiếc hộp bí mật):

Mã hoá bất đối xứng được thực thi lần đầu tiên khi ta tạo kết nối giữa client và server, lần “giao tiếp” đầu tiên này 2 bên sẽ thống nhất cách thức của mã hoá đối xứng được dùng cho các lần giao tiếp tiếp theo.
Khi đã thống nhất cách mã hoá đối xứng rồi, các lần giao tiếp sau chỉ cần sử dụng cách mã hoá này mà không cần dùng thêm chiếc hộp bí mật nữa.

Hết rồi, tổng quan về HTTPS chỉ có bấy nhiêu đó thôi. Chúc vui!

Thế nào là hạnh phúc.

Thế nào là hạnh phúc . Có thể làm một con người bình thường , sống qua hết một đời có lẽ đó là hạnh phúc .
————
Người có IQ cao nhất thế giới: Bất hạnh đến từ hai chữ ‘thần đồng’

William James Sidis sinh ngày 1/4/1898 trong gia đình di cư người Ukraine gốc Do Thái. Ông nổi danh là “thần đồng”, sở hữu IQ khoảng 250-300 và được ghi nhận là người thông minh nhất thế giới.

Thần đồng William James Sidis chịu sự giáo dục hà khắc từ nhỏ bởi bố mẹ ông không chỉ cần đứa con thông minh. Họ muốn đào tạo một thiên tài. Bà Sarah dành tất cả tiền tiết kiệm của gia đình để mua sách báo, trang thiết bị có thể khuyến khích tinh thần học hỏi cho con trai.

Ông Boris áp dụng những liệu pháp tâm lý học với con trai. Nhờ đó, William học chữ chỉ trong vòng vài tháng.

Theo Today Foundout, dưới tham vọng cũng như nỗ lực của cha mẹ, William James Sidis sử dụng ngôn từ thành thạo khi mới 6 tháng tuổi và biết tự dùng thìa để ăn cơm khi 8 tháng tuổi.

Ông bà Sidis rất tự hào về con trai, cũng như phương pháp giáo dục sớm mà vợ chồng ông áp dụng. Họ liên tục xuất bản những tài liệu học thuật cho thấy thành công của hai người trong nuôi dạy con.

Dưới tham vọng của ông bà Sidis, William đương nhiên không thể trải qua những năm đầu đời như bao đứa trẻ khác. Ông thậm chí không có tuổi thơ.

18 tháng tuổi, William bắt đầu đọc báo New York Times. Ngoài ra, ông phải học 7 thứ tiếng, bao gồm tiếng Pháp, Đức, Latin, tiếng Do Thái, Hy Lạp, Nga và Vendergood – ngôn ngữ do chính ông sáng tạo.

7 tuổi, William học chương trình trung học phổ thông. Hai năm sau, ông trúng tuyển ĐH Harvard nhưng không được nhập học do trường đánh giá cậu sinh viên này “chưa trưởng thành về mặt tâm lý”.

Ông bà Sidis tiếp tục gây sức ép với lãnh đạo ĐH Harvard. Năm 11 tuổi, William trở thành sinh viên của ngôi trường danh giá hàng đầu thế giới trong khi bạn cùng tuổi vẫn trải qua tuổi thơ vui vẻ, vô tư.

William James Sidis một lần nữa trở thành tâm điểm truyền thông. Tháng 1/1910, cậu sinh viên đưa ra bài phát biểu công khai đầu tiên trong đời và nó nhanh chóng xuất hiện trên báo chí cả nước.

Sau đó, phóng viên theo chân William khắp nơi trong khuôn viên trường. Ông gần như không có thời gian, không gian riêng tư. 5 năm sau, ông tốt nghiệp hạng ưu, chấm dứt chuỗi ngày không mấy vui vẻ tại Harvard.

Amy Wallace, người viết tiểu sử của William James Sidis, cho biết trong thời gian học tập tại đây, người được gọi là thần đồng thường xuyên bị cô lập và làm nhục vì sự thật thà của mình.

Sau lễ tốt nghiệp, ông phát biểu với báo chí: “Tôi muốn sống một cuộc sống hoàn hảo. Cách duy nhất để thực hiện điều đó là sống tách biệt với người khác. Tôi luôn ghét đám đông”.

————–
Việc rời Harvard không đem lại cho William cuộc sống vui vẻ hơn. Ông tiếp tục sa vào những rắc rối vì những kỳ vọng ngày càng lớn từ phía cha mẹ và cộng đồng.

Năm 1919, ông bị bắt vì dẫn đầu cuộc biểu tình chống chiến tranh. Trong tù, ông gặp người phụ nữ duy nhất ông yêu – bà Martha Foley. Mối quan hệ này không kéo dài, chủ yếu do suy nghĩ lệch lạc mà cha mẹ ông đã tiêm nhiễm, rằng tình yêu, nghệ thuật, tình dục là yếu tố tạo ra “cuộc đời khiếm khuyết”.

Lẽ ra, William bị kết án 18 tháng tù. Nhờ sức ảnh hưởng của ông bà Sidis, ông được thả. Thấy con chệch khỏi con đường trở thành thiên tài, cha mẹ ông tăng cường kiểm soát, theo dõi và cấm đoán ông giao lưu kết bạn với những người lạ. Cha ông có quyết định sai lầm khi đưa ông vào viện điều trị tâm thần hơn một năm.

Chán nản với cuộc sống gò bó do cha mẹ áp đặt, William liên tục chuyển chỗ ở, công việc và đổi tên để tránh sự theo dõi từ truyền thông.

Trong thời gian này, ông viết hàng chục cuốn sách dưới nhiều bút danh, bao gồm về lịch sử nước Mỹ và sở thích sưu tầm vé xe. Ngoài ra, William xuất bản sách về vũ trụ học, đưa ra dự đoán về hố đen. Cuốn sách không được giới học giả đánh giá cao.

Cuộc sống tách biệt giúp William cảm thấy tốt hơn. Ông thích cảm giác cô độc và không hề liên lạc với gia đình hay bất cứ ai thực sự quan tâm ông.

Năm 1924, sự bình yên hiếm hoi ấy bị phá vỡ khi báo chí lần ra tung tích thần đồng ngày nào. Họ đưa loạt bài về công việc tầm thường cùng cảnh sống khốn khổ của người có IQ cao nhất thế giới.

Điều này khiến William xấu hổ và trầm cảm, nó đẩy ông lún dần vào cuộc đời tối tăm. Báo chí tiếp tục khai thác đề tài được dư luận quan tâm này.

Năm 1937, tờ New Yorker đăng bài April Fool, miêu tả quá trình William rơi từ đỉnh cao danh vọng tới cuộc sống khốn khổ, bị nhục mạ. Sau đó, gia đình Sidis khởi kiện tờ báo. Vụ kiện được giải quyết vào 7 năm sau nhưng những tổn thương nó gây ra cho thần đồng đã không thể vãn hồi.

Tháng 7/1944, William đột quỵ trong căn hộ nhỏ thuê ở Boston. Ông không bao giờ tỉnh lại nữa. Người đàn ông sở hữu IQ cao nhất thế giới qua đời ở tuổi 46, chỉ có bức ảnh bà Martha Foley được đặt trong ví làm bạn với ông trong những ngày cuối đời.

[JAVA] Hiểu khái niệm Immutable như thế nào cho đúng?

Khái niệm về immutable luôn chiếm một phần quan trọng trong nhiều ngôn ngữ lập trình ngày nay, Java không phải là ngoại lệ. Java 8 ra đời kèm theo functional programming và java.time.API khiến immutable càng trở nên quan trọng hơn.

#1 Immutable là gì?

Nếu định nghĩa một cách ngắn gọn, ta có immutable là một đặc tính của một đối tượng nào đó trong lập trình.

Ví dụ cụ thể với class. Một class được xếp loại là immutable class nếu các bản thể (instance) mà nó tạo ra không thể thay đổi được. Cụ thể, thông tin lưu trong object đó được gán ngay trong quá trình khởi tạo object, kể từ đó, ta không thể thay đổi thông tin cho object này. Nếu ta cần object đó mang giá trị khác, ta buộc phải làm một object mới.

#2 Ưu điểm của tính immutable

Nếu bạn chưa từng làm việc hoặc chưa nghe đến immutable, có lẽ bạn sẽ nghĩ nó là tính năng thừa. Tuy nhiên immutable mang đến rất nhiều lơị ích cho hệ thống. Cụ thể như sau:

Thứ nhất: hỗ trợ xây dựng hệ thống ổn định. Ưu điểm này đến từ chính đặc tính vốn có của Immutable là không thể thay đổi giá trị sau khi khởi tạo .

Lấy ví dụ về class Bank, đại diện cho một ngân hàng. Ta xét hoàn cảnh sau: khi cuộc khủng hoảng tài chính trôi qua, nhà băng không cho phép tài khoản người dùng có thẻ có giá trị số dư là âm. Để làm được điều này, người ta sẽ thêm một method kiểm tra và các luật sao cho khi có tài khoản bị âm, nó sẽ bắn ra IllegalArgumentException. Kiểu luật này gọi là invariant – luật bất biến.

public class BankAccount{

[...]

    private void validate(long balance) {

        if (balance < 0) {

            throw new IllegalArgumentException("balance must not be negative:"+ balance);

        }

    }

}

Trong một class thông thường, hàm validedate() có thể được gọi bất kì thời điểm nào nếu có xảy ra thay đổi số dư tài khoản. Tuy nhiên với immutable class, ta chỉ cần gọi validate() một lần duy nhất trong constructor.

public BankAccount(long balance) {

    validate(balance);

    this.balance = balance;

}

Không thể thay đổi giá trị của Immutable object. Điều này đúng với một object kể từ lúc nó được khởi tạo cho đến khi bị “dọn dẹp” bởi Garbage Collector. Mỗi khi số dư tài khoản bị thay đổi, một object mới sẽ được tạo ra. Vì thế ta chỉ cần kiểm tra giá trị tài khoản tại thời điểm object tương ứng được khởi tạo. Đồng nghĩa với gọi validate() một lần duy nhất trong constructor. Từ đó, ta có thể tập trung các luật bất biến trong ứng dụng mà ta đang xây dựng và đảm bảo tính nhất quán cho các object trong suốt vòng đời của chúng.

Thứ hai, tính immutable có thể được áp dụng cho các hệ thống đặc thù yêu cầu “khả năng chịu lỗi” (fault-tolerance).

Hãy tưởng tượng bạn cần rút tiền từ ngân hàng. Tại thời điểm mà tài khoản của bạn bị trừ đi số tiền mà ATM sắp nhả ra thì xuất hiện lỗi. Như vậy với normal class, bạn đã mất tiền. Nhưng với immutable class, lỗi sẽ được bắn ra kèm theo đó là tài khoản của bạn không hề thay đổi trừ khi bạn đã nhận được tiền.

public ImmutableAccount withdraw(long amount) {

    long newBalance = newBalance(amount);

    return new ImmutableAccount(newBalance);

}

private long newBalance(long amount) {

    // exception during balance calculation

}

Immutable object không bao giờ rơi vào trạng thái phi nhất quán (inconsistence), ngay cả khi xảy ra exception. Điều này góp phần tăng tính ổn định cho hệ thống.

Thứ ba, tính immutable có thể được chia sẻ giữa các object.

Ví dụ: ta có một object kiểu Account, trong object Account, có thuộc tính kiểu Holder và Balance (tất nhiên chúng cũng là object).

Khi ta copy object Account, ta có thể để 2 bản thể đó sử dụng chung thuộc tính Balance. Và nếu ta thay đổi Balance ở một object Account, nó sẽ không ảnh hưởng tới object Account còn lại. Object còn lại tạo một bản thể (vẫn giữ tính Immutable) của class Account và 2 object cũ – mới này không hề liên quan đến nhau nữa.

Một Immutable object không cần copy constructor khi copy object. Immutable object có thể được chia sẻ tự do khi sử dụng thuật toán lock-free trong môi trường multithread.

Cuối cùng, immutable object là một lựa chọn sáng giá khi sử dụng làm key của Map hoặc làm element của Set.

#3 Nhược điểm của tính Immutable

Nhược điểm lớn nhất của immutable là nó có nguy cơ tác động tiêu cực lên performance. Ta sẽ cần khởi tạo nhiều immutable object so với mutable object, và cứ mỗi object tạo ra thì tài nguyên dự trữ  của hệ thống lại vơi đi một chút.

Vì vậy, để tránh vấn đề đó ảnh hưởng tới quá trình xây dựng ứng dụng, ta cần khảo sát kỹ các yếu tố như: loại thiết bị triển khai ứng dụng, đặc điểm phần cứng của thiết bị đó, kích thước của ứng dụng… Kết quả khảo sát tổng hợp từ các yếu tố này sẽ giúp bạn có quyết định đúng đắn về việc có nên sử dụng immutable object hay không.

#4 Áp dụng

Bây giờ tôi sẽ đưa ra một ví dụ để các bạn thấy tầm quan trọng của immutable trong thực tế và cách tạo ra immutable class.

    public String name;

    public Destination destination;

    public Spaceship(String name) {

        this.name = name;

        this.destination = Destination.NONE;

    }

    public Spaceship(String name, Destination destination) {

        this.name = name;

        this.destination = destination;

    }

    public Destination currentDestination() {

        return destination;

    }

    public Spaceship exploreGalaxy() {

        destination = Destination.OUTER_SPACE;

    }

[…]

}

Để hô biến một class từ Mutable thành Immutable, ta cần thực hienj 4 bước:

  1. Đặt tất cả các trường (field) thành private và final
  2. Loại bỏ các method làm thay đổi state của object
  3. Đảm bảo class hiện tại không thể extend được
  4. Đảm bảo truy cập độc quyền tới mutable field (các trường có tính chất mutable)

Lý thuyết là vậy, chúng ta hãy áp dụng nó vào ví dụ trên, từng bước một.

Bước 1:

Thêm modifier là private giúp các trường không thể bị thay đổi bởi các class nằm ngoài class chứa nó.

Thêm final nhằm mục đích ngăn các tác nhân bên ngoài gán giá trị cho các trường trong class này thông qua biến tham chiếu (nếu có ai đó cố ý làm thế, tất nhiên sẽ xảy ra lỗi)

Bước 2:

Tiếp theo, ta cần “bảo vệ” các object state khỏi sự thay đổi.

public ImmutableSpaceship exploreGalaxy() {

    return new ImmutableSpaceship(name, Destination.OUTER_SPACE);

}

Bất kỳ trường nào mà ta không thay đổi thì giá trị của chúng đều có thể được copy từ object hiện thời. Nếu có thay đổi, object mới sẽ được khởi tạo.

Bước 3:

Để ngăn cản sự thay đổi của class, ta không được phép cho các class khác extend class hiện thời. Lý do: các class con có thể Override các method ở class hiện thời và các method được Override đó hoàn toàn có thể thay đổi object tạo bởi class hiện thời, ví dụ luôn:

public class EvilSpaceship extends Spaceship {

    [...]

    @Override

    public EvilSpaceship exploreGalaxy() {

        this.destination = Destination.OUTER_SPACE;

        return this;

    }

}

Để tránh điều này xảy ra, ta thêm từ khóa final vào phần khai báo class:

public final class Spaceship

Bước 4:

Bước cuối cùng này có vai trò ngăn chặn các truy cập trực tiếp tới mutable field. Cụ thể, chúng ta không nên return các tham chiếu trực tiếp tới Destination object. Thay vào đó, cần tạo một bản copy của mutable object và làm việc với nó.

Với ví dụ trên, ta cần check sự hiện diện của các tham chiếu tới Destination tại các public method và constructor…

Ở method curentDestination, ra thấy object Destination được return – đây chính là vấn đề. Thay vì return tham chiếu thật, hãy tạo bản copy của Destination object và trả về reference trỏ đến bản copy.

public Destination currentDestination() {

    return new Destination(destination);

}
private ImmutableSpaceship(String name, Destination destination) {

    this.name = name;

    this.destination = new Destination(destination);

}

Sau 4 bước, ta thu được sản phẩm:

public final class ImmutableSpaceship {

    private final String name;

    private final Destination destination;

    public ImmutableSpaceship(String name) {

        this.name = name;

        this.destination = new Destination("NONE");

    }

    private ImmutableSpaceship(String name, Destination destination) {

        this.name = name;

        this.destination = new Destination(destination);

    }

    public Destination currentDestination() {

        return new Destination(destination);

    }

    public ImmutableSpaceship newDestination(Destination newDestination) {

        return new ImmutableSpaceship(this.name, newDestination);

    }

[…]

}

Nắm rõ JAVA LAMBDA EXPRESSION cho người mới bắt đầu

Lời nói đầu

Java Lambda Expression (biểu thức Lambda) là một tính năng được thêm vào Java 8. Đây là một tính năng rất thú vị và nó đã góp phần thay đổi xu hướng lập trình trong Java. Đây là tính năng mà mình nghĩ là các bạn newbie nên dành thời gian để tìm hiểu và nắm bắt. Thú thật sau 1 năm làm việc, mình chẳng hề biết đến Lambda là gì. Cho tới khi mình tham gia dự án Java 8, mình bắt đầu tiếp xúc với biểu thức Lambda và nó đã làm thay đổi hoàn toàn tư duy cũng như phong cách code của mình. Trong bài viết này, mình sẽ tập trung giải thích một cách chi tiết nhất có thể để các bạn newbie có thể làm quen và sử dụng biểu thức Lambda vào code của mình. Những gì mình viết đều dựa trên những gì mình mày mò và rút ra trong quá trình làm việc nên hi vọng sẽ giúp ích cho các bạn. Không dài dòng nữa, mình xin bắt đầu ngay đây.

Functional Interface

Trước khi làm quen với Lambda thì chúng ta cần phải nắm rõ một khái niệm rất quan trọng là Functional Interface. Functional Interface là một interface (chắc chắn rồi) chỉ chứa một và chỉ một abtract method. Nên nhớ rõ đặc điểm này: một và chỉ một phương thức abtract. Do đó nó cũng có thể được gọi là Single Abstract Method (SAM – cái tên nói lên tất cả).

Ví dụ về Functional Interface:

interface Hello {
    public void sayHello(String helloMessage); 
}

Java 8 cũng giới thiệu một annotation mới là @FunctionalInterface để chúng ta đánh dấu interface đó là Functional interface. Việc thêm annotation @FunctionalInterface là không bắt buộc tuy nhiên nó là cần thiết khi khai báo một functional interface. Bởi vì việc thêm @FunctionalInterface sẽ giúp bắt lỗi ở thời điểm biên dịch nếu vô tình thêm một method trừu tượng khác nữa vào interface có đánh dấu bởi annotation này.

Một số quy tắc khai báo Functional Interface

  • Một Functional Interface hợp lệ chỉ có duy nhất một method trừu tượng.
  • Một Functional Interface có thể có các phương thức của lớp java.lang.Object
  • Phương thức default and static không phá vỡ quy tắc của Functional interface.
  • Một Functional Interface có thể kế thừa từ một Functional Interface khác chỉ khi nó không có bất kỳ phương thức trừu tượng nào
  • Các Functional Interface đã được định nghĩa trong Java 8 – Java Predefined-Functional Interfaces được đặt trong gói java.util.function
  • Tham khảo chi tiết tại đây

Vì sao chúng ra phải nắm rõ Functional Interface. Nguyên nhân rất đơn giản, một trong các ứng dụng quan trọng nhất của Lambda Expression để tạo ra thể hiện (instance) cho interface đó.

Toán tử mũi tên (->)

Java 8 giới thiệu một toán tử mới là toán tử mũi tên ->. Toán tử này được dùng trong biểu thức Lambda với mục đích chia biểu thức Lambda thành 2 phần: tham số và nội dung thực thi

Ví dụ:

(int a, int b) -> { do something };

Biểu thức Lambda là gì và tại sao phải sử dụng biểu thức Lambda

Biểu thức Lambda có thể được định nghĩa là một hàm ẩn danh (anonymous function). Vì là hàm ẩn danh nên nó có đầy đủ đặt điểm của một hàm là có các tham số (parameters) và nội dung thực thi (body). Tham số của một hàm thì có thể có hoặc không, tương tự nội dung thực thi thì có thể có kiểu trả về hoặc không có kiểu trả về. Biểu thức Lambda sẽ dựa trên danh sách tham số đầu vào và xử lý bằng những lệnh ở phần body để cho ra kết quả.

Biểu thức Lambda cung cấp cách thức implement cho method được định nghĩa ở functional interface. Bên cạnh đó biểu thức Lambda cũng cung cấp các thư viện giúp cải tiến cách thức làm việc với Collection như duyệt, filter, và truy xuất dữ liệu…

Với những đặc điểm trên, Lambda giúp giảm số dòng code. Bên cạnh đó, biểu thức Lambda còn có thể hỗ trợ thực hiện tuần tự (Sequential) và song song (Parallel) hiệu quả hơn thông qua Stream API (mình sẽ không tích hợp kiến thức liên quan đến Stream API vào bài này. Phần kiến thức về biểu thức Lambda và Steam API mình sẽ giới thiệu ở các bài viết sau)

Tham khảo thêm tại đây

Cú pháp của biểu thức Lambda

(argument-list) -> {body}

Biểu thức Lambda trong java gồm có 3 thành phần sau:

  • Argument-list: danh sách tham số, có thể không có, có một hoặc nhiều tham số.
  • Arrow-operator: toán tử mũi tiên được sử dụng để liên kết danh sách tham số và body của biểu thức.
  • Body: nội dung thực thi, là 1 khối lệnh hoặc 1 biểu thức.

Ví dụ về biểu thức Lambda

  • Không có tham số:@FunctionalInterface interface Hello { public String sayHello(); } public class LambdaExpression { public static void main(String[] args) { Hello s = () -> { return "Hello Lambda."; }; System.out.println(s.sayHello()); } }
  • Có 1 tham số:@FunctionalInterface interface Hello { public String sayHello(String name); } public class LambdaExpression { public static void main(String[] args) { Hello s = name -> "Hello, " + name; System.out.println(s.sayHello("Lambda")); } }
  • Có nhiều tham số: @FunctionalInterface interface Hello { public String sayHello(String name, String com); } public class LambdaExpression { public static void main(String[] args) { Hello s = (name, com) -> "Hello, " + name + ". Welcome to " + com; System.out.println(s.sayHello("newbie", "Lambda")); } }

Về khai báo danh sách tham số:

  • Các tham số cách nhau bởi dấu phẩyĐúng: (int a, int b, int n) -> { doSomthing(); }Sai: (int a; int b; int n) -> { doSomthing(); }
  • Danh sách tham số phải được đặt trong ngoặc tròn. Trường hợp có 1 tham số thì không bắt buộc và không cần thiết phải có dấu ngoặc trònĐúng: (int a, int b) -> { doSomthing(); }Đúng: (int a) -> { doSomthing(); }Đúng: a -> { doSomthing(); } //best way of single paramSai: int a, int b -> { doSomthing(); }
  • Không bắc buộc phải khai báo kiểu dữ liệu của tham số. Giả sử trường hợp dùng biểu thức Lambda để implement function interface thì kiểu dữ liệu của tham số sẽ được ngầm hiểu là kiểu dữ liệu đã khai báo ở abtract method. Việc loại bỏ khai báo kiểu dữ liệu tham số trong biểu thức Lambda(int a, int b) -> { doSomthing(); } hoặc có thể viết là (a, b) -> { doSomthing(); }

Về trình bày nội dung thực thi:

  • Nội dung thực thi phải được đặt trong dấu ngoặc nhọn. Trường hợp có một dòng lệnh thì không bắt buộc. Điều này tương tự với nội dung thực thi của lệnh if, for…Đúng: Foo foo = parameter -> buildString(parameter);Đúng:Foo foo = parameter -> {buildString(parameter); return true;}
  • Trường hợp nội dung thực thi gồm nhiều câu lệnh thì không nên đặt trong biểu thức Lambda. Biểu thức Lambda nên chỉ có từ 2-5 dòng lệnh để tránh sự phức tạp về trình bày cũng như mục đích sử dụng biểu thức Lambda.Foo foo = parameter -> { String result = "Something " + parameter; //many lines of code return result; }; Sẽ tốt hơn nếu được viết như sau:Foo foo = parameter -> buildString(parameter); private String buildString(String parameter) { String result = "Something " + parameter; //many lines of code return result; }

Một số ứng dụng của biểu thức Lambda

Ngoài việc được sử dụng để implement Function interface như ở các ví dụ trên thì biểu thức Lambda còn được sử dụng thường xuyên khi làm việc với Collection. Phổ biến nhất là việc áp dụng biểu thức Lambda vào vòng lặp forEach

List<String> list=new ArrayList<String>();  
//init list
list.forEach( n -> System.out.println(n) );  

Biểu thức Lambda cũng được dùng để thay thế các Anonymous inner class. Anonymous inner class: Inner class là class (non static) được viết trong một class khác (out-class). Anonymous class là Inner class nhưng không có ”class’ đặt trước tên của class. Khi thực hiện sắp xếp với Collection, chắc hẳn mọi nguời đều tiếp xúc với một Anonymous inner class là Comparator rồi nhỉ.

Trường hợp dùng Comparator

listDevs.sort(new Comparator<Developer>() {
	@Override
	public int compare(Developer o1, Developer o2) {
		return o2.getAge() - o1.getAge();
	}
});	

Trường hợp dùng Lambda

listDevs.sort((Developer o1, Developer o2)->o1.getAge()-o2.getAge());

Một số lưu ý khi sử dụng biểu thức Lambda

Biểu thức Lambda được sử dụng tốt nhất khi kết hợp với Function interface. Bạn không thể sử dụng biểu thức Lambda với một interface có nhiều hơn một abtract method. Các lưu ý khi khởi tạo một Function interface:

  • Sử dụng @FunctionalInterface Annotation
  • Hãy nghiên cứu về các Functional interfaces nằm trong gói java.util.function trước khi khởi tạo một Functional interfaces nhằm giảm thiểu những việc không cần thiết.
  • Không nên lạm dụng các method default và static trong Functional interfaces. Đặc biệt là cho các Functional interfaces kế thừa từ các Functional interfaces khác.
  • Khi sử dụng biểu thức Lambda hãy chắc chắn số lượng parameter và kiểu giá trị trả về của biểu thức Lambda phải tương ứng với phương thức duy nhất ở Functional interfaces.

Vì biểu thức Lambda là tính năng trong Java 8 nên hãy chắc chắn rằng bạn đã cài đặt Java 8 hoặc mới hơn. Biểu thức Lambda không khả dụng cho Java 7 hoặc các phiên bản sớm hơn.

Biểu thức Lambda cũng được dùng để thay thế các Anonymous inner class. Tuy nhiên, hãy tìm hiểu kỹ về sự khác biệt giữa chúng để có thể sử dụng biểu thức Lambda một cách thích hợp. Tham khảo thêm tại đây

Lời kết

Bài viết ở mức độ basic trên phương diện hiểu biết cá nhân trong quá trình học và làm cũng như vọc vạch đọc thêm các kiểu nên vẫn còn nhiều sai sót. Hi vọng bài viết này sẽ giúp ích cho các bạn khi làm việc với Lambda Expression. Rất mong các bạn có thể góp ý thêm.

Tham khảo

https://viblo.asia/p/gioi-thieu-lambda-expression-trong-java-8-EyORkbklGqB

https://www.javatpoint.com/java-lambda-expressions

https hoạt động như thế nào?

Bài viết tổng hợp cơ chế hoạt động của https

Chút ít về chữ ký điện tử

Chữ ký điện tử là cơ chế bao gồm 3 thuật toán:

  • Thuật toán chọn một khóa bí mật (private key) từ 1 tập các khóa một cách ngẫu nhiên
  • Thuật toán ký. Đầu vào là 1 thông điệp và khóa bí mật. Đầu ra là một chữ ký.
  • Thuật toán kiểm tra chữ ký. Đầu vào là một thông điệp, khóa công khai, và chữ ký. Đầu ra là đồng ý hay từ chối tính thẩm quyền của thông điệp

Do vậy để có chữ ký điện tử, ta cần có thuật toán cho phép  và kiểm tra chữ ký.

Chuyện gì sẽ xảy ra khi browser truy cập 1 site có https

Quá trình browser truy cập 1 site https có thể được mô tả bằng hình ảnh dưới đây (copy từ http://stackoverflow.com/questions/470523/how-does-ssl-really-work)

  1. Browser sẽ truy cập 1 trang web https. Ở đây là https://payment.com
  2. Server hay Load Balancer (LB) của payment.com sẽ trả về certificate để chứng thực rằng website user đang truy cập là website chính thức. Trong certificate là một public key PK, dùng để mã hóa K ở bước 4.
  3. Browser sẽ kiểm chứng certificate (bằng cách chạy thuật toán kiểm tra chữ ký). Quá trình này giúp browser xác định https://payment.com là thật hay giả.
  4. Sau khi kiểm chứng được certificate, browser sẽ tự sinh ra 1 khóa K. Khóa K sẽ được dùng để mã hóa tất cả các liên lạc giữa browser và payment.com sau này. Do quá trình mã hóa các gói tin dùng mã đối xứng, khóa K cần được gửi trở lại payment.com vì nếu không có K, server (LB) không thể nào giải mã được gói tin.
  5. Khóa K được gửi trả lại cho payment.com. Phía payment.com sẽ dùng private key (được bảo vệ) để giải mã gói tin này và qua đó có được thông tin về K.
  6. payment.com và browser dùng khóa K để mã hóa toàn bộ dữ liệu liên lạc sau này.

Certificate là một khối dữ liệu bao gồm rất nhiều thông tin về payment.com. Các thông tin này bao gồm:

  • Tên domain
  • Tên công ty sở hữu
  • Thời gian certificate được cấp
  • Thời hạn certificate
  • Public key PK

Làm thế nào browser kiểm chứng được certificate ở bước 3

Bất cứ người nào đứng giữa browser và payment.com đều có thể làm giả certificate và public key. Bằng cách làm giả certificate, người đứng giữa có thể giả dạng payment.com. Bằng cách giả public key, người đứng giữa có thể dùng khóa private của mình để xem thông tin truyển tải giữa 2 bên. Vậy làm thế nào để ngăn chặn cách tấn công này. Cách giải quyết là: CA (Certificate Authority).

CA là gì? Làm gì?

Trong thực tế, để chứng minh một ai đó trình độ đại học, trường đại học nơi người đó học sẽ cấp cho họ một tấm bằng. Do tấm bằng đó có thể bị làm giả, ta cần một đơn vị chứng minh đó là bằng thật. CA chính là người chứng minh certificate mà payment.com cung cấp là thật! CA bán dịch vụ chứng thực đó bằng cách ký chứng minh rằng certificate của payment.com là thật

Certificate chứng thực cho payment.com sẽ được CA  bằng khóa bí mật của CA. Khóa này chỉ có CA biết và do vậy việc chữ ký là an toàn. payment.com sẽ gửi cho user certificate đã được ký bởi CA cùng với khóa công khai PK2 của khóa bí mật CA dùng để ký certificate. Browser sẽ tiến hành kiểm tra certificate này như bình thường dùng khóa công khai PK2 của CA.

Đến đây vấn đề chưa thực sự được giải quyết vì, khóa công khai của CA cũng hoàn toàn có thể bị làm giả và do vậy certificate hoàn toàn có thể là giả! Giống như thực tế người chứng minh cho tấm bằng đại học cũng có thể bị làm giả. Để chắc chắn việc này, ta có thể ký chứng thực certificate do CA ký là thật. Cách làm có thể hoàn toàn tương tự là dùng khóa bí mật nào đó và ký tiếp và đính kèm khóa công khai PK3 với certificate sau khi được ký. Cứ thế ta có một dãy các certificate và khóa công khai mà certificate sau chứng thực cho certificate trước. Do bản chất đệ quy, ta cần điểm dừng là một certificate mà ta hoàn toàn tin tưởng. Đến đây ta có khái niệm root certificate.

Root certificate

Root certificate là certificate mà ta hoàn toàn tin tưởng. Khi có certificate này, ta có thể tin tưởng những certificate mà được chứng thực bởi certificate này là hoàn toàn hợp lệ (giống trong thực tế là cơ quan công chứng!). Mỗi OS và browser có một danh sách các certificate mà OS và browser đó tin tưởng.

Firefox tin tưởng các certificate có danh sách tại: https://wiki.mozilla.org/CA:IncludedCAs
RHEL có danh sách các certificate tin tưởng tại: /etc/pki/tls/certs/

Do root certificate là certificate cuối cùng dùng để chứng thực các certificate trong chuỗi, khóa bí mật của certificate này cần được bảo vệ nghiêm ngặt. Bất cứ công ty cung cấp dịch vụ CA nào bị tấn công và bị mất khóa bí mật của root certificate đều rất nguy hiểm, bởi vì hackers có thể dùng khóa đó để ký certificate ở bước cuối cùng. Do browser và OS tin tưởng certificate này nên tất cả certificate, không nhất thiết do CA bị hack cung cấp, đều có thể bị làm giả. Các CA do vậy dùng rất nhiều công sức để bảo vệ thật kín đáo khóa bí mật này. Kinh doanh chứng thực CA là kinh doanh về mặt lòng tin, CA hứa sẽ đảm bảo tốt nhất khóa bí mật của họ và ta trả tiền để họ dùng khóa bí mật của họ ký.

Theo đồn đại của giang hồ, verisign dùng cửa lock dày và các tay súng chuyên nghiệp cùng hệ thống truy cập phức tạp để bảo vệ khóa bí mật này.

Xem certificate chain trong thực tế

Đến đây ta chắc đã hiểu phần nào về cơ chế chứng thực cũng như cách hoạt động của HTTPS. Ta sẽ cùng xem chuỗi certificate trong thực tế.

Facebook certificate được ký bởi DigiCert High Assurance CA-3. Bản thân CA-3 được chứng thực bởi EV RootCA.

Các vấn đề liên quan đến https / certificate

Nguyên tắc hoạt động là như vậy, trong thực tế để duy trì và vận hành một hệ thống https cần tốn khá nhiều công sức. Dưới đây là một số case-studies mình gặp trong quá trình vận hành một website. Qua một số case-studies này hy vọng bạn sẽ hiểu tầm quan trọng của mỗi sự kiện và ý nghĩa của nó.

Heartbleed

Sự kiện heartbleed là sự kiện đình đám của năm 2014. Heartbleed là lỗi bảo mật nằm trong bộ thư viện OpenSSL, bộ thư viện chủ đạo xử lý mã hóa trên Linux. Các webserver đều được build sử dụng OpenSSL nếu muốn phục vụ https.

Heartbleed xảy ra khi openssl không kiểm tra độ dài trả về của một chuỗi ký tự và vô tình trả về thông tin nằm sau chuỗi ký tự này trên bộ nhớ. Vô tình phần bộ nhớ này bao gồm khóa bí mật được dùng để ký certificate ban đầu. Bằng cách hỏi máy chủ cho xem chìa khóa bí mật này, hacker có thể dùng nó để giải mã khóa mã hóa liên lạc ở bước 5 và do đó đọc được toàn bộ nội dung của phiên liên lạc.

Heartbleed nguy hiểm bởi việc tấn công này hoàn toàn không để lại dấu vết.

Các công ty cung cấp dịch vụ qua https đã phải xử lý vấn đề này bao gồm các bước sau:

  • Nâng cấp phiên bản openssl
  • Khởi động lại máy chủ web (apache, nginx)
  • Tạo một khóa bí mật mới, certificate mới và yêu cầu CAs ký lại

Diginostar

Diginostar là hãng CAs của Hà Lan bị hacker tấn công và lấy được khóa bí mật. Từ đó tất cả các root certificate của Diginostar đều bị xóa bỏ khỏi browser, do lo sợ hacker sẽ dùng khóa bí mật này làm giả certificate. Điều này dẫn đến sự phá sản của CA.

Qua đấy mới thấy việc bảo vệ khóa bí mật an toàn là vấn đề sống còn của các CAs.

Superfish

Hãng máy tính Lenovo khi bán máy tính đã cài thêm một phần mềm hiển thị quảng cáo đến người dùng. Khi người dùng lướt net, phần mềm này sẽ tự thêm một quảng cáo nhỏ trên browser. Để có thể thêm quảng cáo vào bất cứ chỗ nào, phần mềm này tự ý cài một root certificate vào máy lenovo bán đi. Root certificate này lại là một certificate tự ký, bất cứ ai có máy lenovo đều có thể có được khóa bí mật ký certificate này. Điều này vô tình biến tất cả người dùng máy lenovo thành đối tượng bị làm giả certificate. Tất cả các liên lạc https đều có thể bị làm giả, do vậy việc làm này đã tạo ra một lỗi bảo mật rất nghiêm trọng.

Hãng Lenovo sau đó đã phải xin lỗi người dùng và đưa ra phần mềm gỡ bỏ tool này.

http://support.lenovo.com/vn/vi/product_security/superfish_uninstall

OS quá cũ

Các root certificate đi kèm với máy chủ không phải có thời hạn mãi mãi mà được làm mới qua mỗi lần release một phiên bản của OS. Do vậy việc update OS thường xuyên là điều nên làm. Tuy vậy đối với các máy chủ làm việc bận rộn, việc nâng cấp nhiều khi là điều khó khăn. Từ đây nảy sinh một vấn đề như sau.

Máy chủ thỉnh thoảng hay phải gọi các https thông qua curl, ví dụ gọi twitter api qua https, hay gọi một dịch thanh toán nào đó qua Https. Giống như browser, curl dùng root certificate đi kèm để chứng thực các certificate phía dịch vụ gửi về. Tuy vậy khi root certificate hết hạn, việc chứng thực này sẽ thất bại, kéo theo việc app của bạn sẽ không chạy đúng nữa. Những lúc này việc update root certificate là việc cần phải làm.

Kết luận

Bài viết trình bày khái quát nguyên tắc hoạt động của https cũng như các vấn đề xoay quanh liên lạc dùng https. Hy vọng qua bài viết bạn hiểu rõ hơn về https cũng như lý giải được tầm nghiêm trọng của những vấn đề và sự kiện xoay quanh https.

Làm thế nào để thay đổi cuộc đời bạn?

“Bạn sẽ không bao giờ thay đổi cuộc đời mình cho đến khi bạn thay đổi điều gì đó mà bạn đang làm hằng ngày” – Mike Murdock.

Bắt đầu với một câu tuyên bố đơn giản: Bạn muốn trở thành gì?

Bạn có hi vọng một ngày nào đó trở thành một nhà văn, nhạc sĩ, nhà thiết kế, lập trình viên, phiên dịch viên, một họa sĩ Manga, một doanh nhân hay một chuyên gia về lĩnh vực nào đó?

Làm thế nào để đạt được điều đó? Bạn sẽ viết ý định của bạn vào một mảnh giấy, đặt nó trong một cái chai và thả nó ra biển với hi vọng nó sẽ trở thành sự thật? Không. Vũ trụ sẽ không khiến nó xảy ra, mà chính là bạn.

Bạn có từng đặt cho mình một mục tiêu lớn để hoàn thành vào cuối năm hoặc trong ba tháng? Chắc chắn rồi, nhưng điều đó không khiến bạn hoàn thành. Thực tế, nếu bạn nghĩ lại về hầu hết các ví dụ trong cuộc sống của bạn sẽ thấy việc đặt ra các mục tiêu lớn dài hạn có lẽ không hiệu quả. Bao nhiêu lần chiến lược này đã thành công?

Tôi sẽ đặt ra luật ở đây, dựa trên nhiều trải nghiệm tôi đã thực hiện trong suốt 7 năm qua: không có điều gì thay đổi trừ khi bạn thực hiện thay đổi hằng ngày.

Tôi đã thử các bước hành động hàng tuần, những điều tôi làm hàng ngày, những mục tiêu lớn hàng tháng, nhiều sự thay đổi khác. Không cái nào có tác dụng trừ việc thay đổi hàng ngày.

Nếu bạn không muốn biến nó thành sự thay đổi hàng ngày thì bạn không thực sự muốn thay đổi cuộc sống theo cách này. Bạn chỉ thích ý tưởng học vẽ/nói tiếng Nhật/chơi đàn ghi-ta, lập trình bằng PHP/… Bạn không thực sự muốn làm điều đó.

Vì vậy hãy thay đổi hàng ngày. Cùng xem nó hoàn thành như nào!

Làm sao để biến một nguyện vọng thành một thay đổi hàng ngày

Hãy điểm tên một vài nguyện vọng:

  • Giảm cân
  • Viết một quyến sách
  • Ngừng trì hoãn
  • Yêu một ai đó
  • Trở nên hạnh phúc
  • Du lịch khắp thế giới
  • Uống nhiều nước hơn
  • Học tiếng Anh
  • Tiết kiệm tiền
  • Chụp nhiều ảnh hơn
  • Đọc nhiều sách hơn

Làm thế nào để bạn biến những ý tưởng cao cả này thành những thay đổi hàng ngày? Suy nghĩ về những điều bạn có thể làm mỗi ngày mà có thể làm thay đổi xảy ra hoặc ít nhất đưa bạn tới gần mục tiêu hơn. Điều đó không phải lúc nào cũng dễ dàng nhưng hãy nhìn vào một vài ý tưởng:

  • Giảm cân – bắt đầu đi bộ mỗi ngày trong 10 phút, rồi lên 15 phút sau một tuần, rồi 20 phút,… cho đến khi bạn đi bộ 30-40 phút một ngày thì thực hiện một thay đổi khác – uống nước lọc thay vì soda.
  • Viết một cuốn sách – viết 10 phút mỗi ngày.
  • Ngưng trì hoãn – Tôi có thể đã nghe những lời mỉa mai (và theo nghĩ đen) đùa về cách mọi người đối phó với sự trì hoãn. Dù sao, hãy làm một hành động hàng ngày: đặt ra một Nhiệm Vụ Quan Trọng Nhất vào mỗi buổi sáng, và thực hiện điều đó mỗi 10 phút trước khi mở trình duyệt/thiết bị di động của bạn.
  • Yêu – đi đâu đó mỗi ngày và gặp gỡ/giao tiếp xã hội với những người mới. Hoặc làm điều gì đó hàng ngày mà khiến bạn trở thành một người hấp dẫn.
  • Trở nên hạnh phúc – làm điều gì đó mỗi ngày để làm cho thế giới tốt hơn, để giúp mọi người.
  • Du lịch khắp thế giới – tiết kiệm tiền (xem mục tiếp theo). Hoặc bắt đầu bán đồ của bạn, để bạn có thể gói ghém đồ đạc của mình vào một chiếc ba lô và bắt đầu chuyến du lịch.
  • Tiết kiệm tiền – bắt đầu cắt giảm các khoản chi phí. Bắt đầu nấu nướng và ăn ở nhà. Bán xe và đi xe đạp/đi bộ/xe bus. Bắt đầu tìm kiếm một ngôi nhà nhỏ hơn. Dùng công cụ miễn phí thay vì mua mọi thứ.
  • Uống nhiều nước hơn – uống nước mỗi khi bạn thức dậy, sau đó là mỗi lần bạn nghỉ ngơi (mỗi giờ một lần).
  • Học tiếng Anh – học tiếng Anh ở Duolingo và xem một video trên TED mỗi ngày.
  • Đọc nhiều sách hơn – đọc mỗi buổi sáng và trước khi bạn đi ngủ.

Bạn có ý tưởng. Nhưng không phải tất cả đều là những ý tưởng hoàn hảo, nhưng bạn có thể đưa ra một ý tưởng nào đó tốt hơn cho bạn. Quan trọng là, làm điều đó hàng ngày.

Cách thực hiện thay đổi hàng ngày

Phương pháp này khá là đơn giản và nếu bạn thực sự thực hiện nó, kết quả gần như không thể tin được:

  1. Một thay đổi tại một thời điểm. Bạn có thể phá vỡ quy tắc này, nhưng đừng ngạc nhiên nếu bạn thất bại. Thực hiện một thay đổi trong một tháng trước khi cân nhắc một giây. Chỉ thêm một thay đổi khác nếu bạn đã thành công ở thay đổi đầu tiên.
  2. Bắt đầu nhỏ. OK, tôi đã nói điều này hai lần rồi. Tuy nhiên, không ai làm điều đó. Bắt đầu với 10 phút hoặc ít hơn. Năm phút tốt hơn nếu đó là một thay đổi khó khăn. Nếu bạn vẫn thất bại, giảm xuống còn 2 phút.
  3. Thực hiện cùng thời điểm mỗi ngày. OK, không đúng nghĩa đen trong cùng phút, như vào lúc 6:00 sáng, nhưng sau cùng một cú kích hoạt trong thói quen hàng ngày của bạn – như sau khi uống ly cà phê đầu tiên vào buổi sáng, sau khi bạn đi làm, sau khi bạn về nhà, sau khi bạn đánh răng, tắm, ăn sáng, thức dậy, ăn trưa, bật máy tính hoặc lần đầu tiên gặp vợ mỗi ngày.
  4. Thực hiện một cam kết rất lớn với ai đó hoặc với nhiều người. Hãy đảm bảo rằng đó là người có ý kiến bạn tôn trọng. Ví dụ, tôi đã thực hiện một cam kết học/lập trình PHP ít nhất 10 phút mỗi ngày với bạn của tôi – Tynan. Tôi đã cam kết với vợ, bạn bè, độc giả của blog này, với con tôi và nhiều hơn nữa.
  5. Hãy chịu trách nhiệm. Lấy ví dụ về việc lập trình của tôi với Tynan… mỗi ngày tôi phải cập nhật một bảng tính Google cho biết mình đã lập trình/học được bao nhiêu phút mỗi ngày, và anh ấy có thể kiểm tra bảng tính đã được chia sẻ này. Công cụ bạn sử dụng không quan trọng – bạn có thể đăng lên Facebook hoặc Twitter, gửi email cho ai đó, đánh dấu nó trên lịch, báo cáo trực tiếp. Chỉ cần đảm bảo bạn chịu trách nhiệm mỗi ngày, không phải mỗi tháng. Và đảm bảo rằng người đó đang kiểm tra. Nếu họ không kiểm tra bạn, bạn cần tìm một đối tác hoặc nhóm mới.
  6. Có những kết quả. Kết quả quan trọng nhất của việc làm hay không làm thói quen hàng ngày là nếu bạn không làm vậy thì mọi người sẽ tôn trọng bạn ít hơn, và ngược lại. Nếu hệ thống nhiệm vụ của bạn không được thiết lập theo cách này, hãy tìm một cách khác để thực hiện. Bạn có thể cần thay đổi người mà bạn báo cáo nhiệm vụ. Nhưng bạn có thể thêm các kết quả thú vị khác: tôi đã hứa sẽ hát một bài hát tiếng Nhật trước những người lạ mặt nếu tôi thất bại. Kết quả cũng có thể tích cực – ví dụ như một phần thưởng lớn mỗi tuần nếu bạn không bỏ lỡ một ngày nào. Làm kết quả lớn hơn nếu bạn bỏ lỡ hai ngày liên tiếp và rất lớn nếu bạn bỏ lỡ ba ngày.
  7. Tận hưởng thay đổi. Nếu bạn không như vậy, bạn cũng có thể tìm một thay đổi khác để thực hiện. Nếu hành động hàng ngày cảm thấy buồn tẻ và nhàm chán thì bạn đang làm sai. Tìm một cách khác để tận hưởng nó hoặc bạn sẽ không thể theo đuổi lâu dài. Hoặc tìm một vài thay đổi khác mà bạn thích hơn.

Vậy thôi. Bảy bước khá đơn giản và bạn đã có một cuộc sống thay đổi. Không điều nào trong số này là không thể – thực tế, bạn có thể đưa chúng vào hành động ngay hôm nay.

Thay đổi hàng ngày nào mà bạn sẽ làm hôm nay?

Dịch từ bài viết: How to Change Your Life: A User’s Guide

21 trang web hay mà bạn có thể ghé thăm mỗi khi rảnh rỗi

Bạn thấy chán các trang web cũ? Muốn tìm một vài góc mới của Internet để giúp bạn tìm lại sự hứng thú? Tốt thôi, bạn đã gặp may đấy. Dù bạn đang tìm những trò chơi ngớ ngẩn hay điều gì đó hữu ích thì dưới đây là 21 trang web hay mà bạn nên ghé qua.

1. TED

Với hơn 1900 bài talk thú vị và đầy cảm hứng, chắc chắn bạn sẽ tìm được điều gì đó mà bạn thích.

2. Difference Between

Bạn muốn tìm hiểu sự khác biệt giữa bất cứ điều gì? Ví dụ giữa API và Web Service.

3. The Geocities-izer

Biến bất cứ trang web nào thành một trang với giao diện xấu xí như những năm 90.

4. Wikipedia Random

Rơi vào hố thỏ và khám phá những chủ đề ngẫu nhiên trên Wikipedia.

5. Whizzpast

Nơi tuyệt vời nhất trên Internet để tìm hiểu về những điều tuyệt vời trong lịch sử.

6. Find the Invisible Cow

:trollface:

Hãy chắc chắn rằng bạn đã mở loa (nhưng đừng quá to ).

7. Sporcle

Giải hàng ngàn câu đố hoặc tự bạn tạo ra.

8. Zooniverse

Trở thành một phần của những dự án khoa học thực sự (ví dụ như khám phá bề mặt của mặt trăng) bằng cách tham gia nghiên cứu online.

9. Lang-8

Viết trong một ngôn ngữ mà bạn đang học và người bản xứ sẽ sửa các lỗi của bạn.

10. Silk

Tạo ra các tác phẩm nghệ thuật với con chuột của bạn.

11. Letters of Note

Một bộ sưu tập tuyệt vời của các chữ cái hấp dẫn, bưu thiếp, điện tín và các ghi chú trong quá khứ.

12. Khan Academy

Nếu bạn đang muốn học hỏi thêm điều gì đó thì Khan Academy có hàng trăm khóa học giáo dục miễn phí dành cho bạn.

13. GeoGuessr

Đoán xem hình chụp bởi Google Streetview là ở nơi nào trên thế giới.

14. Feel Good Wardrobe

Trang cung cấp mẹo để mua quần áo.

15. I Need a Prompt

Giống trang You Should Write, nhưng dành cho các nghệ sĩ.

16. Omegle

Cảm thấy muốn nói chuyện với ai đó? Omegle giúp bạn nói chuyện (qua tin nhắn hoặc video) với một người lạ.

17. My Script Font

Tạo ra một font dựa trên chữ viết tay của chính bạn.

18. Live Plasma

Live Plasma là một cỗ máy khám phá âm nhạc. Chỉ cần gõ vào một nghệ sĩ mà bạn thích và nó sẽ hiển thị những nghệ sĩ tương tự.

19. Hippo Paint

Một cuốn sách tô màu hoàn hảo cho cả trẻ em và người lớn – chỉ cần gõ vào thứ gì đó mà bạn thích vẽ và nó sẽ cung cấp cho bạn những hình ảnh.

20. Akinator

Một phù thủy thực sự.

21. Kongregate

Hàng ngàn trò chơi trực tuyến miễn phí, từ những tên tuổi lớn cho đến tư nhân.

Event Loop là gì và hoạt động thế nào?

Event Loop là gì và hoạt động thế nào?

Trước đây thi thoảng có làm Javascript và cũng có nghe nói qua về một số khái niệm cơ bản và hay ho của Javascript như nhân V8 của Google (quá oách), Event-Driven, Non-blocking I/O, Event Loop… những khái niệm giúp JS tận dụng sức mạnh của phần cứng và hàng chục lợi ích khác. Dạo gần đây có làm nhiều về JS, gặp nhiều lỗi quái đản mình mới tự đặt ra câu hỏi là rốt cục tất cả những thứ trên là cái gì?, hoạt động thế nào? và tại sao nó mang lại lợi ích?

Hôm nay qua một số google search và đặc biệt xem được bài thuyết trình này mình thấy Event Loop chính là thứ nguồn gốc, hay ho nhất và muốn chia sẻ, thảo luận cùng mọi người. Đấy là những gì mình hiểu ra chứ chưa chắc đã là chuẩn xác. Anh em có gì góp ý mình cực kỳ hoan nghênh và tiếp thu.

Tất cả các ngôn ngữ lập trình đều được sinh ra để làm thứ ngôn ngữ giao tiếp giữa người và máy. Dù là ngôn ngữ gì đi chăng nữa thì cuối cùng vẫn phải dịch ra mã máy, được load lên memory, chạy từng dòng lệnh, ghi các dữ liệu tạm thời ra bộ nhớ, ổ đĩa rồi giao tiếp các thiết bị ngoại vi… Thế nên để cho tiện mình xin nhắc lại một số khái niệm cơ bản sau.

1. Một số khái niệm cơ bản

1.1 Stack

Stack là một vùng nhớ đặc biệt trên con chip máy tính phục vụ cho quá trình thực thi các dòng lệnh mà cụ thể là các hàm. Hàm chẳng qua là một nhóm các lệnh và chương trình thì gồm một nhóm các hàm phối hợp với nhau. Mỗi khi một hàm được triệu gọi thì nó sẽ được đẩy vào một hàng đợi đặc biệt có tên là stack. Stack là một hàng đợi kiểu LIFO (Last In First Out) nghĩa là vào đầu tiên thì ra sau cùng. Một hàm chỉ được lấy ra khỏi stack khi nó hoàn thành và return.

Nếu trong một hàm (Foo) có triệu gọi một hàm khác (Bar) thì trạng thái hiện tại của hàm Foo được cất giữ trong stack và hàm Bar sẽ được chèn vào stack. Vì đây là hàng đợi LIFO nên Bar sẽ được xử lý trước Foo. Khi Bar xong và return thì mới đến lượt Foo được xử lý. Khi Foo được xử lý xong và return thì Stack rỗng và sẽ đợi các hàm tiếp theo được đẩy vào.

Stack
——————–
| |
——————–
| Bar | <–
——————–
| Foo |
——————–

1.2. Heap

Heap là vùng nhớ được dùng để chưa kết quả tạm phục vụ cho việc thực thi các hàm trong stack. Heap càng lớn thì khả năng tính toán càng cao. Heap có thể được cấp phát tĩnh hoặc cấp phát động bằng mấy lệnh kiểu alloc với malloc (đấy là những gì còn nhớ về C++).

2. Event Loop là gì

Event Loop là cơ chế giúp Javascript có thể thực hiện nhiều thao tác cùng một lúc (concurrent model), trước giờ vẫn nghe nói NodeJs có thể xử lý cả hàng ngàn request cùng một lúc mặc dù nó chỉ dùng một thread duy nhất (Single Threaded). Nếu như ở PHP hay Java thì với mỗi một request sẽ sinh ra một thread để xử lý request đó, các thread hoạt động độc lập, được cấp bộ nhớ, giao tiếp ngoại vi và trả về kết quả. Vậy làm thế nào để NodeJs có thể xử lý cả ngàn request một lúc với chỉ một thread duy nhất?.

Có một sự thật là trên web browser thì trong khi get data từ các url thì người dùng vẫn có thể thực hiện các thao tác khác như click button và gõ vào các ô textbox. Tất cả là nhờ có các web apis và cơ chế hoạt động của Event Loop. Tuy Js Runtime chỉ có một thread duy nhất nhưng các web apis giúp nó giao tiếp với thế giới multi thread bên ngoài, tận dụng các con chip đa nhân vốn rất phổ biến hiện nay. Web apis giúp đẩy các job ra bên ngoài và chỉ tạo ra các sự kiện kèm theo các handler gắn với các sự kiện. Kể cả đối với NodeJs khi không có web apis thì nó vẫn có các cơ chế tương đương khác giúp đẩy job ra bên ngoài và chỉ quản lý các đầu việc. Web Apis hoạt động như vậy thì Event Loop sẽ thế nào ?

3. Event Loop hoạt động như thế nào ?

Event Loop có tên như vậy bởi vì có một vòng lặp vô tận trong Javascript Runtime (V8 trong Google Chrome) dùng để lắng nghe các Event.

while (queue.waitForMessage()) {
queue.processNextMessage();
}

Nhiệm vụ của Event Loop rất đơn giản đó là đọc Stack và Event Queue. Nếu nhận thấy Stack rỗng nó sẽ nhặt Event đầu tiên trong Event Queue và handler (callback hoặc listener) gắn với Event đó và đẩy vào Stack. Đặc điểm của việc thực thi hàm trong JS là sẽ chỉ dừng lại khi hàm return hoặc throw exception. Có nghĩa là trong khi hàm đang chạy thì sẽ không có một hàm khác được chạy, dữ liệu tạm của hàm cũng sẽ không bị thay đổi bởi một hàm khác hay cũng không bị dừng lại cho đến khi hoàn thành (ngoại trừ yield trong ES6).

Như các bạn thấy trên hình thì JS Runtime còn thao tác với một callback queue hay event queue ngoài stack ra. Event queue này khác với stack ở chỗ nó là queue kiểu FIFO (First In First Out). Mỗi khi có một Event được tạo ra, ví dụ user click vào một Button thì một Event sẽ được đẩy vào Event queue cùng với một handler (event listener) gắn với nó. Nếu một Event không có listener thì nó sẽ bị mất và không được đẩy vào Event queue. Để cho dễ hình dung cách thức hoạt động của Event Loop ta lấy một ví dụ như sau :

const fs = require('fs');

function someAsyncOperation(callback) {
  // giả sử đọc file hết 95ms
  fs.readFile('/path/to/file', callback);
}

const timeoutScheduled = Date.now();

setTimeout(logInfo() => {
  const delay = Date.now() - timeoutScheduled;
  console.log(`${delay}ms have passed since I was scheduled`);
}, 100);


// đọc file xong sẽ tiếp tục chờ thêm 10ms
someAsyncOperation(function readFileAsync() => {
  const startCallback = Date.now();

  // chờ 10ms
  while (Date.now() - startCallback < 10) {
    // do nothing
  }
});

đầu tiên phần khai báo biến và hàm sẽ được chạy nhưng không được đẩy vào stack. Tiếp setTimeout() sẽ được đẩy vào stack và thực hiện. Hàm này không có trong Javascript Runtime mà là hàm tiện ích của Browser, nó sẽ khởi tạo một bộ đếm và sau đúng 100ms thì nó sẽ đẩy tham số đầu tiên logInfo (là một callback hoặc có thể gọi là một event listener cũng được) vào Event Queue. Kế đến sẽ chạy hàm someAsyncOperation và đẩy vào stack, vì hàm này async và có callback readFileAsync nên readFileAsync được đẩy luôn vào Event Queue mà không phải chờ như setTimeout để hứng sự kiện đọc xong file (sau 95ms).

         Stack                        Event Queue
-------------------- -------------------
| | | readFileAsync | <--
-------------------- -------------------
| | | |
-------------------- -------------------
| someAsyncOperation | <-- | |
-------------------- -------------------

Để ý là Stack LIFO nên someAsyncOperation sẽ nằm dưới cùng còn Event Queue FIFO nên readFileAsync sẽ nằm trên cùng. Sau khi readFileAsync được đẩy vào Event Queue thì someAsyncOperation return và được lấy ra khỏi Stack. Lúc này Stack không có gì nên Event Queue sẽ được đọc, nên nhớ là Event Queue chỉ được đọc khi Stack trống rỗng. readFileAsync sẽ được đẩy vào Event Queue trước vì nó chỉ mất có 95ms trong khi logInfo thì phải chờ 100ms. readFileAsync này sẽ được lấy khỏi Event Queue và đẩy vào stack để chạy.

       Stack                           Event Queue
-------------------- -------------------
| | ------ | readFileAsync |
-------------------- | -------------------
| | | | logInfo | <--
-------------------- | -------------------
| readFileAsync | <-- | |
-------------------- -------------------

readFileAsync sẽ gặp vòng while và dừng ở đó 10ms. Vậy tổng cộng hàm đọc file sẽ mất 105ms để hoàn thành. Nhưng ở giây thứ 100 thì logInfo được đẩy vào Event Queue (lúc này đã rỗng) trong khi readFileAsync thì còn phải mất thêm 5ms nữa mới hoàn thành. Vì cơ chế của Javascript là chạy đến khi hoàn thành mới thôi nên logInfo không có cách nào để dừng readFileAsync lại để chiếm quyền điều khiển, trừ khi trong readFileAsynccó lệnh yield. Sau 105ms thì readFileAsync return và được lấy ra khỏi Stack.

       Stack                           Event Queue
-------------------- -------------------
| | ------ | logInfo |
-------------------- | -------------------
| | | | |
-------------------- | -------------------
| logInfo | <-- | |
-------------------- -------------------

Một lần nữa Stack lại trống và logInfo được đẩy vào Stack. Như vậy logInfo sẽ phải đợi tổng cộng 105ms để được chạy, chứ không phải 100ms như dự tính. Do đó tham số thứ 2 của setTimeout là thời gian tối thiểu để một Event được đẩy vào Stack và chạy chứ không phải là thời gian chính xác nó sẽ được chạy.

Giả sử bạn có một đoạn code jQuery như sau :

$('#button_1').click(function yield() {
console.log('Ouch!');
});

thì một hoặc vài event sẽ được đẩy vào Event Queue như sau:

Stack                        Event Queue
-------------------- -------------------
| | | yield(Event) | <--
-------------------- -------------------
| Bar | | |
-------------------- -------------------
| Foo | <-- | |
-------------------- -------------------

đặt tên hàm là yield chỉ nhằm mục đích dễ theo dõi, ta hoàn toàn có thể bỏ tên hàm đi trong trường hợp này. Khi Bar và Foo return và được lấy ra khỏi Stack thì yield sẽ được đẩy vào Stack với tham số là DOM Element xảy ra sự kiện click.

Cơ chế run to completion của Javascript có một điểm bất lợi đó là nếu một hàm chạy quá lâu hoặc bị vòng lặp vô tận thì sẽ không có hàm nào được chạy nữa, kết quả là Browser sẽ bị đơ, không phản ứng với các sự kiện như click chuột … Ví dụ :

function foo() {
console.log('i am foo!');
foo();
}

foo();

hàm đệ quy không điểm dừng sẽ liên tục đẩy foo vào Stack cho đến khi đầy, và bạn đoán xem lúc này chúng ta sẽ có cái mà hàng ngày các develop đều tìm kiếm Stack Overflow

      Stack                           Event Queue
-------------------- -------------------
| foo | | Event 1 |
-------------------- -------------------
| foo | | Event 2 |
-------------------- -------------------
| foo | | Event 3 |
-------------------- -------------------

Để tránh tình trạng Browser bị treo vì lỗi lập trình thì các Browser sẽ throw exception trong trường hợp này :

MAXIMUM CALL STACK SIZE EXCEEDED.

Hầu hết các thao tác trong Javascript đều là bất đồng bộ nhưng có một số ngoại lệ thú vị như hàm alert (hàm này là của Browser API, không có trong NodeJs). Khi hàm này được chạy thì bạn không thể thực hiện một thao tác nào khác ngoài click OK.

Đến đây ta có thể thấy cơ chế quản lý theo đầu việc là bí kíp giúp JS Runtime có thể xử lý hàng ngàn tác vụ cùng một lúc. Giống như bạn được giao một đống việc, bạn chia nhỏ từng việc và giao cho đám đệ tử của mình.

LÀM CÁI NÀY CHO ANH. KHI NÀO XONG BÁO ANH NGAY NHÉ !

Sau khi nhận báo cáo từ đám đệ tử bạn chỉ việc tổng hợp và báo lên xếp thôi !

Băm và lưu password đúng cách

Sau khi đọc bài viết băm mật khẩu đúng cách của anh thaidn, mình nhớ lại lúc mình mới ra trường, cũng đã từng nghĩ về vấn đề này (lúc đó mình khá thích môn Bảo Mật Thông Tin ở trường) nhưng chưa bao giờ hiểu tường tận. Chỉ biết là không nên:

  • Lưu password ở dạng plain-text.
  • Hash với một thuật toán hash mạnh, không nên xài MD5, SHA-1 …
  • Hash với salt.

Chỉ hiểu rằng phải nên làm thế, nhưng không hiểu tại sao lại như vậy và một số câu hỏi khác cũng chưa trả lời được như:

  • Password user gửi lên, nên hash ở client hay ở server.
  • Salt nên lưu ở đâu.
  • Salt có cần giữ bí mật hay không?
  • Salt chung cho tất cả, hay salt riêng cho từng user?

Hôm nay, mình quyết định đi tìm câu trả lời cho những vấn đề mình thắc mắc, thay vì mặc định nó đúng.

1. Tại sao không nên lưu plain-text, encrypt hoặc dùng MD5, SHA-1

Nếu lưu plain-text, database bị hack, SQL-injection, password user chìa ra theo một cách không thể dễ dàng hơn để đánh cắp.

Nếu mã hóa 2 chiều, sẽ luôn có một cách để giải mã bằng một chìa-khóa nào đó, sẽ phải tìm cách lưu chìa-khóa một cách an toàn.

MD5 và SHA-1 được chứng minh có đụng độ, nghĩa là 2 password khác nhau, khi hash bằng MD5 hoặc SHA-1 có thể ra cùng một chuỗi.

2. Tại sao phải salt

Ta đã biết, hash algorithm là one-way-function, tức là không thể suy ngược trực tiếp ra password nếu có hash_value (khác với mã hóa, có thể giải mã thông qua chìa-khóa).

Tuy nhiên vẫn có cách để từ hash_value có thể suy gián tiếp ra được password ví dụ brute-force attach, dictionary attach -> điểm chung là ta cần thử và đoán password nhiều lần cho tới khi đúng cái cần tìm.

Một cách khác đó là ta có thể tính toán trước giá trị hash của tất cả các trường hợp và của tất cả các thuật toán -> cách này khó, tốn thời gian, nhưng bây giờ với tốc độ tính toán của máy tính, ta vẫn có thể làm được. Bảng lưu trữ password + hash_value của password gọi là Rainbow Table, có thể tự tạo hoặc tải một số bản miễn phí hoặc trả tiền để mua. Từ bây giờ nếu ta có hash_value ta có thể mapping để suy ra được password.

Tuy nhiên nếu ta chỉ hash mỗi password, ta gặp vấn đề đó là:

  • 2 password giống nhau (user vô tình trùng password) thì chuỗi hash(password) sẽ giống nhau.
  • User cố tình đặt password đơn giản và phổ biến (ví dụ password < 4 kí tự, toàn số, toàn chữ) -> dễ nhớ cho user nhưng dễ tra ngược.

Và nếu chỉ hash password thì nếu mất hash_value, có thể tra trong rainbow table để tìm ra được password của người dùng.

Giờ ta thử thay vì hash(password) ta sẽ hash(salt + password):

Từ md5(123456)

id |          hash_md5                |
---------------------------------------
1  | e10adc3949ba59abbe56e057f20f883e |

Thành md5(7nWZLcCK0vsPzIM + 123456)

id |          hash_md5                |    salt         |
---------------------------------------------------------
1  | 0510210d4b370165658bdc0d0b005244 | 7nWZLcCK0vsPzIM |

Giờ giả sử, ta mất bảng dữ liệu gồm hash_md5, salt, kẻ tấn công sẽ phải tính toán lại rainbow table của tất cả các trường hợp cộng với salt. Nếu salt là random cho từng user, kẻ tấn công sẽ phải tính toán toàn bộ trường hợp cộng với riêng từng salt cho toàn bộ user.

Chi phí cho 2 phép tính trên là vô cùng lớn và tốn rất nhiều thời gian để thực hiện. Vậy tóm lại mục đích của salt và random-salt là:

  • Bảo vệ user kể cả khi user dùng password phổ biến và password không mạnh vì user không thể nhớ được các password phức tạp nhưng tốc độ tính toán của máy tính thì càng ngày càng nhanh.
  • Tạo ra nhiều chi phí tính toán, kẻ tấn công không thể tính toán trước rainbow table.

=> Ta trả lời đc 3 câu hỏi:

  • Salt có thể lưu trong database, cùng với hash_value.
  • Không cần tìm cách giữ bí mật salt, nhưng cũng đừng tự ý công khai salt.
  • Nhưng bắt buộc phải random salt cho từng user.

3. Hash ở đâu?

Giờ giả sử hash(password) ở client-side thì vấn đề là gì?

  • Biết được thuật toán dùng để hash.
  • Salt sẽ phải sinh ra ở client, vì ta cần hash password với salt (hash(salt + password)), và db chỉ lưu kết quả hash, không lưu salt.
  • Nhưng nếu salt sinh ra ở client và salt random thì làm sao để compare với hash_value trong database? Vì lần chứng thực tới, salt sẽ lại random và sẽ khác với kết quả trong database -> salt phải duy nhất cho tất cả các trường hợp.
  • Hoặc salt có thể lưu ở DB, nhưng server phải gửi salt về trước cho user trước khi thực hiện hash -> dễ dàng biết được salt hơn.

Nhìn sơ thì thấy việc dùng duy nhất một salt đã chống lại luận điểm ở mục số 2. Vậy quy trình chứng thực đúng là như thế nào?

  • User sẽ gửi plain-text password lên server và over HTTPs.
  • Server sẽ kiểm tra trong database lấy ra salt của user đó, cộng chuỗi ta được salt + password.
  • Thực hiện hash(salt + password) trên server side.
  • Compare kết quả trên với hash_md5 trong database.

4. Tại sao dùng bcrypt thay cho SHA-512

Kết quả của SHA-512 có độ dài 128 kí tự, độ dài của key là 64 bytes. Trông có vẻ cũng khá chắc chắn, vậy tại sao OWASP recommend sử dụng PBKDF2, bcrypt hoặc scrypt hơn là SHA2?

SHA2 là hash algorithm (tất nhiên), nó được thiết kế với mục tiêu là tốc độ, với các CPU hiện đại, có thể generate hàng triệu kết quả trên giây. Nếu dùng một thuật toán có tốc độ như SHA2 tức là bạn đã đem lợi điểm tới cho kẻ tấn công brute-force. Thuật toán nhanh + cấu hình server mạnh, việc brute-force càng trở lên nhanh chóng hơn.

Trong khi đó, bcrypt được gọi là slow-hash algorithm, bcrypt() mất 100ms để tính toán ra chuỗi hash, chậm hơn 10.000 lần so với sha1().

Có nghĩa là vẫn đạt được mục đích hash nhưng giảm thiểu nguy cơ tấn công brute-force.

Tóm lại: SHA-512 không phải là một thuật toán yếu, mà vấn đề là SHA-512 không phù hợp cho việc hash password. Nếu cần hash password thì ta nên dùng các thuật toán slow hash như PBKDF2, bcrypt và scrypt.

5. Tại sao cần Pepper?

Một thực tế là nếu bạn chỉ có “muối” mà không có “tiêu”, ăn thịt gà luộc sẽ không ngon :v. Giả sử, database bạn chạy RAID-1, một ổ cứng hư và cần thay một ổ cứng mới. Nhưng như ta biết, đĩa bị hư là mirror của đĩa còn lại, bạn phải tiêu hủy ổ cứng hư đó nếu không ai đó có thể lục thùng rác và tái tạo lại một phần dữ liệu trong đĩa hư đó.

Xin lưu ý, bạn cần wipe trước khi vứt bỏ một ổ cứng có dữ liệu dù cá nhân hay server, tuy nhiên đĩa bị sốc điện, bad-sector thì wipe cũng chưa đủ an toàn, tốt nhất nên ngiền ra bã.

Dù random-salt đã làm tăng chi phí tạo ra rainbow table nhưng đời không biết đâu mà lần, kẻ tấn công luôn có những động lực không tưởng để đạt được cái mình muốn. Giả sử kẻ tấn công có một siêu siêu máy tính và một mirror ổ cứng hư lục từ một cái thùng rác nào đó. Với siêu máy tính đó, ta có rainbow-table để tra ngược ra password cần tìm.

Vậy làm sao để giảm thiểu nguy cơ trên? Nguyên tắc là không bỏ tất cả trứng trong một giỏ, đó là pepper. Pepper là một chuỗi tương tự như salt, nhưng khác biệt là ta cần giữ bí mật pepper, lưu ở một chỗ khác ngoài database, và không cần pepper-per-user, chỉ cần 1 pepper là đủ.

Từ

hash(salt + password)

Thành

hash(pepper + salt + password)

Ta nên lưu pepper ở application hoặc ở một service khác, nếu database bị compromise, thì kẻ tấn công cũng không có pepper để tạo ra rainbow-table.

6. Bonus

Trong khi tìm câu trả lời để viết bài này, mình tìm được một bài blog của dropbox nói về cách họ lưu password như thế nào. Thấy có 2 điểm khá hay nên muốn nói thêm.

  • Trước khi hash password với salt-per-user, họ có SHA512(password) trước để cố định độ dài của input-password. Theo Dropbox thì việc này giải quyết 2 issues của bcrypt
    • Một số implementation của bcrypt cắt đầu vào còn 72 bytes.
    • Một số implementation khác của bcrypt thì không cắt đầu vào nhưng dẫn tới một vấn đề khác là DoS attack bởi vì cho phép độ dài mật khẩu tùy ý.
  • Dropbox cũng có global pepper nhưng thay vì dùng nó để hash thì họ encrypt. Tức là thay vì hash(pepper + salt + password) thì họ AES256(salt + password) + global-pepper-key. Theo như họ giải thích thì pepper là một lớp phòng thủ sâu hơn và lưu trữ ở một nơi riêng biệt. Nhưng đồng nghĩa với việc là nơi lưu trữ pepper vẫn có thể bị compromise, và khi bị compromise thì việc rotate key không dễ dàng. Dùng pepper để encrypt vẫn đạt được mục đích bảo mật tương tự nhưng thêm khả năng rotate key khi bị compromise.

7. Migrate

Sau khi viết bài này, Có một câu hỏi về việc làm thế nào migrate một hệ thống dùng SHA1 –> bcrypt. Mình thấy đây là một điểm cũng khá cần thiết nên xin phép note thêm.

Ở đây có 2 trường hợp:

  • Hash password bằng SHA1 nhưng không có salt -> mình gọi là sha1_value.
  • Hash password bằng SHA1 + trong DB có salt-per-user, mình có sha1_value, salt.

Về ý tưởng thì ta sẽ dùng SHA1 như cách Dropbox dùng SHA512 để cố định độ dài input.

Với trường hợp đầu ta cần sinh ra thêm salt-per-user và migrate bcrypt(salt, sha1_value) trong đó sha1_value = SHA1(password) -> Tương tự cách của dropbox, may mắn là do sai thiết kế từ đầu (thiếu salt) nên migrate dễ.

Với trường hợp thứ 2 thì hơi lằng nhằng hơn 1 xíu, ta cần migrate kiểu bcrypt(salt, SHA1(salt, password)) nếu thực sự muốn bcrypt với salt hoặc thực ra chỉ cần bcrypt(SHA1(salt, password) cũng được. Tùy tình huống bạn cần tradeoff có thể lựa chọn cách phù hợp.

8. Thông tin của bạn có an toàn?

Như ta thấy, ta đã làm rất nhiều thứ để đảm bảo rằng thông tin của chúng ta trở lên an toàn. Vậy thực sự thông tin của chúng ta đã an toàn hay không? Câu trả lời rất tiếc là KHÔNG? Thông tin của chúng ta có thể an toàn với “bên ngoài” nhưng không an toàn với “bên trong”. Tại sao lại vậy?

Giờ bắt đầu với thông tin cơ bản nhất như địa chỉ, email, sở thích … Khi ta build staing environment, thông tin user được copy sang một môi trường khác, developer có thể overwrite hash_value của user bằng value của hash(salt + 654321) và dễ dàng đăng nhập trên staing environment với password là 654321 và tất cả các thông tin cơ bản của user đã có thể đọc được. Nhưng developer vẫn không biết chính xác password của user là gì.

Nhưng, lại là nhưng. Người quản trị hệ thống có mọi quyền trên server mà họ quản trị, password dù đã over HTTPs nhưng tới server vẫn là plain-text. Vẫn có thể capture request ngay ở đầu server và output ra plain-text password của user và cuối cùng thì người quản trị hệ thống vẫn biết được chính xác password của user là gì. Đó là lí do tại sao ta không nên dùng một password cho tất cả các dịch vụ.

Vậy làm thế nào để bảo vệ info của user trong trường hợp này, rất tiếc về mặt kỹ thuật không có cách nào để đảm bảo việc này. Ta chỉ có thể áp dụng policy, NDA về mặt con người để hạn chế vấn đề này thôi.

9. Ref

Lưu ý:

  • Trong bài viết dùng MD5 để minh họa cho đơn giản, trong thực tế ta không dùng MD5.
  • Trong bài viết giả định kẻ tấn công bằng cách nào đó có db users, trong thực tế việc này rất khó do có các tầng bảo mật khác như thiết kế infrastructure, define rule/policy về con người … Trong bài này mình không bàn đến các vấn đề đó.

Làm sao x5 năng suất làm việc của bạn?

Ở bài trước, mình đã nói về cách duy nhất giúp bạn trở thành một developer giỏi hơn. Nếu bạn chưa đọc thì có thể đọc tại đây, tuy nhiên mình có thể giúp bạn tóm tắt lại trong một câu, đó là “bạn cần có mục đích và kế hoạch cụ thể để đạt được mục đích đó.”. Nếu mình làm tốt nhiệm vụ trong bài trước thì có lẽ bây giờ bạn đã có một kế hoạch riêng cho bản thân. Và nếu bạn đã có một kế hoạch thì bạn sẽ thấy rằng bạn có một núi công việc cần phải làm, đây là một tín hiệu tốt, vì bạn đã có những công việc cần phải làm của riêng bạn. Vì nếu bạn không tự giao việc cho bản thân, người khác sẽ làm điều đó.

Bản thân mình là một người khá bận rộn. Mình vừa làm công việc ở công ty, vừa làm dự án freelancer, làm vài đồ án ở trường, thêm việc vận hành thedarkknighttech, đọc một đống sách kỹ thuật, đến phòng gym… Mình không kể ra để khoe rằng mình có nhiều thứ cần làm, cái mình muốn nói là trên con đường trở thành một developer “giỏi hơn”, chúng ta có rất nhiều việc cần phải thực hiện. Nếu như bạn không tối ưu hóa được thời gian, hiệu suất thì con đường sẽ trở nên khó khăn hơn rất nhiều.

Một thời gian trước có một bạn developer hỏi cách mình quản lý thời gian, công việc sau khi thấy mình có thời gian ngồi đọc một quyển tiểu thuyết về tình yêu ở quán coffee. Mình chỉ cho bạn ấy một hệ thống mà mình đang áp dụng. Hôm nay mình sẽ nói với bạn về hệ thống này. Mình tin nó có thể giúp bạn x5 năng suất làm việc hiện tại.

Key 1: Sự ưu tiên (priority)

Trước khi nói về hệ thống mà mình đang áp dụng, mình nghĩ bạn nên biết một số yếu tố quan trọng để có được năng suất làm việc hiệu quả. Trong đó, quan trọng nhất, theo mình chính là priority.

Bạn chỉ cần làm vài phép tính là đủ để thấy rằng nếu trừ đi thời gian bạn dùng để ngủ, ăn uống, đi lại, chơi bời… thì bạn chỉ có khoảng 10-15 năm để đạt được tất cả những mục tiêu mà bạn đặt ra. Nếu bây giờ bạn đang 2x và nghĩ rằng bạn còn nhiều thời gian thì hãy tính toán lại một chút, bạn không có nhiều thời gian như thế đâu. Bởi vì chúng ta không có nhiều thời gian, nên ta cần quyết định xem đâu là điều quan trọng cần làm, đâu là điều không quan trọng. Công việc gì quan trọng nhất, quan trọng nhì, quan trọng ba…

Những thứ không quan trọng, bạn nên cắt bỏ. Bởi vì nó sẽ làm bạn phân tâm, bỏ bê những thứ quan trọng hơn. Từ đó không đi đến đâu cả.

Điều này áp dụng cả với kế hoạch dài hạn cũng như trong công việc hàng ngày của bạn. Nếu bạn nhìn vào lịch làm việc hàng ngày của mình, bạn sẽ thấy có những công việc được tô màu đỏ, những công việc được tô màu cam, màu xanh. Những việc màu đỏ là những việc quan trọng nhất, vì vậy mình sẽ cố gắng làm nó đầu tiên trong ngày, vì khi ấy não mình vẫn còn ổn, càng cuối ngày nó sẽ càng tệ, khi ấy mình sẽ làm những việc màu xanh.

Nhớ nhé. Mọi thứ đều có độ ưu tiên riêng của nó.

Key 2: Tận dụng người khác (Leverage)

Mình biết, mình biết, chúng ta là kỹ sư, kỹ sư thì thích tự làm mọi thứ. Nhưng đừng, nếu bạn muốn đi xa, bạn cần học cách tận dụng những nguồn lực bên cạnh bạn. Bởi vì bạn chỉ có 24 giờ một ngày, não bạn chỉ có thể hoạt động tốt trong vài tiếng, đừng cố làm hết mọi thứ.

Khi một người giỏi thứ gì đó, ví dụ như giỏi code chẳng hạn, họ thường nghĩ rằng người khác sẽ không thể làm ra sản phẩm chất lượng cao như họ. Vì vậy họ thường có xu hướng quán xuyến mọi thứ, làm cả những công việc nhỏ nhặt, từ đó bỏ bê những thứ mà lẽ ra họ nên làm ở trình độ của họ. Điển hình như một số manager, leader xuất phát từ vị trí kỹ thuật, khi họ đã ở một vị trí mà công việc của họ nên là quản lý, định hướng… nhưng họ vẫn cố gắng quản lý cả những công việc kỹ thuật nhỏ hàng ngày, bị cuốn vào những công việc linh tinh mà bỏ bê nhiệm vụ chính của mình. Tất cả chúng ta đều cần học cách tận dụng người khác.

Nếu hiện tại bạn không phải là gã tệ nhất trong nhóm, công ty thì bạn có thể thử học cách tận dụng người khác như mình nói ở đây. Hãy thử giao cho người khác (trình độ thấp hơn bạn) những công việc ít quan trọng mà bạn thường làm mỗi ngày và tin tưởng họ. Bạn sẽ thấy được sự khác biệt.

Thêm nữa, trừ khi hiện tại bạn không đủ tiền để mua một đĩa cơm gà, còn không thì bạn cũng nên tận dụng người khác trong những công việc linh tinh như giặt quần áo, dọn nhà…, không tốn quá nhiều tiền những giúp bạn tiết kiệm được rất nhiều thời gian. Hãy để dành thời gian, năng lượng cho những công việc quan trọng hơn.

Hệ thống mà mình đang áp dụng

Hy vọng bạn nắm được phần nào 2 yếu tố tối quan trọng mình đã trình bày ở trên. Chỉ cần áp dụng được 2 yếu tố này là bạn đã có thể x2 năng suất rồi. Tiếp theo sẽ là làm sao để x5.

Kỹ thuật pomodoro

Có lẽ bạn cũng đã từng nghe qua kỹ thuật này rồi. Cơ bản là bạn sẽ làm việc tập trung 100% trong vòng 25 phút, sau đó bạn sẽ được nghỉ 5 phút. Kết thúc 4 pomodoro, bạn sẽ được nghỉ 15 phút.

Kỹ thuật này hiệu quả bởi một vài lý do. Thứ nhất là một số nghiên cứu đã chỉ ra rằng não của bạn chỉ có thể tập trung 100% trong khoảng thời gian từ 25 đến 50 phút, từ 50 phút trở đi bạn sẽ dần mất tập trung. Thứ 2, quan trọng hơn, mọi người thường đánh đồng “làm việc” với việc vừa làm vừa check facebook, check mail, nói chuyện với đồng nghiệp… Với kỹ thuật pomodoro, bạn sẽ làm việc tập trung tối đa trong một khoảng thời gian ngắn. Không facebook, không mail, không nói chuyện, không đi uống nước, không đi vệ sinh…

Hệ thống

Bạn có thể thấy trong hình trên, mình sử dụng trang kanbanflow để chia 1 tuần làm việc của mình thành nhiều cột từ thứ hai đến chủ nhật, ngoài ra còn có cột “Today”, “Done”, “Next week”, “Later”. Vào mỗi tối chủ nhật, mình sẽ ngồi suy nghĩ và lên kế hoạch làm việc cho cả tuần tiếp theo. Sau đó, ví dụ như ngày thứ 3, mình sẽ kéo hết công việc trong cột “Tuesday” sang cột “Today” để thực hiện, vào cuối ngày, các công việc ở cột “Today” sẽ nằm ở cột “Done” hoặc được chuyển qua những ngày sau nếu mình chưa thể thực hiện xong.

Với từng công việc cụ thể ở mỗi ngày, mình áp dụng kỹ thuật pomodoro đã nói ở trên. Đơn giản là click bấm giờ và làm, sau 25 phút chuông sẽ reo và mình được nghỉ 5 phút. Cứ như vậy cho đến khi mình hoàn thành 10 pomodoro trong 1 ngày. Tổng thời gian vào khoảng hơn 4 tiếng làm việc tập trung.

Gần đây, thay vì lướt facebook trong khoảng nghỉ 5 phút, 15 phút mình đã chuyển sang đọc sách. Như vậy là mình có thêm khoảng 50 phút đọc sách mỗi ngày, học thêm được khá nhiều thứ. Bạn không cần thiết phải làm như mình, mình thích đọc nên đọc thôi.

Kết

Mình muốn bạn vào kanbanflow và thử áp dụng hệ thống mà mình đã giới thiệu ở đây. Quan trọng là bạn cần dành cho nó một chút thời gian luyện tập, khi mới áp dụng đôi khi sẽ gặp một só khó khăn.

Đó là tất cả những gì mình muốn nói với bạn hôm nay. Take care!

Cách duy nhất giúp bạn trở thành một developer giỏi hơn

Một developer giỏi hơn, mình muốn giải thích một chút về cụm từ này, bởi vì đa phần mỗi người sẽ có một cách hiểu khác nhau. Ví dụ như, một developer tên là Thích Văn Tiền, giỏi hơn sẽ là kiếm được nhiều tiền hơn. Một developer với mong muốn đem lại lợi ích cho cộng đồng, đóng góp vào bước tiến chung của nhân loại thì giỏi hơn đồng nghĩa với việc tinh thông kỹ thuật, công nghệ hơn. Có cả tá định nghĩa cho cụm từ này. Nhưng mà, cũng có một kiểu developer, developer kiểu này không biết thế nào là giỏi hơn cả. Bạn có thuộc kiểu này không? Mình muốn bạn có một định nghĩa rõ ràng cho việc “giỏi hơn” trước khi đọc tiếp.

Dĩ nhiên là ai cũng muốn trở thành một developer giỏi hơn cả, nhưng khi gặng hỏi rằng giỏi hơn là giỏi như thế nào thì rất hiếm người có thể trả lời một cách rành mạch. Lý do mình muốn bạn có một định nghĩa trước khi đọc tiếp là bởi vì chúng ta sẽ chẳng thể đi tới đâu nếu không có một mục tiêu cụ thể. Nó cũng giống như việc một anh béo muốn giảm cân để tán tỉnh em hàng xóm, anh ta luôn miệng nói rằng muốn giảm cân, giảm cân. Nhưng chỉ cần bạn hỏi xem giảm cân là giảm bao nhiêu cân, khi nào hoàn thành, giảm như thế nào thì anh ta im bặt. Vì thế anh ta không bao giờ có thể giảm cân. Tương tự cho việc bạn muốn cải thiện và trở nên giỏi hơn.

Xem như bây giờ bạn đã có một định nghĩa cơ bản về việc bạn muốn giỏi hơn như thế nào. Bước tiếp theo là cách duy nhất giúp bạn đạt được điều đó, bạn cần có một kế hoạch.

Ngày đó sẽ không bao giờ tới

Cái ngày mà bạn bằng một cách nào đó sẽ trở nên giàu có, bằng một cách nào đó có một body chuẩn, bằng một cách nào đó trở thành một developer giỏi hơn sẽ không bao giờ tới. Mình thấy có một chuyện khá buồn cười là nhiều người tin rằng họ sẽ đạt được những thứ họ muốn trong tương lai, trong khi hiện tại họ không có bất cứ một kế hoạch nào để đạt được những điều đó cả. Giống như một anh mù cứ bước đi theo quán tính và hy vọng sẽ tới được quán bia ở đầu làng. Thế giới không có đủ may mắn để chia cho tất cả mọi người.

Nếu như bây giờ mình hẹn bạn đi coffee vào sáng ngày mai và hỏi “tại sao hôm nay bạn lại đi làm?”. Bạn sẽ trả lời như thế nào?

2 loại mũ

Để trở thành một developer giỏi hơn hay để đạt được những thứ bạn muốn thì bạn cần có 2 cái mũ. Một cái màu trắng và một cái màu đen, trong đó cái màu trắng đại diện cho vai trò “Leader/manager“, cái màu đen đại diện cho vai trò “Worker“. Dĩ nhiên là bạn không cần phải mua 2 cái mũ thật, mình nói thế cho dễ hình dung thôi.

Với 2 loại mũ này, bạn sẽ đội cái màu trắng, trở thành một leader và lên kế hoạch cho những mục tiêu mà bạn hướng tới. Sau khi đã có kế hoạch, bạn cất cái mũ trắng đi, đội cái mũ đen lên và làm việc như một con ngựa theo kế hoạch mà thằng leader mũ trắng đã đề ra. Khi đội mũ đen, bạn không được suy nghĩ, đặt câu hỏi về bất cứ thứ gì trong kế hoạch cả, đó là việc của thằng mũ trắng. Bạn cần tin tưởng thằng mũ trắng, vì đó là phiên bản tốt nhất của bạn. Sau một khoảng thời gian nhất định, tùy vào kế hoạch của bạn, bạn cần cất cái mũ đen đi và đội lại cái mũ trắng, lúc này bạn sẽ chỉnh sửa, thay đổi kế hoạch dựa trên những trải nghiệm thực tế mà bạn đã trải qua để có một kế hoạch phù hợp hơn. Sau đó bạn đội lại cái mũ đen và làm việc như một con ngựa.

Bạn nên dành 10% thời gian làm leader, 90% thời gian làm worker. Đừng quá sa đà vào việc suy nghĩ, lên kế hoạch. Bởi vì cái quan trọng nhất vẫn là hành động, có kế hoạch mà không có hành động thì cũng chỉ là kẻ nói miệng mà thôi.

Làm sao để lên kế hoạch

Đầu tiên là bạn cần có một định nghĩa rành mạch về giỏi hơn như mình đã nói ở trên. Bởi vì mọi kế hoạch đều cần bắt đầu từ mục đích. Hãy nhớ là mục đích càng rõ ràng thì khả năng bạn đạt được chúng càng cao.

Zoom nhỏ bức tranh

Theo kinh nghiệm của mình, thông thường cụm từ “giỏi hơn” đối với developer chúng ta sẽ tương ứng với khoảng thời gian 5-10 năm. Mình thấy rất nhiều bạn định nghĩa giỏi hơn là “lương 100 củ, làm việc ở Sin, Mỹ“, đó là một mục tiêu 5 năm. Vì vậy, khi đội mũ trắng và lên kế hoạch, bạn cần zoom nhỏ bức tranh để có những cái nhìn tổng quát nhất về mục tiêu của bản thân, cách để đạt được chúng. Có nghĩa là nhìn xa hơn.

Lên kế hoạch cụ thể

Cụ thể nhưng cũng không cần cụ thể quá mức, bởi vì bạn không thể dự đoán những thứ sẽ xảy ra với kế hoạch của bạn trong tương lai. Chúng ta chỉ cần có kế hoạch ở mức độ vừa phải, sau đó sẽ điều chỉnh trong khi thực hiện. Mình không có quá nhiều thứ để nói ở phần này, bởi vì nó sẽ khác nhau đối với mỗi người. Tuy nhiên, mục tiêu cuối cùng là sau khi đã có kế hoạch, mỗi việc bạn làm hàng ngày đều phải hướng bạn đến mục tiêu mà bạn đã đề ra.

Tin tưởng quá trình

Việc khó nhất đã xong. Bây giờ thì đội lại cái mũ đen và làm những thứ bạn cần làm thôi. Quan trọng nhất là bạn cần tin tưởng quá trình. Có nghĩa là trong khi làm việc theo những kế hoạch đã đề ra, đôi khi bạn sẽ cảm thấy có gì đó không ổn lắm. Ví dụ như là trong kế hoạch có ghi “5h sáng: đọc sách kỹ thuật”, nhưng khi chuông báo thức reo thì bạn bắt đầu suy nghĩ, rồi bịa ra cả đống lý do để bác bỏ cái kế hoạch đó. Đừng làm như thế, bạn cần tin tưởng quá trình, có nghĩa là tin tưởng thằng leader mũ trắng. Đừng bao giờ tin vào những suy nghĩ của thằng worker mũ đen, vì nó bao giờ cũng lười biếng cả. Dĩ nhiên là cuộc chiến lúc 5h sáng thì không dễ dàng gì, nhưng hãy có gắng tin tưởng và thực hiện những gì bạn đã đề ra. Rồi bạn sẽ cảm thấy vui vì đã làm như vậy.

Cuối cùng

Đó là tất cả những gì mình muốn nói với bạn hôm nay. Hy vọng bạn cảm thấy hữu ích. Đừng quên comment chia sẻ mục tiêu, kế hoạch để trở thành một developer giỏi hơn của bạn với mình và mọi người nhé.

Bảo trọng!

Tại sao Google lại tìm kiếm rất nhanh?

Vào thời đại công nghệ như ngày nay thì việc tìm kiếm thông tin cũng trở nên rất quan trọng. Thử hỏi nếu 1 ngày Google không hoạt động thì thế giới sẽ như thế nào nhỉ? Chắc mình sẽ bị rơi vào thời kì đồ đá mất.

Dùng nhiều Google nhưng nhiều lúc băn khoăn không biết vì sao Google lại tìm kiếm cho ra kết qủa nhanh như vậy.

Search Engine gồm 3 bộ phận chính.

Đó là Search Server, Index, Search Backend.

Trong đó:

  • Search Server đảm nhiệm việc trả về kết quả tìm kiếm cho người dùng.
  • Seach Backend đảm nhiệm việc thu thập thông tin toàn bộ website trên toàn thế giới.
  • Index giống như 1 cơ sở dữ liệu được sử dụng bởi Search Server và Search Backend.

Nhiệm vụ chính của Search Server là trả về kết quả tìm kiếm của người dùng nhanh nhất có thể. Bởi vì nếu không trả về ngay lập tức mà mất 10s, 1 phút, 2 phút mới trả về kết quả thì quả thực sẽ không thể trở thành 1 công cụ tìm kiếm được. Do đó Search Server sẽ được thiết kế để trả về kết quả nhanh nhất có thể.

Mặt khác, nhiệm vụ của Search Backend thì khác hoàn toàn với Search Server. Cho dù xử lí mất 5p, 10p hay 1 tiếng đi chăng nữa thì cũng không thành vấn đề. Miễn là nó thu thập dữ liệu từ toàn bộ website trên toàn thế giới và tạo ra Index mà Search Server dễ dùng là được.

Nhiệm vụ chính của thằng Index là lưu thông tin toàn bộ dữ liệu đã được thu thập từ Search Backend. Khi người dùng tìm kiếm, Search Server chỉ cần tìm trong Index và trả về kết quả là xong. Chứ không phải lúc đó mới bắt đầu đi thu thập dữ liệu và trả về đâu nhé.

Ví dụ như khi tìm kiếm với từ khoá “lập trình” thì khi đó từ khoá “lập trình” đã có sẵn trong Database (hay là Index) của Google rồi. Và nó chỉ trả về kết quả là xong.

Chính vì điều đó mà khiến cho Search Server luôn trả về kết quả ngay tức khắc là vì thế.

Đến đây ít nhiều chúng ta cũng đã hiểu được vì sao Google lại hoạt động nhanh đến thế. Vậy chúng ta thử đi tìm hiểu xem cụ thể bên trong nó hoạt động như nào nhé

Về cơ bản thì Search Server nó cũng không khác gì Web Server cả. Nó chủ yếu đảm nhiệm những nhiệm vụ chính sau:

  • Quản lí truyền thông với người dùng
  • Phân tích request từ người dùng
  • Tìm kiếm thông tin cần thiết từ Index
  • Trả kết quả về cho người dùng

Quay lại với ví dụ bên trên, giả sử như người dùng tìm kiếm với từ khoá “lập trình”. Khi đó lúc này ở Index đã thực sự có kết quả về “lập trình” rồi. Và Search Server chỉ cần lấy kết quả từ Index trả về cho người dùng là xong nhiệm vụ.

Trong trường hợp mà Index không có kết quả nào, thì khi đó Search Search trả về kết quả là “Hiện tại không tìm thấy kết quả nào” đến cho người dùng.

Do đó việc tổ chức dữ liệu trong Index để làm sao mà Search Server có thể lấy nhanh nhất là 1 điều vô cùng quan trọng.
So với Search Server thì Search Backend quả thực nó phức tạp hơn rất nhiều. Về cơ bản Search Backend sẽ bao gồm 2 thành phần chính đó là “Crawling” và “Tạo Index“.

Crawling là có nhiệm vụ đi thu thập toàn bộ trang web trên toàn thế giới về để xử lý. Vì công việc này vô cùng mất thời gian nên nó đã phân tách ra thành nhiều bộ phận con hơn để xử lý, đó là Crawler.

Hiện nay trên toàn thế giới chắc phải có đến tỉ tỉ website mất. Vậy mà Google đi thu thập từng đó website về để phục vụ cho người dùng thì quả thực quá kinh khủng.

Nhưng vì quá trình crawl, thu thập đến việc tạo Index là vô cùng mất thời gian. Nên bạn nào có blog riêng mà sau khi viết bài xong, search trên Google nó không ra là vì thế. Phải đợi Google crawl đến trang web của mình thì lúc đó các bạn search trên Google mới ra được.

Những trang web mà Crawler thu thập sẽ lưu tạm thời vào 1 nơi giống như cơ sở dữ liệu, cái này được gọi là Repository (kho).

Bộ phận tạo Index (Index Creation) sẽ lấy trang web từ Repository ra để phân tích, xử lý và cuối cùng là tạo ra Index để cho Search Server dùng.

Đối với Search Engine thì đây là 1 công việc vô cùng vô cùng mất thời gian. Chính vì luôn có thằng tạo trước dữ liệu như vậy mà đã làm cho Google luôn trả về kết quả ngay như tức thì.

Vậy khi nào thì Google sẽ crawl trang web của mình?

Với trang web nào nhiều người yêu thích, nội dung chất lượng thì luôn luôn được ưu tiên crawl trước. Những trang web nào nội dung kém chất lượng thì sẽ mất tầm 3 đến 1 tuần mới được crawl.

Làm thế nào để thúc Google crawl trang của mình?

Google cung cấp 1 trang để gửi yêu cầu thực hiện crawl. Chỉ cần vào đó đăng kí tên website, gửi nội dung trang muốn crawl là được. Còn nếu không thực hiện thì mình khẳng định sẽ mất tầm từ 3 đến 7 ngày mới được crawl.
Nhiệm vụ chính của Index là lưu dữ liệu 1 cách an toàn và giúp Search Server trả về kết quả nhanh nhất có thể. Để dễ hình dùng thì chúng ta có thể xem Index như là 1 Database.

Trong Index có rất nhiều thông tin, phù hợp với nhiều mục đích tìm kiếm khác nhau.

Ở trong 1 Search Engine thì Index chính là 1 “cấu trúc dữ liệu” mà chỉ có Search Engine mới có thể hiểu được.

Nên việc thiết kế Index như nào, tổ chức dữ liệu ra sao để cho Search Server có thể query và trả về kết quả nhanh nhất có thể là điều vô cùng quan trọng. Và bài hôm nay mình sẽ không đi sâu vào giải thích cách tổ chức dữ liệu của Index nữa. Vì như thế có thể sẽ rất dài và càng làm cho bài viết trở nên phức tạp.

Nên tạm thời mình sẽ dừng ở đây.

Tổng kết

  • Search Engine sẽ bao gồm 3 bộ phận sau:
  • Search Server: nhận yêu cầu từ người dùng, truy vấn trong Index để lấy kết quả và trả kết quả về cho người dùng.
  • Search Backend:Có nhiệm vụ đi thu thập thông tin của toàn bộ trang web trên toàn thế giới, phân tích, xử lý và tạo ra Index để dùng cho Search Server. Search Backend này hoạt động 24/24 không ngừng nghỉ.
  • Index giống như 1 database được tổ chức dữ liệu hợp lý giúp cho Search Server có thể truy vấn 1 cách nhanh nhất có thể.

Các bạn thấy thế nào? Đã hình dung được tại sao mà Google luôn trả về kết quả nhanh như vậy chưa ak?

Mặc dù bài viết này không giúp các bạn tạo ra được 1 Search Engine nhưng ít nhiều cũng giúp các bạn có 1 chút hình dung Search Engine nó làm việc như thế nào.

Tạo trang giống vầy với WordPress.com
Hãy bắt đầu