Lập trình và Toán học
Phần 1: Tự truyện
Tui và Toán đã từng là hai kẻ thù không đội trời chung trong suốt hơn mười lăm năm ròng rã. Ngay từ ánh nhìn đầu tiên đã ghét nhau rồi...
Trong suốt thời gian mài đ*
t trên ghế nhà trường, bọn tui không hề nhìn mặt nhau lấy một lần. Cứ tới giờ toán là tui lại ngồi móc c*
c mũi mơ mộng, bôi trét lên áo con bạn ngồi cạnh bên để rồi trên cánh tay lúc nào cũng chi chít toàn là vết cào cấu, mặc sức cho cô giáo tìm đủ mọi cách để kéo đám tụi tui về với thực tại. Nhỏ nhẹ ân cần có, la hét mắng nhiết xối xả như vòi phun Phô-mô-xa cũng có. Tất cả đều không dủ để ép một thằng con nhà họa sĩ là tui đây cảm thấy hứng thú với môn toán.
Học cấp 1 thì môn toán hãy còn khá là dễ, như móc c*
c mũi vậy. Cũng chỉ là ba cái phép cộng trừ đơn giản, nhân chia cũng muỗi nốt. Gì chứ ba cái trò điền số hay toán tử vào ô trống, thằng tôi đây thừa sức ngồi đếm bằng 10 đầu ngón tay, khi cần thì có thể huy động luôn vài ngón chân lên support. Vốn sẵn thông minh hiếu động rồi (okay, tui biết là tui hơi thiếu khiêm tốn mà) nên tui cứ đủng đỉnh mà vượt qua không ngần ngại.
Tuy thường xuyên đạt điểm 8, 9, nhưng 10 thì hơi hiếm vì tui không tài nào hiểu được các dạng bài nâng cao. Tui hãy còn nhớ rất rõ bản thân tự hỏi một câu hỏi không có ai giải đáp (vì không dám hỏi), là vì thế quái nào mà ông anh tui (lúc đó học lớp 8) lại vò đầu bứt tai một hồi rồi quay sang phán: "Cái này là toán cấp 2, sao cô lại cho mày làm, anh có giải thì trình mày cũng chưa hiểu được bài này đâu." khi thằng tui (lớp 3) vô tình hỏi ổng về một bài toán nâng cao cô vừa ra ở lớp.
Lên cấp 2 thì mối thù truyền kiếp của tui và Toán càng trở nên sâu sắc khi mãi đến đầu năm lớp 8 hay lớp 7 gì đó, tui mới thực sự hiểu thế nào là "định lý Pytago" (học đầu năm lớp 6), qua một buổi thực hành môn toán hiếm hoi duy nhất trong đời. Tui vẫn còn nhớ như in thằng tui cầm cây thước bảng dài xấp xỉ chiều cao của những thằng con trai trong lớp chiến đấu một trận thư hùng với thằng bạn thân bên tổ khác, để rồi lãnh 2 thằng 2 gậy vào mông từ cô giáo. Hình như hơi lạc đề...
Nội dung bài thực hành năm đó đại khái là chờ nắng lên, nghe đâu là lúc 10h sáng, mặt trời với mặt đất lệch nhau 1 góc bao nhiêu độ đó, rồi cần cây thước đo chiều dài bóng của cái cột cờ, đã biết chiều dài của cây thiết bảng, à nhầm, thước bảng. Áp dụng định lý Pytago ta có thể tính được chiều cao của cái cột cờ. Đó là lần đầu tiên tui biết được môn toán còn có ứng dụng được trong thực tế như vậy, ngoài chuyện tính toán ăn chia tiền bạc với bạn bè.
Quay trở lại mối thù truyền kiếp, môn toán tất nhiên càng ngày càng khó đối với tui nên cái mối thù đó cũng càng ngày càng lớn. Thằng tui nhất quyết không học toán mà lao đầu vào game, vẽ và tự học lập trình. Mãi sau này đỗ vào cấp 3 với số điểm suýt soát và vào ĐH khối A với số điểm gần như tiệm cận với điểm chuẩn vào trường, cũng vì toán...
Kể thì cũng khá là hài hước khi ba tui luôn bảo rằng: "Mi ko chịu học toán thì làm răng mà theo nghề lập trình được, có biết đụng tới máy tính là đụng tới toán không hả thằng kia?". Nhưng tui thì vẫn một mực không nghe lời, mắt vẫn dán chặt vào màn hình mà gõ code, trước mặt là tờ báo eChip, hồi đó vẫn còn chuyên mục hướng dẫn lập trình.
Tui ngày đó khá là mơ hồ đối với chuyện tương lai, ai hỏi sau này muốn làm gì cũng bảo: "Làm lập trình viên!". Cô chủ nhiệm cấp 3, dạy môn Văn, hỏi: "Thế lập trình viên là gì?" Tui ngắc ngư, không giải thích được. "Điểm toán của em không cao lắm, em có chắc là sẽ theo được nghề này không?" Thầy toán hỏi, tui cười cho qua chuyện rồi chạy biến. Riêng thầy huấn luyện viên của đội tuyển tin thì không nói gì, mà còn hết sức ủng hộ nữa (phải rồi, có ông thầy dạy tin nào mà đi cản học trò cưng của mình thi vô ngành CNTT chớ).
Vào đến ĐH thì cũng vẫn thế, tui và Toán vẫn không hề bớt ghét nhau một chút nào, và càng ghét hơn khi toán nó trở nên điên loạn qua biết bao nhiêu là thể loại, nào là toán cao cấp, toán rời rạc, ma trận rồi tích phân vi phân cục phân các kiểu chả biết đường nào mà lần. Lại còn cái môn xác suất thống kê rõ là chả biết ứng dụng vào đâu, thế mà cứ bắt học. Suốt 4 năm ĐH, tui chỉ muốn vứt bỏ hết tất cả các môn cơ bản như Toán, thuật toán,... đâm đầu vào học các món chuyên ngành mà thằng tui lúc đó nghĩ là mình cực kì thông minh, phải học như vầy sau này ra mới có nghề có ngỗng mà làm ăn chứ. Mặc dù có đôi lần tự hỏi, kiến thức chuyên ngành mà cũ mèm như thế kia thì tự học cũng được, tốn thời gian lên ĐH để làm cái gì.
Đỉnh cao của mối thâm thù lâu năm với môn Toán của tui là 2 lần làm cho cả lớp bàng hoàng. Một lần, sau khi đã chuẩn bị đầy đủ phao bài các kiểu, thật không may cho thằng tui là lại bị xếp ngồi bàn đầu của phòng thi, còn gì đau hơn khi phao nằm trong túi, nhưng không được dở? Thế là thằng sinh viên năm 4 là tui đây đành nằm ngủ suốt gần 1 tiếng làm bài. Nếu không nhờ cô bạn gái lấy giấy làm bài dùm thì chắc tui cũng ôm vở đi học lại môn đó (thế là thằng tui sau này hạ quyết tâm cưới cho bằng được cô ấy làm vợ vì nghĩ bạn gái thương mình như thế, sau này có đi nhậu về trễ cũng hông có bị la gì đâu, nhưng về khoản này thì tôi đã lầm...). Một lần khác trước đó 2 năm, là vào kì thi hết môn Giải tích ở năm 2 Đại học, sau 10 phút nhận và đọc đề, tui đùng đùng nộp giấy trắng và ung dung bước ra khỏi phòng thi trước con mắt ngỡ ngàng của thầy giám thị cùng lũ bạn bè trong lớp, năm đó tôi học lại môn toán...
Cho đến lúc đó, ngoài ba cái bài thuật toán vớ vẩn cũng ko có dính dáng sâu lắm tới toán, tui vẫn một mực khẳng định: Làm CNTT cần mẹ gì môn Toán chớ.
Vài năm sau, lời tuyên bố hùng hồn năm nào, tôi vẫn còn cho là đúng. Sau gần 6 năm lăn lộn với đủ thể loại công việc trong ngành CNTT, từ freelance code web dạo cho tới làm game, mobile app, vẫn chưa một lần tui dùng tới toán...
Web với Mobile thì khỏi nói làm gì nhỉ, cũng chỉ toàn ba cái CRUD app lặp đi lặp lại, lâu lâu thêm tí Map của Google hay tích hợp thanh toán từ OnePay, Stripe. Đến cả game cũng vậy nốt, toàn bộ các thao tác cần đến toán đều do engine đảm nhiệm hết khiến thằng dốt toán như tui vẫn dương dương tự đắc. Tất nhiên, ngồi vào bàn bật Unity lên thì chuột bay như chớp, gõ code liên hồi, ra game cầm lên bấm bấm nhưng nếu hỏi làm sao để implement được phép dịch chuyển tọa độ của một GameObject hay làm thế nào mà CSS có thuộc tính translate để xoay mấy cái textbox như chong chóng trên màn hình thì tui cũng đành bó tay thôi. Cơ mà cũng chả quan tâm làm gì vì công việc có yêu cầu mình phải biết những thứ đó đâu, vẫn có lương đấy thôi.
Phần 2: Bình loạn
Thực ra cái phần tự truyện hơi dài ở trên viết ra chỉ nhằm mục đích giới thiệu cho mọi người biết tác giả là một con người cực kì ghét toán, và có phần dốt toán =)) nhưng vẫn làm lập trình viên một cách phơi phới không có trở ngại gì cả.
Nói vậy thì không lẽ làm lập trình không cần đến toán thật à?
Đúng là bạn không cần phải giỏi toán để làm lập trình viên. Lĩnh vực lập trình rất rộng, và với mức độ công việc hiện nay ở hầu hết các công ty, có phần thiên về kĩ thuật nhiều hơn là tư duy, cộng thêm sự hỗ trợ đến tận răng của các framework, engine,... và quan trọng nhất là tuỳ theo yêu cầu của công việc mà bạn có cần phải dính nhiều tới toán hay không, thường thì chỉ cần giỏi tiếng Anh và chịu khó tìm tòi, nghiên cứu (viết tắt là: copy & paste từ google, stackoverflow...) là đã đủ đáp ứng rồi.
Không cần toán chúng ta vẫn có thể giải quyết được hầu hết vấn đề, ở một số vấn đề, nếu sử dụng toán thì chúng ta có thể giải quyết chúng hiệu quả hơn, cũng có một vài lĩnh vực bắt buộc chúng ta phải dùng tới toán.
Dưới đây là một số ví dụ cần dùng tới toán (hoặc các kiến thức cơ bản mà có lẽ nhiều người bỏ qua khi còn đi học) trong lập trình:
Ví dụ 1: Áp dụng bitwise operator để tiết kiệm bộ nhớ
Khởi động nhẹ nhàng với một thứ ứng dụng ít liên quan tới toán, mà liên quan nhiều đến lập trình, đó là việc xử lý các phép tính bitwise.
Giả sử bạn đang làm việc trên một trang web form, trên form này có hơn 20 checkbox và nhiệm vụ của bạn là khi submit form, server phải nhận diện được giá trị của cả 20 checkbox đó. Vậy bạn chọn cách nào để lưu giá trị của 20 checkbox đó trên server? Tạo ra 20 biến kiểu boolean
? Hoặc là dùng một mảng chứa 20 phần tử?
Có một cách hiệu quả hơn đó là dùng kĩ thuật bit mask, đại khái ý tưởng của kĩ thuật này là chỉ dùng duy nhất 1 biến, và sử dụng các phép tính bit để nhập nhiều giá trị binary vào biến này. Giúp tiết kiệm được khá nhiều bộ nhớ.
Tham khảo bài viết về cách implement trên C# tại đây: http://blog.aurelienjacquot.fr/2015/04/the-awesomeness-of-flags-the-binary-oriented-net-enums/
hoặc đây: http://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
Hoặc trên JavaScript tại đây: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Flags_and_bitmasks
Đối với C#, các bạn có thể nhét được 63 flags vào trong một biến. Nhưng trong JavaScript, bạn chỉ nhét được tối đa 31 flags. Nguyên nhân là vì C# hỗ trợ đến 64 bit, còn JavaScript thì chỉ xử lý được các con số 32 bit.
Ví dụ 2: Kiểm tra tính thắng thua trong game Tic-Tac-Toe bằng ma trận
Mặc dù ví dụ này có phần không thực tế vì không phải lúc nào cũng sử dụng. Tuy nhiên có lẽ ai cũng từng làm qua.
Khi lập trình trò chơi này, chúng ta thường có một hàm, tạm gọi là checkWin()
để kiểm tra trạng thái của bàn cờ, xác định xem ai là bên thắng cuộc.
Theo suy nghĩ thông thường, chúng ta cứ việc dùng lệnh if
hoặc vòng for
để quét và đếm số quân cờ ở mỗi hàng, cột, đường chéo là ra. Tuy nhiên còn 1 cách giải quyết khác nữa, đó là dùng một vài phép tính với ma trận để xác định.
Chưa biết thực hư chuyện performance có cải thiện hay không, nhưng rõ ràng một vấn đề vớ vẩn như vậy chúng ta vẫn có thể đem một thứ kiến thức toán học-học-xong-không-biết-để-làm-gì như ma trận vào để giải quyết. Vậy thì toán học quả thực rất là lợi hại. (Nhận xét của một thanh niên học lại môn toán, đọc lại phần 1)
Ví dụ 3: Bracket Highlighter cho Sublime hoặc Atom
Cái này thì thú vị đây, giả sử bạn muốn viết một plugin cho Sublime hoặc Atom để làm nhiệm vụ highlight các dấu đóng ngoặc/mở ngoặc (brackets) trong một đoạn code. Vậy bạn sẽ làm như thế nào?
Cách đơn giản thường được sử dụng để giải quyết vấn đề này là dùng cấu trúc Stack
. Quét đoạn code cần xử lý từ trên xuống dưới, khi gặp một dấu mở ngoặc thì ta tống nó vào stack, tiếp tục quét. Khi gặp một dấu ngoặc đóng thì ta tìm coi dấu ngoặc mở cuối cùng vừa được đưa vào stack có cùng loại với dấu ngoặc đóng đang xét hay không, nếu có thì lôi nó ra và highlight nó lên. Nếu không phải thì báo lỗi syntax error ngay!
Chi tiết về cách implement thuât toán này các bạn có thể đọc tại: http://www.willamette.edu/~fruehr/241/labs/lab3.html
Ví dụ 4: Sắp xếp 10 GB dữ liệu giới hạn trong 1 GB bộ nhớ
Đây là ví dụ điển hình của việc xử lý dữ liệu, và đây cũng là câu hỏi thường được hỏi khi các bạn đi phỏng vấn tại các công ty phần mềm lớn. Đọc đến đây đừng có trề môi bảo là vớ vẩn, bây giờ là thời đại mở cửa, việc một anh chàng lập trình viên Việt Nam sang Nhật Bản, Singapore, Malaysia hay thậm chí là Âu, Mỹ để phỏng vấn xin việc cũng không còn là một giấc mơ xa vời nữa đâu, người ta đi đầy ra rồi.
Để giải quyết bài toán này, chúng ta có thể sử dụng nhiều thuật toán, trong đó có thuật toán Merge Sort, xem chi tiết tại: http://stackoverflow.com/questions/6988611/sorting-10gb-data-in-1-gb-memory-how-will-i-do-it
Ví dụ 5: Ứng dụng ma trận vào CSS
Vâng, bạn không có đọc nhầm đâu. Là thứ toán ma trận khô khan nhàm chán đấy, lại có thể kết hợp CSS trong lập trình web, tất nhiên là ứng dụng trong lĩnh vực web development rồi.
Chỉ cần nắm vững kĩ thuật này, bạn hoàn toàn có thể tạo ra những hiệu ứng biến đổi cho các element trên trang web một cách bắt mắt, thậm chí có thể ứng dụng để tự viết các plugin như image slider, các hiệu ứng 3d,... bằng CSS.
Tham khảo bài viết: http://www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/
Kết bài, mình xin phép trích dẫn một câu nói từ một bài viết trên mạng để nhận xét về mối liên quan giữa toán học và lập trình:
You Don’t Need Math Skills To Be A Good Developer But You Do Need Them To Be A Great One
Bạn không cần giỏi toán để trở thành một lập trình viên giỏi. Nhưng bạn chắc chắn cần toán nếu muốn trở thành một lập trình viên toẹt zời!
Hiện nay là thời đại mở cửa, rào cản địa lý trong việc tuyển dụng hầu như rất ít, các công ty nước ngoài bắt đầu chú ý đến các lập trình viên từ các xứ sở xa xôi như Việt Nam, cho nên cơ hội xuất ngoại của lập trình viên Việt không phải là nhỏ. Quan trọng là chúng ta có đủ giá trị để họ bỏ tiền ra tài trợ visa rinh chúng ta về nước họ không?
Để có thể cạnh tranh được với lập trình viên khắp thế giới, chúng ta cần trang bị cho mình những thứ kiến thức chuyên sâu và mới, những thứ công việc xa vời như Data Scientist, Algorithm Developer hay những thứ công nghệ như Deep Learning, Machine Learning đều có thể trở thành những cơ hội mới mà lập trình viên Việt nên nắm bắt. Để làm được điều này thì chúng ta phải tự mình thoát ra khỏi cái định kiến "công việc không yêu cầu" cố hữu, thả sức phi thân vào trang bị kiến thức nền tảng thật tốt để nghiên cứu các lĩnh vực mới ngay từ bây giờ.
Các bài hay có liên quan đến toán, giải thuật nhưng rất nhẹ, dễ hiểu, nên đọc:
- Cấu trúc dữ liệu và giải thuật dành cho Web Developer (https://medium.com/@felipernb/algorithms-data-structures-and-web-development-7772e088f1d3#.kkvgvg67o)
- Ứng dụng xác suất thống kê để implement thuật toán Naive Bayes giúp phân loại từ ngữ (https://alexn.org/blog/2012/02/09/howto-build-naive-bayes-classifier.html)
- Một bài khác cũng là Naive Bayes giúp phân loại nội dung trên Twitter (http://cloudacademy.com/blog/naive-bayes-classifier/)
- Ứng dụng của toán học trong Machine Learning (https://www.toptal.com/machine-learning/machine-learning-theory-an-introductory-primer)
- Xây dựng recommend engine bằng NodeJS (https://www.toptal.com/algorithms/predicting-likes-inside-a-simple-recommendation-engine)