Trích rút vấn đề nhỏ không liên quan
Một kỹ sư không chỉ biết code mà phải biết chia những vấn đề lớn thành những vấn đề nhở và giải quyết lần lượt từng vấn đề một. Hay nói ngắn gọn lại là “Chia để trị”.
Trong bài viết này mình sẽ đưa ra vài lời khuyên để đồng nhất, trích rút chương trình con. Cụ thể là:
- Nhìn vào một function hoặc môt block (gọi chung là chương trình con), hãy tự hỏi rằng “Mục đính cao hơn của đoạn code này là gì”
- Mỗi dòng code nó đã thực hiện trực tiệm mục đích đó chưa? Hoặc nó có bị lập lại không?
- Nếu nhiều dòng giải quyết những tính toàn không liên quan thi viết tách ra thành một hàm riêng
Việc viết thanh hàm chác hản chúng ta làm hàng ngày nhưng trong bài viết này mình sẽ tập chung vào các viết nhưng chương trình con một cách rõ ràng
Bắt đầu với ví dụ đầu tiên bằng Javascript là hàm tìm vị trí gần nhất từ một tập các điểm bao gồm kinh độ và vĩ độ
// Return which element of ‘array’ is closest to the given latitude/longitude.
// Models the Earth as a perfect sphere.
var findClosestLocation = function (lat, lng, array) {
var closest;
var closest_dist = Number.MAX_VALUE;
for (var i = 0; i < array.length; i += 1) {
// Convert both points to radians.
* var lat_rad = radians(lat);*
* var lng_rad = radians(lng);*
* var lat2_rad = radians(array[i].latitude);*
* var lng2_rad = radians(array[i].longitude);*
* // Use the “Spherical Law of Cosines” formula.*
* var dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +*
* Math.cos(lat_rad) * Math.cos(lat2_rad) **
* Math.cos(lng2_rad – lng_rad));*
if (dist < closest_dist) {
closest = array[i];
closest_dist = dist;
}
}
return closest;
};
Trong vòng lăp có một đoạn chương trình con không hê liên quan đến phạm vi bên ngoài của nó chúng ta nên viết nó thành một hàm riêng thay vì phải comment “Convert both points to radians” (Nếu chưa nhớ ngay được công thức lượng giác có thể tra google)
var **spherical_distance** = function (lat1, lng1, lat2, lng2) {
var lat1_rad = radians(lat1);
var lng1_rad = radians(lng1);
var lat2_rad = radians(lat2);
var lng2_rad = radians(lng2);
// Use the “Spherical Law of Cosines” formula.
return Math.acos(Math.sin(lat1_rad) * Math.sin(lat2_rad) +
Math.cos(lat1_rad) * Math.cos(lat2_rad) *
Math.cos(lng2_rad – lng1_rad));
};
Code viền thành hàm spherical_distance() sẽ dễ đọc hơn rất nhiều và không cần comment
Code nguyên gốc
Đây là những chương trình sử lý nhưng công việc cơ bản như sử lý chuỗi, sử dụng bảng băm hay đọc ghi file.
Ví dụ cần đọc nội dung một file: trong php bạn có thể gọi file_get_contents(“filename”) hoặc trong Python open(“filename”).read(). Nhưng trong C++ không được gọn gàng như vậy
ifstream file(file_name);
// Calculate the file’s size, and allocate a buffer of that size.
file.seekg(0, ios::end);
const int file_size = file.tellg();
char* file_buf = new char [file_size];
// Read the entire file into the buffer.
file.seekg(0, ios::beg);
file.read(file_buf, file_size);
file.close();
…
Trường hợp này lên viết lại môt hàm và cớ thể build lai gọn gàng hơn và sử dụng cho mỗi Prọject
Code có mục đích khác
Trong nhiều ừng dụng Web, gần như khi chúng ta sử dụng ajax đều phải có một dialog thông bảo phẩn hồi bằng hàm alert();. Và việc sử lý đưa ra thông bào không liên quan đến phần gửi request
ajax_post({
url: ‘http://example.com/submit’,
data: data,
on_success: function (response_data) {
** var str = “{\n”;**
** for (var key in response_data) {**
** str += ” ” + key + ” = ” + response_data[key] + “\n”;**
** }**
** alert(str + “}”);**
// Continue handling ‘response_data’ …
}
});
Và hầu như không ai chịu viết tách khối vòng lắp ra ngoài
var format_pretty = function (obj) {
** var str = “{\n”;**
** for (var key in obj) {**
** str += ” ” + key + ” = ” + obj[key] + “\n”;**
** }**
** return str + “}”;**
};
Nhưng lợi ích không ngờ
Trong ví dụ phần trên đưa vào hàm format_pretty(); là một ý tưởng hay, đơn gian và thuân tiện. Tuy nhiên thi nhiều lý do tuyệt vời khác. Nó dẽ cái tiến khi phần sử lý này chỉ có một mình. Và giả sử nó có 2 thay đổi như sau:
- Hiển thi biến obj ra object, nếu nó là môt chuỗi văn bản thuần túy hoặc undefined sẽ ném ra ngoại lệ
- Hiển thi giá trị của object. Nếu in trược tiếp ra bao giờ nó cũng là [object Object]
var **format_pretty** = function (obj, indent) {
// Handle null, undefined, strings, and non-objects.
if (obj === null) return “null”;
if (obj === undefined) return “undefined”;
if (typeof obj === “string”) return ‘”‘ + obj + ‘”‘;
if (typeof obj !== “object”) return String(obj);
if (indent === undefined) indent = “”;
// Handle (non-null) objects.
var str = “{\n”;
for (var key in obj) {
str += indent + ” ” + key + ” = “;
str += **format_pretty**(obj[key], indent + ” “) + “\n”;
}
return str + indent + “}”;
};
- Thay vi phải sửa tất cả những chỗ có ajax thì chỉ phải sửa duy nhất ở một hàm.
Chia chức năng dự án rành mạch
Ví dụ một người king doanh cần xem lại Website. Đoạn code Phyton này tạo ra mọt đối tượng Business và thiết lập tên, url, ngày tạo
business = Business()
business.**name** = request.POST[“name”]
url_path_name = business.name.lower()
url_path_name = re.sub(r”[‘\.]”, “”, url_path_name)
url_path_name = re.sub(r”[^a-z0-9]+”, “-“, url_path_name)
url_path_name = url_path_name.strip(“-“)
business.**url** = “/biz/” + url_path_name
business.**date_created** = datetime.datetime.utcnow()
business.save_to_database()
name, url, date_create la 3 phần chính cần phải thiết lập. Cần quan tâm đên url thiết lập bằng regular expression nếu tên là “P.GS, TS Phạm Văn Đông” url sẽ được gán là /biz/pham-van-dong. Và ở đây cần tách doạn tạo url ra
CHARS_TO_REMOVE = re.compile(r”[‘\.]+”)
CHARS_TO_DASH = re.compile(r”[^a-z0-9]+”)
def **make_url_friendly**(text):
text = text.lower()
text = CHARS_TO_REMOVE.sub(”, text)
text = CHARS_TO_DASH.sub(‘-‘, text)
return text.strip(“-“)
Và giờ format code sẽ đều đặn hơn rất nhiều
business = Business()
business.**name** = request.POST[“name”]
business.**url** = “/biz/” + **make_url_friendly**(business.name)
business.**date_created** = datetime.datetime.utcnow()
business.save_to_database()
Tạo một interface mà bạn cần
Khi có một đối tượng json { “username”: “…”, “password”: “…” } cần mã hóa và đưa vào URL và sử dụng lớp Cipher để chuỷen thành chuôi ma hóa không phải là một đường dẫn nữa. Nhưng khi cần một URL có độ tin cậy cao hơn
user_info = { “username”: “…”, “password”: “…” }
user_str = json.dumps(user_info)
**cipher** = **Cipher**(“aes_128_cbc”, key=PRIVATE_KEY, init_vector=INIT_VECTOR, op=ENCODE)
encrypted_bytes = **cipher.update**(user_str)
encrypted_bytes += **cipher.final**() # flush out the current 128 bit block
url = “http://example.com/?user_info=” + base64.urlsafe_b64encode(encrypted_bytes)
…
Nhưng để rõ hơn là chúng ta muốn tạo ra một URL bảo mật hơn thay vi chỉ tạo ra một URL nên viết thành một hàm khác
def url_safe_encrypt(obj):
obj_str = json.dumps(obj)
cipher = Cipher(“aes_128_cbc”, key=PRIVATE_KEY, init_vector=INIT_VECTOR, op=ENCODE)
encrypted_bytes = cipher.update(obj_str)
encrypted_bytes += cipher.final() # flush out the current 128 bit block
return base64.urlsafe_b64encode(encrypted_bytes)
user_info = { “username”: “…”, “password”: “…” }
url = “http://example.com/?user_info=” + **url_safe_encrypt**(user_info)
Tổng hợp
Một cách đơn giản về chường này là tách các mã tổng quát từ dự án cụ thể. Khi kết thúc dự án, hầu hết cắc code chung sẽ được say dụng thành thư viện nhỏ và các hàm hỗ trợ
Lý do chính của kỹ thuật này giúp lập trình viên tập chung nhỏ hơn, các vấn đề được xác định rõ tách ra khỏi dự án của bạn. và kết quả la nhưng vấn đền hỏ được giải quyết triệt đẻ, chính xác hơn. Bạn cũng có thể sử dụng lại