LẬP TRÌNH
BÀI HỌC: VIỆC PHỨC TẠP SẼ TRỞ NÊN ĐƠN GIẢN KHI BẠN CHIA NHỎ CHÚNG RA
Nếu gỡ lỗi là quá trình loại bỏ các lỗi thuộc về phần mềm thì lập trình lại là quá trình đặt các lỗi đó vào.
−EDSGER DIJKSTRA, nhà khoa học máy tính danh tiếng
▪ ▪ ▪
T
ôi bắt đầu kiếm sống nhờ web từ năm 2007, khi tôi bỏ công việc toàn thời gian là trưởng phòng marketing cho công ty Procter & Gamble để thành lập công ty tư vấn và xuất bản của riêng mình.
Trang web quan trọng nhất của tôi, PersonalMBA.com, là phương kế sinh nhai của tôi: Tôi là một giáo sư kinh doanh hiệu quả, nhưng tôi không làm việc ở trường đại học. Mỗi năm, tôi lại cập nhật danh sách những cuốn sách kinh doanh tốt nhất dành cho những người muốn tự học kiến thức cơ bản nhất của kinh doanh.
Danh sách tài liệu nên đọc của The Personal MBA có một lượng độc giả yêu thích lâu năm kể từ khi ấn bản đầu tiên được phát hành năm 2005, và phần cập nhật cho danh sách đáp ứng được làn sóng quan tâm của các độc giả trên khắp thế giới. Kể từ năm 2005, PersonalMBA.com đã được hơn hai triệu lượt truy cập.
Cuốn sách đầu tiên của tôi, MBA cá nhân: Làm chủ nghệ thuật kinh doanh (The Personal MBA: Master the Art of Business) (2010), là sự mở rộng của trang web PersonalMBA.com, và đã trở thành cuốn sách bán chạy nhất. Một phần của việc viết sách là phải xác định làm thế nào để truyền bá ngôn ngữ, vì thế sau nhiều năm, tôi đã làm việc chăm chỉ để thu hút được nhiều người đọc mới.
Kết quả là cuốn sách đã được đề cao trong tờ New York Times, Wall Street Journal, Fortune, Forbes và FastCompany, cũng như trên nhiều trang web blog nổi tiếng khác. Mỗi lần cuốn sách hay trang web của tôi được giới thiệu lại có hàng nghìn người ghé thăm trang PersonalMBA.com chỉ trong một khoảng thời gian ngắn.
Cái giá của sự tiến bộ
Cùng lúc có hàng nghìn vị khách ghé thăm trang web của bạn là một điều tuyệt vời, với điều kiện là những vị khách đó có thể thực sự truy cập được vào trang web của bạn. Đó chính là vấn đề của tôi: bất cứ khi nào trang web của tôi được một lượng lớn khách ghé thăm, nó lại bị nghẽn mạng, chỉ để lại cho những vị khách đó một mẩu thông tin báo lỗi khó hiểu.
Và đây là một ví dụ điển hình: Lifehacker.com, một trang blog nổi tiếng, đã giới thiệu cuốn MBA cá nhân ba lần trong vòng bảy năm qua. Mỗi lần lại có hàng nghìn người cố gắng truy cập vào trang PersonalMBA.com cùng một lúc, làm nghẽn máy chủ (máy tính cung cấp trang web theo yêu cầu của khách nghé thăm) của trang web. Thay vì cung cấp thông tin được yêu cầu, máy chủ của tôi lại đưa ra thông điệp “Lỗi thiết lập kết nối với cơ sở dữ liệu” hoặc “Lỗi 503”, thông điệp số tương đương với việc máy chủ nài xin lòng khoan dung.
Mỗi lần máy chủ của tôi sập vì quá tải, một phần linh hồn của tôi cũng chết theo. Toàn bộ thời gian dành cho việc quảng bá trang web của tôi đã thành công cốc. Hàng nghìn độc giả tò mò cuối cùng đã chịu quan tâm tới điều tôi giới thiệu, nhưng vì máy chủ của tôi bị sập, họ lại phải quay trở ra cùng với tâm trạng thất vọng và trống rỗng. Công tác marketing của tôi cũng rất tốt, nhưng hệ thống của tôi lại không thể xử lý được nhu cầu bất ngờ.
Kiểm tra vấn đề
Lúc đầu, giải pháp của tôi là tăng cường cho máy chủ bằng cách tăng năng lực xử lý và thêm bộ nhớ. Điều đó có tác dụng, nhưng chỉ tại một thời điểm nào đó. Ngoài thời điểm đó ra, trang web của tôi có thể bị nghẽn và sập bất cứ lúc nào – chuyện thường xảy ra cùng lúc với những lần marketing thắng lợi.
Khi đó, PersonalMBA.com đang chạy trên hệ thống quản lý trang web nổi tiếng là WordPress. WordPress được tối ưu hóa để dễ sử dụng và cài đặt, không chạy dưới tải nặng. Theo cấu hình mặc định của WordPress, tất cả các trang web đều yêu cầu khởi động một tầng hoạt động của máy chủ, tạo ra hàng trăm yêu cầu ẩn nhằm cung cấp trang web tới người đọc.
Điều đó khiến cho yêu cầu đối với mỗi trang web trở nên “đắt đỏ”. Nghĩa là, mỗi yêu cầu lại đòi hỏi một lượng lớn bộ nhớ và năng lực xử lý mới hoàn thành được. Nếu một khách xem năm trang trên web, người khách đó đã tạo ra năm yêu cầu đắt. Nếu hàng nghìn khách cùng đưa ra yêu cầu vào cùng một thời điểm, máy chủ sẽ phải cố gắng thực hiện hàng nghìn quá trình xử lý cùng một lúc.101
Hệ thống hỏng
Trong tình huống này, chiếc máy chủ tội nghiệp bị bao vây sẽ cố gắng đáp trả tất cả các yêu cầu, nhưng vì mỗi yêu cầu lại đòi hỏi rất nhiều nguồn khác nhau, máy chủ sẽ hết bộ nhớ trước khi các yêu cầu được thực hiện. Lúc đó, máy chủ giơ cờ trắng đầu hàng, còn khách là người kém may mắn.
Để giải quyết vấn đề này, tôi đã đổi công ty quản trị web năm lần, và đã dành hàng trăm giờ nghiên cứu làm thế nào để các máy chủ chạy trên nền WordPress có thể giữ mạng được trong tình trạng tải nặng. Mỗi cấu hình máy chủ mới lại tăng mức độ phức tạp, và mỗi lần cài đặt mới lại đòi hỏi phải liên tục bảo dưỡng nhiều hơn.
Cuối cùng tôi đã xây dựng cấu hình máy chủ riêng cho mình, viện dẫn một loạt các yêu cầu hệ thống phức tạp để cài đặt, định cấu hình và thay đổi các ứng dụng máy chủ phức tạp mà tôi chỉ hiểu vừa đủ. Mỗi một lỗi hoặc một vấn đề mà tôi gặp phải trong quá trình hình thành hoặc duy trì đều ngốn của tôi hàng giờ nghiên cứu và tìm cách xử lý.
Thế vẫn chưa hết, tính phổ biến và bảo mật kém của WordPress khiến nó trở thành món mồi ngon cho các tin tặc và những kẻ gửi thư rác. Cứ khoảng một tuần, một lập trình viên ẩn danh lại tìm thấy một vài lỗ hổng mới, sau đó sử dụng chúng để kiểm soát tài khoản của người sử dụng hoặc gửi đầy thư rác vào hàng triệu blog ở WordPress.
Chỉ riêng việc bảo mật cho quá trình cài đặt WordPress và duy trì các cập nhật phần mềm hàng đầu cũng đủ là một việc làm toàn thời gian rồi, đặc biệt khi bạn duy trì nhiều trang web. (Lúc đó tôi duy trì cùng lúc 12 trang web và đã thất bại một cách thảm hại.)
Đến một lúc, tôi chợt nhận ra mình đã dành nhiều thời gian hơn để giữ cho các trang web này luôn ở trạng thái trực tuyến thay vì nghiên cứu và viết cho các độc giả của mình đọc. Điều đó chẳng có ý nghĩa gì. Tôi không chỉ làm lãng phí khả năng của mình, mà còn không thực sự học cách lập trình. Tôi chỉ đang học một mớ những thứ liên quan tới một tình huống cụ thể và chỉ áp dụng cho việc chạy WordPress. Chẳng hay ho gì.
Tôi đã quyết định tìm cách khác để duy trì các trang web của mình, và không tốn nhiều thời gian lắm để tìm được một giải pháp thay thế đầy hứa hẹn.
Giải pháp tiềm năng
Một hôm, tôi tình cờ đọc được một bài luận về Jekyll, chương trình quản lý web của Tom Preston-Werner (nổi tiếng với vai trò người sáng lập kho mã nguồn mở GitHub). Jekyll được thiết kế để thay thế cho những hệ thống như WordPress bằng cách khiến cho việc chạy web mà không cần phụ thuộc vào những yêu cầu đắt đỏ trở nên dễ dàng hơn.
Hãy tưởng tượng bạn có hàng trăm tài liệu xử lý chữ chứa thông tin quan trọng, và bạn cần phải biến tất cả chúng thành giống nhau – cùng phông chữ, cùng kiểu đề mục… Nếu bạn viết một chương trình có thể áp dụng một thiết kế trang web mà bạn chọn cho tất cả các tập tin một cách tự động (thay vì cập nhật từng tập tin bằng tay) thì bạn sẽ tiết kiệm được rất nhiều thời gian.
Đó chính xác là điều mà Jekyll làm được cho các trang web. Hãy chạy một lệnh đơn, và Jekyll sẽ tạo ra một trang web sử dụng các tập tin trong máy tính có chứa thông tin trang web và mẫu thiết kế. Nếu bạn thay đổi thiết kế hoặc nội dung trang, bạn chỉ cần chạy lại Jekyll, toàn bộ trang web sẽ được cập nhật các thay đổi một cách tự động, giúp bạn tiết kiệm được rất nhiều sức lực.
Jekyll đem lại một cơ hội đầy hứa hẹn. Về mặt lý thuyết, tôi có thể thay thế WordPress chỉ với một thư mục gồm các tập tin văn bản đơn giản trong máy tính của mình. Trang web của tôi có thể mở rất nhanh, ổn định và tôi sẽ tiết kiệm được cho mình hàng trăm giờ bảo dưỡng máy chủ mỗi năm.
Tuy nhiên, vẫn có một vấn đề: Jekyll được viết bằng Ruby, ngôn ngữ lập trình mà tôi không biết. Tôi không có chút ý niệm nào về việc viết mã bằng Ruby hay chạy các ứng dụng Ruby phục vụ những người dùng thực sự. Một số việc tôi cần phải làm để chạy PersonalMBA.com đòi hỏi nhiều hơn là việc định dạng đơn giản.
Để chạy các trang web sử dụng Jekyll của mình, tôi phải học cách lập trình và triển khai các ứng dụng web chạy bằng Ruby.
Học cách viết mã
Tôi muốn dành một khoảng thời gian để học cách lập trình, nhưng những dự án khác luôn chiếm vị trí ưu tiên. Nếu tôi có thể học cách viết mã, cơ hội kinh doanh và xuất bản của tôi sẽ được mở rộng đáng kể, vì mọi thứ tôi làm để xây dựng doanh nghiệp đều được chạy trên web.
Có một điểm quan trọng cần phải lưu ý là tất cả mọi việc tôi làm cho tới thời điểm này đều không phải là lập trình. HTML và CSS, hai ngôn ngữ tôi sử dụng để xây dựng các trang web đều được gọi là ngôn ngữ “đánh dấu” (markup). Mã HTML và CSS không được thông minh cho lắm, nó chỉ yêu cầu máy tính thể hiện cho người sử dụng một tập tin văn bản theo một cách cụ thể nào đó (ví dụ như “bôi đen đoạn văn bản này” hay “đề mục của phần này được để ở cỡ chữ 24”).
Việc hình thành máy chủ của tôi cũng như vậy. Dù tôi sắp xếp các phần mềm lại với nhau, thì cũng không phải là tôi đang lập trình thực sự. Thay vào đó, tôi chỉ cài đặt các chương trình được viết sẵn, sau đó thay đổi một vài cài đặt. Lập trình viên viết ra các ứng dụng mà tôi đang sử dụng, nhưng tôi không cần phải có kiến thức về lập trình để sử dụng được chúng. Lập cấu hình máy chủ và quản lý là kỹ năng hữu dụng, nhưng không phải lập trình.
Vậy “lập trình” là gì?
Suy nghĩ đầu tiên của tôi: Lập trình là bắt máy tính làm việc, nhưng suy nghĩ đó chưa cụ thể và có ích. Làm gì? “Việc” ở đây là việc gì?
Mười năm trước, tôi đã theo học hai khóa lập trình cơ bản ở trường cao đẳng, thế nên việc không thể đưa ra được một định nghĩa hữu dụng khiến tôi thấy hơi xấu hổ. Thành thật là thế. Tôi nhớ được một vài thuật ngữ cơ bản như biến số (variable), vòng lặp (loop), dữ liệu vào (input), dữ liệu ra (output), chức năng (function), hướng đối tượng (object orientation) và một khái niệm gì đó gọi là sắp xếp nổi bọt (bubble sort) nhưng không biết gì hơn nữa.
Yêu cầu của khóa học là học được ngôn ngữ lập trình C++, và tôi nhớ là mình đã rất chán nản khi mất hàng tiếng đồng hồ để tìm một dấu chấm phẩy bị thiếu khiến cả chương trình của tôi bị tê liệt. Tôi còn nhớ thầy giáo của tôi đã nói câu gì đó đại khái là: “Bạn sẽ không bao giờ sử dụng tới sắp xếp nổi bọt cho một ứng dụng thực sự nào cả, nhưng dù sao chúng ta vẫn cứ phải học”.
Tôi đã viết một số chương trình cơ bản cho khóa học vì tôi buộc phải viết: mục tiêu là phải vượt qua khóa học với xếp loại giỏi, và tôi đã làm được. Đáng tiếc là những chương trình mà chúng tôi viết khi đó không có giá trị sử dụng bên ngoài lớp học, và tôi chưa từng sử dụng những khái niệm đó trong một thời gian dài. Dù tôi vẫn nhớ được một số từ, nhưng tôi vẫn phải bắt đầu lại với việc tìm hiểu các ý tưởng chính.
Vì tôi không thể định nghĩa được việc tôi đang làm là gì khi nói tôi muốn “học lập trình”, nên tôi gặp khó khăn trong việc xác định mức độ thành thạo mục tiêu. “Tạo ra một chương trình máy tính” có vẻ cụ thể hơn, nhưng vẫn chưa hữu ích lắm.
Đã đến lúc để giới thiệu tôi đã biết gì về lập trình:
Tôi biết các lập trình viên là người “viết” các chương trình, điều đó có nghĩa là đó là một công việc sáng tạo, có thể được hoàn thành bằng nhiều cách khác nhau.
Các chương trình thường được gọi là “ứng dụng”, và hai từ này có thể dùng để thay đổi cho nhau được.
Khi các chương trình máy tính được “chạy” hoặc ”thực hiện”, chúng sẽ tiến hành những việc mà chúng được viết để thực hiện, bất kể việc đó là gì.
“Dữ liệu vào” và “dữ liệu ra” là hai khái niệm khá dễ nhớ, vì chúng hay được sử dụng. Dữ liệu vào là thông tin hoặc dữ liệu mà chương trình sử dụng, và dữ liệu ra là điều bạn nhận được khi chương trình chạy xong.
“Biến số” về cơ bản là trình giữ chỗ cho một thứ gì đó thay đổi. Bạn có thể tạo ra bao nhiêu biến số tùy thích, và khiến những biến số này tượng trưng cho bất cứ điều gì bạn muốn.
Bản thân “chương trình” là một bộ chỉ lệnh chi tiết và các quy tắc, nói cho máy tính biết chính xác phải làm gì với dữ liệu vào. Khi chương trình chạy xong, nó sẽ cho bạn dữ liệu ra.
Chương trình “hỏng” hoặc hiển thị thông báo lỗi khi có điều gì đó không ổn hoặc máy tính không thể xác định được cần phải làm gì tiếp theo.
Giờ chúng ta bắt đầu đến một nơi nào đó. Và đây là một bước “tháo dỡ” rất cơ bản: Thay vì “lập trình”, giờ chúng ta có ba khái niệm nhỏ hơn cần phải xử lý:
Dữ liệu vào – thông tin bạn sử dụng để thực hiện một quá trình.
Quá trình – một loạt các bước mà chương trình thực hiện với dữ liệu vào.
Dữ liệu ra – kết quả cuối cùng của chương trình.
Sự phân chia này hữu ích hơn nhiều. “Viết một chương trình máy tính” có nghĩa là xác định bạn bắt đầu với thông tin gì, các bước miêu tả chính xác điều mà máy tính sẽ thực hiện với những dữ liệu đầu vào đó, và xác định đầu ra mà máy tính sẽ trả lại khi chương trình hoàn thành quá trình thực hiện.
Hãy nghĩ về biểu đồ tiến trình – thứ có vẻ là hình ảnh tinh thần hữu dụng cho thấy cách các chương trình vận hành. Bạn bắt đầu quá trình với một vài dữ liệu đầu vào cụ thể. Suốt quá trình, bạn thực hiện những hành động cụ thể khi các điều kiện cụ thể đúng hoặc sai. Quá trình kết thúc khi bạn đến được điểm cuối của biểu đồ tiến trình, và bạn có được dữ liệu đầu ra: Kết quả cuối cùng của quá trình hoàn thiện mà biểu đồ tiến trình miêu tả.
Tạo ra một chương trình máy tính dường như là một cách khác để thực hiện quá trình suy nghĩ mà bạn vẫn làm khi tạo ra một biểu đồ tiến trình. Bạn sẽ hỏi những câu hỏi giống nhau và giống như thế này:
Mình bắt đầu với cái gì?
Chuyện gì sẽ xảy ra lúc bắt đầu quá trình?
Chuyện gì sẽ xảy ra sau đó? Và sau đó nữa?
Khi nào quá trình kết thúc?
Mình có được gì khi quá trình kết thúc?
Biểu đồ tiến trình miêu tả câu trả lời cho các câu hỏi này dưới dạng hình ảnh, còn các chương trình miêu tả chúng bằng cách sử dụng câu chữ, nhưng quá trình suy nghĩ thì giống hệt nhau.
Sự tương đồng về biểu đồ tiến trình có ích vì nó đưa ra một vài gợi ý về những khái niệm có thể quan trọng khác.
Điều kiện là những mệnh đề kiểu như:
“Nếu X đúng/sai thì thực hiện Y”
“Nếu X là/không phải là Y thì thực hiện Z”
“Khi X đúng/sai thì thực hiện Y”
“Khi X là Y thì thực hiện Z”
“Trong khi X đúng/sai thì thực hiện Y”
“Trong khi X là Y thì thực hiện Z”
X, Y và Z trong trường hợp này là các biến số, nghĩa là nó có thể tượng trưng cho bất cứ thứ gì. Biến số có thể tượng trưng cho các con số, giống như trong đại số cơ bản, hoặc chúng có thể tượng trưng cho các từ. Đôi khi biến số chỉ là các chữ cái hoặc biểu tượng, và đôi khi chúng lại là các từ. Dù là gì thì chúng cũng thể hiện bất cứ điều gì bạn đang làm việc cùng.
Mệnh đề điều kiện (phần NẾU… THÌ…, KHI… THÌ…) giống như các mũi tên có câu hỏi trong biểu đồ tiến trình. Hãy nghĩ về việc lái ô tô: NẾU đèn giao thông chuyển sang màu đỏ, THÌ dừng lại. KHI đèn giao thông chuyển sang màu xanh, THÌ đi. KHI đèn giao thông có màu vàng, giảm tốc độ và chuẩn bị dừng lại.
Những mệnh đề điều kiện này đáng được đào sâu hơn chút nữa, vì có một số mô hình phổ biến. Đúng/sai có vẻ xuất hiện nhiều, và TRONG KHI dường như ám chỉ cho chúng ta biết chúng ta nên tiếp tục làm điều gì đó thay vì chỉ thực hiện một hành động.
Trong tất cả các trường hợp, mệnh đề điều kiện có chứa tuyên bố xác định nên hay không nên thực hiện hành động. Tuyên bố này được gọi là một điều kiện, và nó có thể tồn tại dưới nhiều dạng. Đôi khi điều kiện có dạng cơ bản là so sánh đúng/sai (Đèn đang đỏ à?), và đôi khi nó lại là phép so sánh toán học (X lớn hơn 100 à?), và đôi khi nó hàm chứa cả sự suy luận logic (Đèn báo hiệu dừng KHÔNG đỏ à?).
Mục đích của điều kiện là xác định liệu quá trình liên quan có nên xảy ra hay không. Nếu điều kiện đúng hoặc hợp lý, chương trình sẽ thực hiện chỉ lệnh. Nếu không, chỉ lệnh có liên quan sẽ bị bỏ qua, và chương trình sẽ chuyển sang chỉ lệnh tiếp theo.
Biến số đúng/sai được gọi là biến số Boolean, thuật ngữ khá phổ biến dùng để chỉ một việc gì đó chỉ có hai lựa chọn. Có/không và bật/tắt cũng là các biến số Boolean. Biến số Boolean rất quan trọng trong các chương trình máy tính vì chúng là đơn vị cơ bản của cả những quá trình đơn giản (như đúng/sai trong biểu đồ tiến trình) và việc bật/tắt nút công tắc điện nhỏ xíu ở góc máy tính.
TRONG KHI trong trường hợp này là một kiểu điều kiện đặc biệt được gọi là vòng lặp. Vòng lặp khiến cho quá trình đang được yêu cầu lặp lại cho tới khi điều kiện được đáp ứng. Trở lại với ví dụ lái xe: TRONG KHI đèn giao thông đang đỏ, không được đi.
Rất đơn giản, đúng không? Nếu chúng ta nghĩ về việc viết một chương trình máy tính giống như vẽ một biểu đồ tiến trình thì quá trình cơ bản sẽ dễ hình dung hơn rất nhiều.
Chỉ còn một vấn đề nhỏ cuối cùng: Chuyện gì sẽ xảy ra nếu máy tính bị kẹt, không biết phải làm gì, hoặc chỉ lệnh mà máy tính đang cố gắng thực hiện không có nghĩa hoặc không thực hiện được? Chuyện gì sẽ xảy ra?
Chương trình “tê liệt” – chương trình dừng hoàn toàn và thường đưa ra một thông điệp báo lỗi thay vì kết quả như mong muốn. Tất cả chúng ta đều đã chứng kiến lỗi Windows đáng sợ “màn hình xanh lè” hoặc “Lỗi 404: không tìm thấy trang web” trong khi duyệt web. Có điều gì đó bất ngờ xảy ra, máy tính “bối rối” và chương trình tê liệt.
Là một lập trình viên máy tính, công việc của bạn là ngăn chặn tình trạng tê liệt và lỗi sai, không để chúng xảy ra. Cách tốt nhất để thực hiện điều đó là đảm bảo chương trình luôn có được thông tin nó cần để hoàn thành quá trình như dự kiến, nhưng điều đó không phải lúc nào cũng là điều có thể. Trong những trường hợp mà sự không chắc chắn là điều khó tránh khỏi, sẽ có ích khi có một cách để khôi phục khi chương trình thất bại trong khi cố gắng hoàn thành một quá trình nào đó.
Những câu lệnh phục hồi lỗi này được gọi là ngoại lệ, và chúng rất hữu ích. Bạn có thể nghĩ về chúng như những câu điều kiện lỗi-đặc biệt: NẾU chương trình chuẩn bị hỏng theo cách X, THÌ thực hiện Y thay vì để (nó) hỏng.
Ngoại lệ gần giống như thêm máy phát dự phòng cho tòa nhà bệnh viện. Hầu hết thời gian, máy phát chỉ để đó không sử dụng. Tuy nhiên, khi mất điện, máy phát khởi động, và bệnh viện sử dụng điện từ máy phát thay vì chìm trong bóng tối. Đó là một thiết bị hữu ích nếu trong bệnh viện đang có những bệnh nhân phải sử dụng những máy móc hỗ trợ sự sống chạy bằng điện. Thất bại hoàn toàn rất nguy hiểm, do đó, kế hoạch dự phòng là điều cần thiết.
Đó chính là lập trình cơ bản. Xác định dữ liệu đầu vào. Đặt biến số. Tạo ra những quá trình dẫn tới đầu ra mong muốn. Hãy nghĩ về các quá trình này như một biểu đồ tiến trình, thêm điều kiện và ngoại lệ nếu cần thiết. Nếu mọi chuyện tốt đẹp, bạn cung cấp dữ liệu đầu vào, chạy chương trình và nhận được kết quả mong muốn.
Đây là sự đơn giản hóa tối đa một hoạt động phức tạp, nhưng nó đủ chi tiết để trở nên hữu ích cho những người mới có thể lập trình. Bằng cách chia nhỏ lập trình theo cách này, sẽ dễ hơn để bạn biết phải bắt đầu từ đâu.
Ngôn ngữ lập trình
Đây là phần thủ thuật: Máy tính không nói cùng thứ ngôn ngữ với con người. Về cơ bản, máy tính làm việc bằng cách bật và tắt công tắc điện nhỏ xíu theo những cách vô cùng đặc biệt. Nếu máy tính không có cách dịch yêu cầu theo ngôn ngữ của con người thành việc bật công tắc điện, máy tính không thể thực hiện được điều chúng ta yêu cầu.
Đó chính là điều mà ngôn ngữ lập trình thực hiện: Chúng đưa cho người lập trình một cách cụ thể để nói cho máy tính biết khi nào bắt đầu, cần phải làm gì và khi nào thì dừng lại. Chúng cũng cho phép người lập trình xác định thế nào là dữ liệu đầu vào, quá trình, dữ liệu đầu ra, và cần phải làm gì khi chương trình chạy xong.
Mỗi ngôn ngữ lập trình có một cách riêng để viết yêu cầu, gọi là cú pháp (syntax). Cú pháp của ngôn ngữ có chứa các quy tắc mà máy tính sử dụng để dịch các yêu cầu thành các tín hiệu bật-tắt điện tử nhỏ xíu.
Mỗi ngôn ngữ lại có một cách để xác định biến số, điều kiện và ngoại lệ riêng. Chi tiết có thể khác nhau, nhưng khái niệm cốt lõi thì giống nhau.
Nghĩ như một lập trình viên
Lập trình viên thường nghĩ về vấn đề theo cách được gọi là giải mã (pseudocode): ngôn ngữ giống như mật mã, nhưng lại không đủ cụ thể để máy tính có thể thực hiện được. Hãy nghĩ về nó như một dạng phác họa. Giải mã giúp bạn nghĩ thông qua quá trình giải quyết vấn đề.
Ví dụ về việc lái xe mà tôi đã sử dụng chính là một dẫn chứng về giải mã. Nếu tôi bước vào xe và nói to : “NẾU tôi xoay chìa khóa THÌ động cơ sẽ khởi động”, thì sẽ chẳng có chuyện gì xảy ra cả. Điều đó không có nghĩa là câu nói đó vô dụng. Mệnh đề đó chỉ là một cách nghĩ thông qua các bước cần thiết để giải quyết một vấn đề hoặc nhận được một kết quả mong muốn.
Bạn có thể sử dụng những khái niệm lập trình cơ bản mà chúng ta đã thảo luận để phác thảo một vài chương trình đơn giản cho những nhiệm vụ phổ thông.
Có một cách thú vị để tự mình thử nghiệm điều đó: Hãy tìm một người bạn, và nhờ người đó giúp bạn hoàn thành một nhiệm vụ đơn giản như “làm bánh sandwich”. Quy tắc duy nhất là người bạn đó của bạn chỉ được làm chính xác những gì bạn bảo anh ta làm, không hơn, không kém. Anh ta không được học bất cứ thứ gì, và chỉ được thực hiện mọi yêu cầu theo đúng nghĩa đen của nó.
Chỉ vài phút, bạn sẽ thấy mình có một cuộc hội thoại như thế này:
Bạn: Nhấc bánh mì lên.
Người bạn: Mình không hiểu từ “nhấc lên”.
Bạn: Di chuyển tay bạn tới chỗ mà mình nói và nắm lấy nó.
Người bạn: Mình không hiểu từ “tay”.
Bạn: (thở dài) Nó đây này. [Bạn chỉ vào tay của người bạn.]
Người bạn: Hiểu rồi.
Bạn: Di chuyển tay bạn tới chỗ mà mình nói và nắm lấy nó.
Người bạn: Mình không hiểu từ “nắm”.
Bạn: Gập ngón tay của bạn như thế này này. [Bạn làm mẫu, gập và thả các ngón tay ra.]
Người bạn: Hiểu rồi.
Bạn: Di chuyển tay tới chiếc bánh mì và nắm lấy nó.
Người bạn: Mình không hiểu từ “bánh mì”.
Bạn: Chính là thứ này này! [Bạn chỉ vào chiếc bánh mì.]
Người bạn: Hiểu rồi.
Bạn: Di chuyển tay tới chiếc bánh mì và nắm lấy nó.
Người bạn: [Di chuyển tay tới chiếc bánh mì, gập ngón tay và nhả ra. Chiếc bánh mì không xê dịch.]
Bạn: ĐÂY LÀ MỘT TRÒ CHƠI NGỚ NGẨN!
Đó là một ví dụ ngớ ngẩn, nhưng lại gần giống với việc lập trình như thế nào và có cảm giác ra sao, đặc biệt là ở giai đoạn đầu.
Chiếc máy tính giống như người bạn của bạn, không hiểu được bất cứ điều gì bạn yêu cầu một cách dứt khoát. Bất cứ quá trình phức tạp nào mà bạn cố gắng định nghĩa cần phải được chỉ rõ, không mập mờ.
Đây chính là điều khiến lập trình trở nên khó khăn: Chỉ một sự mơ hồ nhỏ hoặc một yêu cầu không chính xác cũng có thể khiến toàn bộ chương trình bị hỏng. Lập trình là một nghề thủ công không rộng lượng xét ở góc độ đó: Đoạn mã của bạn hoặc là đúng hoặc sai, và cần phải được thể hiện bằng chi tiết chính xác.
Máy tính không ấn tượng với sự quyến rũ hay hóm hỉnh. Nếu đoạn mã của bạn chưa hoàn thiện, hoặc viết không tốt, thì ứng dụng của bạn sẽ bị hỏng, bạn sẽ mất dữ liệu, hoặc bạn sẽ tạo ra một lỗi (bug): Một mẩu mã độc tạo ra những hệ quả không mong đợi hoặc không dự đoán được. Giống như toán học, logic hoặc phát huy tác dụng hoặc không. Không có điểm A nào cho nỗ lực cả.
Như đã nói, trong lập trình không có một giải pháp duy nhất cho một vấn đề cụ thể nào đó giống như trong toán học. Có hàng nghìn cách để tạo ra kết quả mong muốn với lượng dữ liệu đầu vào cụ thể. Là một lập trình viên, bạn có thể chọn cách tiếp cận dựa trên những công cụ mà bạn có.
Khi bạn đã quen với việc máy tính không thể đọc được ý nghĩ của bạn, bạn sẽ học cách bắt đầu đưa ra những yêu cầu mà hệ thống có thể hiểu được, theo đúng cách mà bạn đã học để định nghĩa các thuật ngữ và làm mẫu các hành động cơ bản cho người bạn của bạn trong ví dụ “làm bánh sandwich” trước khi đưa ra những yêu cầu phức tạp.
Điều gì khiến lập trình ứng dụng web khác biệt?
Lúc này chúng ta đã có một định nghĩa về lập trình. Nó đã được đơn giản hóa, nhưng vẫn đủ để hiểu điều chúng ta đang cố thực hiện lúc này.
Tôi không quan tâm tới tất cả các loại lập trình, tôi chỉ muốn viết các chương trình có thể chạy trên các trang web. Nếu bạn đã từng sử dụng những chương trình gửi thư dựa trên web như Gmail, Hotmail, Yahoo Mail hoặc đại loại như vậy, bạn sẽ biết tôi đang nói về điều gì. Những chương trình này chạy trên trình duyệt internet của bạn. Bạn không cần phải tải chương trình phần mềm về máy tính để sử dụng. Bạn chỉ cần chỉ trình duyệt của bạn tới trang web đó, đăng nhập và bạn đã có thể sử dụng.
Sự khác biệt giữa phần mềm chạy tại chỗ và phần mềm chạy từ xa trên máy chủ web là một sự khác biệt quan trọng. Để phát triển một ứng dụng web, trước tiên bạn cần viết một ứng dụng, sau đó thử nghiệm để xem nó có hoạt động không. Tất cả việc phát triển và thử nghiệm đó đều diễn ra trên máy tính của riêng bạn.
Khi chương trình đã hoạt động, bạn có thể gửi nó tới một máy chủ web “sản xuất” để những người khác cũng có thể truy cập được. Mọi người trên internet không thể truy cập vào máy tính cá nhân của bạn từ trang web, nên việc đăng tải phần mềm lên một máy chủ web được truy cập thoải mái là bước cần thiết để mọi người có thể sử dụng được chương trình của bạn.
Điều đó có nghĩa là quá trình phát triển gồm hai giai đoạn quan trọng: lập trình và thử nghiệm, sau đó đẩy chương trình hoàn thiện lên máy chủ sản xuất từ xa để sử dụng thực sự. Tôi cần phải xác định hai giai đoạn này hoạt động như thế nào.
Từ kinh nghiệm với HTML và CSS, tôi còn biết thêm một điều: cả hai đều “ngu ngốc”, với chúng, bạn không thể yêu cầu một trang web cơ bản chứa được bất cứ thông tin gì.
Giả sử bạn có một tập tin trang web với nội dung “Xin chào, thế giới!” và bạn muốn thay từ “thế giới” bằng tên của một người truy cập trang web. Đó là một suy nghĩ thú vị, nhưng các trang web cơ bản không có cách nào để phân loại thông tin để sau này sử dụng lại. Chúng chỉ hiển thị văn bản trong tập tin, và tập tin cũng không được phép tự cập nhật.
Thuật ngữ kỹ thuật chỉ hiện tượng này là trạng thái (state). Các trang web để cơ bản được xây dựng bằng cách sử dụng HTML và CSS không có trạng thái, vì thế chúng được coi là các nguồn “không có trạng thái”. Bạn có thể thêm một mẫu nhỏ cho trang web hỏi tên người sử dụng với một nút Lưu ở bên cạnh, nhưng cái nút này không thực sự lưu bất cứ thông tin nào trừ khi bạn tạo được một chỗ riêng để chứa các thông tin đó.
Đó chính là lý do tại sao các ứng dụng web lại sử dụng hai cách tiếp cận phổ biến để lưu trữ dữ liệu cho sau này: Cơ sở dữ liệu (database) và bộ nhắc nhỏ (cookie(1)).
Cách tốt nhất để hiểu cơ sở dữ liệu làm gì là tưởng tượng một chồng thẻ ghi chú. Giả sử bạn đang cố gắng tạo ra một cuốn sổ địa chỉ, và bạn muốn ghi tên, số điện thoại, địa chỉ e-mail, giới tính và tuổi của mỗi người bạn của bạn.
Mỗi người bạn có một chiếc thẻ ghi chú riêng, và thông tin của họ được ghi trên tấm thẻ đó. Nếu một trong số họ thay đổi địa chỉ e-mail, giả sử như vậy, bạn có thể xóa thông tin cũ đi và cập nhật tấm thẻ với thông tin mới. Khi bạn nhìn vào tấm thẻ của một người bạn nào đó, bạn có thể nhìn thấy tất cả các thông tin của họ cùng một lúc.
Bạn có thể nghĩ về cơ sở dữ liệu như một chồng các tấm thẻ ghi chú đó. Mỗi tấm thẻ trong chồng đó được gọi là một bản ghi (record(2)). Bạn có thể có bao nhiêu bản ghi trong cơ sở dữ liệu tùy thích, nhưng đến một lúc nào đó, chồng thẻ sẽ trở nên khó quản lý. Thường sẽ hiệu quả hơn nếu chia chồng thẻ đó thành những chồng nhỏ hơn, ít hơn: gia đình và bạn bè vào một chồng, đồng nghiệp ở một chồng khác, chẳng hạn như vậy.
Điều đó có rõ ràng không? Và đây mới là điều thú vị: Hãy tưởng tượng chồng thẻ ghi nhớ của bạn lúc này là một chồng thẻ ma thuật. Bạn có thể nói chuyện với thẻ ma thuật và yêu cầu nó cho bạn xem những tấm thẻ phù hợp với một số điều kiện cụ thể, chẳng hạn như:
“Hãy cho ta xem thẻ của John Smith”.
“Hãy cho ta xem tất cả các thẻ có giới tính là nữ”.
“Hãy cho ta xem tất cả các thẻ có tuổi lớn hơn 50”.
Khá hữu ích, đúng không? Về cơ bản, đó chính là điều mà cơ sở dữ liệu thực hiện: Chúng cung cấp cho bạn một cách để lưu trữ các thông tin đã được cơ cấu, cũng như cách để lấy lại thông tin đó theo bất cứ cách nào mà bạn muốn.
Mỗi một mẩu dữ liệu mà bạn đặt vào một tấm thẻ được gọi là trường dữ liệu (field). Trường dữ liệu trong cơ sở dữ liệu của bạn càng nhiều thì bạn càng có nhiều cách để lấy lại dữ liệu khi bạn muốn.
Cơ sở dữ liệu là cách phổ biến nhất để lưu trữ dữ liệu trên ứng dụng web. Nếu bạn muốn lưu giữ thông tin như tên người sử dụng, địa chỉ e-mail và các thông tin khác thì sử dụng cơ sở dữ liệu là hợp lý nhất. Một khi John Smith đăng nhập vào ứng dụng của bạn, bạn có thể để ứng dụng của bạn lấy được tên qua bản ghi cơ sở dữ liệu của John, sau đó hiển thị “Xin chào, John Smith!”
Một cách phổ biến khác để lưu giữ thông tin trên ứng dụng web là sử dụng cookie: Một đoạn văn bản rất nhỏ được lưu trên máy tính của người sử dụng. Cookie đặc biệt hữu dụng khi lưu giữ một lượng nhỏ dữ liệu vốn không cần tồn tại trong một thời gian dài.
Trong trường hợp chương trình sổ địa chỉ, sẽ thích hợp khi lưu giữ một cookie khi John Smith đăng nhập. Tập tin cookie về John sẽ chứa các thông tin như tên đăng nhập (username) = johnsmith và đăng nhập (loggedin) = đúng. Nếu John Smith thoát ra khỏi ứng dụng, nhưng sau đó quay trở lại, thì ứng dụng có thể nhận ra đoạn cookie và cho phép anh ta truy cập mà không yêu cầu phải đăng nhập lại. Có thể đặt để cookie hết hạn trong một khoảng thời gian cụ thể nào đó, khiến nó trở nên có ích cho kiểu lập trình này. (Nếu bạn đã từng nhìn thấy dòng chữ “Nhớ mật khẩu này” trên một trang web thì đó chính là cách cookie hoạt động.)
Điều mà chúng ta đang thực hiện lúc này chính là phân chia. Đây không phải danh sách toàn diện những điều khiến lập trình web trở nên độc đáo, nhưng nó lại đủ hoàn chỉnh để cung cấp một bộ khung đơn giản về điều tôi cần phải học: biến số, điều kiện, ngoại lệ, môi trường cục bộ/sản xuất, cơ sở dữ liệu và cookie.
Bạn có thấy việc chia nhỏ này có ích không? Tôi đã bắt đầu với một khái niệm mơ hồ về điều tôi muốn làm, và giờ tôi đã có một danh sách những kỹ năng nhỏ quan trọng cần phải học.
Nhưng tôi vẫn chưa sẵn sàng để học đâu. Bạn có nhớ tôi đã đề cập đến việc máy tính không hiểu được ngôn ngữ của con người không? Tôi cần phải chọn được một ngôn ngữ lập trình để viết các chỉ lệnh cho chương trình của mình, mà việc này đòi hỏi phải nghiên cứu thêm một chút.
Chọn ngôn ngữ để lập trình ứng dụng web
Có hàng nghìn ngôn ngữ lập trình khác nhau, và ngôn ngữ mới vẫn được sáng tạo hàng ngày. Cú pháp của mỗi ngôn ngữ lại khác nhau và chịu ảnh hưởng lớn của việc ngôn ngữ đó được thiết kế để hoàn thành. Có một số ngôn ngữ tối ưu cho một số nhiệm vụ cụ thể hơn so với một số ngôn ngữ khác.
Trước khi bắt tay vào thực hiện, tôi đã quyết định dành một tiếng mò mẫm các trang web lập trình lớn để xem ngôn ngữ nào được các nhà phát triển ứng dụng web khuyên dùng. Công việc nghiên cứu ban đầu này sẽ giúp tôi quyết định cần phải học ngôn ngữ nào và luyện tập kỹ năng ban đầu nào.
Hai trong số những điểm đến phổ biến nhất của các nhà lập trình là Stack Overflow và Hacker News, vì thế tôi bắt đầu bằng cách tìm kiếm lời khuyên về ngôn ngữ tốt nhất để học.
Stack Overflow là một trang web hỏi-và-đáp. Đó là nơi để hỏi những câu kiểu như: “Làm thế nào tôi có thể thực hiện được X?” Những người lập mã có kiến thức và kinh nghiệm hơn sẽ trả lời những câu hỏi đó bằng những gợi ý, cách tiếp cận hoặc sửa lỗi cụ thể, khiến cho Stack Overflow trở thành điểm đến tốt nhất khi bạn muốn tìm kiếm sự giúp đỡ để xử lý những vấn đề lập trình.
Hacker News là trang web tin tức xã hội: Một bộ sưu tập các đường dẫn (link) đến các cuộc thảo luận có liên quan. Các chủ đề trên Hacker News thay đổi theo từng phút, nhưng thường xoay quanh những phát triển mới trong lập trình, công nghệ và kinh doanh, khiến cho Hacker News trở thành một địa chỉ lý tưởng để tìm kiếm các ý kiến, ít nhất là bán chuyên về những phát triển mới trong lập trình.
Ngôn ngữ, thư viện và kỹ thuật mới được các nhà lập trình trên khắp thế giới tạo ra hàng ngày. Một vài sự kết hợp giữa công nghệ và cách tiếp cận khá hữu ích đối với một số vấn đề, nhưng có những sự kết hợp lại không được như vậy. Thường thì bạn không thể biết được cho tới khi bạn thử.
“Tốt nhất”, theo thuật ngữ lập trình, có liên quan tới vấn đề mà bạn đang cố gắng xử lý và tới những ưu tiên cụ thể của bạn. Nhìn chung, lời khuyên là (1) chọn công cụ giúp bạn xử lý vấn đề hiệu quả và (2) nếu bạn được lựa chọn, hãy lựa chọn công cụ mà bạn thấy thích sử dụng. Chỉ thế là đủ.
Việc duyệt dữ liệu của Stack Overflow và Hacker News khiến tôi rơi vào tình trạng quá tải thông tin: Có quá nhiều thông tin để xử lý cùng một lúc, đặc biệt là khi bạn không quen với công nghệ. Tôi cần phải giảm bớt các tạp nhiễu nếu muốn tìm thấy lời khuyên cụ thể hơn.
Và đây là một thủ thuật nghiên cứu mà hầu hết mọi người không biết: Những cỗ máy tìm kiếm thông thường cho phép bạn giới hạn sự tìm kiếm của bạn trong một trang web cụ thể thay vì dàn trải ở tất cả các trang. “Mật mã” để làm được việc này trong Google như sau:
“cụm từ cần tìm” trang: (vidu).com
Hãy thay thế “cụm từ cần tìm” bằng cụm từ mà bạn đang tìm kiếm, và “vidu.com” bằng trang web mà bạn muốn tìm kiếm. Dấu ngoặc kép có nghĩa là tìm kiếm chính xác cụm từ đó. Không có dấu ngoặc kép, Google sẽ cho ra các kết quả là các trang có chứa tất cả các từ trong cụm từ đó, nhưng không hẳn theo đúng thứ tự bạn muốn.
Bằng cách sử dụng thủ thuật này, tôi đã tìm được một vài biến thể của cụm từ “lập trình ứng dụng web”, “học cách viết mã” và “lập trình cho người mới bắt đầu”, sau đó dành thêm một giờ nữa hoặc để đọc các kết quả.
Đây là điều tôi đã tìm thấy: Những nhà phát triển web dày dạn kinh nghiệm gợi ý nên bắt đầu với một trong hai ngôn ngữ phổ biến là Ruby hoặc Python. Ruby và Python khá dễ học, và có thể cho bạn một nền tảng vững chắc về các khái niệm lập trình quan trọng. Ruby phổ biến với các nhà lập trình quan tâm tới các ứng dụng web, còn Python lại phổ biến hơn với các nhà khoa học và toán học, do nó sở hữu nhiều thư viện toán học, khoa học và đồ họa.
Ruby và Python, mỗi một ngôn ngữ lại có những cộng đồng nhà phát triển năng động, những nguồn tải tài liệu và sách miễn phí, những chương trình và công cụ có sẵn khiến cho các tính năng quan trọng dễ thực hiện hơn. Chọn ngôn ngữ nào để sử dụng xem ra chủ yếu lại là vấn đề tham khảo.
Sau khi đọc một vài ví dụ về mã được viết bằng mỗi loại ngôn ngữ này, tôi đã quyết định sẽ học Ruby. Dưới con mắt chưa qua đào tạo của tôi, mã Ruby có vẻ sạch, dễ đọc và tương đối dễ hiểu. Vì phần lớn những ý tưởng và thủ thuật mà tôi học sử dụng Ruby sẽ chuyển sang những ngôn ngữ khác mà có thể sau này tôi sẽ học, nên tôi cần phải làm sao để quá trình học thú vị ngay từ ban đầu.
Ngoài ra, có rất nhiều chương trình và công cụ mà tôi muốn sử dụng để hỗ trợ hoặc để học được ngôn ngữ Ruby. Đặc biệt, Jekyll được viết bằng Ruby, nên học Ruby sẽ giúp tôi giải quyết được một vấn đề nan giải. Python cũng có những công cụ tương tự, nhưng có vẻ phức tạp, khó sử dụng.
Chọn một bộ khung
Ngoài việc đưa ra lời khuyên về ngôn ngữ lập trình, các nhà lập trình ứng dụng web còn có ý kiến gay gắt về bộ khung (frame works): Thư viện về mã giúp cho việc thực hiện những việc mà hầu hết các ứng dụng đều cần trở nên dễ dàng hơn.
Thư viện rất quan trọng vì máy tính thực hiện chính xác những gì bạn yêu cầu chúng làm. Không hơn, không kém.
Đó là một thủ thuật, vì đoạn mã mà bạn cung cấp là tất cả những gì mà máy tính quan tâm. Điều đó cũng giống như câu nói của Carl Sagan, nhà vật lý học nổi tiếng: “Nếu bạn muốn có một chiếc bánh táo từ con số không, thì trước tiên bạn cần phải tạo ra một vũ trụ”.
“Vũ trụ” trong chương trình của bạn được xác định bởi (1) chỉ lệnh và yêu cầu trong cơ sở mã, (2) thư viện mà chương trình của bạn nhập về, và (3) hệ thống mà chương trình đang chạy trên đó. Nếu đoạn mã đó là cần thiết để hoàn thành một hoạt động cụ thể nhưng lại không tồn tại trong hệ thống, thì chương trình của bạn sẽ không chạy hoặc báo lỗi.
Hầu hết các ngôn ngữ lập trình đều chứa những thư viện phổ biến mà hầu hết các chương trình đều cần, nhưng chỉ có một số công cụ chuyên dụng. Đó chính là lúc cần phải có bộ khung. Thay vì mã hóa mọi thứ ngay từ đầu – việc này sẽ tốn rất nhiều thời gian, việc sử dụng bộ khung giúp bạn nhập và sử dụng những thư viện đáng tin, đã qua kiểm tra dành cho những nhiệm vụ cụ thể, từ đó giúp bạn tập trung vào phần cốt lõi của ứng dụng thay vì tái tạo lại cả vũ trụ.
Hiện tại, Ruby tự hào với một vài bộ khung phát triển ứng dụng web chính. Trong số đó có hai bộ khung phổ biến nhất là Ruby on Rails và Sinatra.
Ruby on Rails (thường được viết tắt là Rails) là một trong những bộ khung ứng dụng web quan trọng hàng đầu do Ruby phát triển. Được David Heinemeier Hansson tạo ra năm 2004, Rails dễ dàng trở thành bộ khung Ruby phổ biến nhất, và được sử dụng để phát triển một vài ứng dụng thành công ở công ty 37signals – công ty ứng dụng web thuộc sở hữu tư nhân mà Hansson là đối tác. Tính tới nay, đã có hàng nghìn doanh nghiệp phát triển ứng dụng web quan trọng với công việc kinh doanh bằng cách sử dụng Rails.
Rails phụ thuộc nhiều vào “người tạo”: Các chương trình được cài đặt sẵn tạo ra một lượng lớn mã văn bản thảo sẵn với một yêu cầu đơn nhất. Văn bản thảo sẵn sau đó được điều chỉnh dựa trên những yêu cầu độc đáo của người lập trình. Thay vì dành hàng giờ tạo ra một ứng dụng ngay từ đầu, Rails giúp các nhà phát triển tạo ra một ứng dụng chức năng mà không tốn nhiều công sức, chỉ cần họ biết họ đang làm gì.
Ngược lại, Sinatra là bộ khung rất nhỏ được Blake Mizerany thiết kế và phát triển. Thay vì phụ thuộc vào người tạo ra, Sinatra tập trung vào việc cung cấp cho người phát triển một số chức năng đơn giản phổ biến mà hầu hết các ứng dụng đều cần, sau đó là hết nhiệm vụ.
Ứng dụng Sinatra tạo cảm giác đơn giản hơn so với ứng dụng Rails. Một yêu cầu đơn nhất trong Rails cũng có thể tạo ra ít nhất 10 thư mục và 20 tập tin. Ngược lại, ứng dụng Sinatra thường không được chứa đầy đủ trong một tập tin đơn lẻ. Thay vì tạo ra hàng tấn mã có thể cần phải loại bỏ, Sinatra lại ưu tiên việc giữ cho dự án đơn giản và chỉ thêm đủ mã để hoàn thành công việc.
Giống như chọn ngôn ngữ, chọn bộ khung chủ yếu cũng là vấn đề tham khảo và chọn công cụ tốt nhất cho công việc. Rails thường được sử dụng cho những dự án lớn với nhiều người lập trình, còn Sinatra phù hợp với những dự án nhỏ hơn. Hai ứng dụng này có nhiều tính năng giống nhau, vì thế, một bài phân tích mới đây trên trang RubySource.com đã kết luận rằng, cuối cùng đó là sự lựa chọn mang tính chủ quan.
GitHub là kho mã nguồn mở mà nhiều người lập trình sử dụng để tung ra và duy trì các dự án của họ. Thật dễ tìm thấy ví dụ về các ứng dụng được viết bằng Rails và Sinatra để có cảm nhận về mỗi loại khung, vì thế tôi đã dành thêm một giờ nữa để duyệt các dự án công khai.
Ở đây có một nguy cơ không hề nhỏ: Để đạt được tiến bộ trong lập trình, bạn cần phải cam kết một việc. Một khi bạn đã chọn được ngôn ngữ và bộ khung, sẽ dễ hơn nhiều để bắt đầu học mọi thứ bạn cần biết để viết được một chương trình. Tuy nhiên, nếu bạn chần chừ trong việc đưa ra lựa chọn, bạn có thể mất hàng năm chỉ để cố gắng tìm kiếm môi trường lập trình “hoàn hảo”.
Sẽ tốt hơn khi chọn một ngôn ngữ và bộ khung cuốn hút bạn, cam kết khám phá nó trong một khoảng thời gian, và chấp nhận những đánh đổi không thể tránh được thay vì mất hàng năm “tìm kiếm” và không tiến bộ được chút nào. Duyệt Stack Overflow và Hacker News hàng ngày không phải là lập trình.
Cuối cùng, tôi đã quyết định là sẽ bắt đầu với Sinatra. Vì dù rằng Rails có thể tiết kiệm rất nhiều thời gian nếu bạn biết bạn đang làm gì, nhưng tôi lại không biết tôi đang làm gì.
Trực giác của tôi nói cho tôi biết Sinatra là lựa chọn tốt nhất tại thời điểm đó. Cú pháp rõ ràng, đơn giản và dễ hiểu. Mã duy nhất tồn tại trong ứng dụng Sinatra là mã mà người phát triển thêm vào. Có nhiều tài liệu viết về bộ khung và dễ tìm thấy những ví dụ về các ứng dụng đang hoạt động trên GitHub, cũng như sự giúp đỡ trên Stack Overflow.
Có thể một lúc nào đó trong tương lai, tôi sẽ thử Rails. Nhưng lúc này, tôi sẽ bắt đầu với Sinatra.
Chia nhỏ kết quả cuối cùng
Khoảng 5 giờ đồng hồ tìm kiếm sơ bộ đã đem lại tất cả những gì tôi cần để bắt đầu: chia nhỏ công việc lập trình web, ngôn ngữ, bộ khung và một dự án cụ thể. Đã đến lúc bắt tay vào làm việc.
“Viết mã một ứng dụng Sinatra phục vụ cho trang web Jekyll” là mức độ thành thạo mục tiêu của tôi, nhưng tôi cần phải chia nhỏ những gì ẩn trong mệnh đề này để xác định được điều tiếp theo cần thực hiện. Tôi cần phải làm được việc gì?
Thêm một giờ nghiên cứu, tôi đã đi đến các quyết định sau:
1. Chạy Jekyll tạo ra trang web hoàn thiện từ các tập tin thống kê cục bộ. Tôi sẽ cần tạo ra một mẫu HTML cho trang web đó với các thẻ định dạng đặc biệt, và xuất khẩu kho lưu trữ các bài đăng tải từ trang PersonalMBA.com – việc này được miêu tả trong một bài hướng dẫn của Paul Stamatiou.
2. Ứng dụng Sinatra xử lý các yêu cầu từ khách ghé thăm trang web, chuyển giao các tập tin được yêu cầu. Tôi cần phải viết ứng dụng này ngay từ đầu.
3. Cả trang web Jekyll hoàn thiện và ứng dụng máy chủ Sinatra đều cần phải được đăng tải trên một máy chủ web.
4. Để hoàn thiện tất cả nhiệm vụ này, tôi cần xác định cách cài đặt phiên bản mới nhất của Ruby, cũng như Sinatra và các chương trình khác mà tôi cần, vào máy của tôi.
Yêu cầu cuối cùng này là một ví dụ hay ho về việc tìm kiếm các công cụ cần thiết. Nếu tôi không thể xác định được cách để cài đặt Ruby vào máy của mình thì tôi không thể làm được bất cứ việc gì, vậy nên đó sẽ là điểm khởi đầu tốt nhất.
Quan trọng là phải lưu ý rằng công nghệ web thay đổi hàng ngày. Nhiều khả năng là những yêu cầu cụ thể trong phần này sẽ trở nên lỗi thời khi bạn đọc cuốn sách này. Đừng lo lắng, vì phương pháp mới là điều quan trọng, chứ không phải yêu cầu.
Tương tự như vậy, bạn sẽ bị thôi thúc là phải che đậy phần mã trong chương này. Đó là một thôi thúc tự nhiên: Nó có vẻ phức tạp và bạn sẽ không thể ngay lập tức biết được nó có nghĩa là gì.
Tôi khuyến khích bạn đấu tranh chống lại sự thôi thúc này. Những cái tên, yêu cầu và biểu tượng này cũng không quen thuộc với tôi, giống như với bạn. Chương này nói về quá trình xác định điều này có nghĩa là gì, và làm sao để sử dụng nó. Nếu bạn cố gắng đọc mã, bạn sẽ nhận được nhiều hơn từ chương này.
Tiến lên nào!
Nâng cấp Ruby
Tôi đã có máy tính, đó là điểm khởi đầu, vì bạn không thể lập trình được nếu không có máy tính.
Hiện tại, tôi đang sử dụng một chiếc MacBook Air của Apple, hệ điều hành Mac OS X 10.6. Chỉ cần thực hiện một thao tác tìm kiếm nhanh là biết hệ điều hành đó là Ruby phiên bản 1.8.7 cài đặt sẵn. Đó là một tin tốt, vì về mặt lý thuyết tôi có thể bắt đầu chạy các chương trình Ruby trên chính máy tính của mình.
Vấn đề là Ruby 1.8.7 không phải là phiên bản mới nhất của Ruby. Khi tôi cố cài đặt Jekyll, hệ thống báo cho tôi biết chương trình cần phiên bản mới nhất 1.9.1, điều đó có nghĩa là tôi sẽ phải xác định cách nâng cấp. Tôi đành quay lại với Google thôi.
Một số thao tác tìm kiếm cơ bản đưa ra kết quả là hai chương trình được thiết kế để việc quản lý công đoạn cài đặt Ruby được dễ dàng hơn: rbenv và ruby-build. Cả hai chương trình đều được duy trì bởi Sam Stephenson, người đã phát triển Ruby ở 37signals. Cùng với đó, những chương trình này có thể giúp bạn cài đặt những phiên bản mới của Ruby và nói cho máy tính của bạn biết cần phải sử dụng phiên bản Ruby nào.
Có một bản hướng dẫn về trang tư liệu rbenv cho biết cách cài đặt chương trình vào máy của bạn. Các yêu cầu cài đặt như sau:
$ cd ~
$ git clone git://github.com/sstephenson/ruby-build.git
$ cd ruby-build
$ sudo ./install.sh
$ cd ..
$ git clone git://github.com/sstephenson/rbenv.git .rbenv
$ mkdir –p ~/.rbenv/plugins
$ cd ~/.rbenv/plugins
$ git clone git://github.com/sstephenson/ruby-build.git
$ echo ‘export PATH=“$HOME/.rbenv/bin:$PATH”‘ >> ~/.bashprofile
$ echo ‘eval “$(rbenv init -)”‘ >> ~/.bashprofile
$ exec $SHELL
$ rbenv install 1.9.3-p125
$ rbenv rehash
$ rbenv global 1.9.3-p125
Điều này trông có vẻ đáng sợ, nhưng đó chỉ là một danh sách các yêu cầu mà thôi. Hãy chia nhỏ nó ra.
Những yêu cầu này được đưa vào một chương trình có tên là Terminal, được cài đặt sẵn trong các máy tính của Apple. Nếu bạn đã từng nhìn thấy các hacker trên phim gõ điên cuồng vào máy tính đang hiển thị những dòng văn bản dài ngoằng, có nghĩa là chiếc máy tính đó đang chạy chương trình Terminal.
Tôi mở Terminal và nhập yêu cầu đầu tiên:
$ cd ~
Yêu cầu này rất dễ hiểu. “$” là ký hiệu Terminal hiển thị khi nó đã sẵn sàng cho một yêu cầu mới. “cd” là viết tắt của “change directory” (chuyển thư mục), một thuật ngữ khác để chỉ thư mục. Tìm kiếm nhanh cho tôi biết “~” là viết tắt của “thư mục gốc của người sử dụng”, thư mục trong máy tính của tôi, nơi lưu giữ hồ sơ.
Tôi gõ yêu cầu và nhấn nút Enter. Lúc này, Terminal hiển thị như sau:
joshkaufman $
Đó là điều đáng mừng, tôi đang ở thư mục gốc của mình. Tôi gõ yêu cầu thứ hai:
$ git clone git://github.com/sstephenson/ruby-build.git
Máy tính trả lại:
git: command not found (không tìm thấy yêu cầu)
Có vẻ như chương trình git không được cài đặt trong máy của tôi. Tôi cần phải xác định cách cài đặt nó.
“Git” là gì?
Sau khi tìm kiếm hướng dẫn về cách cài đặt git vào Mac OS X, tôi thấy Heroku Toolbelt. Heroku là công ty máy chủ ứng dụng web nên họ có hứng thú với việc giúp cho các nhà phát triển có thể dễ dàng tạo ra các ứng dụng web.
Heroku Toolbelt là chương trình cài đặt một vài công cụ phát triển phần mềm phổ biến mà các nhà lập trình cần có để phát triển ứng dụng trên Heroku. git là một trong những chương trình đó.
Tôi tải gói cài đặt về, chạy và được xác nhận là mọi thứ được cài đặt chính xác. Đã đến lúc thử lại yêu cầu trước:
$ git clone git://github.com/sstephenson/ruby-build.git
Tôi nhận được kết quả là:
Cloning into ruby-build…
remote: Counting objects: 1004, done.
remote: Compressing objects: 100% (453/453), done.
remote: Total 1004 (delta 490), reused 937 (delta 431)
Receiving objects: 100% (1004/1004), 108,77 KiB, done.
Resolving deltas: 100% (490/490), done.
Thành công! “Done” (hoàn thành) là một dấu hiệu tốt, và tôi không nhận được thông báo báo lỗi. Tiến lên nào!
Tôi tiếp tục với phần còn lại của các yêu cầu. Dựa trên thông tin trong phần hướng dẫn cài đặt, tất cả những gì tôi phải làm là tải các tập tin cần thiết, sử dụng một yêu cầu được gọi là echo để tự động thêm đoạn văn bản vào tập tin xác định cấu hình máy tính của tôi, sau đó khởi động lại chương trình có tên là SHELL trên máy tính để lưu lại các thay đổi. Một khi SHELL khởi động lại, rbenv và ruby-build đã được cài đặt. Oa!
Giờ đã đến lúc để cài đặt phiên bản mới nhất của Ruby:
$ rbenv install 1.9.3-p125
Chương trình tự động tải mã nguồn Ruby và xây dựng nó, đẩy ra một lượng ấn tượng các thông tin chạy trong chương trình Terminal đang được xử lý. (Lúc này tôi cảm thấy mình giống như một người lập trình đích thực trong phim của Hollywood.)
Yêu cầu này giúp máy tính nhận ra có một phiên bản mới của Ruby đã được cài đặt.
$ rbenv global 1.9.3-p125
Yêu cầu này đặt phiên bản 1.9.3-p125 là phiên bản mặc định của Ruby trên chiếc máy tính này. Tài liệu hướng dẫn cho tôi biết chạy yêu cầu này có thể đảm bảo chắc chắn máy tính của tôi đang sử dụng phiên bản mới:
$ ruby -v
Và tôi nhận được:
ruby 1.9.3p125 (2012-02-16 revision 34643) [x8664-darwin11.3.Ø]
Thành công rồi! Đó chính là điều phải đạt được, dựa trên bản hướng dẫn.
Theo tài liệu, nếu tôi muốn cài đặt một phiên bản mới của Ruby vào chiếc máy tính này, tất cả những gì tôi phải làm là chạy lại rbenv install, rbenv rehash và rbenv global. Quá dễ.
Dù rằng lúc đầu các yêu cầu nhìn có vẻ đáng sợ, nhưng thực ra chúng lại rất đơn giản. Những thứ trông không khác gì thảm họa ngôn ngữ thực ra lại chỉ là những ký hiệu. Một khi bạn biết ký hiệu đó tượng trưng cho cái gì thì các yêu cầu đó tự nhiên cũng trở nên dễ hiểu.
Hãy nhớ, chẳng ai sinh ra đã biết điều này (lập trình). Hầu hết thời gian, tất cả những gì bạn cần phải làm là dành vài phút để đọc tài liệu, sau đó cố gắng thực hiện theo tài liệu đó.
Cài đặt thư viện Ruby (Gems)
Giờ thì phiên bản mới nhất của Ruby đã được cài đặt. Đã đến lúc xác định cách cài đặt các thư viện mà tôi cần, bao gồm cả Sinatra.
Các thư viện của Ruby được gọi là gems, và hóa ra là chúng rất dễ cài đặt. Dưới đây là các yêu cầu để cài đặt gem Sinatra:
$ gem install sinatra
Để cập nhật Sinatra, đưa ra yêu cầu như sau:
$ gem update sinatra
Chẳng có gì dễ dàng hơn thế!
Tuy nhiên, trước khi tôi cài đặt quá nhiều thư viện, tôi muốn chắc chắn là chương trình gem được cập nhật. Vì máy tính của tôi sử dụng phiên bản Ruby cũ, nên có vẻ như các phần mềm liên quan cũng cần phải cập nhật theo.
Sau một thời gian ngắn tìm kiếm, tôi tìm thấy yêu cầu cập nhật chương trình gem của Ruby:
$ gem update--system
Đơn giản.
Khi tôi chạy yêu cầu gem install (cài đặt gem), tôi để ý thấy yêu cầu cũng cài đặt các gem bổ sung, như rack, rack-protection và tilt. Những thư viện phụ này được gọi là (thư viện) phụ thuộc (dependencies). Sinatra phụ thuộc vào những thư viện đó để chạy, vì thế yêu cầu gem install cài đặt chúng một cách tự động.
Đọc sách
Lúc này tôi đã sẵn sàng chạy ứng dụng Ruby, tôi quyết định nhấc hai cuốn sách tham khảo về Ruby được nhiều người trên Stack Overflow khuyên đọc: Người thành thạo Ruby (The well- Grounded Rubyist) (2009) của David A. Black và Ruby hùng biện (Eloquent Ruby) (2011) của Russ Olsen. Cả hai cuốn đều là sách vỡ lòng được thiết kế để giới thiệu cho độc giả những khái niệm và thủ thuật Ruby phổ biến, cũng như những đoạn văn bản tham khảo cơ bản nhất.
Tôi còn mua cả cuốn Sinatra: Cài và chạy (Sinatra: Up and Running) (2011) của Alan Harris và Konstantin Hasse. Cuốn sách này được thiết kế như phần giới thiệu cơ bản về bộ khung Sinatra. Dù có rất nhiều tài liệu về Sinatra trên mạng, nhưng cuốn sách này cũng có rất nhiều ví dụ – điều này giúp bạn dễ dàng xác định được cách sử dụng Sinatra cho những nhiệm vụ phổ biến.
Như vậy là có rất nhiều tài liệu tham khảo để bắt đầu, vì thế tôi đã dành ra 90 phút để xem nhanh tất cả những gì tôi thu lượm được từ trước đến giờ.
Tôi ngồi xuống cùng với đống sách, và với mỗi cuốn tôi lại đọc lướt bảng đề mục và phụ lục, chú ý tới những thuật ngữ và ý tưởng có vẻ quan trọng. Tôi cũng nắm bắt các khái niệm xuất hiện đi xuất hiện lại, cũng như thứ tự của phần mở đầu. Tôi đọc các đề mục chính và các cột nội dung bên lề. Khi đã xử lý xong đống sách, tôi cũng làm tương tự với các trang web.
Và đây là điều tôi đã học được. Ngoài biến số, điều kiện, ngoại lệ và những điều cơ bản khác của lập trình, Ruby được xây dựng quanh hai ý tưởng cốt lõi là đối tượng và phương pháp.
Đối tượng là danh từ của thế giới lập trình. Đó là những thứ chúng ta có thể làm gì đó (về hoặc với chúng). Giả sử tôi muốn tạo ra một biến số mới trong Ruby được gọi là firstname, và tôi muốn nó có tên tôi. Trong Ruby, yêu cầu đó như sau:
firstname = “Josh”
Rất đơn giản. Bằng cách đặt “Josh” trong dấu ngoặc kép, tôi đang nói cho Ruby biết firstname là một chuỗi ký tự (string): Dãy vừa có chữ vừa có số. Điều đó khiến firstname trở thành một đối tượng trong loại “chuỗi ký tự”. (Loại là một kiểu đối tượng cụ thể với những đặc điểm nhất định.)
Chuỗi ký tự không nhất thiết chỉ là loại các đối tượng. Đây là đối tượng thuộc loại số nguyên:
million = 1000000
Nếu đối tượng là danh từ trong lập trình thì phương pháp lại là động từ. Chúng là những việc mà chúng ta có thể làm về (hoặc với một đối tượng).
Giả sử tôi có hai chuỗi đối tượng có chứa tên và họ của tôi:
firstname = “Josh”
lastname = “Kaufman”
Tôi có thể sử dụng dấu cộng (+) để ghép những chuỗi ký tự này lại với nhau, thuật ngữ để chỉ việc xếp chúng lại gần nhau:
fullname = firstname + lastname
Một câu đố vui, fullname (tên đầy đủ) có chứa gì? Nếu bạn đoán là “Josh Kaufman” thì bạn đã nhầm.
Hãy nhớ, máy tính chỉ làm chính xác những gì bạn bảo nó làm. Chúng ta chưa bảo nó thêm khoảng cách giữa “Josh” và “Kaufman”, vì thế nó sẽ không thêm đâu. Tên đầy đủ trong trường hợp này là “JoshKaufman”.
Nếu chúng ta muốn sửa lỗi sai nho nhỏ này, chúng ta cần phải thay đổi đoạn mã để thêm khoảng cách vào:
fullname = firstname + “ “ + lastname
Dấu + là một phương pháp, và cách phương pháp hoạt động phụ thuộc vào các đối tượng mà chúng ta đang xử lý. Nếu chúng ta sử dụng số nguyên thay vì chuỗi ký tự, hệ thống sẽ thực hiện phép cộng thay vì phép ghép:
sum = million + million
Tổng (sum) đó bằng bao nhiêu? “2000000”
Các phương pháp được cài đặt sẵn của Ruby có thể giúp bạn thực hiện ngay được rất nhiều việc thú vị. Giả sử tôi muốn thấy tên đầy đủ của mình được viết ngược. Thay vì phải viết bằng tay hoặc viết một chương trình nho nhỏ để đảo ngược các chữ cái, tôi có thể sử dụng phương pháp reverse (đảo lộn) có sẵn dành cho mọi đối tượng chuỗi ký tự:
fullname.reverse
Và đây là kết quả tôi nhận được: namfuaKhsoJ
Tôi cũng có thể sử dụng nhiều hơn một phương pháp cùng một lúc. Nếu tôi muốn đảo lộn các chữ cái trong tên của mình và tất cả các chữ cái đều được viết thường, thì tôi có thể chạy đoạn mã này:
fullname.reverse.downcase
Kết quả nhận được là: namfuakhsoj. Chính xác luôn!
Học viết mã Ruby chủ yếu là học cách sử dụng, sáng tạo và điều khiển các đối tượng, các lớp và các phương pháp. Ngôn ngữ này có rất nhiều thứ được cài đặt sẵn, và Ruby cho phép bạn tạo ra, điều chỉnh hoặc loại bỏ các đối tượng, các lớp và các phương pháp tùy theo ý thích của bạn. Điều đó khiến ngôn ngữ này hữu dụng và linh động hơn.
Tài liệu hướng dẫn chính thức của Ruby có chứa danh sách kiểu mẫu của tất cả những đối tượng và phương pháp có thể sử dụng ngay. Xem nhanh một lượt có vẻ là hơi quá, nhưng điều đó lại giúp bạn nhận ra bạn không cần phải sử dụng tất cả những thứ đó. Chúng mang tính lựa chọn, và bạn có thể sử dụng chúng khi cần.
Tài liệu hướng dẫn còn có một mục đích khác, đó là khi bạn cố gắng làm điều gì đó mà Ruby không hiểu được, thông tin báo lỗi có thể nói cho bạn biết chương trình đã bị hỏng ở đâu.
Giả sử chúng ta đang cố gắng chạy một chương trình như sau:
animal = “Zebra” (con vật = “ngựa vằn”)
number = 7 (số lượng = 7)
puts animal + number (in con vật + số lượng)
Lệnh put là cách nói khác của lệnh in (print). Chúng ta muốn chương trình hiển kiểu chữ animal + number có nghĩa là gì.
Và đây là kết quả tôi nhận được khi cố gắng chạy chương trình:
TypeError: can’t convert Fixnum into String from program.
rb:3:in ‘+’
(Lỗi đánh máy: Chương trình không thể chuyển số đã nhập thành chuỗi ký tự
rb:3:in ‘+’)
Nếu không sử dụng ngôn ngữ máy tính thì: bạn không thể sử dụng số học để cộng một số vào một từ mà vẫn có nghĩa được, vì thế máy tính đã hiển thị thông báo báo lỗi. Thế chẳng khác nào cố gắng thực hiện phép chia cho không (0), nên chương trình đã dừng lại.
Để sửa chương trình, chúng ta hoặc là cần phải đổi số thành một chuỗi ký tự để phương pháp + có thể ghép hai biến số lại với nhau, thay vì cố gắng sử dụng số học; hoặc là phải điều chỉnh chương trình để thực hiện một việc gì đó khác.
Và đây là chương trình đã được sửa đổi:
animal = “Zebra”
number = 7.to_s
puts animal + number
(con vật = “ngựa vằn”
số lượng = 7.to_s
In con vật + số lượng)
Khi chạy chương trình, chúng ta sẽ nhận được kết quả là “Zebra7” (“Ngựa vằn 7”). Phương pháp được cài đặt sẵn .to_s đã biến số 7 thành chuỗi ký tự, vì thế Ruby có thể thực hiện phép ghép.
Chúng ta cũng có thể làm điều gì đó hoàn toàn khác biệt, kiểu như thế này:
animal = “Zebra”
number = 7
number.times {puts “#{animal}”}
(con vật = “ngựa vằn”
số lượng = 7
số lượng.lần {in “#{con vật}”})
Và đây là kết quả:
Zebra
Zebra
Zebra
Zebra
Zebra
Zebra
Zebra
(Ngựa vằn)
Chúng ta vừa sử dụng vòng lặp điều kiện cơ bản được tích hợp sẵn trong Ruby: number.times có nghĩa là “thực hiện việc này X lần, với X là giá trị của biến là số lượng”. Nếu chúng ta thay đổi giá trị của biến động vật hay số lượng, chúng ta sẽ thay đổi kết quả. (Đúng vậy, bạn có thể điều chỉnh chương trình này để in “gấu túi” hàng tỉ lần nếu bạn thực sự muốn.)
Nhận xét và gỡ lỗi
Khi đọc, tôi còn để ý một đặc điểm cơ bản nữa trong Ruby: nhận xét. Bất cứ khi nào bạn bắt đầu một dòng chương trình với # (thường được gọi là “dấu thăng”), Ruby sẽ dịch dòng đó như một lời nhận xét và sẽ bỏ qua nó.
Thêm nhận xét cho một chương trình khiến cho việc theo dõi chương trình đó trở nên dễ dàng hơn, vì bạn có thể giải thích bằng ngôn ngữ đơn giản điều bạn đang cố gắng thực hiện. Và nhận xét trong chương trình “Animal Print” trông sẽ như thế này:
# Assign variables
animal = “Wombat”
number = 1000000000
# Print loop
number.times {puts “#{animal}” }
(# Gán biến số
con vật = “gấu túi”
số lượng = 1000000000
# vòng lặp in
số lượng.lần {in “#{con vật}” }
Nhận xét cũng là một thủ thuật khắc phục sự cố cơ bản: bạn có thể chú thích một vài dòng mã cùng một lúc để cô lập vấn đề hoặc lỗi sai. Kết hợp với các câu lệnh in (print hoặc put) được đặt đúng chỗ, bạn có thể thực hiện chương trình từng bước một để đảm bảo mọi thứ đều hoạt động đúng như mong đợi.
Sau tổng cộng 8 tiếng nghiên cứu và cài đặt, giờ tôi đang chạy phiên bản mới nhất của Ruby. Tôi đã có thể cài đặt bất cứ thư viện nào mà tôi muốn, và tôi đã có kiến thức cơ bản về cách thức hoạt động của các chương trình Ruby.
Quan trọng là cần phải chú ý rằng, tới tận lúc này tôi vẫn chưa thực sự lập trình được bất cứ thứ gì. Toàn bộ quãng thời gian vừa rồi được dùng vào việc nghiên cứu, cài đặt Ruby, và xem viết một chương trình Ruby sẽ có cảm giác như thế nào.
Giờ hãy cùng khám phá những chương trình phức tạp hơn.
Đã đến lúc phải bắt tay vào làm rồi đây…
Ứng dụng #1: Trang web tĩnh bằng Sinatra
Tôi đã có ý tưởng cho ứng dụng web đầu tiên của mình: một ứng dụng Sinatra phục vụ cho trang web HTML cơ bản. Mức độ thành thạo mục tiêu của tôi đối với ứng dụng này là:
1. Tạo ra một ứng dụng Sinatra cơ bản có thể đưa một trang web đơn giản đến người sử dụng cuối cùng (người đọc).
2. Kiểm tra ứng dụng trên máy tính của tôi để đảm bảo nó hoạt động.
3. Triển khai ứng dụng đó vào sản xuất trên Heroku, khiến nó “sống” để những người đọc thực sự có thể sử dụng.
Chính xác là vậy. Không có gì đặc biệt, chỉ là một chương trình Sinatra đơn giản chạy trên một máy chủ công cộng.
Vậy thì tôi nên bắt đầu từ đâu? Hãy cùng điểm lại bản liệt kê những mục cần kiểm tra của tôi:
1. Chọn một dự án đáng yêu.
2. Tập trung năng lượng của bạn vào chỉ một kỹ năng.
3. Xác định mức độ thành thạo mà bạn mong muốn.
4. Phân chia kỹ năng thành những kỹ năng nhỏ.
5. Tìm được những công cụ then chốt.
6. Loại bỏ những rào cản để luyện tập.
7. Dành thời gian chuyên tâm luyện tập.
8. Tạo vòng phản hồi nhanh.
9. Luyện tập tính giờ.
10. Nhấn mạnh số lượng và tốc độ.
Tôi có một dự án được xác định rõ ràng. Tôi đã chia nhỏ kỹ năng và tôi biết chương trình này trông như thế nào khi được hoàn thành. Điều đó đưa tôi đến với những công cụ cần thiết: Có thứ gì cần để hoàn thành dự án này mà tôi chưa có không?
Hóa ra là còn: Tôi chưa có tài khoản Heroku. Điều đó dễ giải quyết: Tôi truy cập vào trang Heroku.com, click vào ô Đăng ký, xác nhận địa chỉ e-mail và tạo mật khẩu.
Vì tôi đã tải Heroku Toolbelt (chương trình tôi đã sử dụng để cài đặt git), thư viện (gem) Heroku cũng đã có trên máy của tôi, nên tôi đã sẵn sàng.
Dựa trên tài liệu hướng dẫn, còn một điều cuối cùng tôi cần phải làm để máy tính của tôi có thể “nói chuyện” được với Heroku, đó là tạo ra “chìa khóa SSH” – một tập tin đặc biệt đóng vai trò như mật khẩu. Một khi đã có chìa khóa, tôi sẽ phải đăng tải lên Heroku để hệ thống có thể nhận biết được máy tính của tôi và cho phép nó truy cập.
May mắn là Heroku có tài liệu hướng dẫn về cách làm việc này. Tôi đã chạy yêu cầu này để tạo chìa khóa:
$ ssh-keygen –t rsa
… và yêu cầu này để đăng nhập vào Heroku:
$ heroku login
… và yêu cầu này để thêm chìa khóa vào tài khoản Heroku của tôi:
$ heroku keys:add
Tuyệt vời. Tôi đã vào được. Giờ tôi bắt đầu viết ứng dụng như thế nào?
Tạo ra ứng dụng cơ bản
Đã đến lúc duyệt qua tài liệu của Heroku. Điều tuyệt vời là có tới hai tài liệu hướng dẫn có vẻ hữu dụng:
“Bắt đầu với Ruby trên Heroku”
“Triển khai các ứng dụng dựa trên Rack (Rack-based Apps)”
Dựa trên những hướng dẫn này, có vẻ như tôi cần phải:
1. Tạo ra các tập tin chương trình trên máy tính của tôi.
2. Thêm chúng vào “kho git” (bất kể đó là gì…)
3. Sử dụng yêu cầu git push heroku master để gửi ứng dụng hoàn thiện lên Heroku.
May mắn là tài liệu hướng dẫn có một ví dụ, và đó là một ứng dụng Sinatra! Việc này sẽ dễ dàng hơn tôi tưởng.
Tôi tạo một thư mục trong máy tính của mình. Thư mục này được gọi là thư mục “gốc”, và tất cả các tập tin trong chương trình sẽ được lưu giữ ở đây.
Tiếp theo, tôi mở phần mềm biên tập văn bản (tôi đang sử dụng TextMate) và tạo ba tập tin theo đúng hướng dẫn:
application.rb
config.ru
Gemfile
Phần cốt lõi của chương trình sẽ nằm ở application.rb. Các ứng dụng của Ruby luôn có phần đuôi là .rb.
config.ru là nơi cài đặt cấu hình Rack. Hãy nhớ là Sinatra được xây dựng trên nền Rack, nên hoàn toàn dễ hiểu khi nó có một tập tin xác định cấu hình riêng. Các tập tin “Rackup” có phần đuôi là .ru.
Gemfile là nơi xác định gem nào sẽ được chương trình sử dụng. Chương trình của bạn sẽ chỉ có một Gemfile, nên nó vẫn luôn được gọi là “Gemfile”. Có vẻ cũng đơn giản.
Sau khi tạo các tập tin, tài liệu hướng dẫn Heroku gợi ý nên viết một chương trình đơn giản “Xin chào, thế giới!” để kiểm tra việc thiết lập. Và đây là điều trong application.rb:
require ‘sinatra’
get ‘/’ do
“Hello World!”
end
(yêu cầu “sinatra”
nhận ‘/’ làm
“Xin chào Thế giới!”
kết thúc)
Còn đây là những gì diễn ra trong config.ru:
require ‘./application.rb’
run Sinatra::Application
(yêu cầu ‘./ứng dụng.rb’
chạy Sinatra::Ứng dụng)
Và đây là những gì diễn ra trong Gemfile:
source ‘http://rubygems.org’
gem ‘sinatra’
(nguồn ‘http://rubygems.org’
gem ‘sinatra’)
Như vậy là cũng không nhiều mã lắm và cũng tương đối dễ hiểu, đúng không?
Gemfile nói cho máy chủ biết phải thêm gem Sinatra vào, có như vậy mới chạy được ứng dụng. Gem sẽ được tải về từ RubyGems.org.
Tập tin config.ru thiết lập ứng dụng chính, sau đó thực hiện chương trình.
Khi chương trình được chạy, nó sẽ hiển thị dòng chữ “Xin chào Thế giới!” bất cứ khi nào có ai đó truy cập “/” (ký hiệu để chỉ trang chủ của một trang web).
Có thực sự dễ dàng thế không nhỉ?
Tài liệu hướng dẫn cho tôi biết còn một việc nữa cần phải làm, đó là lưu giữ các tập tin trong kho git (đôi khi được viết tắt thành “kho”). Thực ra tôi không chắc điều đó có nghĩa là gì, nhưng tôi biết là git đã được cài đặt, và họ cung cấp các yêu cầu:
$ git init
$ git add -A
$ git commit -m “Initial Commit”
Yêu cầu đầu tiên tạo ra một kho git mới trong thư mục gốc hiện có. Yêu cầu add -A thêm tất cả các tập tin trong thư mục vào kho. Yêu cầu commit -m” chuyển các tập tin tới kho, cùng với tin nhắn từ người lập trình cho biết điều gì đang được chuyển. (Tôi vẫn không hiểu sự khác nhau giữa “thêm” và “chuyển”, nhưng tôi đã ghi chú để tìm hiểu thêm sau.)
Sau khi nhập những yêu cầu này, máy tính thông báo với tôi:
[master (root-commit) 8ed1099] Initial commit
3 files changed, 9 insertions(+), 0 deletions(-)
create mode 100644 Gemfile
create mode 100644 application.rb
create mode 100644 config.ru
([thực hiện (chuyển-gốc) 8ed1099] chuyển chữ đầu
3 tập tin đã đổi, 9 lồng ghép(+), 0 xóa(-)
tạo trạng thái 100644 Gemfile
tạo trạng thái 100644 ứng dụng.rb
tạo trạng thái 100644 config.ru)
Có vẻ như đã được! Chỉ còn một việc cần làm nữa thôi, đó là tạo một máy chủ mới còn trống trên Heroku, sau đó “đẩy” chương trình của tôi lên máy chủ đó.
Tôi chạy đoạn yêu cầu này để tạo máy chủ:
$ heroku create
($ tạo heroku)
Và tôi nhận được:
Creating shielded-springs-2049 … done, stack is stack is bamboo-ree-1.8.7
http://shielded-springs-2049.heroku.com/|git@heroku.com:shielded-springs-2049.git
Git remote heroku added
Đã thành công! “Ngăn xếp” (stack) cho biết phần mềm mà máy chủ đang chạy, và thông điệp cho tôi biết URL của máy chủ.
Còn đây là yêu cầu cuối cùng:
$ git push heroku master
Nếu tất cả đều ổn, tôi sẽ chính thức đẩy ứng dụng đầu tiên của tôi lên Heroku.
Và đây là kết quả tôi nhận được:
Heroku receiving push
Ruby/Sinatra app detected
Gemfile detected, running Bundler version 1.0.7
Unresolved dependencies detected; Installing…
Using-without development:test
! Gemfile.lock will soon be required
!Check Gemfile.lock into git with ‘git add Gemfile.lock’
! See http://devcenter.heroku.com/articles/bundler
Fetching source index for http://rubygems.org/
Installing rack (1.4.1)
Installing rack-protection (1.2.0)
Installing tilt (1.3.3)
Installing sinatra (1.3.3)
Using bundler (1.0.7)
Your bundler is complete! It was installed into ./.bundle/gems/
Compiled slug size: 500K
Launching … done, v4
http://shielded-springs-2049.heroku.com deployed to Heroku
Giờ là lúc kiểm tra thành quả đây… Tôi mở trình duyệt web, điều hướng tới http://shielded-springs-2049.heroku.com và đây là điều tôi nhìn thấy:
“Xin chào, Thế giới!”
ĐÃ THÀNH CÔNG!
Đến thời kỳ của Sinatra
Giờ thì ứng dụng đơn giản của tôi đã được hình thành và đang chạy, cuối cùng tôi cũng có thể bắt đầu học cách vận hành của Sinatra. Tài liệu hướng dẫn về Sinatra rất dễ hiểu, và có rất nhiều ví dụ, chính vì thế mà tôi đã quyết định là sẽ bắt đầu từ đó.
Cốt lõi của các ứng dụng Sinatra là tuyến/hướng. Cách tốt nhất để hiểu được khái niệm này là xem ví dụ.
Các ứng dụng Sinatra cơ bản của chúng ta đều có một tuyến đơn, tuyến này chứa “gốc” trang web nho nhỏ của chúng ta. Những người sử dụng internet thường coi gốc trang web là trang chủ của trang web.
Nếu bạn truy cập google.com hay yahoo.com, trình duyệt web của bạn sẽ gửi một yêu cầu đến máy chủ của Google hoặc Yahoo. Yêu cầu này được gọi là yêu cầu NHẬN (GET), và nó buộc máy chủ phải cho bạn biết bất cứ thứ gì trong thư mục gốc của trang web. Giao thức (protocol), hay dạng thức máy tính sử dụng để gửi yêu cầu, được gọi là HTTP (chữ viết tắt của “hypertext transfer protocol” có nghĩa là giao thức truyền tải siêu văn bản). “http://” mà bạn vẫn nhìn thấy ở đầu mỗi trang web có nghĩa như thế.
GET là dạng yêu cầu HTTP phổ biến nhất, nhưng đó không phải là dạng duy nhất. Còn có thêm ba “động từ” HTTP nữa, đó là:
POST – gửi một nguồn lên máy chủ
PUT – cập nhật nguồn trên máy chủ
DELETE – xóa nguồn trên máy chủ
Nếu bạn đã từng đăng một nhận xét công khai trên một trang web, nhận xét của bạn được gửi tới máy chủ bằng cách sử dụng một lệnh POST. Nếu bạn viết sai và chỉnh sửa lại lời nhận xét đó thì lời nhận xét đã được chỉnh sửa của bạn được gửi tới máy chủ thông qua một lệnh PUT. Nếu bạn nghĩ nhận xét của mình thật ngớ ngẩn và chọn xóa nó đi, trình duyệt sẽ gửi một lệnh DELETE.
Các tuyến bao hàm các lệnh GET, POST, PUT và DELETE chính là cốt lõi cho thấy cách vận hành của các ứng dụng Sinatra. Mỗi một tuyến bạn tạo ra là một điều kiện: “Thực hiện X nếu tuyến Y nhận được một yêu cầu GET/POST/PUT/DELETE”.
Các tuyến của Sinatra còn có thể chứa các biến được gọi là tham số (parameter). Các ứng dụng Sinatra thường sử dụng tham số như dữ liệu đầu vào cho quá trình có trong mỗi tuyến.
Hãy cùng thay đổi ứng dụng Sinatra đơn giản “Xin chào, Thế giới!” lúc trước của chúng ta để chào người sử dụng bằng tên của họ. Và đây là tuyến sẽ thực hiện điều đó:
get ‘/hello/:name’ do
“Hello, #{params[:name]}!”
end
Ứng dụng này hoạt động bằng cách cho phép máy chủ nhìn vào bất cứ điều gì trong phần “tên” của tuyến, sau đó sử dụng nó vào ứng dụng này. Yêu cầu trong tuyến là một chỉ lệnh đơn giản để hiển thị tham số “tên” tới người sử dụng.
Sinatra cho phép bạn đặt tên cho các tham số (ví dụ như : name), nhưng nó cũng có tham số đại diện (hay còn gọi là “splat”) có thể chứa bất cứ thứ gì.
Và đây là cách chúng ta sử dụng nó trong ứng dụng “Hello” đã được điều chỉnh của chúng ta:
get ‘/hello/*’ do
“Hello, #{params[:splat]}!”
end
Có vẻ khá thú vị. Giữa các tham số được đặt tên và các tham số đại diện, bạn có thể tạo ra một số tuyến rất thông minh. Các tuyến bạn tạo ra sẽ quyết định cách thức vận hành ứng dụng Sinatra của bạn.
Như vậy là đã đủ chi tiết cho việc xác định cách viết một chương trình đáp ứng được mức độ thành thạo mục tiêu của tôi. Vì Jekyll đang hình thành những tập tin mà ứng dụng sẽ truyền tải để đáp lại yêu cầu GET của người sử dụng, nên tất cả những gì tôi cần phải làm là viết một vài tuyến chấp nhận những yêu cầu đó, tìm kiếm tập tin chính xác trong hệ thống và chuyển nó đến người đọc.
Dựa trên tài liệu hướng dẫn Jekyll, chương trình đặt các trang web hoàn thiện vào một thư mục được gọi là “trang” trong kho gốc. Tuyến tới trang đó được Jekyll tự động tạo ra. Nếu chúng ta muốn chuyên trang About (về trang web) có trên http://example.com/ about, chúng ta cần phải đặt một tuyến về About trong các tập tin Jekyll của chúng ta, và chương trình sẽ tạo tập tin in_site/about/index. html trong thư mục gốc của trang web.
Điều đó có nghĩa là tôi phải tạo ra một tuyến mới trong Sinatra để đọc một tập tin nào đó theo yêu cầu GET của người sử dụng. Và việc tạo ra đó như sau:
# Index handler
get ‘/?’ do
## File.read(“_site/index.html”)
end
# Post handler
get ‘/*/?’ do
## File.read(“_site/#{params[:splat]}/index.html”)
end
File.read(“”) là yêu cầu được cài vào Ruby. File là một đối tượng, và .read là một phương pháp. Cách sử dụng rất đơn giản: Điều gì xuất hiện trong phần (“”) chính là vị trí của tập tin mà bạn muốn chương trình đọc, có liên quan tới thư mục gốc của ứng dụng. Đơn giản thôi.
Chuyện gì sẽ xảy ra nếu tập tin đó không tồn tại? Nếu vậy thì cần phải có ngoại lệ, và Sinatra có hai tuyến lỗi cơ bản được cài đặt sẵn: not_found (không tìm thấy) và error (lỗi). Hãy làm cho cả hai tuyến đều trở lại cùng một trang lỗi:
not_found do
## File.read(“_site/error/index.html”)
end
error do
File.read(“_site/error/index.html”)
end
Tất cả những thứ khác đều giữ nguyên. Tôi sẽ không thay đổi bất cứ thứ gì ở config.ru hoặc Gemfile. Tôi sẽ chỉ thêm các tuyến mới cho kho git của chương trình, xác nhận thay đổi, sau đó đẩy chương trình đã được cập nhật lên Heroku. Xong!
Ứng dụng web hoạt động đầu tiên của tôi đã hoàn thành. Phải mất cả tiếng để tôi xác định cần phải thực hiện những bước đó như thế nào, và thêm một tiếng nữa để xác định làm cách nào để chuyển thông tin và thiết kế trang web của tôi từ WordPress sang Jekyll.
Tổng thời gian để hoàn thiện là khoảng 10 tiếng, bao gồm cả thời gian nghiên cứu và xem lại khái niệm lập trình. Cũng không tồi!
Ứng dụng #2: Codex, cơ sở dữ liệu ghi chú cá nhân
Ứng dụng đầu tiên của tôi đã hoạt động, và nó hoạt động rất tốt. Nó đơn giản, nhưng trong trường hợp này, đó lại là một lợi thế lớn. Càng ít phần động có nghĩa là chương trình càng ít bị hỏng.
Giờ hãy cùng tìm hiểu một thứ phức tạp hơn một chút.
Bạn có nhớ cuộc thảo luận về cơ sở dữ liệu của chúng ta lúc trước không? Các trang web cơ bản không thể tự cập nhật, vì thế chúng không thể lưu giữ thông tin được. Ứng dụng đầu tiên chỉ hoạt động vì các tập tin tĩnh: chúng không thay đổi. Bất cứ thay đổi nào đối với các tập tin đều được thực hiện thông qua Jekyll, một chương trình tách biệt. Ứng dụng này nhanh và ổn định vì nó không phụ thuộc vào cơ sở dữ liệu.
Vậy còn những ứng dụng sử dụng cơ sở dữ liệu thì sao? Cơ sở dữ liệu là một phần lớn của các ứng dụng web nói chung, vì thế tôi cần phải hiểu cách thức hoạt động của chúng. Để học về cách chúng hoạt động, tôi cần phải bắt đầu làm việc với một dự án phụ thuộc vào cơ sở dữ liệu.
Một trong những ứng dụng tôi sử dụng hàng ngày là Backpack, một ứng dụng được 37signals phát triển. Lợi ích lớn nhất của Backpack là tạo ra các “trang” chứa được bất cứ thứ gì (văn bản, danh sách, hình ảnh, tập tin…) Khi bạn lưu thông tin trong một trang vào Backpack, sau này bạn có thể truy cập vào thông tin đó từ bất cứ máy tính nào, vì tất cả các thông tin đều được lưu giữ trong cơ sở dữ liệu của ứng dụng.
Tôi tự hỏi là: Liệu tôi có thể tự mình tạo ra thứ gì đó tương tự như vậy không? Cũng đáng để thử đây… nhưng tôi phải bắt đầu như thế nào?
Trong khi nghiên cứu Jekyll, tôi đã đọc được một bài viết của Tom Preston-Werner, nhà lập trình đã tạo ra Jekyll. Bài viết đó có tên là “Phát triển phần mềm dựa trên Readme” (Readme(3) Driven Development).
Readme là tập tin được người lập trình đưa vào thư mục gốc của ứng dụng trong quá trình viết mã. Tập tin này chứa các thông tin về cách thiết lập, xác định cấu hình và sử dụng chương trình.
Tom lập luận rằng, tốt nhất là nên viết tập tin Readme cho chương trình đầu tiên, trước khi bạn bắt đầu viết mã. Hầu hết những người lập trình đều viết mã trước, sau đó mới (có thể) viết Readme. Như thế là đã bỏ lỡ một cơ hội: viết Readme trước giúp bạn xác định chính xác chương trình sẽ làm việc như thế nào. Readme có thể là một công cụ thiết kế mà cũng có thể là một tài liệu hướng dẫn.
Tôi lấy một cuốn sổ ghi chép và ghi lại những việc tôi muốn ứng dụng của mình làm được, cũng như những đặc điểm mà tôi muốn ứng dụng của mình có:
Chương trình là một ứng dụng ghi nhớ và tham khảo đơn giản.
Ứng dụng được thiết kế cho một người sử dụng.
Ứng dụng sử dụng Sinatra và cơ sở dữ liệu để tạo ra, lưu giữ, cập nhật và xóa các bản ghi dữ liệu.
Ứng dụng cho phép người sử dụng tạo ra các trang có các định dạng thú vị như bôi đen, nghiêng, có đề mục…
Ứng dụng yêu cầu phải nhập mật khẩu để truy cập, và giữ thông tin trong cơ sở dữ liệu an toàn nhất có thể.
Ứng dụng có giao diện đẹp.
Ứng dụng có thể dễ dàng được triển khai trên Heroku hoặc một trang chủ tương tự khác.
Tôi sẽ gọi ứng dụng này là Codex, một từ cổ dùng để chỉ “sách”, vì ứng dụng này sẽ chủ yếu được sử dụng như thông tin hay danh sách tham khảo, và những thứ tương tự như vậy.
Thuật ngữ lập trình web dùng để chỉ loại ứng dụng này là “CRUD”, là từ viết tắt của Create (tạo ra), Read (đọc), Update (cập nhật) và Delete (xóa). Cần phải đề cập rằng những chức năng này về cơ bản đều giống như GET, POST, PUT và DELETE, vì vậy hoàn toàn có thể sử dụng các tuyến của Sinatra để xây dựng ứng dụng này. Khác biệt lớn nhất là việc đưa cơ sở dữ liệu vào.
Có những kiểu lựa chọn cơ sở dữ liệu nào trên Heroku? Tôi không biết, phải xem lại tài liệu hướng dẫn thôi.
Theo mặc định, Heroku sử dụng cơ sở dữ liệu được gọi là Postgres. Mỗi ứng dụng mới được phân bổ một cơ sở dữ liệu phát triển mặc định. Điều đó có tác dụng với tôi, nhưng làm thế nào tôi có thể sử dụng được, và tôi cần phải sử dụng cái gì để thử nghiệm chương trình trên máy tính của mình?
Nhập DataMapper
Để trả lời những câu hỏi này, tôi quyết định tìm kiếm trên Stack Overflow. Tất cả các ý kiến trên trang web này đều đồng nhất ở một điểm, đó là sử dụng thư viện có tên là DataMapper giúp cho việc phát triển này trở nên đơn giản hơn.
DataMapper là kiểu chương trình được gọi là “công cụ vẽ bản đồ mối quan hệ đối tượng” (object relational mapper), thường được viết tắt là ORM. ORM giải quyết được một vấn đề cấp thiết đối với những người lập trình: Cơ sở dữ liệu thường sử dụng ngôn ngữ riêng, loại ngôn ngữ khác với ngôn ngữ mà các nhà lập trình sử dụng để tạo ra ứng dụng. Ngôn ngữ cơ sở dữ liệu phổ biến nhất là SQL, ngoài ra còn có hàng trăm thứ ngôn ngữ khác.
Giả sử chúng ta là người lập trình cho trang web Amazon.com, và chúng ta muốn hiển thị một danh sách các cuốn sách của nhà văn J. K. Rowling, tác giả của loạt truyện Harry Potter nổi tiếng. Khi đó, yêu cầu SQL sẽ như sau:
SELECT * FROM Book WHERE author = “J.K. Rowling” ORDER BY title;
Lệnh này sẽ lấy ra tất cả các bản ghi có trường “author” chứa tên “J.K. Rowling” từ cơ sở dữ liệu tên Book và sắp xếp chúng theo thứ tự bảng chữ cái của tên sách.
Đáng tiếc là việc làm cho SQL hay bất cứ ngôn ngữ truy vấn cơ sở dữ liệu nào khác chạy mượt mà với những ngôn ngữ lập trình như Ruby là cả một vấn đề. Lập trình bằng một loại ngôn ngữ đã đủ khó rồi, huống hồ là bằng vài loại ngôn ngữ cùng một lúc.
Nhưng đó lại chính là nơi ORM phát huy tác dụng: Chúng cho phép người lập trình viết mã bằng một ngôn ngữ, sau đó ORM sẽ dịch ngôn ngữ đó sang ngôn ngữ của cơ sở dữ liệu. Dễ dàng hơn nhiều.
Như vậy, DataMapper là một thư viện, giúp cho việc liên lạc với cơ sở dữ liệu bằng cách sử dụng Ruby trở nên dễ dàng hơn. Theo mặc định, DataMapper cung cấp một loạt những đặc tính hữu ích cho việc tạo ra, đọc, cập nhật và xóa bản ghi truy cập cơ sở dữ liệu. Vì DataMapper được hình thành một thời gian, và đã được thử nghiệm cẩn thận, nên trong hầu hết các trường hợp, sử dụng nó sẽ đáng tin hơn nhiều so với việc tự tạo ra một loại mã cơ sở dữ liệu riêng.
DataMapper có thể sử dụng như một loại gem, và được cài đặt như sau:
$ gem install data_mapper
DataMapper là một thư viện lớn, vì thế nên cài đặt từng bước một. Đây là khái niệm được gọi là “hệ mô-đun”, và nó là dấu hiệu xác nhận việc lập trình tốt. Dưới đây là yêu cầu cài đặt toàn bộ các gem riêng lẻ:
$ gem install dm-core dm-aggregates dm-constraints dm-migrations dm-transactions dm- serializer dm-timestamps dm-validations dm-types
Thay vì cài đặt toàn bộ thư viện, bạn có thể chỉ cài đặt những phần mà chương trình của bạn sẽ sử dụng, như vậy sẽ hiệu quả hơn nhiều.
Sử dụng DataMapper
Giờ thì DataMapper đã được cài đặt, tôi cần phải xác định cách sử dụng nó để (1) “nói chuyện” với cơ sở dữ liệu và (2) thiết lập cơ sở dữ liệu để lưu trữ và lấy lại các thông tin mà tôi muốn.
Dựa trên tài liệu hướng dẫn về Postgres của Heroku, yêu cầu dưới đây sẽ cho phép ứng dụng Sinatra của tôi “nói chuyện” được với cơ sở dữ liệu:
DataMapper.setup(:default, ENV[‘DATABASE_URL’] ||
“sqlite3://#{Dir.pwd}/database.db”)
Trong trường hợp này, ký hiệu || được sử dụng như một cách khác để nói “hoặc”. ENV[‘DATABASEURL’] là một biến mà Heroku sử dụng để tượng trưng cho cơ sở dữ liệu trong ứng dụng của bạn. Nếu cơ sở dữ liệu này không có thì nó sẽ sử dụng lựa chọn thứ hai – cơ sở dữ liệu được gọi là Sqlite.
Sqlite được mặc định cài đặt trên các dòng máy tính của Mac, nên nó đã sẵn sàng để sử dụng. DataMapper có thể “nói chuyện” được với cả Postgres và Sqlite nếu tôi cài đặt hai gem này:
$ gem install dm-sqlite-adapter dm-postgres-adapter
Điều này có nghĩa là ứng dụng của tôi sẽ sử dụng Postgres khi nó được chạy trên Heroku, và sử dụng Sqlite khi nó chạy trên máy tính của tôi. Trong trường hợp nào thì đoạn mã của tôi cũng vẫn như vậy, ngay cả khi cơ sở dữ liệu sử dụng loại ngôn ngữ khác. Điều đó thực sự rất tuyệt.
Nhắc tới việc chạy ứng dụng này trên máy tính của tôi… Làm sao để làm được điều đó?
POW!
Tôi tìm kiếm thông tin về cách chạy kiểu chương trình này trên máy của tôi từ hai trang Stack Overflow và Hacker News. May mắn là có một số lựa chọn. Có vẻ như tôi có thể cài đặt các loại thư viện (như Foreman hoặc Shotgun) để chạy ứng dụng này khi tôi nhập một yêu cầu vào Terminal, hoặc tôi có thể cài đặt một chương trình để giữ cho chương trình luôn chạy.
Chương trình trong cách thứ hai nêu trên là Pow, một “máy chủ Rack cấu hình số 0 cho Mac OS X”. Trang web cam kết giúp cho việc thiết lập duy trì phát triển nội bộ trên máy tính của tôi trở nên đơn giản và chỉ mất không quá một phút. Nghe có vẻ tuyệt với tôi!
Việc cài đặt Pow chỉ mất khoảng 10 giây: Nó đòi hỏi phải có một yêu cầu Terminal để tải về và cài đặt ứng dụng. Một khi đã được cài đặt, bạn phải chạy một yêu cầu để nối chương trình của bạn với chương trình Pow, và Pow sẽ cho phép bạn được chạy nó trên máy tính của bạn.
Có một gem của Ruby được gọi là Powder có tác dụng giúp cho quá trình này thậm chí còn dễ dàng hơn:
$ gem install powder
Khi gem đó đã được cài đặt, bạn chạy đoạn mã này để cài đặt Pow:
$ powder install
Sau đó, bạn vào kho dữ liệu gốc ứng dụng của bạn và nhập yêu cầu này vào:
$ powder link
Vậy thôi. Kho gốc của tôi được gọi là “codex”, vì thế ứng dụng của tôi lúc này đã có thể chạy trên máy tính cá nhân của tôi tại http://codex.dev, và tôi có thể thử nghiệm “tác phẩm” của mình.
Nếu tôi thay đổi yêu cầu này sẽ khởi động lại chương trình:
$ powder restart
Thật đơn giản. Giờ tôi đã sẵn sàng bắt tay vào xây dựng. Tôi dành ra một tiếng rưỡi mối tối để viết mã, và tôi sẽ tiếp tục cho tới khi hoàn thành.
Viết mã, kiểm tra, sửa lại
Lúc này, tôi sẽ miêu tả điều tôi sẽ thực hiện thay vì cách tôi thực hiện.
Đây là hình ảnh ứng dụng mà tôi muốn có khi hoàn thành:
Bạn sẽ để ý thấy là thiết kế này có ba phần: thanh điều hướng trên cùng, khu vực nội dung chính và thanh bên. Tôi đặt chúng lại với nhau bằng cách sử dụng Bootstrap do Mark Otto và Jacob Thornton tạo ra (cả hai cùng là lập trình viên ở Twitter).
Thay vì tạo ra một thiết kế trang web ngay từ ban đầu, Bootstrap là một thư viện HTML và CSS viết sẵn, cho sử dụng hoàn toàn miễn phí. Sử dụng Bootstrap sẽ tiết kiệm rất nhiều thời gian: bạn có thể đặt một mẫu cơ bản ban đầu cho ứng dụng của bạn chỉ trong vài phút thay vì vài ngày.
Đơn vị cơ bản của ứng dụng này là “trang” (page), nơi hiển thị bản ghi được lưu giữ trong cơ sở dữ liệu. Thông tin trang thuộc khu vực nội dung chính. Có một nút dẫn tới màn hình, nơi có danh sách tất cả các trang trong cơ sở dữ liệu, và hai nút ở cuối. Nút đầu tiên giúp bạn biên tập, chỉnh sửa trang hiện tại, và nút thứ hai cho phép bạn thực hiện thao tác xóa.
Thanh bên có ba tính năng chính. Ở trên cùng, có một khung mẫu cho phép bạn tạo một trang mới, việc này đòi hỏi phải nhập tiêu đề. Thứ hai, có một danh sách các trang mà người sử dụng đã thêm vào thanh bên, được coi như khu vực tham khảo nhanh. Thứ ba, có một phần tham khảo liên quan tới việc định hình, giúp người sử dụng nhớ được cách sử dụng những tính năng định hình phổ biến.
Thanh điều hướng ở trên cùng có vẻ khá đơn giản. Nó có chứa một đường dẫn (link) tới trang chủ, và một đường dẫn thứ hai tới màn hình “danh sách tất cả các trang”. Tôi có thể thêm các mục khác cho thanh điều hướng sau đó nếu tôi thích, nhưng đó là tất cả những gì tôi thực sự cần lúc này.
Mỗi ứng dụng web đều có một trang chủ, vì thế tôi cần phải quyết định tôi muốn có những gì trên trang chủ đó. T rong trường hợp này, tôi chỉ muốn hiển thị bản ghi trang chủ trong cơ sở dữ liệu.
Vậy thì có gì trong một trang? Vì mỗi trang là một bản ghi cơ sở dữ liệu, và các bản ghi có các trường chứa thông tin thực, nên tôi cần phải nói với DataMapper là cần phải thiết lập các trường nào. Và đoạn mã để làm được việc đó là như thế này:
class Page
include DataMapper::Resource
property :id, Serial
property :title, String
property :content, Text
property :lastupdated, DateTime
end
DataMapper.finalize
Đoạn mã này sử dụng DataMapper để tạo ra một loại đối tượng mới được gọi là trang (page). Lúc này Ruby có thể sử dụng trang như bất cứ một đối tượng nào khác, và tôi có thể tạo ra và sử dụng các phương pháp xây dựng, điều chỉnh và xóa các trang. Khi tôi tạo ra một sự thay đổi trên một trang, sự thay đổi đó sẽ được lưu giữ trong cơ sở dữ liệu thông qua DataMapper.
Lệnh DataMapper.finalize yêu cầu ứng dụng thiết lập những trường này trong cơ sở dữ liệu thực nếu chúng chưa tồn tại.
Như vậy là cơ sở dữ liệu của tôi đã được thiết lập, giờ là lúc xác định tuyến nào Sinatra có thể kỳ vọng phục vụ. Dưới đây là danh sách của tôi, dựa trên những gì tôi biết từ trước đến giờ:
# Show home page
get ‘/’
# Creates new note from “new page” form
post ‘/’
# Displays requested note
get ‘/:url/’
# Edits requested note
get ‘/:url/edit’
# Saves user edits to note
post ‘/:url/edit’
# Deletes specified note
delete ‘/:url/’
# List all pages in database
get ‘/all/’
# Error handling
not-found
error
Đó là một danh sách hay ho. Ứng dụng của tôi sẽ xoay quanh những yêu cầu mà tôi tạo ra cho mỗi tuyến.
Slug, Slug mọi nơi!
Bạn còn nhớ khi tôi nói rằng, cơ sở dữ liệu giống như một chồng thẻ ghi nhớ ma thuật, và bạn có thể tìm chúng theo bất cứ cách nào mà bạn muốn không? Chúng ta cần một cách để tìm kiếm bản ghi các trang cụ thể, đó chính là lý do tại sao bạn thấy: url trong những tuyến này. Nội dung của tham số url sẽ nói cho cơ sở dữ liệu biết phải lấy lại bản ghi nào.
Chúng ta có thể sử dụng tiêu đề trang như một tham số, nhưng có một vấn đề, đó là trình duyệt web không thích những thứ như chỗ trống, chữ cái viết hoa và các ký tự đặc biệt (kiểu như $ và %) xuất hiện trong địa chỉ web. Trong khi đó, tiêu đề trang rất có thể sẽ có những thứ đó, vì vậy bạn cần có một cách để loại bỏ chúng.
Chuỗi ký tự duy nhất xác định trang web được gọi là slug. Phần slug trang web của tôi được thực hiện dựa trên tiêu đề trang với những nguyên tắc sau để đảm bảo địa chỉ web thân thiện:
1. Tất cả các chữ cái đều được viết thường.
2. Không có ký tự đặc biệt – chỉ có chữ cái và số.
3. Không có khoảng trống – tất cả các khoảng trống nên được thay thế bằng dấu gạch ngang.
Phương pháp để thực hiện việc này là tạo ra một cách chấp nhận tiêu đề trang, sau đó chuyển nó sang định dạng slug. Đảm nhận việc chăm sóc những sự thay thế đó là một chương trình có tên gọi là regular expressians, nó biến đổi hoặc tìm kiếm văn bản trong chuỗi ký tự dựa trên các nguyên tắc được định sẵn.
Giờ tôi đã có thể sử dụng phương pháp slug hóa để biến đổi một chuỗi ký tự kiểu như “Tiêu đề Trang” thành “tiêu đề-trang”, để phù hợp với việc sử dụng trong địa chỉ trang web.
Ngoài ra, nếu chúng ta lưu trữ slug cùng với tiêu đề của trang, chúng ta có thể sử dụng nó để lấy lại bản ghi trang bằng cách sử dụng tham số: url.
Tạo trang
Tôi bắt đầu bằng việc viết ra danh sách các tuyến cần thiết. Tuyến “trang chủ” rất dễ: tôi điều hướng nó tới /home/slug vì tôi muốn trang chủ thể hiện bản ghi chính.
Tuyến “tạo trang” được gắn kết với một mẫu nhỏ ở phần trên cùng của thanh phụ. Người sử dụng nhập tiêu đề trang vào mẫu này, sau đó kích vào nút. Hệ thống nắm bắt tiêu đề trang, slug hóa nó, sau đó lưu tiêu đề, slug, và thời gian tạo ra cơ sở dữ liệu. Sau đó, hệ thống sẽ gửi yêu cầu GET có chứa slug, hiển thị trang mới.
Có một chi tiết nhỏ rất quan trọng trong tuyến “tạo trang”: chuyện gì sẽ xảy ra nếu trang đó đã có rồi? Tôi không muốn viết đè lên một trang đã có chứa dữ liệu. Vô tình đánh mất dữ liệu là điều không thể chấp nhận được.
May mắn là DataMapper giải quyết được vấn đề đặc biệt này bằng một phương pháp được tích hợp sẵn .first-or-create (lần đầu-hay-tạo ra). Trước khi tạo trang, DataMapper sẽ kiểm tra xem trang đó đã có hay chưa. Nếu trang đó đã tồn tại, DataMapper sẽ không viết đè lên nó, và thay vào đó, Sinatra sẽ điều hướng trình duyệt tới trang web đã có đó. Vấn đề đã được giải quyết.
Chỉnh sửa trang
Chỉnh sửa trang liên quan tới hai tuyến riêng biệt. Tuyến đầu tiên nhận (GET) trang người sử dụng muốn, chỉnh sửa, sau đó hiển thị nội dung trong bản ghi của trang dưới dạng mà người sử dụng có thể chỉnh sửa được.
Để hiển thị những trang này, ứng dụng dựa vào một cú pháp mẫu được gọi là ERB – yêu cầu cơ bản của HTML, và Ruby. ERB cho phép người lập trình viết HTML có chứa các thành tố có thể thay đổi được. Vì ERB xử lý trang trước khi nó được hiển thị tới người sử dụng, nên nó có thể thay đổi văn bản trên trang mỗi khi trang được tải, dựa trên các yêu cầu trong mẫu của Ruby.
Nút lưu (save) trên màn hình chỉnh sửa có nhiệm vụ gửi yêu cầu đăng (POST) tới ứng dụng để cập nhật bản ghi của trang.
Xóa trang
Việc xóa trang đòi hỏi phải lưu ý đến một điểm: Cần phải nhớ, vô tình làm mất dữ liệu là không thể chấp nhận được. Nếu bạn chuẩn bị xóa một trang, bạn cần phải chắc chắn rằng người sử dụng thực sự có ý định xóa trang đó.
Sẽ là sai nếu liên kết trực tiếp nút xóa với tuyến xóa (DELETE) trong ứng dụng. Cách đó sẽ xóa trang ngay cả khi người sử dụng vô tình kích vào nút.
Chiến lược tốt hơn là sử dụng quá trình gồm hai giai đoạn. Việc nhấn vào nút xóa trên trang đưa người sử dụng tới một màn hình xác nhận tiêu đề của trang mà người sử dụng muốn xóa. Nếu người sử dụng muốn thực hiện, họ có thể kích vào nút xác nhận để gửi yêu cầu XÓA (DELETE). Nếu người sử dụng vô tình nhấn vào nút xóa, họ có thể nhận được nút quay lại (back) hoặc hủy (cancel) trên trình duyệt web.
Lần đầu khởi chạy ứng dụng
Các tính năng cơ bản đã được đặt vào đúng vị trí, nhưng tôi lại gặp phải một vấn đề: Khi tôi kiểm tra ứng dụng bằng cách truy cập vào trang chủ, ngay lập tức tôi nhận được thông báo báo lỗi. Chương trình đang cố gắng tìm kiếm bản ghi trang chủ trong cơ sở dữ liệu, nhưng nó không tồn tại vì tôi chỉ vừa mới bắt đầu ứng dụng!
Giải pháp cho vấn đề này là tạo ra một “quá trình quản lý một lần”, sử dụng chương trình có tên gọi là Rake. Các chương trình Rake được lưu giữ trong tập tin Rake (Rakefile), thuộc thư mục gốc của ứng dụng.
Rakefile hoạt động như những ứng dụng Ruby thông thường, chỉ khác một điều: Chúng tồn tại bên ngoài chương trình chính của bạn, và bạn cần phải thao tác bằng tay để chạy các yêu cầu đó.
Đó chính là điều khiến Rake trở nên hữu dụng khi thực hiện những việc như thêm các thông tin mặc định cho cơ sở dữ liệu trước khi chúng ta chính thức chạy chương trình thực. Tôi sao chép phần quan trọng của application.rb vào Rakefile, sau đó đưa ra yêu cầu tạo một trang “chủ” mới trong cơ sở dữ liệu. Sau đó, tất cả những gì tôi cần phải làm là chạy yêu cầu này một lần:
$ rake setup
Rake tạo ra bản ghi trang “chủ”, và ứng dụng của tôi không còn báo lỗi khi khởi động nữa. Khi tôi đẩy ứng dụng này lên Heroku, tôi sẽ chạy yêu cầu Rake từ xa để cài đặt cơ sở dữ liệu trước khi tôi cố gắng sử dụng ứng dụng đó.
Đến lúc này, chúng ta đã đặt được tất cả các đặc tính quan trọng vào đúng vị trí của chúng. Giờ là lúc để thêm một số điều thú vị.
Thêm phần hỗ trợ thanh bên
Tôi vừa mới nhận ra là tôi đã không đưa cách tạo thêm trang vào thanh bên như ý định ban đầu của mình. Đặc tính này đòi hỏi phải có Boolean, vì nó chỉ có hai giá trị: Trang này được cho là sẽ hiển thị ở thanh bên, hoặc là không.
Tôi đã thêm đoạn mã này vào trường phân loại của DataMapper:
Property : sidebar, Boolean, :defaul => false
Tôi khởi động lại ứng dụng, biên tập bản ghi, và toàn bộ chương trình bị phá hủy. Oái!
Tôi cố gắng xác định xem sai ở đâu, nhưng tôi không gặp may. Sau khi bới tung tài liệu hướng dẫn về DataMapper và tìm kiếm trên Stack Overflow, tôi đã phát hiện ra là sử dụng các biến Boolean theo cách này không phù hợp với dạng HTML. Cần phải có một cách tiếp cận khác:
property :sidebar, Enum[ :yes, :no ], :default => no
Đây là một cách khác để làm điều tương tự. Enum, viết tắt của từ “enumerate” (đếm, liệt kê), tạo ra một danh sách các lựa chọn, và định dạng sẽ quyết định cần phải lưu lựa chọn nào trong cơ sở dữ liệu.
Thêm phần bảo an
Thế còn thông tin đăng nhập thì sao? Nếu tôi đẩy ứng dụng này lên Heroku mà không đòi hỏi tên đăng nhập và mật khẩu thì bất cứ ai cũng có thể nhìn thấy những gì tôi lưu giữ trong cơ sở dữ liệu.
Hóa ra là các trình duyệt web hiện đại đều hỗ trợ một giao thức bảo an được gọi là Thẩm định quyền cơ bản HTTP. Đây là một cách đơn giản để yêu cầu người sử dụng nhập tên đăng nhập và mật khẩu trước khi họ có thể sử dụng chương trình. Nếu người sử dụng không thể cung cấp được thông tin chứng tỏ quyền được truy cập thì họ sẽ được điều hướng sang trang báo lỗi.
Dưới đây là đoạn mã cho phép thẩm định quyền cơ bản trong Sinatra:
user Rack::Auth::Basic, “Restricted Area” do |username, password|
[username, password] == [ENV[‘ADMIN_USER’], ENV[‘ADMIN_ PASS’]]
end
Trong trường hợp này, tôi đang lưu giữ tên đăng nhập và mật khẩu thực sự trên Heroku như các biến số môi trường mà tôi có thể đặt bằng một lệnh Terminal. Điều đó cho phép tôi sử dụng cùng một đoạn mã cho nhiều ứng dụng khác nhau, cũng như cho phép bạn nhìn thấy đoạn mã này nhưng không cho bạn thấy mật khẩu của tôi!
Đây cũng là một ví dụ cho thấy tại sao việc biết Sinatra được xây dựng trên nền Rack lại là điều quan trọng. Có rất nhiều thư viện như Rack::Auth::Basic, và tôi có thể sử dụng bất cứ thư viện nào trong số đó với Sinatra.
Mã hoàn thiện
Dưới đây là phần mở đầu trong tập tin Readme của Codex:
Codex là một ứng dụng web tham khảo dành cho một người sử dụng được viết bằng Ruby. Codex sử dụng Sinatra và DataMapper để tạo ra, lưu giữ, cập nhật và xóa các bản ghi trang từ cơ sở dữ liệu đơn giản có tên là Postgres. Ứng dụng đã sẵn sàng để triển khai ngay lập tức tr ên Heroku.
Định dạng Markdown được sử dụng cho tất cả các trang, khiến cho việc viết các trang phức tạp trở nên dễ dàng hơn nhờ công cụ đánh dấu đơn giản. Thẩm định quyền HTTP và SSL bắt buộc dành cho tất cả các lưu lượng (traffic), giữ cho thông tin của bạn được bảo mật. Giao thức tự mồi (bootstrap) giúp cho các trang của bạn trông đẹp và cuốn hút hơn.
Tài liệu Readme còn tiếp tục với những hướng dẫn chi tiết về cách cài đặt ứng dụng trên Heroku. “Phát triển phần mềm dựa trên Readme” là một cách tiếp cận rất tốt.
Tổng cộng, Codex khiến tôi mất 10 tiếng để xây dựng. Chính vì vậy mà tổng thời gian đầu tư cho việc học lập trình của tôi đã được nâng lên con số 20 giờ. (Tôi mất nhiều thời gian để viết chương này hơn so với việc viết một ứng dụng thực sự.)
Sau khi tạo ra Codex, tôi đã tham dự một buổi gặp mặt những người lập trình sử dụng Ruby ở địa phương, và đã tình nguyện giải thích cách chương trình hoạt động. Phản hồi rất tích cực, và tôi đã được khen ngợi vì phần mã viết gọn gàng, cô đọng và dễ hiểu. Một trong số những người tham gia còn nhận xét rằng, chất lượng phần mã còn tốt hơn các dự án được những lập trình viên chuyên nghiệp viết mà ông ấy đã thấy.
Nhiệm vụ đã hoàn thành.
Tóm lược lại phương pháp
Hãy cùng tổng kết lại những điều cốt lõi trong phương pháp mà tôi đã sử dụng để học cách lập trình:
Tôi đã dành một chút thời gian để học lập trình và ứng dụng web nói chung là gì, sau đó chia nhỏ những kỹ năng này thành những kỹ năng nhỏ hơn, dễ hiểu và dễ thực hành hơn.
Tôi đã đặt ra mức độ thành thạo mục tiêu bằng cách chọn hai dự án cụ thể mà tôi muốn tạo ra, sau đó xác định những dự án này sẽ như thế nào khi được hoàn thành.
Tôi đã chia nhỏ những dự án này thành những bước nhỏ hơn, sau đó xác định những bước nhỏ nào có vẻ quan trọng nhất.
Tôi đảm bảo rằng tôi có những công cụ cần thiết để làm việc (ví dụ như phiên bản mới nhất của Ruby), và tôi có thể tìm và sử dụng được bất cứ công cụ phụ trợ nào mà tôi cần.
Tôi đã tìm được một số nguồn đáng tin về lập trình, nhưng tôi chỉ đọc lướt qua phần hướng dẫn để bắt tay vào viết các chương trình thực sự.
Trước tiên tôi làm việc với những bước nhỏ quan trọng nhất, như xác định cách để kiểm tra các chương trình trên máy tính, đẩy ứng dụng đã hoàn thành lên máy chủ sản xuất,…
Tôi đã sử dụng các ví dụ tham khảo để bắt đầu và gây dựng sự tự tin, sau đó thử nghiệm nhiều cách tiếp cận khác nhau để xác định làm cách nào để lập trình được những tính năng mà tôi muốn.
Khi tôi mắc lỗi, chương trình sẽ bị hỏng và gửi cho tôi một thông điệp báo lỗi, tạo ra một vòng lặp phản hồi nhanh.
Sau khi mắc lỗi, tôi đã thử nghiệm một số cách để sửa lỗi. Nếu tôi không thể tự mình sửa được lỗi, tôi sẽ tìm kiếm sự giúp đỡ.
Tôi tiếp tục sử dụng cách tiếp cận xây dựng/ thử nghiệm/ sửa sai cho tới khi các chương trình được hoàn thành.
Tổng thời gian sử dụng: khoảng 20 tiếng. 10 tiếng dùng để nghiên cứu, và 10 tiếng còn lại là để lập trình hai ứng dụng mà hiện tại đã được hoàn thành và đưa vào sử dụng.
Từ đây tôi sẽ đi đâu tiếp
Tôi vẫn đang tiếp tục lập trình các ứng dụng web kể từ khi hoàn thành các dự án cơ bản này, tập trung vào những chương trình giúp cho việc điều hành doanh nghiệp của tôi trở nên dễ dàng hơn.
Tôi tự hào nói rằng toàn bộ công việc kinh doanh của tôi hiện tại đều chạy trên phần mềm mà tôi tự mình tạo ra. Các ứng dụng của tôi có thể thực hiện các giao dịch bằng thẻ tín dụng, gửi thư điện tử và quản lý việc truy cập trang web cho các khách hàng của tôi. Bằng cách học viết mã, giờ tôi đã có một đội quân robot nho nhỏ được lập trình để thực hiện mệnh lệnh của mình.
Mất bao lâu để viết được tất cả những chương trình đó? Tổng cộng là khoảng 90 giờ, bao gồm cả 20 giờ mà tôi đã trình bày chi tiết trong chương này.
Và đây, thêm một lợi ích nữa: Bất cứ khi nào tôi thấy một lĩnh vực kinh doanh của mình có vẻ nhàm chán và lặp đi lặp lại, tôi sẽ bắt đầu nghĩ tới việc viết mã. Chương trình có thể xử lý vấn đề này sẽ hoạt động như thế nào? Thường thì sẽ có cách để hệ thống hóa quá trình đó theo cách khiến cho cuộc sống thường nhật của tôi trở nên dễ dàng hơn.
Tôi cũng sẽ học thêm những thủ thuật mới, kiểu như tùy chỉnh máy tính để việc lập trình được nhanh hơn. Tôi sẽ học phím tắt trên bàn phím khi chỉnh sửa văn bản để tiết kiệm thời gian, và tôi vừa mới nâng cấp Terminal lên iTerom2 và Z-Shell để việc viết mã trở nên dễ dàng hơn.
Tôi vẫn đang luyện tập và chưa phải là chuyên gia, dù theo bất cứ tiêu chuẩn nào. Tôi phải nghiên cứu mọi thứ, và tôi vẫn phải mất một lúc mới giải quyết được vấn đề, lỗi sai và lỗi. Thật sự rất khó chịu.
Tuy nhiên, tôi vẫn đang tạo ra những chương trình có thể giải quyết các vấn đề theo cách trực diện và đáng tin. Đó thực sự là điều có ý nghĩa.
Tôi chiến đấu với chiếc máy tính, và tôi thắng.