Khi sử dụng SQL, chắc hẳn các bạn đã biết có một cái gọi là NULL (mình gọi là cái vì NULL không phải là một giá trị) Để so sánh với NULL thì các bạn sẽ dùng toán tử is và is not thay vì =(equal) hoặc là <>(not equal)
null.sql
1
SELECT*WHEREfieldISNULL
Bạn đã bao giờ tự hỏi tại sao lại không dùng (=) và (<>). Đầu tiên chúng ta hãy thử nhé
và kết quả nhận được sẽ là “2” và “5”. Từ đấy có thể thấy một điều đơn giản là: để so sánh với NULL chúng ta chỉ có thể dùng IS và IS NOT. Vậy nếu bạn thực hiện các phép toán với NULL thì sao? Mọi phép toán như cộng ,trừ ,nhân ,chia ,concat mà có sự tham gia của NULL đều cho kết quả là NULL cả.
Đầu tiên để hiểu lý do thì chúng ta phải biết là tại sao lại có giá trị NULL. Giá trị NULL trong SQL mục đích chính là để nhằm tạo ra một cách thể hiện cho cái gọi là “không có thông tin hoặc thông tin không phù hợp” (missing information and inapplicable information). Do đó về mặt tự nhiên, bạn sẽ nói là field X không có thông tin, chứ sẽ không nói là field X bằng (equal) không có thông tin, đúng không. Tuy nhiên lý do trên không có giá trị về mặt giải thích.
Để giải thích cặn kẽ thì chúng ta phải đi lại một chút về khái niệm Logic. Về mặt toán học thì có rất nhiều loại LOGIC. Boolean logic được biết đến nhiều nhất. Bản chất của Boolean là chỉ tồn tại 2 giá trị TRUE, FALSE và các phép toán trên chúng. Do đó Boolean được xếp vào loại 2VL (2 valued logic). Tuy nhiên logic trong SQL rất tiếc lại không phải Boolean, vì trong SQL sẽ tồn tại 3 khái niệm logic: TRUE, FALSE, và Unknown ( hay chính là NULL ). Do đó logic trong SQL gọi là 3VL (3 valued logic). Trong Boolean chỉ có 2 phép so sánh là equal (=) và not(<>), tuy nhiên với 3VL như SQL sẽ có thêm phép so sánh là IS và IS NOT. Kết hợp 3 loại giá trị với các phép so sánh đó sẽ cho chúng ta kết quả là 3 loại bảng truth table dưới đây:
(trích dẫn từ Wikipedia)
Trên đây là những kiến thức hết sức basic về giá trị NULL trên SQL, hy vọng có thể giúp các bạn đỡ nhầm lẫn khi thực hiện các phép toán với NULL.
Ở bài viết trước tôi đã đề cập đến cách sử dụng mock để viết unittest. Unittest có tác dụng không chỉ trong việc đảm bảo các đoạn code mới được viết thêm không phá vỡ các yêu cầu logic trước đó, trong bài viết này, tôi sẽ chia sẽ các kinh nghiệm sử dụng unittest để refactoring các đoạn code
Một trong những vấn đề khi viết các hàm đó là các hàm thường quá phức tạp. Robert Martin trong cuốn sách “Clean code - a handbook of Agile Software Craftmenship” đã nói về nói về các quy tắc khi thiết kế hàm: Quy tắc đầu tiên của function đó là chúng nên nhỏ, quy tắc thứ hai là chúng nên nhỏ hơn thế nữa" (The first rule ò functions is that they should be small. The second rule of functions is that they should be smaller than that). Function càng ngắn thì càng dễ hiểu, function càng ngắn thì nó càng tách biệt so với các hàm khác. Và hơn thế nữa hàm càng ngắn, thì test càng đơn giản. Vậy làm thế nào để biết function bạn viết là đủ ngắn hay chưa? Nếu để test 1 hàm cần tới hơn 20 dòng code, theo bản thân tôi, hàm đó nên được viết lại.
Hãy xét một ví dụ sau
models.py
1234567891011121314151617181920212223
classOrder(models.Model):# define fields in heredefcreate_final_pdf_file(self,client_order_id):front_image=self.tree.create_frontcover_image()back_image=self.tree.create_backcover_image(client_order_id)ifself.order_type==Order.SOFT_COVER:frontcover_file=pdf.create_pdf_from_images([image_helper.save_image(front_image),None],self.book_size)backcover_file=pdf.create_pdf_from_images([None,image_helper.save_image(back_image)],self.book_size)input_files=[frontcover_file,self.cached_pdf_file,backcover_file]elifself.order_type==Order.HARD_COVER:hardcover_image=self.create_hardcover_image(back_image,front_image)hardcover_size=self.PDF_SIZES[self.size_type]hardcover_file=pdf.create_pdf_from_images([image_helper.save_image(hardcover_image)],hardcover_size)input_files=[hardcover_file,self.cached_pdf_file]new_path=pdf.merge_pdf_files(input_files)returnnew_path
Hàm create_final_pdf_file nhận tham số là một client_order_id, tạo ra một pdf file tương ứng client_order_id, và trả về đường dẫn của pdf file đó. Hàm này tạo ra một ảnh cover trước, và ảnh cover sau, sau đó ghép với một file pdf có sẵn để tạo nên final_pdf.
Tuy nhiên tuỳ theo giá trị của self.order_type mà cách tạo các ảnh trước và ảnh sau là khác nhau.
Nếu chỉ dừng ở đây, bản thân tôi, thấy khá hài lòng với hàm create_final_pdf_file. Hàm dài vừa đủ, không quá dài (19 lines), chỉ có một input đầu vào, và 1 output đầu ra. Tuy nhiên, nếu viết testcase cho hàm này, chúng ta sẽ thấy có vấn đề
Đoạn code test trên có vấn đề gì? Để test hàm create_final_pdf_file, chúng ta cần viết 2 test case, cho 2 trường hợp trong đoạn code if-else. Và 2 đoạn code test bị lặp lại khá nhiều, đặc biệt là ở việc mock các objects. Chúng ta có thể viết lại test case gọn hơn bằng cách viết một function chung, hoặc một function tạo ra các mock object và gọi nó trong từng hàm test. Nhưng liệu có phải đó là vấn đề chính.
Điều tôi muốn nói ở đây là: Code smell trong test code có nguyên nhân từ test code, hay từ bản thân đoạn code chúng ta muốn test. Hãy xem lại hàm create_final_pdf_file. Hàm nãy đã thực sự tốt? Một hàm tốt, là một hàm chỉ nên làm một việc. Hàm create_final_pdf_file ở đây, ngoài việc gọi các hàm khác, còn thêm vào nó đoạn xử lý logic xét kiểu của order. Đoạn code if-else xử lý 2 logic khác nhau, chúng nên được tách ra thành một hàm khác.
Hàm create_final_pdf_file sau khi được refactoring, đã trở nên đơn giản và dễ đọc hơn, thay vì phải lướt qua 19 lines, và đọc hiểu logic của đoạn code if-else, giờ đây bạn có thể hiểu nó chỉ bằng create_input_files. Và code test mới cho hàm create_final_pdf_file như sau
Việc tách logic của đoạn code tạo 2 input files ra thành một hàm create_input_files, làm cho hàm create_final_pdf dễ hiểu hơn, nói cách khác, nó che giấu thông tin không cần thiết cho lập trình viên khi đọc tới đoạn code của create_final_pdf. Hàm create_final_test giờ đây không làm gì khác ngoại việc gọi tới các hàm khác. Không có bất cứ logic nào được đặt trong hàm này. Trên thực tế rất nhiều lập trình viên sẽ không viết test cho những hàm như create_final_pdf nữa. Họ chỉ cần viết test cho 4 hàm create_input_files, create_backcover_image, create_frontcover_image, và cached_pdf_file là đủ.
Tóm lại, bạn có thể tìm kiếm code smell trong unittest, và refactoring hàm mà unittest đó muốn test
Ý nghĩa: p có giá trị giống greeting, giá trị của p không đổi, và nó là 1 con trỏ, trỏ đến dữ liệu kiểu chả, và dữ liệu của là hằng số.
Cuối cùng
Quy tắc xoắc ốc giúp ta hiểu ý nghĩa khai báo C/C++ một cách dễ dàng. Bây giờ với quy tắc này, bạn chắc chắn khai báo dưới đây dễ hiểu như ăn kẹo rồi phải không? void (signal(int, void (fp)(int)))(int);