Home Blog Page 172

Tổng hợp các tài liệu về Convolutional Neural Network – chuẩn bị cho Quiz 02 Kambria Code Challenge

Có thể bạn chưa biết, Quiz 02 của Kambria Code Challenge sẽ tập trung vào chủ đề Convolutional Neural Networks. Cuộc thi sẽ diễn ra vào cuối tuần sau ngày 29/02/2020.

Convolutional Neural Network (CNNs – Mạng nơ-ron tích chập) là một trong những mô hình Deep Learning trong công nghệ trí tuệ nhân tạo. Thuật ngữ “convolutional – tích chập” có nghĩa là các hàm toán học tích hợp từ những hàm riêng biệt.

Các ứng dụng của CNNs chủ yếu ở các hệ thống AI cấp cao như trong Robot có ứng dụng AI, các trợ lý ảo, xe tự lái. Trong bài viết này, TopDev sẽ tổng hợp những nội dung về Convolutional Neural Network để giúp bạn nhanh chóng ôn tập kiến thức trước khi tham gia Quiz 02.

Serie các bài viết cơ bản về CNN – dành cho những bạn mới tìm hiểu về Deep Learning và mô hình Convolutional Neural Network:

Serie các bài viết về ứng dụng của CNN trong thực tế:

Chúc bạn chuẩn bị tốt trước khi dự thi Quiz 02 – Kambria Code Challenge!

—–

Thông Tin Quiz 02

⏰Thời gian: 14h00 – 14h45 (giờ Việt Nam) ngày 29/2/2020

📌Đăng ký tại: http://bit.ly/KambriaQuiz02

📢Thông tin chi tiết tại: http://bit.ly/KambriaQuiz02Announcement

5 bài học quý giá cho 20 năm “chinh chiến” trong ngành lập trình

Nhu cầu về developer trong ngành lập trình  tăng lên đáng kể trong 4 đến 5 thập kỷ gần đây, trung bình tăng gấp đôi trong mỗi 5 năm. Kết quả là, một lập trình viên với 5 năm kinh nghiệm sẽ có nhiều cơ hội làm việc tại những công ty mơ ước hơn so với lập trình viên ít năm kinh nghiệm. 

Trong những năm bạn đi làm việc, bạn không chỉ làm việc mà còn tích lũy cho mình những bài học đáng giá. Đó gọi là kinh nghiệm, và còn là thứ tạo khác biệt giữa bạn – người làm việc lâu năm và newbie mới vào nghề. Thử hỏi: nếu bạn là người đi làm lâu năm mà không biết gì, giống như người mới vào nghề, vậy bạn đi làm vì điều gì? 

  Bách khoa toàn thư giải quyết mọi vấn đề của lập trình viên mới học code!

Những điều mình chia sẻ dưới đây được chắt lọc từ những bài học, vấp ngã đáng nhớ trong 20 năm theo đuổi lập trình và nhảy việc tại nhiều nơi khác nhau. 

Copy, paste code là điều tối kỵ trong lập trình

Nếu như bạn đã từng làm như vậy, copy code ở source nào đó và paste vào project của bạn, edit sao cho match và chạy được, thì tốt nhất bạn nên ngừng việc đó lại.

Cũng giống như việc bạn lấy cách tính lương, tính thuế của Nhật mà áp dụng vào Việt Nam vậy, rồi đổi tên lại. Mỗi nơi có một đặc điểm, đặc thù khác nhau, không thể bê nguyên xi từ đất nước khác vào đất nước mình được.

Copy-paste code thường xảy ra với những người mới bắt đầu học lập trình. Có nhiều rủi ro khi bạn làm như vậy, tình huống tốt nhất bạn cần chuẩn bị sẵn là quy trình và theo dõi hệ thống của mình thường xuyên, để đảm bảo bạn sẵn sàng ứng biến khi gặp sự cố, nếu như bạn không muốn leader của mình luôn cằn nhằn và luôn “chen chân” vào khi bạn đang cố fix nó. 

Một điều cần lưu ý đó là khi ban bắt đầu build gì đó phức tạp hơn ngay trên code trước đó của mình, và bạn cần phải đảm bảo rằng vẫn mang tính đồng bộ. 

Ví dụ, bạn triển khai một database bất cứ khi nào có một thay đổi đối với cột Tổng nhưng vẫn đảm bảo rằng Pretax Total cộng Tax vẫn bằng Tổng. Hoặc bạn viết code để ghi lại cảnh báo khi value không khớp với giá trị được gán trong tệp cấu hình. Và trường hợp xấu nhất xảy ra là tất cả dữ liệu không đồng bộ. Với những tình huống như vậy, bạn không có gì phải lo lắng cả, vì việc tính toán và tìm ra xem lỗi ở đâu không phải là nhiệm vụ của bạn mà là của một người khác, một bộ phận khác, bạn là lập trình viên, bạn chỉ code thôi. 

Nhưng có cách để khắc phục tình trạng đó là hãy chủ động trong code của mình, đừng copy-paste code của người khác. Vì khi chính bạn build thì bạn sẽ biết nó trục trặc ở đâu ngay. 

Code có trách nhiệm

Có một quan niệm sai lầm cho rằng, bạn càng viết nhiều code thì chứng tỏ bạn càng làm việc hiệu quả, thật ra không phải vậy. Không nên tư duy code là “tài sản” càng nhiều càng tốt. Mà tư duy code như một phần “trách nhiệm”, viết ít nhưng phải chất lượng và hiệu quả. Một đoạn code như một đoạn mã ADN, quan trọng cấu thành nên sản phẩm và thành công của doanh nghiệp. Vì vậy chúng ta cần CHẤT hơn LƯỢNG.

Vậy chất đó lấy đâu ra? Đọc đến đây chắc nhiều bạn sẽ thắc mắc: ủa? Ông này bị lag à, nói chẳng hiểu cái gì. Các bạn bình tĩnh, hãy đọc tiếp thôi rồi sẽ hiểu 

Tôi dành ra nhiều năm làm việc cho vị trí tư vấn quản lý. Công việc chính của tôi là thực hiện các đánh giá dựa trên cơ sở dữ liệu và giúp lãnh đạo công nghệ thông tin đưa ra các quyết định chiến lược về codebase. Vì vậy tôi xem xét, phân tích và thu thập dữ liệu từ rất nhiều nguồn. Tôi đã thu thập thông tin thống kê chi tiết về hơn 1000 codebase của khách hàng. Sau đó, tôi đã lấy dữ liệu đó và chạy phân tích, tìm kiếm mối quan hệ tương quan. Nếu tôi không thu thập càng nhiều thông tin càng tốt thì tôi sẽ không có nguồn dữ liệu để phân tích, điều quan trọng là bạn cần có cơ sở dữ liệu thiệt nhiều data, còn có thể hiểu là bigdata, thì kết quả phân tích sẽ tương quan hơn nhiều. 

Senior Developer: Đừng quá tin nhau người ơi

Ở độ tuổi 23, tôi có công việc đầu tiên của mình, đó là kỹ sư phần mềm, tôi nhận ra các lập trình viên senior ở đó đầy lòng nhiệt huyết của tuổi trẻ. Đồng nghiệp của tôi – những người trung bình có trên dưới 20 năm kinh nghiệm trong ngành – tôi học được rất nhiều điều thú vị từ họ, biết được nhiều ngôn ngữ lập trình khác nhau cũng từ họ. 

Tôi đưa cho các bạn một bức tranh tổng thể đẹp đẽ như vậy để các bạn bất ngờ ở những điều tiếp theo thôi (surprise :v) 

Nếu bạn là người mới vào làm trong công ty, đương nhiên bạn sẽ giống như tôi vậy, luôn hoài nghi với những lời nói của các lập trình viên đàn anh. Họ có thể thảo luận về kiến trúc hệ thống hoặc thiết kế thành phần của phần mềm. Họ hiểu về kiến trúc thiết kế và sử dụng các mẫu có sẵn. Và những người này có khả năng phát hiện được vấn đề có khả năng phát sinh và biết làm sao để tối ưu trước khi nó xảy ra. Nhưng không phải hầu hết lập trình viên senior đều như vậy, nếu bạn may mắn, bạn sẽ gặp được người tài. 

Nhưng nhìn lại, chuyện vui tôi kể phía trên thực ra toàn là những lập trình viên giỏi và tôi học được từ họ rất nhiều thứ. May thay tôi cũng học được từ chính “bước đi đầu” trong sự nghiệp của mình.  

Đôi khi một sinh viên mới tốt nghiệp cũng có thể làm việc cùng với những lập trình trên 20 năm kinh nghiệm cũng đều là bình thường. Tôi không nói khoe khoang. Tôi nói những điều này để cảnh báo bạn những lập trình viên đàn anh ngoài kia trông có vẻ là giỏi, nhưng không phải là tất cả. Vì vậy, khi bạn là người mới trong công ty, đừng quá chú ý, để tâm đến những lời nói của các lập trình viên senior và cố xem cái nào đúng cái nào sai. Tự bản thân bạn đi xác nhận những lời nói của họ (tốt nhất là lúc khi không có họ ở đó) 

TDD thật sự ngon!

Khi nói đến bất cứ điều gì về lập trình, hoặc liên quan đến lập trình, chúng ta đều có xu hướng đưa mọi thứ vào để so sánh 

  • IDE với lightweight editor?
  • Apple, Windows, hoặc Linux? 
  • Bạn nghĩ gì về PHP?
  • Tabs hay Space? 

Đưa tất cả những điều này lên bàn cân, bạn biết đấy sẽ có những cuộc cãi nhau nảy lửa. Vì vậy, dù có nói gì đi nữa thì tôi vẫn sẽ lao đầu vào lập trình dù có TDD hay là không. Ý định của tôi không phải là để lên lớp giảng giải cho ai mà chỉ nhằm chia sẻ kinh nghiệm của bản thân mình.

Cách đây khoảng 10 năm, tôi luôn hoài nghi TDD, công cụ unit testing, và tôi đã quyết định viết một bài blog lý giải lý do TDD chưa hẳn là một sự lựa chọn hay. 

Đó là một ngày kinh khủng và tồi tệ. Mọi thứ cứ thế diễn ra và tôi ghi note trong mớ bằng chứng, chứng minh đó là một cách kinh khủng để làm mọi thứ. Nhưng sau đó một thứ hay ho xảy đến. 

Tôi tập trung hoàn toàn và dành ra 4-5 tiếng một ngày để viết code mà không chạy application nào để xem có sự thay đổi nào không. Cứ mỗi 10 phút tôi kiểm tra lại để chắc chắn nó đang hoạt động.

Tôi nhận ra rằng tôi đắm chìm trong mớ hỗn độn đó, dành ra nhiều giờ để fix mớ đấy. Nhưng sau tất cả, một điều kì lạ xảy ra, mọi thứ work một cách mượt mà. Lần đầu tiên mọi thứ hoạt động hoàn hảo đến vậy, tôi đã code mà không cần đến sự hỗ trợ của GUI đấy. Tôi đã học được kĩ thuật này, thành thạo về nó. Tôi đã kiểm tra hiệu ứng của unit testing trên code và thấy hiệu ứng rõ ràng là tốt. Bạn hãy tìm hiểu về TDD thử xem, sẽ không làm bạn hối tiếc đâu. 

Luôn biết cách chứng thực ý tưởng của mình 

Bạn sẽ nghe những thứ như “đó không phải là bản design đẹp” hoặc “nó chưa có hiệu quả”. Và bạn cũng sẽ chỉ nghe như thế mà không có một sự kiểm chứng nào (vì người ta là sếp mà, bạn là lính nào dám bật lại). Hãy cải thiện điều này. 

Bạn có nghĩ rằng công việc của nhóm cũng đang ảnh hưởng đến uy tín và sự tín nhiệm của bản thân không ? Việc chứng minh được hiệu quả của giải pháp mà mình đưa ra sẽ giúp bạn giành được sự tôn trọng và sự thăng tiến (lên vị trí lãnh đạo chẳng hạn) trong sự nghiệp của mình. 

Đã có ai trong team yêu cầu bạn sử dụng một nguồn khác hoặc API khác, hơn là cái bạn đang sử dụng chưa? Điều đó chắc sẽ làm bạn không hài lòng nhỉ? 

Hãy chứng minh là team mem của bạn đã sai. Chạy thực nghiệm để chứng minh điều đó thay vì lớn tiếng tranh cãi nhau ai đúng ai sai. Bắt tay vào làm và chứng minh điều đó sẽ có giá trị xác thực hơn là những suy nghĩ hiện diện trong đầu. Đôi khi bạn nghĩ mình đúng khi bắt gặp hoài nghi, nhưng đôi khi bạn nhận ra rằng mình sai, dù là gì thì đều có giá trị tốt. 

Khả năng code đảm bảo được bạn có miếng ăn (vì bạn là lập trình viên mà). Nhưng khả năng code kết hợp với việc luôn kiểm chứng lại những gì mình đã làm sẽ giúp bạn tiến xa (dù là một chút). Bạn kiểm chứng lại rồi thì sẽ khó ai bắt bẻ được bạn, hay tranh giành lấy mất công, lấy mất danh tiếng của bạn; điều này sẽ hỗ trợ trong sự nghiệp thăng tiến của bạn. 

Những điều tôi chia sẻ không phải là “luật lệ ngành” mà chỉ là những bài học tôi đúc kết trong suốt sự nghiệp của mình. Bạn có câu chuyện nào trong nghiệp đi code thì kể với TopDev, tụi mình cùng tranh luận. 

Đừng bỏ lỡ cơ hội nâng cấp kỹ năng liên quan của nghề:

Xem thêm việc làm Senior Developer hấp dẫn tại TopDev

TopDev via DaedTech

Cảm ơn Vim, mình đã dừng code bằng VS Code.

Tác giả: Nguyễn Hữu Đồng

Trước tiên, cảm ơn a Nguyễn Ngọc Thịnh đã giới thiệu cho mình một code editor rất là tuyệt vời, sau khi học sử dụng Vim, mình đã không thể quay lại dùng VS Code.

Trước tiên, mình sẽ nếu một số điểm mạnh của vim(neovim) so với vs code.

  • Tốc độ code : Thực sự thì khi đã quen với vim thì tốc độ code của bạn sẽ lên một tầm cao mới, copy, paste, search, replace code, comment code, tất cả đều bằng phím tắt cả.
  • Navigation : Navigate giữa các dòng, đầu dòng cuối dòng cực kì nhanh với phím tắt, chuyển giữa các file, search file rất nhanh
  • Nhẹ : vim rất nhẹ, mình có cảm giác khi code với vscode thì con mac air của mình không thể thở nổi, quạy quay như máy cày, nhưng khi code với vim, mình không gặp trường hợp đó, nó rất nhẹ, đôi khi còn không thể nghe tiếng quạt chạy
  • All in terminal : code với vim mình không cần phải switch qua lại giữa vscode với terminal nữa, tất cả trong terminal, kết hợp với iTerm2 nữa thì thật là tuyệt vời. Navigate, tạo mới, tắt, thay đổi khoảng cách giữa các tab đều bằng phím tắt. Nhanh hơn dùng chuột 96,69 lần.
  • Kho plugin cực kì đầu đủ và nhẹ nhàng : nếu bạn cần màu sắc màu mè, highlight như vscode đã có vim-monokai-pro, muốn autocomplete đã có coc-nvimmuốn show sidebar đã có scrooloose/nerdtreemuốn fuzzy search đã có fzfmuốn comment code đã có tpope/vim-commentary và còn rất nhiều nữa, các bạn có thể tìm tại đây vim-awesome.com.
  • Khác biệt : giữa một rừng các thanh niên code bằng vscode, bản thân mình lúc đầu thấy a Nguyễn Ngọc Thịnh code bằng vim mình rất chi là thần tượng, ui huyền thoại trong truyền thuyết là có thật :v đến giờ mặc dù mình đã code được bằng vim nhưng vẫn thấy anh rất chi là ngầu, và rất chi là khác bọt.

À sau màn giới thiệu mình sẽ hướng dẫn các bạn setup vim để code theo phong cách mì ăn liền, còn nếu các bạn muốn học từ đầu thì có thể đọc qua cuốn kinh thánh vim tựa là Learn Vim The Hard Way

Trước hết để bạn phải download vim về từ trang chủ.

# Tải vềcurl -LO https://github.com/neovim/neovim/releases/download/nightly/nvim-macos.tar.gztar xzf nvim-macos.tar.gz# Để chạy neovim./nvim-osx64/bin/nvim

Sau đó bạn hãy đẩy nhanh quá trình cài đặt plugin và setup file cấu hình bằng cách down file cấu hình sẵn từ trang vim-bootstrap

Sau khi download file config đổi tên nó thành file “init.vim” và đặt trong đường dẫn “~/.config/nvim” như hình dưới.

Sau đó mở nvim lên và nvim sẽ làm công việc của nó, download các plugin. Sau khi cài đặt xong tiến hành khởi động lại nvim gõ phím “:PlugStatus”

Hãy ghé qua kinh thánh vim ở trên và học một số phím tắt, sau đó mở project lên và chiến nào, sau khi đọc kinh thánh bạn sẽ có thể Map key để thao tác một cách nhanh nhất có thể.

"" MyCustomnoremap <Leader>ff :Grep<CR>noremap <Leader>rp :%s///g<Left><Left><Left>noremap <Leader>f<Enter> :FZF<Enter>noremap qq :qa!<Enter>

Đơn cử nếu mình muốn search file trong folder, sau khi map key như bên trên mình chỉ cần bấm “ ,f<enter> “ là mình đã có thể search nhanh file rồi. Muốn thoát không cần lưu chỉ cần nhấn phím q hai lần…

Comment code cực kì dễ dàng.

comment code

Search và Replace

find and replace

Mình có làm code trên vim một cách rất thoải mái, dường như mình chưa gặp vấn đề gì với vim khi sử dụng nó cả, khi gặp gì khó hãy cứ google cộng đồng sử dụng Vim rất đông đảo và rất nhiệt tình. Mà mình chắc chắn khi bạn đọc hết cuốn kinh thánh thì bạn đã có thể sử dụng Vim một cách thành thục và diêu luyện.


Cá nhân mình, mình rất yêu Vim và code bằng vim, code trên MacOS, cài thêm iTerm2, zsh shell cùng một vài zsh plugin nữa thì cuộc sống của bạn sẽ bớt tẻ nhạt đi rất nhiều, mình càng ngiện gõ phím hơn, và đường như mỗi khi đụng đến máy là chỉ muốn code nữa thôi, mặc dù công việc chính để kiếm tiền không phải là code ( mà là bán hàng ngoài chợ hihi)

Đến đây mình xin dừng bài viết tại đây, cảm ơn các bạn đã đọc bài và hẹn gặp lại các bạn

Bài viết gốc được đăng tải tại Medium

Lỗ hổng XSS – Tấn công lấy cắp phiên đăng nhập của người dùng

Nhắc tới các lỗ hổng bảo mật điển hình của một hệ thống web, không thể không nhắc tới lỗ hổng mang tên XSS (cross-site scripting). Đây là một lỗ hổng cũng rất phổ biến và nguy hiểm, không thua kém gì so với người anh em của nó là lỗ hổng bảo mật SQL injection. Đây là một lỗ hổng tương đối dễ hiểu và đơn giản về mặt bản chất, nhưng không vì thế mà nó ít tồn tại trong thực tế. Ngược lại, rất nhiều hệ thống, kể cả các hệ thống lớn cũng thường xuyên gặp phải lỗ hổng này.

Tấn công XSS là gì?

Một cách ngắn gọn, ta có thể định nghĩa XSS như sau:

XSS là một kĩ thuật tấn công, trong đó kẻ tấn công sẽ chèn các đoạn mã độc (thường là Javascript) vào bên trong trang web, các đoạn mã này sẽ được thực thi khi người dùng truy cập và hiển thị các trang có chứa những đoạn mã đó.

Nguồn gốc của cái tên Cross-site script cũng khá thú vị, nó liên quan tới vị trí lưu và thực thi các đoạn mã độ. Không giống như lỗ hổng Sql injection, nơi mà mã độc được thực thi ở server, XSS là một dạng tấn công trong đó mã độc được thực thi ở máy client. Bởi vì mã độc được chứa ở server nhưng lại được thực thi ở client, tên gọi “cross-site” bắt nguồn chính vì lí do này.

Tìm hiểu cách mà lỗi XSS xảy ra

Mô hình chung của lỗ hổng XSS

Để thực hiện tấn công XSS, kẻ tấn công sẽ lợi dụng các lỗ hổng bảo mật của trang web, nơi mà hệ thống cho phép người dùng nhập và lưu trữ các đoạn mã độc trên server. Mỗi khi người dùng tải trang về, thì các đoạn mã độc này sẽ được thực thi ở phía trình duyệt.

Ta nhận thấy, để một lỗi XSS xảy ra, phải bao gồm 2 quá trình:

  • Thứ 1: Kẻ tấn công chèn các đoạn mã độc vào hệ thống web
  • Thứ 2: Người dùng truy cập vào trang web
Một chu trình tấn công XSS điển hình

Chú ý rằng, tấn công XSS sẽ không thể xảy ra được nếu như người dùng không thực sự truy cập vào hệ thống web. Điều này có nghĩa là dữ liệu lưu ở Cơ sở dữ liệu phía Server vẫn an toàn mặc dù mã độc đã được chèn vào hệ thống. Mục tiêu mà XSS nhắm tới là thực thi mã độc ở phía trình duyệt, nhằm đánh cắp dữ liệu ở phía người dùng (ví dụ: cookies) để có thông tin chứng thực user khi truy cập trái phép vào hệ thống.

Phân loại lỗ hổng XSS và ví dụ

Có thể tạm chia XSS thành 2 loại chính: Stored-XSS và Reflected-XSS. Cả 2 đều là đưa những đoạn mã độc tới máy người dùng để thực thi, cụ thể là việc hiển thị các nội dung được sinh ra trong quá trình trang web hoạt động, tuy nhiên cách thức có đôi chút khác biệt, ta sẽ tìm hiểu chúng ngay sau đây.

Stored-XSS

Loại tấn công XSS này chủ yếu tập trung vào khai thác việc “thiếu kiểm tra” dữ liệu truyền vào khi cho người dùng nhập liệu vào hệ thống. Điển hình nhất của loại tấn công này là lợi dụng các trường dữ liệu nhập vào từ người dùng: các ô comment trong trang blog, các ô điền nội dung của thông tin tài khoản (tên, địa chỉ, …), …

Giả sử trang web của chúng ta có ô nhập nội dung comment như sau, với mỗi nhận xét mà người dùng nhập vào, hệ thống sẽ lưu trữ lại và hiển thị sau đó:

Với các nội dung nhập thông thường, thì hệ thống sẽ hiểu đây là những kí tự bình thường và không gặp vấn đề gì khi hiển thị. Tuy nhiên, nếu có một ai đó thử tấn công vào hệ thống của ta với nội dung nhập vào là:

<script>alert("XSS attack!");</script>

Khi đó, rất có thể những nội dung hiển thị sẽ bị hiểu lầm là một đoạn mã Javascript thay vì chỉ là một đoạn văn bản thông thường. Thay vì hiển thị nội dung, đoạn mã Javascript trên sẽ được trình duyệt kích hoạt và trong tình huống này một hộp thoại sẽ được hiển thị ra:

Nếu bạn thử nhập liệu đoạn mã trên vào các hệ thống web, và thấy đoạn mã Javascript được kích hoạt, tức là hệ thống đó tồn tại lỗ hổng bảo mật XSS. Sẽ rất nguy hiểm nếu kẻ tấn công lợi dụng lỗ hổng này để chèn vào các đoạn mã Javascript âm thầm lấy cắp cookie chứa sessionID của phiên đăng nhập người dùng. Khi đó, với thông tin lấy cắp được, kẻ tấn công có thể mạo danh người dùng để truy cập vào hệ thống web, từ đó lấy cắp nhiều thông tin hơn nữa.

Reflected-XSS

Tương tự với cách tấn công ở trên, kẻ tấn công cũng sẽ nhắm tới những “dữ liệu có thể được truyền vào” từ người dùng. Cụ thể là mã độc được gắn trực tiếp vào link trang web thông qua các tham số của URL, một khi bạn truy cập vào đường link có chứa mã độc, thì đoạn mã độc sẽ được thực thi.

Giả sử trang web của ta cho phép người dùng tìm kiếm sản phẩm theo tên, cách triển khai của hệ thống là truyền tham số tìm kiếm thông qua phương thức GET trên URL. Trong tình huống không tìm thấy kết quả, dữ liệu sẽ trả về thông báo như sau:

Trong tình huống này, kẻ tấn công sẽ lợi dụng đường dẫn URL ở trang kết quả khi cố tình truyền một đoạn mã Javascript thông qua tham số keyword ở URL, và dụ dỗ người dùng nhấn vào các link dạng như thế này:

https://abc.com/search.php?keyword=<script>alert("XSS attack!");</script>

Khi đó, nếu như hệ thống tồn tại lỗ hổng XSS, đoạn mã Javascript trên sẽ được kích hoạt, và ta sẽ nhận được kết quả không mong muốn như sau:

Cũng như Stored-XSS, việc tồn tại các lỗ hổng cho phép thực thi mã Javascript trái phép có thể dẫn tới hậu quả rất nghiêm trọng, vì kẻ tấn công hoàn toàn có thể lấy được thông tin phiên đăng nhập để mạo danh người dùng.

Khắc phục lỗ hổng XSS

Như đã đề cập ở trên, mấu chốt của kĩ thuật tấn công này nằm ở việc hiển thị các nội dung được nhập vào ở client, do vậy để phòng tránh thì ta sẽ kiểm soát chặt chẽ các nơi có thể hiển thị nội dung mà người dùng được phép nhập vào.

Cũng tương tự như cách phòng chống Sql injection, mỗi khi nhận vào dữ liệu, ta sẽ thực hiện kiểm tra và mã hoá các “kí tự đặc biệt” và “các kí tự điều khiển” có nguy cơ gây hại cho chương trình. Khi đó những kí tự đặc biệt sẽ được biến đổi thành dạng được gọi là html entities, ví dụ như sau:

Kí tự HTML entity
< <
> >
& &

Khi thực hiện mã hóa chuỗi thành html entities, về mặt hiển thị thì người dùng sẽ không bị ảnh hưởng vì trình duyệt vẫn hiển thị nó dưới dạng kí tự thông thường, ta chỉ nhận ra điều này khi dùng công cụ debugger của trình duyệt mà thôi:

Để thực hiện việc mã hóa kí tự thành html entities, các ngôn ngữ phía server đều cung cấp sẵn công cụ cho ta để làm việc này. Cụ thể là với PHP, mọi người có thể sử dụng hàm htmlentities() để thực hiện việc mã hóa này, ví dụ như sau:

$keyword = "<script>alert('XSS attack!');</script>";

// DO NOT USE $keyword without using htmlentities()
echo "Not found any result for keyword: " . htmlentities($str);

Tóm lại

Có thể thấy, nguyên nhân của lỗ hổng XSS và cách khắc phụ nó không hề phức tạp, lập trình viên có thể phòng chống cách dễ dàng. Tuy nhiên đây lại là một trong những lỗ hổng tồn tại nhiều nhất trong các hệ thống web, nguyên nhân đến từ cả hai phía chủ quan và khách quan.

Hầu hết các framework hiện đại đều đã cũng cấp sẵn các công cụ phía nền tảng để ngăn chặn lỗi XSS khi hiển thị thông tin ở tầng View, và các trình duyệt cũng có cơ chế chặn việc gửi request khác tên miền (CORS – Cross-Origin Resource Sharing), nhưng không vì thế mà lập trình viên không cần phải làm gì. Việc nắm được nguyên nhân và sử dụng hợp lí việc mã hóa các chuỗi cần hiển thị thành html entities sẽ giúp cho hệ thống web của ta an toàn hơn rất nhiều.

TopDev via Nhungdongcodevui

[Tự học C++] Giới thiệu về phạm vi(scope) của biến hoặc hàm cục bộ

Biến cục bộ

Các tham số của hàm, cũng như các biến được xác định bên trong thân hàm, được gọi là các biến cục bộ (trái ngược với các biến toàn cục, mà chúng ta sẽ thảo luận trong chương tiếp theo).

1
2
3
4
5
6
int add(int x, int y) // function parameters x and y are local variables
{
    int z{ x + y }; // z is a local variable too
 
    return z;
}

Trong bài học này, chúng tôi sẽ xem xét một số đặt điểm của các biến cục bộ một cách chi tiết hơn.

Vòng đời của biến cục bộ

Chúng tôi đã thảo luận về cách định nghĩa biến như int x; làm cho biến được khởi tạo khi câu lệnh này được thực thi. Các tham số của hàm được tạo và khởi tạo khi hàm được gọi và các biến trong thân hàm được tạo và khởi tạo tại thời điểm định nghĩa.

Ví dụ:

1
2
3
4
5
6
int add(int x, int y) // x and y created and initialized here
{
    int z{ x + y }; // z created and initialized here
 
    return z;
}

Câu hỏi tiếp theo là, khi nào thì một biến cục bộ bị hủy? Các biến cục bộ bị hủy theo thứ tự ngược lại của việc khởi tạo nó khi tới dấu ngoặc nhọn cuối cùng của hàm, nơi mà nó được định nghĩa.

1
2
3
4
5
6
int add(int x, int y)
{
    int z{ x + y };
 
    return z;
} // z, y, and x destroyed here

Giống như thời gian sống của một con người, chính là thời gian giữa lúc sinh và lúc chết của họ, thời gian sống của đối tượng được định nghĩa là thời gian giữa việc tạo ra và hủy nó. Lưu ý rằng việc tạo và hủy biến xảy ra khi chương trình đang chạy (được gọi là thời gian chạy), không phải lúc biên dịch. Do đó, Vòng đời là một thuộc tính trong thời gian chạy chương trình.

Các quy tắc dựa trên xung quanh việc tạo, khởi tạo và hủy đối tượng. Nghĩa là, các đối tượng phải được tạo và khởi tạo trước thời điểm nó định nghĩa và bị hủy ở phần cuối của dấu ngoặc nhọn.

Trong thực tế, đặc tả của C ++ cung cấp cho trình biên dịch rất nhiều tính linh hoạt để xác định khi nào các biến cục bộ được tạo và hủy. Các đối tượng có thể được tạo ra sớm hơn hoặc bị hủy ngay sau đó cho mục đích tối ưu hóa. Thông thường, các biến cục bộ được tạo khi hàm được gọi và bị hủy theo thứ tự ngược lại khi tạo hàm. Chúng ta sẽ thảo luận chi tiết hơn về điều này trong các bài học trong tiếp theo, khi chúng ta nói về ngăn xếp các cuộc gọi.

Ở đây, có một chương trình phức tạp hơi phức tạp giúp thể hiện thời gian tồn tại của một biến có tên x:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
void doSomething()
{
    std::cout << "Hello!\n";
}
 
int main()
{
    int x{ 0 }; // x's lifetime begins here
 
    doSomething(); // x is still alive during this function call
 
    return 0;
} // x's lifetime ends here

Trong chương trình trên, vòng đời của x chạy từ điểm định nghĩa đến hết hàm main. Điều này bao gồm thời gian trong quá trình thực thi hàm doSomething.

Nhiều vị trí tuyển dụng C++ đãi ngộ tốt trên TopDev

Phạm vi cục bộ

Một phạm vi chính là một vùng đươc xác định mà nơi đó các biến, hàm, đối tượng.. có thể được truy cập trong code mà không phát sinh lỗi. Khi một định danh(Tên biến, tên đối tượng or hàm…) có thể được truy cập, chúng ta nói nó nằm trong phạm vi. Khi một định danh không thể được truy cập, chúng tôi nói nó nằm ngoài phạm vi. Phạm vi là một thuộc tính thời gian khi biên dịch và cố gắng sử dụng một định danh khi nó không nằm trong phạm vi sẽ dẫn đến một lỗi biên dịch.

Phạm vi của biến đổi cục bộ bắt đầu tại điểm định nghĩa biến và dừng ở cuối dấu ngoặc nhọn, nơi mà chúng được xác định (hoặc cho các tham số của hàm, ở cuối hàm). Điều này đảm bảo các biến không thể được sử dụng trước điểm định nghĩa (ngay cả khi trình biên dịch chọn để tạo chúng trước đó).

Ở đây, một chương trình thể hiện phạm vi của một biến có tên x:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
// x is not in scope anywhere in this function
void doSomething()
{
    std::cout << "Hello!\n";
}
 
int main()
{
    // x can not be used here because it's not in scope yet
 
    int x{ 0 }; // x enters scope here and can now be used
 
    doSomething();
 
    return 0;
} // x goes out of scope here and can no longer be used

Trong chương trình trên, biến x có phạm vi tại điểm định nghĩa và đi ra khỏi phạm vi ở cuối hàm main. Lưu ý rằng biến x không nằm trong phạm vi bên trong của hàm doSomething. Thực tế là gọi hàm main doSomething không liên quan trong trường hợp này.

Lưu ý rằng các biến cục bộ có cùng định nghĩa về phạm vi và thời gian tồn tại. Đối với các biến cục bộ, phạm vi và thời gian tồn tại được liên kết – nghĩa là, thời gian sống của biến biến bắt đầu khi nó đi vào phạm vi và kết thúc khi nó vượt ra khỏi phạm vi.

Một vi dụ khác

Đây là một ví dụ phức tạp hơn một chút. Hãy nhớ rằng, vòng đời là một thuộc tính trong thời gian chạy và phạm vi là thuộc tính trong thời gian biên dịch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
int add(int x, int y) // x and y are created and enter scope here
{
    // x and y are visible/usable within this function only
    return x + y;
} // y and x go out of scope and are destroyed here
 
int main()
{
    int a{ 5 }; // a is created, initialized, and enters scope here
    int b{ 6 }; // b is created, initialized, and enters scope here
 
    // a and b are usable within this function only
    std::cout << add(a, b) << '\n'; // calls function add() with x=5 and y=6
 
    return 0;
} // b and a go out of scope and are destroyed here

Và chúng ta đã làm xong.

Lưu ý rằng nếu hàm add được gọi hai lần, tham số x và y sẽ được tạo và hủy hai lần – một lần cho mỗi cuộc gọi. Trong một chương trình có nhiều hàm và lệnh gọi hàm, các biến được tạo và hủy thường xuyên.

Tuyển dụng intern C++ đãi ngộ tốt, ứng tuyển ngay TopDev

Tách biệt giữa các Hàm

Trong ví dụ trên, nó dễ dàng thấy rằng các biến a và b là các biến khác nhau từ x và y.

Bây giờ hãy xem xét chương trình tương tự sau đây:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
int add(int x, int y) // add's x and y are created and enter scope here
{
    // add's x and y are visible/usable within this function only
    return x + y;
} // add's y and x go out of scope and are destroyed here
 
int main()
{
    int x{ 5 }; // main's x is created, initialized, and enters scope here
    int y{ 6 }; // main's y is created, initialized, and enters scope here
 
    // main's x and y are usable within this function only
    std::cout << add(x, y) << '\n'; // calls function add() with x=5 and y=6
 
    return 0;
} // main's y and x go out of scope and are destroyed here

Trong ví dụ này, tất cả những gì chúng ta đã thực hiện là thay đổi tên của các biến a và b bên trong hàm main thành x và y. Chương trình này biên dịch và chạy giống hệt nhau, mặc dù các hàm main và add cả hai đều có các biến có tên x và y. Tại sao điều này làm việc?

Đầu tiên, chúng ta cần nhận ra rằng mặc dù các hàm main và add cả hai đều có các biến có tên x và y, các biến này là khác biệt. X và y trong hàm main không liên quan gì đến x và y trong hàm add – chúng chỉ xảy ra để chia sẻ cùng tên.

Thứ hai, khi bên trong hàm main, các tên x và y được định nghĩa trong hàm main. Những biến đó chỉ có thể được nhìn thấy (và được sử dụng) bên trong hàm main. Tương tự, khi bên trong hàm add, tên x và y tham chiếu đến tham số hàm x và y, chỉ có thể nhìn thấy (và được sử dụng) bên trong add.

Nói tóm lại, cả add và main đều không biết rằng hàm kia có các biến cùng tên. Bởi vì các phạm vi không chồng chéo nhau, nên nó luôn luôn rõ ràng với trình biên dịch mà x và y đang được nhắc đến bất cứ lúc nào.

Chúng ta sẽ nói nhiều hơn về phạm vi cục bộ và các loại phạm vi khác, trong một chương tiếp theo.

Nơi định nghĩa biến cục bộ

Các biến cục bộ bên trong thân hàm nên được định nghĩa tại nơi gần với lần sử dụng đầu tiên của chúng là hợp lý nhất:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
int main()
{
    std::cout << "Enter an integer: ";
    int x{}; // x defined here
    std::cin >> x; // and used here
 
    std::cout << "Enter another integer: ";
    int y{}; // y defined here
    std::cin >> y; // and used here
 
    int sum{ x + y }; // sum defined here
    std::cout << "The sum is: " << sum << '\n'; // and used here
 
    return 0;
}

Trong ví dụ trên, mỗi biến được định nghĩa ngay trước khi nó được sử dụng lần đầu tiên. Ở đó, bạn không cần phải nghiêm khắc về vấn đề này – nếu bạn thích hoán đổi các dòng 5 và 6, thì đó là điều tốt.

Nguồn gốc bài viết từ CafeDev
Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev

Tại sao phải chọn giữa R hay Python trong khi bạn có thể chọn cả 2?

Package reticulate cho phép ngôn ngữ lập trình R và Python có thể hoạt động cùng nhau – sau đây chính là 1 bài hướng dẫn mình muốn giới thiệu với các bạn.

Cả ngôn ngữ lập trình R và Python có nhiều điểm chung cũng như vài khác biệt. Hầu hết các ý tưởng tiềm ẩn về cấu trúc dữ liệu của 2 ngôn ngữ này khá là giống nhau. Có nhiều package data science đang tồn tại cho cả 2 ngôn ngữ lập trình này. Nhưng R lại được thiết lập theo 1 cách mà mình sẽ mô tả như là ‘dữ liệu trước, ứng dụng sau’. Trong khi Python thì  ngược lại khi nó nghiêng về việc phát triển ứng dụng được điều hướng từ ‘outlet’ nhiều hơn. Mình có 1 ví dụ: các lập trình viên Javascript sẽ dễ học ngôn ngữ lập trình Python hơn là R, vốn đã quen với syntax và việc quản lý ‘environment’. 

Hơn thế nữa, mình đã làm việc cả trên R và Python và đã có lúc gặp phải các tình huống mà mình sẽ muốn dùng cả 2 cùng với nhau. Điều này xảy ra vì 1 vài lý do, và lý do phổ biến nhất chính mình gặp phải là khi bạn đang build 1 thứ gì đó ở R, và bạn cần functionality mà chính bạn hay ai đó đã viết rồi bằng ngôn ngữ lập trình Python. Chắc chắn rằng bạn có thể viết lại nó với R, nhưng mình có cách tiện hơn để giúp bạn làm điều này.

Package reticulate trong R cho phép bạn có thể thực hành code Python bên trong 1 session của R. Thực ra package này đã có mặt được vài năm và ngày 1 phát triển hơn, nhưng phải đến gần đây mình mới thực sự cần tới nó. Nên sẵn tiện đây mình muốn viết vài dòng để tóm tắt 1 bài hướng dẫn luôn. Nếu bạn là 1 R native, việc sử dụng reticulate và chạy nó đòi hỏi bạn phải hiểu 1 chút về cách vận hành của Python – và cách nó thường quản lý ‘environment’ ra sao – và bài hướng dẫn của mình sẽ giúp bạn vận hành nó nhanh hơn khi là bạn phải tự mày mò 1 mình. 

Tuyển IT python nhiều ngành nghề hot

Environment trong R và Python

Bất kỳ dự án lập trình nào cũng đều tổ chức trong 1 environment, nơi chứa và truy cập tất cả mọi thứ nó cần hay được tạo nên trong quá trình vận hành của nó. Trong ngôn ngữ R, 1 environment tổng quát thông thường đều khả dụng với tất cả dự án ngôn ngữ dựa trên R và đều được cài đặt sẵn các gói cho việc truy cập. Có nghĩa là tất cả các dự án trong ngôn ngữ R thường đều được chạy trên cùng 1 environment cốt lõi (core environment) như nhau. Mình có 1 cách nghĩ về việc này là bạn hãy thử tưởng tượng tất cả mọi người trong nhà bạn đều sử dụng chung 1 cục sạc cho iPhone của họ. Nên để sạc điện thoại, họ phải rời khỏi phòng mình để tới nơi có sạc, và nếu họ bán chiếc điện thoại đi, người mua sẽ cần tự lo việc mua đồ sạc khác. 

Tuy nhiên, trong Python, mỗi dự án thường cần được thiết lập để hoàn toàn có thể ‘self-contain’ – với environment của riêng nó, bản copy base Python của riêng nó và các bản copy độc lập của tất cả ‘module’ mà nó cần để vận hành. Tương tự ví dụ trên bạn thử nghĩ về điều này như là mỗi người trong nhà bạn đều có riêng 1 cục sạc cho iPhone của họ. Họ không cần phải ra ngoài và cắm nó ở nơi nào khác, và khi họ bán chiếc điện thoại đi, thì nó cũng sẽ đi kèm với cục sạc rồi.

Trong khoản xét về các tiến trình cài đặt cũng như các nguồn tài nguyên disk/ memory thì model của Python khá là xa xỉ, nhưng bù lại lại nó cho phép việc chuyển đổi các cá thể độc lập đi kèm cấu hình tối thiểu của các dự án dễ dàng hơn. Không quá khó để thấy nó đã phát triển hiệu quả ra sao, khi nó vượt qua tư duy quy củ của việc phát triển phần mềm truyền thống, đó cũng là lý do tại sao mình nghĩ Python như hướng về ứng dụng (application driven) nhiều hơn. 

  Trải nghiệm lần đầu viết thư viện Python từ ngôn ngữ biên dịch

Đây là tí hình ảnh mình tự phác thảo ra để giải thích các khoản đơn giản về điểm khác biệt giữa cách mà các environment thường hoạt động trong ngôn ngữ R và Python: 

ngôn ngữ lập trình
ngôn ngữ lập trình

Cấu hình Environment điển hình trong R và Python

Giờ đây, nếu bạn muốn Python liên lạc được với R, thì nó vẫn cần tìm environment của riêng nó – bạn không thể chỉ đơn giản bắt nó truy cập global environment của R. Việc này cũng giống như bạn đang nói tiếng Việt với người nước ngoài để hỏi đường vậy..

Cho nên là để có thể làm Python hoạt động được bên trong dự án R của bạn, bạn cần phải có 2 thứ:

  1. 1 environment Python được thiết lập bên trong dự án R của bạn, để Python có thể định rõ phương hướng 
  2. Package reticulate cho việc chuyển ngữ code Python để nó có thể hoạt động được trong R

Thiết lập 1 environment cho Python

Từ giờ trở đi mình sẽ cho các bạn 1 ví dụ đơn giản. Cứ cho rằng mình đang có 1 dự án R trong RStudio, vốn đang cần 1 function mà mình đã viết rồi bằng ngôn ngữ lập trình Python. Và đây là function đơn giản mà mình đã lưu trong 1 script Python có tên light_years.py trong thư mục dự án R của mình có tên test_python (đúng vậy, RStudio cho phép bạn tạo các script Python!). Function này lấy khoản cách với đơn vị kilomet lẫn mile như là 1 input và tính toán sẽ mất bao nhiêu năm để di chuyển trong khoản cách đó với tốc độ ánh sáng – nói cách khác, khoản cách trong bao nhiêu năm ánh sáng sẽ là:

from scipy.constants import c
def light_years(dist, unit = "km"):
    c_per_year = c * 60 * 60 * 24 * 365.25
    if unit == "km":
        dist_meters = dist * 1000 
    elif unit == "mi":
        dist_meters = dist * 1.60934 * 1000
    else:
        sys.exit("Cannot use that unit!")
        
    return dist_meters/c_per_year

Mình đang dùng 1 function rất đơn giản ở đây để làm rõ cho bài viết này, hơi phi thực tế, hơi hơi ngớ ngẩn 1 chút vì mình đã import toàn bộ package scipy chỉ để lấy được value của hằng constant, hi vọng là bạn cũng hiểu được ý đồ của mình.  

Cũng như chúng ta đã bàn luận ở trên, chúng ta cần phải cung cấp cho đoạn code này 1 environment. Nó sẽ cần:

    1. 1 version của Python để hoạt động xuyên suốt
    2. Truy cập tới package scipy để nó có thể lấy constant c = tốc độ ánh sáng 

Không quá khó để thiết lập 1 environment Python cho dự án R của bạn. Cho thấy tầm quan trọng của environment dự án trong Python là như thế nào, sự hiện diện của nhiều công cụ quản lý environment, vốn cũng dễ dàng sử dụng. 

Bộ tool yêu thích của mình là Anaconda. Hiện đang có 2 version trên thị trường. Version đầy đủ, chứa cả vũ trụ rộng lớn bao gồm tất cả những gì mà 1 environment có thể cần, bao gồm tất cả những module thường được sử dụng nhất của Python. Và theo sau là Miniconda, vốn dễ dàng hơn trên disk space và thích hợp hơn cho nhiều người dùng Python được giới hạn. Bạn có thể lấy Miniconda cho hệ điều hành của bạn tại đây. Hãy chắc chắn rằng bạn đang tải Conda phù hợp với version Python bạn muốn làm việc cùng.

1 khi bạn đã cài đặt Conda rồi, nếu bạn đang dùng MacOS hay Linux, bạn sẽ thường phải cài đặt các environment của bạn bằng cách dùng dòng lệnh. Chỉ cần định vị nó tới thư mục dự án R (trong trường hợp của mình là test_python) trong phần terminal và dùng lệnh này:

conda create --name test_python

Chỉ đơn giản vậy thôi, bạn đã tạo ra được 1 environment Python. Mình thường đặt tên environment của mình giống như tên thư mục dự án để tránh sự nhầm lẫn trong tương lai.

Bây giờ bạn cần nói với Conda để dùng environment đó cho dự án này, cho nên hãy dùng lệnh này ngay tại dòng lệnh trong thư mục test_python của bạn:

conda activate test_python

Và bây giờ bạn đã liên kết dự án này tới environment Python, và có 1 bản sao của của base Python trong đó để đoạn code của bạn chạy qua.

Cuối cùng, function của chúng ta cần package scipy, nên chúng ta sẽ cần có nó bên trong environment. Điều này cũng dễ như việc chỉ cần gõ cái này vào bên trong thư mục dự án đã kích hoạt của bạn:

conda install scipy

Conda rồi sẽ cài đặt scipy và tất cả phụ thuộc mà nó nghĩ sẽ cần bên trong environment đang hoạt động của bạn và bạn đã sẵn sàng để bắt đầu rồi – dễ như ăn kẹo vậy.

Sau đó bạn sẽ cần nói với R nơi nó có thể tìm Python trong environment này, nên nếu bạn dùng lệnh sau đây, bạn có thể lấy 1 list tất cả các environment và hướng nó tới chỗ environment được cài đặt: 

conda info --envs

Điều này nói cho mình biết rằng, như 1 ví dụ, rằng environment của mình đã được cài đặt tại /Users/topdev/opt/miniconda3/envs/test_pythonMình vẫn luôn có thể tìm các executable Python bên trong thư mục ‘bin’ con – nên hướng đi đầy đủ tới executable Python cho dự án của mình là /Users/topdev/opt/miniconda3/envs/test_python/bin/python3, vì mình đang dùng Python 3. Đây là tất cả những gì chúng ta cần để nói với R nơi nó có thể tìm được environment của Python. 

  Viết chương trình Xoá các File trùng lặp bằng Python

Chạy function Python của bạn trong R


Bây giờ, dù bạn đã thiết lập environment Python như cách mình làm qua Conda, hay là bạn đã dùng virtualenv, bạn đã qua phần khó khăn nhất rồi. Các phần còn lại đơn giản hơn bởi vì đã có reticulate lo liệu.

Đầu tiên, bạn cần phải cho R biết nơi để tìm executable Python trong đúng environment nơi nó load dự án của bạn. Để làm điều này, hãy bắt đầu với 1 file text trống và thêm những điều sau đây, thay thế hướng đi của mình tới bất cứ hướng nào phù hợp với executable Python bên trong environment dự án bạn đã tạo.

Sys.setenv(RETICULATE_PYTHON = "/Users/topdev/opt/miniconda3/envs/test_python/bin/python3")

Bây giờ hãy lưu file text này bên trong thư mục dự án với tên .Renv. Đây là 1 file ẩn mà R sẽ thực thi bất cứ khi nào bạn mở project của bạn trong RStudio. Nên hãy shutdown RStudio và restart nó trong khi vẫn đang mở dự án test_python và nó bây giờ có thể được định vị tới environment của Python.

Nếu bạn vẫn chưa cài đặt package reticulate của R, thì đã đến lúc bạn cần phải làm rồi đó. 1 khi đã cài đặt, bạn có thể thử vài test trong phần terminal để xem nếu mọi thứ đang đi theo đúng hướng hay không. 

Đầu tiên bạn có thể test xem liệu R biết vị trí của Python không. reticulate::py_available() nên trả về “TRUE”. Bạn cũng có thể kiểm tra nếu các module Python bạn cần đã được cài đặt: reiculate::py_module_available(“scipy”) sẽ trả về “TRUE”. Giả sử cả 2 đều hoạt động tốt, bạn đã sẵn sàng để mang function của bạn vào R rồi.

Bạn có thể source đoạn script Python của bạn 1 cách đơn giản:

reticulate::source_python("light_years.py")

Giờ bạn đã có function light_years() sẵn sàng như 1 fucntion R. Hãy xem sẽ mất bao nhiêu năm để du hành 1 triệu tỷ dặm với tốc độ ánh sáng:

> light_years(1000000000000000, "mi")
[1] 170.1074

Thật tuyệt phải không nào! Rõ ràng đây là 1 ví dụ khá đơn giản nhưng nó thực sự cho bạn biết tất cả những thứ bạn cần về cách tích hợp code Python vào script R của bạn. Bạn có thể tưởng tượng cách bạn có thể đem tất cả các loại function hay package vốn chỉ đang dành riêng cho Python và làm cho chúng hoạt động được trong R – khá là thú vị phải không nào.

Gần đây mình cần một thuật toán phát hiện cộng đồng đồ thị mới (graph community detection algorithm) có tên là leidenalg cho sự triển khai vốn chỉ tồn tại trong Python, nhưng tất cả code dự án đang hiện hữu của mình lại đang ở R. Nên mình đã dùng reticuate như cách mình vẫn thường làm để giải quyết vấn đề này.

Để biết thêm về cách sử dụng Anaconda hay Miniconda để thiết lập environment Python, hướng dẫn sử dụng cho người dùng sẽ ở đây. Để tìm hiểu thêm về các loại function có sẵn để dịch từ Python sang R, có 1 họa tiết ‘reticulate khá ổn ở đây. Chào tạm biệt !

TopDev via towardsdatascience

Cơ hội việc làm cntt hấp dẫn tại TopDev đang chờ bạn!

Kambria Code Challenge – Cuộc thi mới dành cho các lập trình viên AI

Kambria Code Challenge là chuỗi các bài thi và hackathon trực tuyến liên quan đến lĩnh vực Trí tuệ nhân tạo (AI) được thiết kế để thu hút sự tham gia của các lập trình viên khắp nơi trên thế giới.

Đây là cơ hội để các bạn kiểm tra kiến thức về thuật toán AI, chứng minh các kỹ năng về lập trình của bạn, đồng thời nhận phần thưởng và phát triển cơ hội nghề nghiệp với các công ty công nghệ là đối tác của Kambria.

Quiz 02 của Kambria Code Challenge được tổ chức với chủ đề mới: Convolutional Neural Network. Cuộc thi sẽ diễn ra vào thứ bảy ngày 29 tháng 2 năm 2020. Các bạn hãy xem qua các nội dung trong bài viết bên dưới, click vào đường link và nhấp vào nút “Join This Challenge” để đăng ký tham gia.

Kambria Code Challenge – Quiz 02: http://bit.ly/KambriaQuiz02

Giải Thưởng Kambria Code Challenge:

  • Giải Nhất: trị giá $150
  • Giải Nhì: trị giá $100
  • 2 Giải Ba: mỗi giải trị giá $50

Giải thưởng sẽ được chi trả 50% bằng USDT, hoặc bằng Việt Nam Đồng, và 50% bằng KAT token.

Lưu ý: Quiz 04 sẽ là vòng thi cuối với giải thưởng lớn nhất của chuỗi cuộc thi Kambria Code Challenge. Các bạn thí sinh cần tham gia tối thiểu 2 quiz để được tham gia Quiz 04.

Ngoài ra, các lập trình viên có điểm số cao nhất khi tham dự các cuộc thi của Kambria Code Challenge sẽ có cơ hội được giới thiệu đến các công ty công nghệ là đối tác của Kambria cho cơ hội nghề nghiệp. 

Phần Thưởng Dành Cho Các Bạn Đăng Ký Sớm!

Chương trình sẽ tặng thưởng dành cho 150 bạn đăng ký sớm nhất tham gia Kambria Code Challenge. Các bạn cần hoàn thành bài quiz và đạt tối thiểu 25% tổng số điểm để được nhận giải.

Cấu trúc giải thưởng:

10,000 KAT token cho 20 bạn đăng ký sớm nhất

5,000 KAT token cho 30 bạn đăng ký tiếp theo

2,000 KAT token cho 100 bạn đăng ký còn lại

Các bước tham gia dự thi:

  1. Click “Join This Challenge”
  2. Điền đầy đủ thông tin trên trang hồ sơ cá nhân (Profile Page)
  3. Tham gia thi Kambria Code Challenge – Quiz 02

KAT là token được sử dụng trên platform của Kambria: nền tảng mã nguồn mở đầu tiên trên thế giới áp dụng công nghệ blockchain cho lĩnh vực AI và robotics.

Website: App.kambria.io/bounty

Tìm việc IT lương cao, đãi ngộ tốt trên TopDev ngay!

Tại sao team Discord chuyển từ Go sang Rust?

Tác giả: Jesse Howarth

Ngôn ngữ Rust đang dần trở thành sự lựa chọn hàng đầu cho rất nhiều domain. Điển hình với Discord, chúng ta có thể thấy thành công của Rust trên cả client side và server side. Ví dụ, chúng tôi dùng nó cho đường pipeline mã hoá video từ Go Live (client side) và dùng cho Elixir NIFs (server side). Mới đây nhất, chúng tôi đã tiến hành cấp tốc cải thiện hiệu suất dịch vụ bằng cách chuyển từ Go sang Rust. Bài viết này sẽ giải thích thêm tại sao nó lại thích hợp với Discord chúng tôi, quy trình nó thế nào và kết quả hậu chuyển đổi ra sao.

The Read States service

Discord là một công ty thiên sản phẩm, nên hãy bắt đầu câu chuyện bằng một số chi tiết về product. Mảng dịch vụ mà chúng tôi thay Go bằng Rust được gọi là dịch vụ “Read States” – Theo dõi trạng thái đọc tin nhắn. Mục đích tối thượng của nó là theo dõi xem bạn đã đọc những tin nhắn và kênh nào. Cứ mỗi khi bạn mở Discord thì “Read States” sẽ được kích hoạt với mỗi khi tin nhắn được gửi đi hoặc được đọc.

Ngày trước khi ứng dụng Go, Read States không thể hỗ trợ một số yêu cầu về sản phẩm. Thường thì nó khá nhanh, nhưng cứ lâu lâu sẽ lại bắt gặp những khoảng chậm ảnh hưởng xấu đến trải nghiệm người dùng. Sau khi tìm hiểu chúng tôi đã hiểu ra các đợt nhiễu này là do feature chính của Go: Model bộ nhớ và Garbage Collector (GC) – bộ phận gom rác của nó.

Tại sao Go không đạt được kỳ vọng của chúng tôi?

Để giải thích cụ thể hơn tại sao Go không thể giúp chúng tôi đạt được thứ mình muốn, hãy cùng “đào mộ” sâu hơn về cấu trúc dữ liệu, quy mô, các access pattern, và kiến trúc của dịch vụ.

Cấu trúc data mà chúng ta hay dùng để lưu trữ thông tin trạng thái đọc thường gọi cho thuận là “Read State” (kiểu trạm Read State chứa read states…). Discord có cả tỉ cái Read State này. Cứ mỗi User một kênh là sẽ có một Read State. Mỗi Read State có rất nhiều counter cần được update hết và thường sẽ reset về lại 0. Ví dụ, một trong các counter sẽ là bạn có bao nhiêu lần @được_tag trên một kênh.

Để có được update counter nhanh gọn, mỗi Read State server đều có một cache Least Recently Used – LRU (cache ít được dùng nhất gần đây) trên Read States. Có đến hàng triệu users trên mỗi cache, và cả triệu Read States trên mỗi cache. Và chưa kể là cả trăm ngàn cái update cache mỗi giây. 

Cụ thể hơn, chúng tôi đã hỗ trợ cache bằng một cái database cluster Cassandra. Một khi cache key đã bỏ, chúng tôi sẽ gửi Read States của bạn về database. Chúng tôi còn set thời gian cho mỗi lần gửi về database mỗi 30 giây trong tương lai bất cứ khi nào Read State được cập nhật. Có khoảng cả mười ngàn database viết đè mỗi giây.

Trong ảnh bên dưới, bạn sẽ thấy thời gian phản hồi và cpu hệ thống trong thời gian đỉnh điểm khi còn dùng Go. Nếu bạn để ý thì cứ 2 phút sẽ có một đợt nhiễu CPU và chậm trễ khá mạnh.

Vậy tại sao lại là 2 phút?

Về việc dùng Go, mỗi khi bỏ cache key, bộ nhớ vẫn chưa trống ngay. Thay vào đó, bộ phận gom rác (garbage collector) sẽ chạy liên tục để tìm xem có phần bộ nhớ nào không có references và giải phóng nó. Nói cách khác, thay vì giải phóng phần bộ nhớ không còn dùng nữa, bộ nhớ sẽ còn ở đó một lát cho đến khi bộ phận gom rác xác định được có cần dùng đến nó nữa không. Trong thời gian này, Go sẽ phải làm rất nhiều thứ để xác định bộ nhớ nào làm chậm chương trình và cần giải phóng. 

Những đợt nhiễu chắc chắn đã biết được tác động của hiệu suất của bộ phận gom rác, tuy nhiên chúng tôi đã viết code Go rất hiệu quả rồi và có rất ít allocation (chỉ định). Chúng tôi không tạo quá nhiều rác.

Sau khi đào sâu hơn vào trong source code Go, chúng tôi nhận ra rằng Go sẽ buộc bộ phận gom rác này phải chạy mỗi 2 phút (tối thiểu). Nói cách khác, nếu bộ phận gom rác không hoạt động trong 2 phút, mặc cho có heap growth, Go vẫn bắt nó phải chạy.

Chúng tôi tìm ra rằng có thể điều chỉnh bộ phận gom rác để hoạt động thường xuyên hơn để ngăn chặn các trường hợp nhiễu lớn, vì thế chúng tôi ứng dụng một điểm endpoint lên dịch vụ để thay đổi ngay phần gom rác GC Percent. Đáng tiếc là dù cho chúng tôi định hình GC Percent như thế nào chẳng có gì thay đổi cả. Tại sao? Hoá ra lý do là vì chúng tôi chưa định vị bộ nhớ đủ nhanh để buộc garbage collector phải chạy thường xuyên hơn. 

Chúng tôi tiếp tục đào sâu hơn và hiểu ra rằng các đợt nhiễu lớn không phải do khối lượng lớn bộ nhớ cần giải phóng, mà là do garbage collector cần phải scan cả LRU cache để xác định xem bộ nhớ có hoàn toàn không được dùng đến nữa không. Ngay khi chúng tôi đã tìm được một cache LRU nhỏ hơn để nhanh hơn vì garbage collector chỉ sẽ scan ít hơn. Từ đó chúng tôi add thêm một setting mới vào service để thay đổi size của LRU cache và thay đổi cả kiến trúc để có thể chia ra nhiều cache LRU trên một server.

Và chúng tôi đã đúng! Với cache LRU nhỏ hơn, garbage collector gây ra các đoạn nhiều nhỏ hơn. 

Không may thay, cái phải đánh đổi cho việc dùng cache LRU nhỏ hơn đó là thời gian trễ cao hơn. Bởi vì nếu cache nhỏ hơn thì Read State của user có thể sẽ không nằm trên cache đó. Nếu vậy đồng nghĩa rằng sẽ phải lội vào database load …

Sau một lượng load đáng kể thử nhiều cache capacity khác nhau, chúng tôi tìm được một setting khá oke. Không thật sự xuất sắc, nhưng vừa-đủ-xài và với quy mô ngày càng lớn, chúng tôi để cho nó chạy như thế một thời gian.

Trong thời gian đó chúng tôi thấy được ngày càng nhiều công ty thành công với Rust ở những phần khác của Discord và cuối cùng đã quyết định sẽ tạo nên một framework và thư viện cần để build đầy đủ các dịch vụ trong Rust. Đây là ứng cử viên sáng giá để chuyển sang Rust vì nó nhỏ gọn, nhưng tôi cũng mong rằng Rust sẽ sửa được các lỗi nhiễu này. Vì thế chúng tôi tiến hành nhiệm vụ mới: chuyển Read State sang Rust, hi vọng rằng Rust đúng là một ngôn ngữ dịch vụ và cải thiện được trải nghiệm người dùng.

  Git - Học nghiêm túc một lần (Phần 1)
  Cấu hình SSH Key cho Github

Quản lý bộ nhớ trong Rust

Rust rất nhanh và thân thiện với bộ nhớ: không có runtime và garbage collector, nó có thể thúc đẩy các dịch vụ quan trọng về hiệu suất, chạy trên dịch vụ nhúng, và dễ tích hợp với các ngôn ngữ khác.

Rust không có bộ phận garbage collection, nên chúng ta sẽ tìm hiểu xem liệu nó có cùng nhiễu chậm như Go.

Rust sử dụng một phương pháp quản lý bộ nhớ rất độc mà kết hợp với dạng bộ nhớ “sở hữu”. Căn bản là, Rust sẽ theo dõi được ai có thể đọc và viết lên bộ nhớ. Nó hiểu rằng khi nào chương trình cần dùng bộ nhớ và giải phóng ngay lập tức khi nó không cần dùng đến nữa. Nó sẽ thúc đẩy quy luật của bộ nhớ trong thời gian compile, dường như không thể có bug runtime memory. Bạn sẽ không cần phải theo dõi bộ nhớ một cách thủ công – Compiler sẽ lo chuyện này.

Vậy trong phiên bản Rust của Read States services, khi Read State của một user đã bị xoá khỏi LRU cache nó sẽ lập tức được giải phóng khỏi bộ nhớ. Bộ nhớ read state không ở yên đợi garbage collector gom nó. Rust biết rằng nó không còn được dùng đến nữa và sẽ giải phóng nó ngay. Không có quá trình runtime nào để xác định nó có cần được giải phóng hay không.

Async Rust

Có một vấn đề với hệ sinh thái Rust. Vào thời gian này service đã được ứng dụng lại, Rust stable (**) không được thích hợp và thân thiện với Rust async cho lắm. Với dịch vụ network, lập trình bất đồng bộ (asynchronous programming) là một yêu cầu bắt buộc. Có rất ít các thư viện cộng đồng có thể kích hoạt được async Rust, nhưng nó sẽ đòi hỏi một lượng lớn thủ tục và các thông báo lỗi thì vô cùng khó hiểu.

May mắn thay, team Rust đã miệt mài ngày đêm để làm sao cho lập trình bất đồng bộ dễ dàng hơn, và nó đã có sẵn trên kênh của Rust. 

(**) Rust cung cấp 2 kênh distribution chính: nightly, beta, và stable. Các feature bất ổn định (unstable features) thì chỉ có trên nightly Rust.

Discord chưa bao giờ e dè trước công nghệ mới hứa hẹn cả. Ví dụ, chúng tôi là một trong những người đầu tiên áp dụng Elixir, React, React Native, và Scylla. Nếu có một phần công nghệ nào đó hứa hẹn, chúng tôi không ngại xử lý các khó khăn sẵn có và bất ổn định về edge. Đây là một trong những cách chúng tôi nhanh chóng đạt 250+ triệu user với chỉ dưới 50 kỹ sư.

Việc đón nhận các feature async mới trong Rust là một ví dụ điển hình cho thấy chúng tôi luôn sẵn lòng đón nhận các công nghệ mới và hứa hẹn. Là team kỹ thuật, chúng tôi quyết định chọn Rust nightly và sẽ tiếp tục chạy nightly cho đến khi async được hỗ trợ trên stable. Cứ thế chúng tôi đã cùng xử lý không biết bao nhiêu vấn đề, và đến hiện tại Rust stable đã hỗ trợ cho Rust async. Sự liều lĩnh của chúng tôi cuối cùng cũng xứng đáng.

Áp dụng, load testing và launch 

Việc viết lại code khá là nhanh gọn. Nó bắt đầu từ giai đoạn dịch, rồi gút nó lại sao cho có nghĩa. Ví dụ, Rust có hệ thống gõ rất tuyệt vời hỗ trợ rất tốt cho generic programming, nên chúng ta có thể vứt phần code Go trước đó tồn tại vì thiếu generics đi được rồi. Ngoài ra, Model bộ nhớ của Rust cũng có phần an toàn bộ nhớ trên các thread, nên chúng tôi mới có thể bỏ đi một số mục bảo vệ bộ nhớ thủ công trong Go.

Khi bắt đầu load testing, chúng tôi ngay lập tức hài lòng với kết quả. Độ trễ trong Rust thì tương đương với Go mà không có latency spikes nào!

Cái đáng nói là chúng tôi không phải tốn nhiều công sức vào việc tối ưu hoá vì bản Rust đã được viết sẵn rồi. Kể cả khi nó là tối ưu hoá căn bản, Rust cũng đã vượt trội hơn hẳn so với phiên bản cực kì thủ công của Go. Đây là một minh chứng tuyệt vời cho việc viết các chương trình hiệu quả với Rust dễ dàng như thế nào so với việc “đào bới” mà chúng tôi phải làm với Go.

Tuy nhiên, chúng tôi không hài lòng chỉ đơn giản vì nó giống với hiệu suất của Go. Sau một thời gian kiểm tra và tối ưu hoá hiệu suất, chúng tôi đã vượt xa Go trên gần như mọi thông số hiệu suất. Tất cả từ độ trễ, CPU, và bộ nhớ trên Rust đều tốt hơn.

Tối ưu hoá hiệu suất của Rust bao gồm: 

  1. Chuyển sang BTreeMap thay vì HashMap trên LRU cache để tối ưu hoá dung lượng bộ nhớ.
  2. Thay thế bớt thư viện thông số đầu tiên và thay bằng cái được dùng trong Rust concurrency mới.
  3.  Giảm số bản sao bộ nhớ đang làm. 

Từ đó mà chúng tôi chính thức vận hành như thế.

Việc launch thì khá trơn tru vì chúng tôi đã cho chạy thử. Chúng tôi đưa nó vào một canary node duy nhất, tìm thấy một vài trường hợp còn thiếu và sửa chúng. Ngay sau đó chúng tôi đã đưa nó ra toàn bộ dịch vụ.

Bên dưới là kết quả thu được.

Go là màu tím, Rust là màu xanh.

Nâng khả năng của cache 

Sau khi service đã chạy khá thành công được vài ngày, chúng tôi quyết định đã đến lúc thử nâng năng suất của LRU cache lên lần nữa. Trên bản Go như đã đề cập, việc nâng mức trần của LRU cache sẽ dẫn đến việc thu gom rác lâu hơn. Chúng tôi không phải giải quyết với phần gom rác nữa, nên chúng tôi phải tìm cách tăng size của cache và đạt hiệu suất tốt hơn. Chúng tôi tăng bộ nhớ trong các box, tối ưu hoá cấu trúc data để dùng ít bộ nhớ hơn, và tăng khả năng cache lên đến 8 triệu Read States. 

Chỉ cần nhìn các kết quả bên dưới bạn sẽ nắm rõ hơn rất nhiều. Bạn có thể thấy, thời gian trung bình đang được đo bằng micro giây và tối đa số @mentions được đo bằng mili giây.

Hệ sinh thái cải tiến 

Finally, another great thing about Rust is that it has a quickly evolving ecosystem. Recently, tokio (the async runtime we use) released version 0.2. We upgraded and it gave us CPU benefits for free. Below you can see the CPU is consistently lower starting around the 16th.

Cuối cùng, một điều tuyệt vời khác về Rust là nó có một hệ sinh thái phát triển nhanh chóng. Gần đây, tokio (thời gian chạy async mà chúng tôi sử dụng) đã phát hành phiên bản 0.2. Chúng tôi đã nâng cấp nó và nhận được CPU miễn phí. Dưới đây bạn có thể thấy CPU luôn thấp hơn bắt đầu từ ngày 16.

Lời kết

Đến thời điểm này, Discord đang sử dụng Rust cho nhiều mảng xuyên suốt stack phần mềm. Chúng tôi dùng nó cho game SDK, thu video và mã hoá cho Go Live, Elixir NIFs, các dịch vụ backend và nhiều thứ khác.

Khi bắt đầu project mới hay thành phần phần mềm, chúng tôi luôn cân nhắc về Rust trước. Dĩ nhiên là chúng tôi chỉ dùng nó khi thật sự phù hợp.

Ngoài hiệu suất ra, Rust cũng có nhiều ưu điểm cho team kĩ sư sử dụng. Ví dụ, phần type safety và borrow checker của nó rất dễ cho kỹ sư có thể code tái cấu trúc khi yêu cầu về sản phẩm thay đổi hoặc ngôn ngữ mới được phát hiện cần học. Ngoài ra, hệ sinh thái và công cụ rất tuyệt vời và có một động lượng đáng kể đằng sau chúng.

Nếu đã đọc đến đây, hy vọng rằng bạn đã có chút hứng thú với Rust hoặc đã thích Rust được một thời gian. Nếu bạn muốn được giải quyết các vấn đề liên quan đến Rust một cách chuyên nghiệp, đừng ngần ngại cân nhắc apply vào Discord. 

Đừng bỏ lỡ những bài viết hay liên quan:

Xem thêm việc làm Software Developers hấp dẫn tại TopDev

Bài viết gốc được đăng tải tại Blog.Discorsapp

7 lý do bạn không nên sử dụng TypeScript

TypeScript có phải là con ác chủ bài, ngôn ngữ của tương lai, viết TypeScript thì mọi thứ sẽ không thể nào còn lỗi, những lý do khiến bạn phải suy nghĩ lại những nhận định trên

Rất nhiều người yêu TypeScript, nó “giải quyết” rất nhiều vấn đề mà JS gặp phải, một ngôn ngữ “thay thế” cho JS, nó sẽ báo bạn ngay nếu code bạn có vấn đề và dễ đọc hơn. Có nhiều nhiều lý do được đưa ra để bạn nên dùng TypeScript, bài này ngược lại đưa cho bạn 7 lý do không nên dùng TypeScript

Tìm việc làm Typescript lương cao lên đến 3000 USD

Quá mạo hiểm

Tại sao lại mạo hiểm? Nếu TypeScript thêm định nghĩa type và kiểm tra lúc compile, IDE còn thông báo ngay lúc nếu kiểu dữ liệu không khớp. Chính xác đó là lý do. TypeScript chỉ kiểm tra kiểu dữ liệu lúc compile và chỉ sử dụng kiểu có định nghĩa. Tất cả các network call, API và thư viện bổ sung chưa có type sẽ không có cách nào tương tác với TypeScript.

Nếu trong JS, chúng ta không đặt giả định về kiểu sẽ nhận được, không tự nhủ “cái này chắc chắn” sẽ trả về kiểu string, chúng ta luôn biết phải kiểm tra giá trị thật sự của biến nhận được trước khi sử dụng. Với TS, bạn phụ thuộc compiler làm việc này, nhưng sẽ có rất nhiều thứ phải làm. Bạn vừa phải bỏ thời gian viết định nghĩa cho từng tỉ tỉ thứ, rồi bỏ thêm mớ thời gian để đảm bảo các định nghĩa bạn viết ra phải đúng lúc chạy, vậy mục tiêu cuối cùng của tất cả những thứ đó là gì?

Quá rối rắm

Mặt trái của sự thật: một ngôn ngữ được kỳ vọng sẽ đem đến sự minh bạch, sạch sẽ, dễ đọc hơn lại đem đến điều người lại. Để minh họa, hãy nhìn thử một đoạn TS sau

// TODO: do this more elegantly
;((currentReducer as unknown) as Reducer<NewState,NewActions>) = nextReducer

static create: Function = <T>(subscribe?: (subscriber: Subscriber<T>) => TeardownLogic) => {
  return new Observable<T>(subscribe);
}

 

Đóng code trên lấy từ thư viện Redux và RxJS. Nếu bạn đang viết React và thích HOC, thì bạn sẽ hiểu viết bổ sung TypeScript sẽ đem đến mồ hôi và nước mắt cho các đồng nghiệp khác như thế nào.

Không giải quyết vấn đề

TS bảo là giải quyết các vấn đề mà JS đang gặp. Nhưng sự thật là KHÔNG. Dynamic typing chưa bao giờ là vấn đề với những lập trình viên JS (có mình luôn), bạn sẽ phàn nàn vậy “NaN === NaN” không phải là vấn đề sau, việc có cũng được không có cũng được dấu chấm phẩy ; không phải là vấn đề à,… một vài lý do khác nữa. TypeScript cũng chẳng giải quyết như bạn tưởng tượng đâu, nó chỉ giới thiệu một chuẩn mới, làm phân cực công đồng JS thêm thôi.

Thậm chí, nếu việc thiếu type trong JS là một vấn đề, TS không giải quyết luôn. Những ngôn ngữ thật sự giải quyết nó là Java, C, C# và các ngôn ngữ compiled.

Chẳng thay thế, chỉ là phần mở rộng

TS sau cùng cũng complie về JS, nó không hề là một ngôn ngữ có thể thay thế JS như tự sướng. Những gì TypeScript có thể làm, sẽ bị giới hạn trong những gì JS làm được. Đừng ảo tưởng với TS là bạn đã đủ chinh chiến trên mọi chiến trường, đừng tin vào lời dối trá đó, hãy tìm hiểu nhiều hơn sức mạnh thực sự của JS và linh động kiểu dữ liệu mang lại gì cho bạn, lúc đó bạn sẽ thấy mình đã tiến xa hơn những gì cái khung TS đã đóng bạn lại.

Mã nguồn mở, có thật vậy không?

Nhiều lý do đưa ra khi sử dụng TS là vì nó mã nguồn mở. Đúng, nhưng chưa đủ. Nó vẫn chịu sự chi phối từ Microsoft, một tập đoàn độc quyền khổng lồ nổi tiếng nhất thế giới, Microsoft chia sẻ mã nguồn nó như một động thái tiếp thị và lôi kéo thêm lập trình viên. Đừng lẫn lộn giữa mã nguồn mở với sự dân chủ: Microsoft vẫn ở đây và có quyền làm mọi thứ với TS, bạn chẳng làm gì được ngoài việc đứng nhìn. JS, lại khác, được cộng đồng đảm trách, sẽ không thay đổi bất cứ thứ gì nếu không được sự đồng ý từ số đông cộng đồng.

Các công ty lớn sử dụng…

Không ít các cá nhân có trách nhiệm lựa chọn ngôn ngữ cho dự án lại đưa đây làm một lý do để sử dụng TS. Vậy có tính đến chuyện các công ty lớn cũng có những bộ codebase cũ mèm, lỗi thời. Việc người khác chọn một thứ gì đó, chắc gì thứ đó cũng hợp với mình.

Nhiều tính năng hơn

Xưa rồi, khi TS được giới thiệu năm 2012, các tính năng như class chưa có trên JS. Nhưng nay đã là 2020, hơn 8 năm nay, JS đã tiến một bước rất xa, phải nói đúng hơn là giờ TS còn phải chạy theo JS

Từ quan điểm của một cá nhân không thấy nhiều lợi ích mà TypeScript mang lại.

Kết quả hình ảnh cho TypeScript

Bài viết gốc được đăng tải tại Vuilaptrinh

Tham khảo thêm các vị trí tuyển lập trình it hấp dẫn tại đây

Tìm hiểu tham số và đối số trong hàm C++

Đặt vấn đề

Trong bài học trước, chúng ta đã học về hàm có thể trả về một giá trị cho người gọi hàm đó. Chúng ta đã sử dụng điều đó để tạo ra một hàm getValueFromUser mà chúng ta đã sử dụng trong chương trình này:

#include <iostream>
int getValueFromUser()
{
 	std::cout << "Enter an integer: ";
	int input{};
	std::cin >> input;  
	return input;
}
 
int main()
{
	int num { getValueFromUser() };
	std::cout << num << " doubled is: " << num * 2 << '\n';
	return 0;
}

Tuy nhiên, điều gì sẽ xảy ra nếu chúng ta muốn đầu ra của một hàm để cho vào một hàm khác? Bạn có thể thử một cái gì đó như thế này:

#include <iostream>
 
int getValueFromUser() // this function now returns an integer value
{
 	std::cout << "Enter an integer: ";
	int input{};
	std::cin >> input;  
	return input; // added return statement to return input back to the caller
}
 
// This function won't compile
// The void return type means the function won't return a value to the caller
void printDouble()
{
	std::cout << num << " doubled is: " << num * 2 << '\n';
}
 
int main()
{
	int num { getValueFromUser() };
	printDouble();
	return 0;
}

Điều này đã không được biên dịch, vì hàm printDouble không biết định danh num là gì?. Bạn có thể thử định nghĩa num là một biến bên trong hàm printDouble():

void printDouble()
{
	int num{}; // we added this line
	std::cout << num << " doubled is: " << num * 2 << '\n';
}

Mặc dù điều này giải quyết lỗi của trình biên dịch và làm cho chương trình có thể biên dịch được, nhưng chương trình vẫn không hoạt động chính xác (nó luôn in ra 0 và 0 nhân đôi là 0). Cốt lõi của vấn đề ở đây là hàm printDouble không có cách truy cập giá trị mà người dùng đã nhập.

Chúng ta cần một số cách để truyền giá trị của num cho hàm printDouble để printDouble có thể sử dụng giá trị đó trong thân hàm của nó.

Tìm việc làm C++ nhanh chóng trên TopDev

Tham số và đối số

Trong nhiều trường hợp, Khi có thể truyền thông tin đến một hàm được gọi, để hàm đó có dữ liệu để làm việc. Ví dụ, nếu chúng ta muốn viết một hàm để thêm hai số, chúng ta cần một số cách để nói cho hàm biết về hai số sẽ thêm khi chúng ta gọi nó. Chúng tôi làm điều đó thông qua các tham số của hàm và đối số.

Tham số và đối số

Tham số là gì?

Tham số (Parameter) là một biến được sử dụng trong một hàm. Các tham số của hàm hoạt động gần như giống hệt với các biến được định nghĩa bên trong hàm, nhưng có một điểm khác biệt là chúng luôn được khởi tạo với một giá trị được cung cấp bởi người gọi của hàm.

Ví dụ trong C++:

void greet(std::string name) {
    std::cout << "Hello, " << name << "!" << std::endl;
}

Trong ví dụ trên, name là một tham số của hàm greet. Nó đại diện cho giá trị mà hàm sẽ nhận khi được gọi.

Tham số xác định loại dữ liệu mà hàm sẽ xử lý và cách thức mà hàm hoạt động dựa trên dữ liệu đó.

Các tham số của hàm được định nghĩa trong khai báo hàm bằng cách đặt chúng ở giữa dấu ngoặc đơn sau tên hàm, với nhiều tham số được phân tách bằng dấu phẩy.

Dưới đây là một số ví dụ về các hàm với số lượng tham số khác nhau:

// This function takes no parameters
// It does not rely on the caller for anything
void doPrint()
{
    std::cout << "In doPrint()\n";
}
 
// This function takes one integer parameter named x
// The caller will supply the value of x
void printValue(int x)
{
    std::cout << x  << '\n';
}
 
// This function has two integer parameters, one named x, and one named y
// The caller will supply the value of both x and y
int add(int x, int y)
{
    return x + y;
}

Đối số là gì?

Đối số (Argument) là một giá trị được truyền từ người gọi đến hàm khi thực hiện lệnh gọi hàm. Đối số được truyền cho các tham số tương ứng đã được định nghĩa trong hàm, và nó xác định giá trị cụ thể mà hàm sẽ xử lý.

Ví dụ

greet("Alice");

Trong ví dụ này, "Alice" là một đối số được truyền vào hàm greet. Đối số này sẽ được gán cho tham số name, và hàm greet sẽ thực hiện in ra dòng chữ “Hello, Alice!”.

Một ví dụ khác:

doPrint(); // this call has no arguments 
printValue(6); // 6 is the argument passed to function printValue() 
add(2, 3); // 2 and 3 are the arguments passed to function add()

Lưu ý rằng nhiều đối số được phân tách bằng dấu phẩy.

Cảnh báo về thứ tự đối số của hàm

Đặc tả trong C ++ không định nghĩa rằng các đối số có khớp với các tham số theo thứ tự từ trái sang phải hoặc từ phải sang trái hay không. Khi sao chép giá trị, thứ tự là không thống nhất. Tuy nhiên, nếu các đối số là các lệnh gọi hàm, thì điều này có thể có vấn đề:

someFunction(a(), b()); // a() or b() may be called first

Nếu xem xét từ trái sang phải, a() sẽ được gọi trước b(). Nếu xem xét từ phải sang trái, b() sẽ được gọi trước a(). Điều này có thể có hoặc không có hậu quả, tùy thuộc vào những gì hàm a() và b() làm.

Nếu điều quan trọng là một đối số đ trước, bạn nên xác định rõ thứ tự thực hiện, như vậy:

int avar{ a() }; 

// a() will always be called first 

int bvar{ b() }; 

// b() will always be called second 

someFunction(avar, bvar); 

// it doesn't matter whether avar or bvar are copied first because they are just values

Đặc tả trong C ++ không xác định liệu các hàm sẽ lấy các đối số từ trái sang phải hay phải sang trái. Do đó nên cẩn thận không thực hiện các cuộc gọi hàm ngay trong các đối số của hàm nào đó khi có vấn đề trong thứ tự gọi các hàm.

Làm thế nào các tham số và đối số làm việc với nhau

Khi một hàm được gọi, tất cả các tham số của hàm được tạo dưới dạng các biến và giá trị của từng đối số được sao chép một cách khớp vào tham số tương ứng. Quá trình này được gọi là gán giá trị vào (pass by value).

Ví dụ:

#include <iostream>
 
// This function has two integer parameters, one named x, and one named y
// The values of x and y are passed in by the caller
void printValues(int x, int y)
{
    std::cout << x << '\n';
    std::cout << y << '\n';
}
 
int main()
{
    printValues(6, 7); // This function call has two arguments, 6 and 7
 
    return 0;
}

Khi hàm printValues ​​được gọi với các đối số 6 và 7, tham số x của printValues được tạo và khởi tạo với giá trị 6 và tham số y của printValues được tạo và khởi tạo với giá trị 7.

Điều này dẫn đến kết quả đầu ra:

6 7

Một ví dụ khác, cộng hai số lại với nhau và trả về kết quả cho người gọi:

#include <iostream>
 
// add() takes two integers as parameters, and returns the result of their sum
// The values of x and y are determined by the function that calls add()
int add(int x, int y)
{
    return x + y;
}
 
// main takes no parameters
int main()
{
    std::cout << add(4, 5) << '\n'; // Arguments 4 and 5 are passed to function add()
    return 0;
}

Thực hiện bắt đầu chạy từ đầu hàm main. Khi add (4, 5) được thực hiện, hàm add được gọi, tham số x được khởi tạo với giá trị 4 và tham số y được khởi tạo với giá trị 5.

Câu lệnh return trong hàm add sẽ thực hiện x + y để tạo ra giá trị 9, sau đó được trả về hàm main. Giá trị 9 này sau đó được gửi đến std :: cout để được in lên console.

Đầu ra: 9

Lưu ý rằng số lượng đối số thường phải khớp với số lượng tham số hàm hoặc không thì trình biên dịch sẽ đưa ra lỗi. Đối số được truyền cho một hàm có thể là bất kỳ biểu thức hợp lệ nào (vì về cơ bản, đối số chỉ là một trình khởi tạo giá trị cho tham số và các khởi tạo có thể là bất kỳ biểu thức hợp lệ nào).

Tuyển dụng intern C++ đãi ngộ tốt, ứng tuyển ngay TopDev

So sánh tham số và đối số

Mặc dù tham số và đối số liên quan mật thiết với nhau, nhưng có những khác biệt quan trọng mà bạn cần hiểu rõ:

Tiêu Chí Tham Số (Parameter) Đối Số (Argument)
Định Nghĩa Biến được khai báo trong định nghĩa của hàm, đại diện cho giá trị mà hàm sẽ nhận khi được gọi. Giá trị thực tế được truyền vào hàm khi gọi hàm.
Vị Trí Được khai báo trong phần định nghĩa của hàm. Được truyền vào trong phần gọi hàm.
Chức Năng Xác định loại dữ liệu và số lượng dữ liệu mà hàm có thể nhận. Cung cấp giá trị cụ thể mà hàm sẽ xử lý trong một lần gọi cụ thể.
Ví Dụ int sum(int a, int b)ab là tham số. sum(3, 7)37 là đối số.
Phạm Vi Hoạt động như biến cục bộ bên trong hàm. Giá trị cụ thể được gán cho tham số khi hàm được gọi.
Tính Mặc Định Có thể có giá trị mặc định trong một số ngôn ngữ lập trình. Không có giá trị mặc định; giá trị được xác định khi gọi hàm.
Thời Điểm Được Xác Định Xác định tại thời điểm định nghĩa hàm. Xác định tại thời điểm gọi hàm.

Bảng này tóm tắt sự khác biệt chính giữa tham sốđối số, giúp dễ dàng phân biệt và áp dụng đúng trong lập trình.

Trên đây là tổng hợp kiến thức về tham số và đối số trong C++, đăng ký theo dõi TopDev để tiếp tục series tự học C++ bạn nhé!

Nguồn tham khảo: CafeDev
Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev

[Tự học C++] Giới thiệu literals và operators

Literals

Hãy xem xét hai dòng sau:

1
2
std::cout << "Hello world!";
int x{ 5 };

“Hello word” là gì?. Nó là literal, Một chữ(literal) (còn được gọi là hằng số kiểu chuỗi(literal constant)) là một giá trị cố định đã được chèn trực tiếp vào code.

Tuy nhiên, giá trị của một chữ(Literals) là cố định và không thể thay đổi (do đó nó được gọi là hằng số), trong khi giá trị của một biến có thể được thay đổi thông qua khởi tạo và gán.

Operators(Toán tử)

Trong toán học, một phép toán là một phép tính toán liên quan đến 0 hoặc nhiều giá trị đầu vào (được gọi là toán hạng) tạo ra một giá trị mới (được gọi là giá trị đầu ra). Một hoạt động cụ thể được thực hiện bằng một cấu trúc nào đó (thường là ký hiệu hoặc cặp ký hiệu) được gọi là toán tử.

Ví dụ, như trẻ em, tất cả chúng ta đều học rằng 2 + 3 bằng 5. Trong trường hợp này, 2 và 3 là các toán hạng và ký hiệu + là toán tử cho chúng ta áp dụng phép toán cộng trên toán hạng để tạo ra giá trị mới 5.

Ví dụ: toán tử cộng sẽ được gọi là toán tử + và toán tử trích xuất sẽ được gọi là toán tử >>.

Bạn có thể đã khá quen thuộc với các toán tử số học từ việc sử dụng khá phổ biến trong toán học, bao gồm phép cộng (+), phép trừ (-), phép nhân (*) và phép chia (/). Trong C ++, gán (=) cũng là một toán tử, cũng như << (chèn) và >> (trích xuất). Một số toán tử được sử dụng nhiều hơn một ký hiệu, chẳng hạn như toán tử đẳng thức (==), cho phép chúng ta so sánh hai giá trị để xem chúng có bằng nhau không. Ngoài ra còn có một số toán tử là các từ (ví dụ: new, delete và thrown).

Các toán tử trong C ++ có ba loại khác nhau:

Toán tử đơn(Unary operators) chỉ hành động trên một toán hạng. Một ví dụ về toán tử đơn là toán tử -. Ví dụ, đã cho -5, toán tử – lấy toán hạng bằng 5 và lật dấu của nó để tạo ra giá trị đầu ra mới -5.

Toán tử nhị phân(Binary operators) hoạt động trên hai toán hạng (được gọi là trái và phải). Một ví dụ về toán tử nhị phân là toán tử +. Ví dụ, được cho 3 + 4, toán tử + lấy toán hạng bên trái (3) và toán hạng bên phải (4) và áp dụng phép toán bổ sung để tạo ra giá trị đầu ra mới là 7. Toán tử chèn (<<) và trích xuất (>>) là toán tử nhị phân , lấy std :: cout hoặc std :: cin ở bên trái để xuất hoặc biến thành đầu vào ở bên phải.

Toán tử ternary(Ternary operators) hành động trên ba toán hạng. Cái này chúng tôi sẽ trình bày sau.

Lưu ý rằng một số toán tử có nhiều hơn một nghĩa tùy thuộc vào cách chúng được sử dụng. Ví dụ, toán tử – có hai bối cảnh. Nó có thể được sử dụng ở dạng đơn nhất để đảo ngược một số ký hiệu (ví dụ: để chuyển đổi 5 thành -5 hoặc ngược lại) hoặc có thể được sử dụng ở dạng nhị phân để thực hiện phép trừ (ví dụ: 4 – 3).

Tìm việc làm C++ nhanh chóng trên TopDev

Chuỗi operators

Các toán tử(operators) có thể được nối với nhau sao cho đầu ra của một toán tử có thể được sử dụng làm đầu vào cho một toán tử khác. Ví dụ, được đưa ra như sau: 2 * 3 + 4, toán tử nhân đi trước và chuyển đổi toán hạng trái là 2 và toán hạng phải là 3 thành giá trị mới là 6 (trở thành toán hạng bên trái cho toán tử cộng). Tiếp theo, toán tử cộng thực thi và chuyển đổi toán hạng trái là 6 và toán hạng phải là 4 thành giá trị mới là 10.

Chúng tôi sẽ nói nhiều hơn về thứ tự cuả các toán tử về sau này. Cho đến nay, nó đủ để biết rằng các toán tử số học thực hiện theo thứ tự giống như chúng làm trong toán học tiêu chuẩn: Dấu ngoặc đơn trước, sau đó là Số mũ, sau đó là Phép nhân & Phép chia, rồi Phép cộng & Phép trừ.

Nguồn gốc bài viết từ CafeDev
Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Giới thiệu

Hiện nay, biểu đồ của nhà khoa học dữ liệu đang ở mức đỉnh điểm. Hướng tới năm 2020, thực sự không có quá nhiều các chuyên gia ở ngoài kia có thể phân biệt trắng, đen hay tuân thủ các câu lệnh từ 1 nhà khoa học dữ liệu.

Mình đã từng thấy mấy ông ‘không phải là khoa học gia dữ liệu’ (hay các gã ‘không phải là kĩ thuật viên’) nhìn vào 1 nhà khoa hc dữ liệu như là 1 siêu nhân. Có hàng tá các lý do cho việc này (gồm cả việc cường điệu quá theo truyền thông) nhưng không cần phải bận tâm vì công việc của 1 nhà khoa học dữ liệu là 1 việc làm cao quý.

Hãy xem thử biểu đồ ‘Hype Cycle’ được xuất bản bởi Gartner cho Artificial Intelligence năm 2019 bên dưới: 

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Để ủng hộ, đây là “Báo cáo về các việc làm triển vọng của Linkedin” và mình chắc rằng bạn sẽ đoán ra ngay công việc đang đứng top danh sách là gì rồi:

Các con số này khá là ngạc nhiên. Từ các công ty ‘Fortune 500’ tới các của hàng bán lẻ, tổ chức vòng quanh thế giới đều muốn xây dựng 1 đội hình bao gồm các chuyên gia khoa học dữ liệu hàng đầu. Năm 2019 vốn đã phá mọi kỉ lục trước đó của việc đầu tư vào ngành khoa học dữ liệu và AI.

Nhưng mặc dù có bao nhiêu xu hướng tích cực này, mình vẫn có 1 cảm giác không thoải mái tiềm ẩn. Các nhà khoa học dữ liệu đang từ bỏ hay đổi nghề 1 cách nhanh chóng. Tại sao điều này lại đang xảy ra? Liệu có điều gì mà chúng ta chưa biết?

Hãy phân tích 5 lý do chính tại sao các nhà khoa học dữ liệu lại đang rời bỏ công việc gần như là ước mơ của họ. Nếu như bạn cũng đang đối mặt với điều này, hay muốn chia sẻ kinh nghiệm riêng của mình, hãy chia sẻ nó với cộng đồng trong phần bình luận cuối bài nhé !
5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

  1. Kỳ vọng và Thực tế – Góc khuất to lớn !

Đây là 1 trong những vấn đề phổ biến nhất trong lĩnh vực khoa học dữ liệu. Có 1 khuất mắt ngày càng lớn giữa việc các nhà khoa học dữ liệu mong đợi và việc họ thực sự làm trong ngành công nghiệp này.

Có nhiều nguyên nhân cho điều này và có thể đa dạng tùy theo trường hợp của mỗi người. Các cấp độ về kinh nghiệm cũng đóng vai trò lớn trong vực sâu của sự kỳ vọng này.
5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Hãy lấy ví dụ về các nhà khoa học dữ liệu đầy tham vọng. Thông thường, họ tự học và thu thập kiến thức thông qua sách vở và các khóa học online. Họ không có cơ hội nhiều để tiếp xúc với các dự án ngoài đời thực hay là dataset. Mình cũng đã gặp khá nhiều ‘các nhà khoa học dữ liệu đầy tham vọng’, những người mà hầu như không biết tí gì về:

  • Cách 1 đường ống ‘machine learning’ hoạt động 
  • Vai trò của kỹ thuật phần mềm trong kỹ năng tổng thể về khoa học máy tính 
  • Việc đặt 1 model vào khâu sản xuất/ triển khai 1 model có ý nghĩa như thế nào, v.. v..
  • Sự quan trọng của việc ‘dọn dẹp dữ liệu’ mà vốn nó đã ngốn khá nhiều thời gian của bạn

Cũng như tôi đã giới thiệu trước đó, cơ hội để chơi đùa với các bộ công cụ ‘machine learning hào nhoáng’ và các framework hiện đại nhất khá là quyến rũ cho các tân binh (và những người khác, thật sự!) 

“ Đây chính là thực tế – ngành công nghiệp này không hoạt động như thế. Có quá nhiều yếu tố để tạo ra một dự án khoa học dữ liệu gần với những gì chúng ta trải nghiệm trong các cuộc thi khoa học dữ liệu online.

Làm cách nào để bạn thu thập và lưu trữ dữ liệu, cách để chúng thực hiện ‘version control’, cách để triển khai model vào khâu sản xuất – đây chỉ là vài khía cạnh chính mà các tổ chức mong rằng bạn sẽ biết. 

Sự mong đợi lệch lạc này là thứ cản đường chính và dẫn tới việc các nhà khoa học dữ liệu từ bỏ công việc của họ. Mình luôn luôn muốn khuyên các tân binh và các nhà khoa học dữ liệu nghiệp dư có thể trao đổi liên tục với các senior và các cựu sinh viên tổ chức của họ để xóa góc khuất giữa kỳ vọng và thực tế. 

2. Định hướng vai trò của các nhà khoa học dữ liệu tới mục đích kinh doanh

Đây cũng là 1 trong những vấn đề ít phổ biến hơn. Điều này chủ yếu là do sự cường điệu quá mức về ngành khoa học máy tính và trí thông minh nhân tạo (AI) trong những năm gần đây.

Giám đốc điều hành, CxO, C-Suite, nhà đầu tư – tất cả những người có tên tuổi trong giới kinh doanh của các doanh nghiệp đều muốn thể hiện rằng tổ chức hoặc dự án của họ luôn đi đầu trong những tiến bộ công nghệ mới nhất. Và AI ngay bây giờ chính là lĩnh vực để đầu tư.

Vấn đề là – chúng ta đã thấy hàng tá các ông senior tin rằng AI chính là mấu chốt cho các vấn đề kinh doanh của họ. Và nếu họ đầu tư vào AI cùng các chuyên gia phù hợp, họ sẽ tìm ra giải pháp nhanh hơn và tiết kiệm được 1 nửa thời gian. 

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Tuy nhiên, đó không phải là những gì sẽ diễn ra. Các dự án khoa học dữ liệu thông thường tương quan rất nhiều trải nghiệm, thử nghiệm, ‘error method’ và sự lặp đi lặp lại của cung 1 quá trình trước khi họ có thể với tới kết quả cuối cùng. Và đôi khi đòi hỏi hàng tháng trời để có thể đạt được kết quả mong muốn.

” Data Warehouse và cơ sở hạ tầng AI đều yêu cầu khoản đầu tư khủng (tùy thuộc vào quy mô của công ty) và các khám phá trong công việc có thể mất khá lâu cũng như việc hình thành ‘insight’ hoạt động từ những vùng dữ liệu rộng lớn cũng thường ngốn nhiều thời gian. Đây cũng là lý do tại sao các nhà khoa học dữ liệu đòi hỏi sự tiếp cận linh hoạt – 1 nơi mà họ có thể cống hiến thời gian và không gian để làm việc trên dữ liệu.

Điều này thường không đạt được thỏa thuận với các trưởng nhóm kinh doanh trong nhiều lĩnh vực. Các nhà khoa học dữ liệu cuối cùng cảm thấy khó chịu với khả năng lãnh đạo của các senior và những mong đợi không thực tế của bản thân, dẫn đến một cuộc di cư hàng loạt trong các dự án.

Làm cách nào để các nhà khoa học dữ liệu và trưởng nhóm kinh doanh có thể làm việc hiệu quả:

  • Thiết lập sự liên lạc mật thiết giữa khoa học dữ liệu và các nhóm kinh doanh. Họ cần phải có sự gắn kết và phối hợp với nhau
  • Khai thác trực giác kinh doanh và kiến thức từ các trưởng nhóm kinh doanh. Điều này có thể hoạt động 1 cách thần kỳ cho các nhà khoa học dữ liệu
  • Cùng phát triển 1 ma trận hiệu năng có thể đo đạc được cho kinh doanh để đo đạc sự tiến triển hiệu năng của các nhà khoa học dữ liệu
  • Sự linh hoạt đóng vai trò thiết yếu và là 1 trong những tố chất quan trọng cho 1 nhà khoa học dữ liệu

Tôi sẽ rất khuyến khích các chuyên gia khoa học dữ liệu và các trưởng nhóm kinh doanh xem thử series bên dưới của Tiến sĩ Om Deshmukh. Ông ta đã lập nên khuôn khổ cho việc vận hành thành công 1 dự án khoa học dữ liệu 1 cách rất chi tiết:

3. Sự thiếu hụt việc nâng cao kĩ năng cho các chuyên gia khoa học dữ liệu 

Ai mà không thích những thử thách mới? Tôi sẽ tranh luận rằng lĩnh vực khoa học dữ liệu sẽ chín muồi hơn nhờ những gì thử thách mang tới, như việc tạo nên tiến độ nhanh hơn, dẫn đến sự tiến bộ. Hãy chọn tên miền Natural Launguage Processing (NLP) chẳng hạn. Số lượng các tiến triển đã xảy ra trong vòng 2 năm qua thật sự rất ấn tượng. 

Hầu hết các khoa học dữ liệu sẽ rất thích làm việc với những kỹ thuật và framework mới. Ý mình là, ai mà tận hưởng được việc dựng lên rồi cứ lặp đi lặp lại trên cùng model đệ quy logistic (logistic regression model) suốt mấy năm trời đây chứ?

“ Vai trò của các nhà khoa học dữ liệu không tránh khỏi yếu tố trì trệ. Có 1 bức tường ngăn cản bạn sẽ gặp phải trong 1 thời điểm nhất định và cảm giác mong muốn các thử thách mới sẽ luôn sục sôi trong bạn. 

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Hãy thêm điều này, về 2 yếu tố chúng ta đã nhắc ở trên về việc lo liệu các mong đợi. Đây là một sự pha trộn mọi thứ khá nhức nhói, phải không nào? Không thể tránh được viêc bất cứ nhân viên nào cũng sẽ chịu đựng sự thiếu động lực sau 1 thời điểm nhất định.

Điều này đặc biệt đúng tại các công ty lớn nơi độ linh hoạt thấp. Mình chắc rằng rất nhiều trong số các bạn đã trải nghiệm điều này, nhất là với những người đã làm việc tại các công ty ‘blue-chip. Các startup và doanh nghiệp cỡ vừa vẫn tốt hơn về vấn đề này (nhưng họ cũng đưa ra một loạt các thử thách khác nhau).

Có 3 lý do chính mà mình đã gặp phải, vốn dẫn đến việc bào mòn nhân sự:

  • Sự thiếu hụt cơ sở hạ tầng: Đây là trường hợp phổ biến với hầu hết các doanh nghiệp, họ thiếu hụt cơ sở hạ tầng như hệ thống máy tính, độ tiếp cận tới các bộ công cụ v..v.. để hỗ trợ vai trò của 1 nhà khoa học dữ liệu
  • Phạm vi kinh doanh: năng lực hoạt động của doanh nghiệp có thể hơi hạn chế và hạn hẹp. Tới 1 thời điểm, nó có thể gây khó khăn cho 1 nhà khoa học dữ liệu để suy luận nhiều insight hơn từ dữ liệu
  • Sự thiếu hụt nghiên cứu và phát triển: Là 1 nhà khoa học dữ liệu bạn sẽ thích khám phá nhiều lĩnh vực bên ngoài phạm vi công việc của bạn. Ví dụ: nếu bạn là 1 chuyên gia Thị giác Máy tính (Computer Vision) và muốn nghiên cứu thêm về NLP rồi tới vùng R&D sẽ là nơi tốt nhất cho bạn. Hầu hết các công ty điều thiếu sót điều này và dẫn đến việc hao hụt.
4. Không có quy chuẩn rõ ràng trong các khoản chi trả lương

À ha, mình có thể thấy ánh mắt chói lòa của bạn khi đọc tới tiêu đề này. Lương bổng là 1 trong những lý do chính khiến mọi người muốn nhảy vào ngành khoa học dữ liệu và làm việc như 1 sự nghiệp toàn thời gian.

Chúng ta thường thấy bảng các báo cáo từ McKinsey, Glassdoor v…v..  nơi họ giới thiệu mức lương trung bình cao vút dành cho các nhà khoa học dữ liệu. Hầu hết các tay mơ sẽ phải động lòng một khi thấy các con số được đưa ra trong các bảng báo cáo.

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Lương của 1 nhà khoa học dữ liệu thì cao ngút trời. Mình đảm bảo rằng bạn đã đọc các bản tin trong năm nay. Và thấy các nhà khoa học dữ liệu hàng đầu đang được săn lùng bởi các công ty như Google và Apple (Ian Goodfellow là 1 ví dụ)

Điều này đang thường xuyên xảy ra. Các nhà khoa học dữ liệu, những người đang làm công việc đặc biệt trong lĩnh vực tương ứng của họ, thường được truy tìm bởi hơn 500 công ty Fortune, nơi đưa ra mức lương khá cao trong khi các công ty vừa và nhỏ thì lại không đưa ra được mức lương cao lắm (thường là vậy).

Mình cảm thấy đã đến lúc cần tiêu chuẩn hóa / quy chuẩn khi nhắc tới việc bù đắp xứng đáng. Ngay cả trong các công ty dạng vừa, nơi cần phân biệt rõ ràng khi so mức lương của 1 tân binh với kỹ năng cao đối với 1 nhà khoa học dữ liệu có kinh nghiệm với cùng cấp độ kỹ năng. Không quy chuẩn hóa mức lương có thể dẫn đến: 

  • Không hài lòng, ảnh hưởng hiệu năng làm việc ngay cả đối với 1 nhân viên có tiềm năng cao
  • Nguyên nhân chính cho việc các nhân viên tiêm nhiễm nhau trong văn phòng, xem xét về các cơ hội làm việc tốt hơn ở các nơi khác

1 lần nữa – khía cạnh này thật ra không khác nhiều so với các công việc khác, phải không nào? 

5. Tiếp xúc nhiều với các dự án khoa học dữ liệu khác nhau trên các nền tảng khác nhau

Bạn sẽ ước gì nhiều hơn giữa 2 sự lựa chọn này:

  • Lựa chọn 1: 1 công việc nhẹ – lương cao nơi bạn có thể điều chỉnh các kỹ năng và kết quả để đạt được các mục tiêu công ty, hay là
  • Lựa chon 2: 1 cuộc sống với công việc đầy linh hoạt nơi bạn có thể làm việc bất cứ đâu và đạt được sự tự trưởng thành cao?

Hầu hết các bạn đều chọn Lựa chọn 2. Ai mà không thích sự linh hoạt tại nơi làm việc và thoải mái tự chọn điều bạn muốn làm? 

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Ngày nay, có khá nhiều sự lựa chọn cho 1 nhà khoa học dữ liệu để lựa chọn:

  • Họ có thể thử vận may của mình tại các cuộc thi trên các nền tảng như Kaggle, Analytics Vidhya v..v.. và thắng các khoản tiền thưởng thú vị và danh vọng trong cộng đồng
  • Các freelancer được yêu cầu khá nhiều do những công ty ngày nay thường có hứng thú với các dự án ngắn hạn 
  • Các nhà khoa học dữ liệu freelance biết hầu hết về Spark, Hadoop, Hive, Pig, SQL, Neo4J, MySQL, Python, R, Scala, TensorFlow, NLP, Computer Vision hay bất kỳ thứ gì của machine learning bởi vì họ phải nhảy vào các vấn đề và khám phá ra cách giải quyết nó
  • Viết blog và thương hiệu cá nhân cũng là sự lựa chọn đang khá ‘hot’ trong thời điểm này đối với các nhà khoa học dữ liệu. Chẳng hạn như là Grant Sanderson – ổng là 1 trong những người mà mình yêu thích !

Các tổ chức thường không thể đề nghị hết những điều này cho các chuyên gia khoa học dữ liệu thường trực về các lý do logistic hiển nhiên hay những lý do liên quan tới dự án. 

Làm cách nào để các công ty có thể giữ được các Chuyên gia khoa học dữ liệu hàng đầu của mình?

5 nguyên nhân chính vì sao các nhà khoa học dữ liệu rời bỏ công việc của mình

Đây là 1 vài cách mình đã thử và kiểm nghiệm, thứ mà 1 doanh nghiệp có thể duy trì hầu hết các tài năng khoa học dữ liệu của mình:

  • Tạo ra 1 môi trường học tập mạnh mẽ: Đây là điều thiết yếu cho sự phát triển cá nhân và chuyên nghiệp hóa của 1 cá thể. Lĩnh vực này đang bùng phát với nhiều thứ mới mẻ để khám phá hơn mỗi ngày và với tốc độ này sẽ rất quan trọng để cung cấp một môi trường học tập tiến bộ cho các nhà khoa học dữ liệu
  • Xây dựng 1 đội ngũ Nghiên cứu và Phát triển mạnh mẽ: Tạo 1 đội ngũ R&D có thể tạo điều kiện cho việc nghiên cứu chất lượng và có thể thực hiện được trong lĩnh vực. Cho phép các nhân viên điều hướng nghiên cứu về các chủ đề chuyên sâu cũng là 1 công thức tuyệt vời
  • Tiêu chuẩn hóa sự bù đắp của họ: Tiêu chuẩn sự bù đắp sẽ chiếm từ từ được lòng tin và cho các nhà khoa học sự đảm bảo rằng họ đang được hưởng thù lao xứng đáng dựa vào các tiêu chuẩn tốt nhất của ngành công nghiệp này (cũng dễ hiểu thôi, điều này khá khó để thực hiện được)

Lời cuối

Mọi thứ về lĩnh vực khoa học dữ liệu đều rất là năng động. Chúng ta vẫn đang cố tìm hiểu rất nhiều thứ nên việc sắp đặt trên 1 khía cạnh hay 1 quá trình hay cấu trúc vẫn cho thấy nhiều sự khó khăn cho các doanh nghiệp.

Ngày qua ngày, mình tin rằng chúng ta sẽ có những hệ thống và tiến triển mạnh mẽ đúng lúc, và các nhà khoa học dữ liệu sẽ có 1 môi trường làm việc trọn vẹn. Quan điểm này cần phải thực hiện, cả từ quan điểm kinh doanh cũng như của các nhà khoa học dữ liệu

Mình cũng rất muốn nghe về các quan điểm của bạn về điều này. Không biết bạn có đang làm việc về các vấn đề khoa học dữ liệu không? Liệu bạn đã từng trải nghiệm bất cứ vấn đề nào mình đề cập ở trên không? Hay bất kỳ vấn đề nào khác mà bạn muốn chia sẻ? Hãy cho chúng mình biết ở phần ‘bình luận’ bên dưới nhé! 

Topdev via Analytics Vidhya

Đừng quên xem thêm:
Học ngôn ngữ gì cho Data Science?
Top các khóa học Computer Science, Programming, Data Science MIỄN PHÍ cần học ngay
Top 15 thư viện Python tốt nhất cho Data Science

Cơ hội việc làm Data science hấp dẫn tại TopDev đang chờ bạn!

 

 

 

 

 

Tư duy lập trình phục vụ cuộc sống

Bài viết được chia sẻ tại Spiderum
Cho đến thời điểm này, một trong những quyết định sáng suốt nhất cuộc đời mà tôi có thể khẳng định được với cá nhân mình, đó là đi học lập trình. Dĩ nhiên tôi không phải là lập trình viên, và cũng không có ý định trở thành lập trình viên (mặc dù ước vọng thầm kín của tôi vẫn là một ngày được làm bá chủ C++), nhưng những bài học về giải quyết vấn đề (problem-solving) trong cuộc sống mà việc học lập trình đã đem lại cho tôi thì giá trị phải cao gấp mấy lần việc đọc ba cái sách self-help nhảm nhí.
Mà self-help thì làm sao?
Và với bài viết này, tôi sẽ chỉ cho bạn thấy những bài học đó là gì, với hy vọng rằng chúng sẽ có ích cho bạn. Và biết đâu đấy, có thể nhờ chúng mà bạn sẽ quyết định xách đít lên và đi học lập trình thì sao?
Ngoài ra thì như đã nói, tôi không phải là lập trình viên. Thế nên trong nội dung bài viết có chỗ nào hiểu sai về concept lập trình, hy vọng được dựa trên tính hiệu quả thực tế mà chiếu cố.

Chia nhỏ vấn đề

Một trong những thứ đầu tiên mà bạn phải làm trong hầu hết mọi chương trình học lập trình, đó là flowchart. Điều này là bởi để viết được cả một chương trình lớn là không hề dễ dàng, và việc bạn cần phải làm là chia nhỏ các bài toán lớn thành các vấn đề nhỏ hơn đến hết mức có thể để bạn có thể quản lý chúng dễ dàng.
Sơ đồ hình dung các loại vòng lặp trong R
Thật vậy, đối với các lập trình viên, không giống với hình dung của nhiều người, khi được giao nhận việc phát triển một sản phẩm phần mềm, họ sẽ không bắt tay vào thực hiện ngay lập tức. Việc đầu tiên họ làm luôn luôn là vẽ ra một sơ đồ giải thuật với flowchart hoặc một số công cụ vẽ bản đồ tư duy khác.
Trên sơ đồ giải thuật đó, họ sẽ xác định các thuộc tính của bài toán, các phương án tiếp cận, các khả năng có thể xảy ra và thứ tự ưu tiên của các đầu việc, rồi sau đó mới xác định các đầu việc cụ thể ở từng giai đoạn, và cuối cùng mới đến thực hiện. Điều này là bởi, việc bắt tay vào thực hiện công việc, tác vụ cụ thể chỉ là những vấn đề nhỏ. Còn những câu hỏi trên diện rộng, liên quan đến cấu trúc của chương trình, khả năng mở rộng và duy trì trên đường dài của chương trình mới là những vấn đề lớn. Và chỉ cần chúng ta vội vàng hay coi nhẹ việc giải quyết những vấn đề này sớm, thì càng về đường dài, hậu quả của những sai lầm này sẽ ngày càng nặng nề. Khái niệm này thường được gọi là nợ kỹ thuật (technical debt).
Tương tự như trong cuộc sống hay trong công việc của bạn. Mỗi khi bạn phải đối mặt với một vấn đề phức tạp, ví dụ như một kế hoạch xây nhà, mua nội thất, trả nợ, đặt thiết kế và in áo đồng phục cho hội nhóm hay tổ chức của bạn, lên kế hoạch đi chơi cuối tuần cho gia đình, quản lý các tác vụ trong một dự án của công ty, v.v. thì việc đầu tiên mà bạn cần làm là ngồi xuống, làm một tách trà ăn một miếng bánh, và vẽ một sơ đồ từng bước các đầu việc cụ thể mà bạn cần phải làm, các vấn đề nhỏ mà bạn cần phải giải quyết, thứ tự giải quyết thế nào để tiết kiệm thời gian và chi phí, và các phương án dự phòng ra sao. Điều này sẽ giúp bạn dự đoán trước được phần lớn các khả năng có thể xảy ra khi giải quyết vấn đề ở mọi thời điểm, và đưa ra được phương án giải quyết cần thiết, để tránh phải gánh nợ.
Một ví dụ về nợ kỹ thuật trong cuộc sống:
Bạn vừa chuyển ra khỏi chỗ ở cũ, và đang cần tìm một căn nhà để thuê ở. Công ty bạn làm việc nằm ở Mai Dịch, còn người yêu của bạn thì nhà lại ở Hà Đông. Bạn quyết định tìm thuê một căn nhà ở gần khu vực Hà Đông, để tiện còn chạy qua chạy lại chỗ người yêu, cuối tuần còn đi chơi muộn không lo đưa đón ngược đường. Xác định là sẽ ở đây lâu dài, bạn quyết định thuê nhà với kỳ hạn hợp đồng là 1 năm, đồng thời đầu tư lắp đặt điều hòa tủ lạnh cho đầy đủ tiện nghi. Tuy nhiên chỉ hai tháng sau khi bạn chuyển về chỗ ở mới thì bạn và người yêu chia tay. Giờ thì lợi ích của việc ở gần nhà người yêu đã mất, đồng thời mỗi sáng bạn phải mất đến gần 50 phút đi đường để di chuyển từ Hà Đông đến Mai Dịch, vừa tắc đường vừa nóng vừa bụi bặm. Bạn vừa đi vừa nghĩ đến cảnh lúc chuyển nhà đi lại phải tháo dỡ điều hòa với tủ lạnh và thuê người chuyên chở mà thấy khổ. Đây chính là món nợ kỹ thuật mà bạn phải gánh vì đã đưa ra quyết định sai lầm trong việc chọn vị trí thuê nhà (và chọn yêu đối tượng kia.)
Và cũng giống như trong lập trình, bạn càng tỉnh táo và khéo léo khi đưa ra các quyết định ban đầu bao nhiêu, thì kết quả bạn nhận được về sau sẽ càng chuẩn xác và càng đúng tiến độ bấy nhiêu.

Giảm cảm tính

Công cụ chia nhỏ vấn đề không chỉ dừng lại ở mô hình flowchart.
Có rất nhiều khi trong cuộc đời cũng như công việc của mình, bạn phải đối mặt với hai lựa chọn khác nhau, nhưng bạn cảm thấy chúng lại cân bằng nhau. Lựa chọn nào cũng có những cái lợi cũng như những cái bất lợi của nó, và bạn không biết làm thế nào để đặt được chúng lên bàn cân, bởi đơn giản vì chúng không có cùng một đơn vị đo và một hệ quy chiếu.
Nhưng có một tin mừng là chúng thực ra không cần thiết phải cảm tính đến thế. Việc chúng ta có thể làm, như đã nói, đó là chia nhỏ vấn đề cảm tính lớn ra thành những vấn đề cảm tính nhỏ hơn.
Tôi lấy một ví dụ cụ thể:
Bạn đang đứng trước hai sự lựa chọn khó khăn về sự nghiệp. Một là tiếp tục làm việc cho công ty A là công ty hiện tại của bạn, và hai là chuyển sang công ty B làm. Cả hai lựa chọn đều có những điểm mạnh cũng như điểm yếu của riêng mình. Vậy thì làm thế nào để bạn đưa ra được quyết định?
Tại đây, việc bạn cần làm là lên danh sách tất cả những điểm có lợi cũng như những điểm bất lợi của từng lựa chọn đối với cá nhân bạn. Và giả sử bạn có một số đầu mục như sau:

Công ty A

Có lợi
  • Sếp là chuyên gia với nhiều năm kinh nghiệm trong ngành.
  • Được sếp hứa hẹn sẽ training trực tiếp 1-1 nếu ở lại.
  • Môi trường làm việc startup trẻ trung, vui vẻ và thoải mái. Các đồng nghiệp đều rất tâm đầu ý hợp với mình.
  • Thời gian di chuyển đến công ty mỗi sáng là 15 phút.
Bất lợi
  • Lương thấp hơn khoảng 20% so với với nhu cầu sinh hoạt.
  • Có thông tin cho rằng lời hứa của sếp là không thực sự đáng tin cậy.
  • Áp lực công việc sẽ rất lớn nếu như sếp không thể thực hiện được lời hứa training, và mình sẽ mất thêm ít nhất là 3-6 tháng nữa mới có thể thấy được kết quả cho quyết định của mình nếu ở lại. Và cơ hội sang bên công ty B sẽ khép lại chỉ trong vòng khoảng 1 tháng nữa.

Công ty B

Có lợi
  • Chắc chắn sẽ được training trực tiếp vì công ty B đã xây dựng xong quy trình training rất quy củ, mặc dù người train không có nhiều kinh nghiệm bằng sếp bên công ty A.
  • Mức lương cao hơn 20% so với nhu cầu sinh hoạt.
  • Sản phẩm của công ty này phù hợp với tiêu chuẩn đạo đức của bạn hơn so với sản phẩm của công ty A.
  • Địa điểm công ty rất gần với chỗ làm của người yêu bạn và bạn có thể dành thời gian đi ăn cùng nhau vào buổi trưa.
Bất lợi
  • Vì là công ty lớn nên môi trường làm việc rất khắt khe, yêu cầu nhân viên phải mặc đồng phục vào Thứ Hai và Thứ Sáu. Nếu đến muộn quá 15 phút vào buổi sáng, bạn sẽ mất luôn chấm công của sáng hôm đó. Ngoài ra còn có khả năng bạn sẽ phải quan tâm đến chính trị chốn văn phòng.
  • Thời gian di chuyển đến công ty mỗi sáng là 35 phút, lại đi qua một đoạn đường rất bụi và không có cây xanh.
Sau khi đã có được danh sách tất cả các điểm ưu và điểm nhược của từng lựa chọn mà bạn có thể nghĩ ra được như trên, bạn tiến hành tính điểm cho từng đầu mục dựa trên giá trị ưu tiên của cá nhân bạn (hay nói cách khác là cảm tính) trên thang điểm từ -5 đến 5 (hoặc cũng có thể là một thang điểm nào đó khác như -7 đến 7 hay -10 đến 10, miễn là thang điểm này có tâm tại 0; cá nhân tôi cho rằng thang điểm -5 đến 5 là hợp lý nhất). Các điểm có lợi sẽ là điểm số dương, và các điểm bất lợi sẽ là điểm số âm.
Cuối cùng tính tổng lại, bạn sẽ có một bảng như sau:
Bảng tính điểm các đầu mục của hai lựa chọn
Sau khi đã thu về kết quả tổng điểm, bạn có thể thấy lựa chọn công ty B có sức nặng hơn lựa chọn công ty A là 2 điểm, và do đó có lẽ bạn nên lựa chọn công ty B. Hai điểm là một con số không lớn, mà nếu bạn không chia nhỏ các đầu mục của mỗi lựa chọn ra và đưa chúng trở về cùng một hệ quy chiếu là thang điểm từ -5 đến 5, thì bạn sẽ khó lòng có thể nhận ra được sự khác biệt rất nhỏ này. Mặc dù về bản chất, các con số này cũng đều mang tính cảm tính và không thể chuẩn xác 100%, nhưng chí ít là chúng tỏ ra rõ ràng hơn là hai lựa chọn đơn sơ giữa công ty A và công ty B ban đầu.

Dán nhãn & phân bổ mọi thứ

Một trong số các công cụ cơ bản để xây dựng một chương trình là các biến (variable). Biến cũng có nhiều loại biến, được phân biệt bằng các kiểu dữ liệu (data type), ví dụ như kiểu nhị phân đúng-sai là boolean, kiểu ký tự là char, kiểu số nguyên là int. Thế rồi bạn cũng có các công cụ không phân biệt bằng kiểu dữ liệu như biến, mà lại phân biệt bằng cấu trúc như lệnh If-Else, vòng lặp, mảng, struct, hàm, v.v. Việc bạn lựa chọn đúng công cụ để xử lý đúng loại đối tượng là vô cùng quan trọng, bởi nó sẽ xác định tính hiệu quả trong khả năng xử lý vấn đề của bạn.
Tương tự như trong cuộc sống. Nếu “Kiểu dữ liệu” là chất lỏng thì phải đựng bằng chai, còn nếu là thủy tinh dễ vỡ thì phải để vào hộp xốp. Giấy tờ cá nhân quan trọng thì phải cất vào cùng một nơi, còn giấy tờ đã không còn giá trị gì thì có thể sử dụng để làm nháp. Nếu thời gian không phải là lựa chọn cơ cấu đúng đắn, thì phải chọn lấy nhân lực. Nếu crush thuộc tuýp người lãng mạn thích đọc sách, thì mình phải tiếp cận bằng con đường văn thơ chữ nghĩa, thay vì bằng con đường phú quý và thẻ VISA. Nếu nhân viên thuộc dạng người có tham vọng, thì phải lấy cái sản phẩm hay con đường sự nghiệp làm công cụ khuyến khích họ, thay vì chỉ chăm chăm lương thưởng.
Mỗi một quyết định “dán nhãn & phân bổ” đúng đắn mà bạn đưa ra, là bạn đã giúp cho cuộc đời được thêm phần gọn gàng và dễ quản lý hơn cho chính mình.

Tối giản ở đâu và bao nhiêu

Hay thực ra câu hỏi là chúng ta có nên hiểu biết về chính trị? Và biết bao nhiêu là đủ?
Đối với một người lập trình viên, thì một trong những câu hỏi đau đầu nhất và cũng yêu cầu kinh nghiệm trong nghề dạn dày nhất, đó chính là việc khi nào thì nên trừu tượng hóa (abstraction), và bao nhiêu lớp trừu tượng hóa là đủ.
Các cấp độ trừu tượng trong lập trình
Ở cấp độ cơ bản nhất trong lập trình, chúng ta biết rằng có một đoạn code thực hiện một tác vụ cụ thể và nhất định—nhận vào một tham số và trả về một kết quả—mà ta sẽ sử dụng lại nhiều lần, thì chúng ta có thể thiết lập để đoạn code đó để nó trở thành một “hàm.” Và hàm này sẽ hoạt động như một module riêng biệt: nó nhận đầu vào và trả về đầu ra. Đó được gọi là trừu tượng hóa.
Việc trừu tượng hóa này này đem lại một số lợi ích, và một trong số đó là việc bạn có thể yên tâm rằng mỗi khi bạn cần đến chức năng của đoạn code này, bạn chỉ việc gọi hàm đó ra, đưa cho nó những tham số nó cần, và nó sẽ trả về cho bạn kết quả mà bạn yêu cầu, và bạn sẽ không cần phải quan tâm xem nó hoạt động như thế nào nữa. Ta có thể tạm hình dung rằng, việc hàm đó hoạt động như thế nào là vấn đề bậc thấp (low-level), còn việc ta sử dụng công cụ đó để giải quyết công việc của mình thế nào là vấn đề bậc cao (high-level).
Trong cuộc sống cũng tương tự. Mỗi một tiên đề, mỗi một giả định, mỗi một niềm tin mà chúng ta có về bản chất của một sự vật hay một sự việc, cũng là một lớp trừu tượng hóa như vậy. Ví dụ:
Bạn biết rằng giá mỗi lít xăng rơi vào khoảng 20.000đ, do đó nếu hôm nay đổ xăng chúng ta có thấy giá xăng ở mức 20.520đ/lít, thì bạn có thể tạm tin rằng đó là giá xăng đã được nhà nước ban hành, chứ không phải là trạm xăng có ý định lừa bạn.
Bạn ngồi ở một tiệm cà phê, và có một người đàn ông đến hỏi bạn có muốn đánh giày hay không. Bạn bảo rằng có, thế là ông ta đưa cho bạn một đôi dép khá cũ nát để đi tạm, rồi cầm đôi giày của bạn đi mất. Ba tiếng sau không thấy ông ta quay lại, bạn xác định rằng ông ta đã lấy cắp đôi giày của bạn.
Định lý Pythagoras đã chứng minh rằng bình phương cạnh huyền bằng tổng bình phương hai cạnh góc vuông, do đó để tính ra cạnh huyền thì bạn chỉ cần tính được hai cạnh góc vuông là xong, khỏi phải chứng minh lại.
Bạn biết rằng kể từ năm 1986, Việt Nam đã chuyển từ cơ chế kinh tế kế hoạch hóa tập
trung bao cấp sang cơ chế kinh tế thị trường, cho phép các doanh nghiệp tư nhân tồn tại và cho phép bàn tay của thị trường thúc đẩy kinh tế. Từ đó kinh tế Việt Nam phát triển, đời sống nhân dân được cải thiện. Bạn thấy rằng như thế này là đủ, không cần phải quan tâm gì nữa làm gì cho phiền.
Bạn có thể thấy rằng, những giả định trên giúp cho bạn được dễ dàng hơn trong cuộc sống, thay vì phải suy nghĩ và kiểm chứng cho từng khả năng mà bạn có thể nghĩ ra một, bởi vì sức người và thời gian của bạn là có hạn. Bạn không thể cứ mỗi lần cần dùng là lại phải chứng minh lại định lý Pythagoras, hay bạn phải kiểm chứng khả năng rằng có lẽ người đàn ông kia trong lúc đánh giày của bạn đã gặp phải tai nạn bởi một người lái xe say rượu. Nếu như không có trừu tượng hóa, hay nói cách khác là tạm chấp nhận rằng một số điều là đúng mặc dù chưa có đủ cơ sở, thì bạn sẽ không thể mua nổi một mớ rau 5.000đ ngoài chợ.
Tuy vậy, bạn cũng có thể thấy, hoặc là không, rằng một trong số những giả định nêu trên là không hợp lý cho lắm.
Và đó cũng chính là vấn đề của việc trừu tượng hóa. Nó chỉ cho bạn nhìn thấy bề nổi để bạn có thể sống dễ dàng hơn và tập trung vào những gì quan trọng với mình. Thế nhưng điều đó cũng đồng nghĩa rằng nó đã trở thành một lớp vỏ bọc phức tạp để che giấu đi cái bề chìm. Và nhỡ như có một vấn đề nào đó có nguồn gốc xuất phát từ bề chìm, thì sẽ rất khó để bạn có thể truy ra được nguồn gốc của nó. Và vì thế, bạn cần phải biết đưa ra một lựa chọn hết sức thông minh trong việc lúc nào thì cần trừu tượng hóa, và lúc nào thì không. Tương tự trong cuộc sống cũng vậy: biết giả định rằng cái gì cái gì về cơ bản là đúng, không cần phải nghĩ nữa, và cũng hiểu rằng cái gì đòi hỏi chúng ta phải có cái nhìn sâu sắc hơn.

Nếu những vấn đề thường ngày của bạn là những vấn đề bậc cao, thì chính trị là những vấn đề bậc thấp. Bởi chỉ khi chính trị ổn, thì cuộc sống của bạn mới êm đẹp để bạn tập trung lo sống.

Nhiều bạn trẻ cũng hỏi tôi, giống như tôi cũng thường tự hỏi chính mình, rằng em có nên quan tâm đến chính trị hay không, và quan tâm bao nhiêu là đủ. Và mặc dù tôi ghét phải trả lời thế này, nhưng sự thực là bao nhiêu cũng không đủ. Cũng giống như code bậc thấp trong lập trình, bạn càng biết sâu thì bạn càng có lợi. Tuy nhiên, chi phí thời gian và công sức là không hề nhỏ, và do đó vấn đề chính bạn cần lưu ý là cân bằng nó với bản thân, với cuộc sống và với công việc hàng ngày của bạn như thế nào.

Thói quen ghi chép

Trong lập trình, nhất là khi phải làm việc trong một dự án dài hơi, khi phải làm việc với một ai đó khác, hay có người sẽ phải đến làm việc tiếp trên code của bạn, thì một trong những quy tắc sống còn trong quá trình code của bạn là comment, về cơ bản nghĩa là ghi chép.
Đừng quên comment code của bạn
Việc ghi chép này là vô cùng quan trọng. Khi bạn đang thực hiện một tác vụ nào đó với một logic rất cụ thể, nhưng bạn lại chưa có yếu tố nào khác tương tác với logic của tác vụ này, thì bạn sẽ phải tìm cách ghi chép lại logic của nó để sau này khi bạn cần phải tương tác với nó, bạn còn có thể làm được mà không phải mò mẫm xem lại xem hôm đó mình ăn cái gì mà có thể code như thế này.
Tương tự trong cuộc sống cũng có rất nhiều những trường hợp như vậy. Bạn được nhận một voucher giảm giá cho một cửa hàng mua sắm mới khai trương, và trên voucher có mã giảm giá và số điện thoại của cửa hàng. Tuy nhiên, hiện tại bạn lại đang ở chỗ làm và chưa thể thực hiện ngay được việc đến cửa hàng đó hoặc là gọi điện cho họ để đặt mua, nên bạn quyết định sẽ ghi lại mã giảm giá và số điện thoại của họ để đến tối về nhà bạn có thể thực hiện được việc bạn muốn làm. Và đó cũng tương tự như những ngày sinh nhật của bạn bè, số điện thoại của đồng nghiệp, giấy nhắc nhở công việc cá nhân, kế hoạch cho giai đoạn tiếp theo của dự án, tài liệu mô tả của bộ phận thiết kế gửi cho bộ phận kỹ thuật, v.v. Luôn ghi nhớ trong đầu rằng, khi bạn phải làm việc với một ai khác, hay là phải làm việc với chính bản thân mình trong tương lai cũng vậy, hãy dành cho họ một sự cảm thông sâu sắc và ghi chép lại để trang bị cho họ những thông tin cần thiết để họ có thể làm việc hiệu quả được với bạn.
Mặt khác, đôi khi bạn cũng cần phải lưu ý cách bạn ghi chép hay là khối lượng bạn ghi chép. Bởi trong lập trình, dù ít hay nhiều thì khi bạn comment dài dòng quá lố, compiler cũng phải mất thời gian đi qua comment của bạn (mặc dù nó sẽ bỏ qua), do đó phần nào làm chậm thời gian xuất chương trình. Cũng giống như việc bạn ghi chép lại vào điện thoại hay vào sổ tay vậy. Dung lượng của chúng có hạn, và thời gian ghi chép hay đọc lại của bạn cũng có hạn, vì thế hãy ghi chép sao cho thật thông minh, rõ ràng, không thiếu cũng không thừa.

Giải phóng bộ nhớ khi không dùng

Khi xây dựng một chương trình, bạn luôn luôn cần phải theo dõi khối lượng đối tượng, dữ liệu, cũng như các vùng bộ nhớ trên hệ thống máy tính hay các loại tài nguyên hệ thống khác, và nhanh chóng giải phóng những gì mà chương trình không còn cần sử dụng nữa ra khỏi bộ nhớ, để dành nó cho các tác vụ tiếp theo.
Hãy tự dọn bàn của mình trước khi bạn crash
Bạn có thể hình dung ổ cứng máy tính của bạn là cái nhà kho, còn bộ nhớ của bạn là cái mặt bàn. Hoặc cũng có thể ổ cứng máy tính là nhà bạn, còn bộ nhớ là chỗ làm của bạn. Hay như chính trên máy tính của bạn, thì theo một cách nào đó, màn hình desktop cũng là một dạng bộ nhớ của bạn. Bộ nhớ là nơi bạn tạm để những tác vụ, những công cụ, cũng như các thành phần của công việc hiện tại đang dang dở và yêu cầu phải có quyền truy cập hay khả năng tiếp cận cao với các đối tượng này. Thế nhưng bạn cần phải nhớ rằng bộ nhớ của bạn chỉ là tạm thời, và vì thế nó có giới hạn. Khi bạn đã hoàn thành một công việc nào đó, hãy nhớ đến việc dọn dẹp rác trên bộ nhớ. Thứ gì không cần nữa thì hãy trả lại về đúng nơi lưu trữ. Chỉ có thể bằng cách đó, tâm trí của bạn mới có thể được giải phóng để các tác vụ sau được giải quyết hiệu quả hơn. Vả lại, bản thân việc giải phóng bộ nhớ và nhìn nó được gọn gàng, sạch sẽ, và quan trọng nhất là tối ưu, cũng là một cách để đem lại cảm giác rằng bạn đã hoàn thành công việc xuất sắc vậy.
Dẫu biết rằng các ngôn ngữ lập trình bậc cao hiện nay như C# đã có khả năng tự động quản lý bộ nhớ (garbage collection), nhưng bài học thực tế của việc giải phóng bộ nhớ vẫn luôn mang giá trị cao.

Lời kết

Tôi sẽ không ngần ngại khi nói rằng lập trình quả thực xứng đáng là một môn cần được đưa vào giảng dạy mở rộng ở cấp phổ thông, bởi những công cụ mà nó đem lại cho chúng ta trong việc tư duy về giải quyết vấn đề là vô cùng hữu dụng, dù cho bạn có là ai đi chăng nữa. Bởi khi và chỉ khi bạn bắt buộc phải làm việc với những giới hạn, thì từ đó mới có thể sinh ra được những cách giải quyết tối ưu.
  50 keywords mà mọi JAVA developer nên biết
  Một vài lỗi mà những lập trình viên mới có thể mắc phải
  13 kênh Youtube lập trình tiếng Việt giúp bạn trở thành Fullstack developer
Có thể bạn quan tâm:

5 công cụ nguồn mở các thư viện cần biết

Đã có thời khi làm việc trong thư viện tôi đã thấy rất khó chịu (như nhiều thủ thư khác) vì đã có quá ít lựa chọn về phần mềm thực sự làm được những gì tôi cần. Trong các thư viện chúng tôi đã quá quen thuộc với mô hình người bán hàng = phần mềm. Ở những nơi một nhà bán hàng kiểm soát sản phẩm và trong khi có thể có những sản phẩm tương tự khác, thì chúng cũng bị một nhà bán hàng khác kiểm soát.

Điều này giải thích vì sao các thư viện cần phải nhìn sâu sát hơn phần mềm nguồn mở.

Bằng việc loại bỏ “chủ sở hữu” (có nghĩa là nhà bán hàng) khỏi phương trình ở trên, chúng tôi có được nhiều sự tự do để tạo ra phần mềm làm những gì chúng tôi muốn, cách chúng tôi muốn, khi chúng tôi muốn. Một trong những điều khó khăn nhất để dạy các thư viện đang chuyển sang giải pháp nguồn mở là sức mạnh bây giờ nằm trong tay của họ để chỉ huy phần mềm.

Vì lý do đặc biệt này, tôi dạy nhiều lớp tập huấn về phần mềm nguồn mở cho các thư viện, và tôi luôn thấy nó thú vị khi tôi mang tới các công cụ mà những người tham dự chưa bao giờ nghe thấy về chúng. Đúng là khó để bắt kịp tất cả các ứng dụng có ngoài đó, nên tôi đã biên dịch một danh sách lớn với 5 công cụ nguồn mở mà nhiều thư viện hơn nên biết về chúng.

SubjectsPlus

SubjectsPlus là công cụ chỉ dẫn đối tượng nguồn mở. Đối với các dạng không phải thư viện đọc điều này: chỉ dẫn đối tượng là một tài nguyên chung trong các thư viện để chỉ cho mọi người tới các tài nguyên thích hợp về một chủ đề cụ thể. Khi tôi lần đầu làm việc trong các thư viện, những gì chúng tôi từng làm việc với từng là hàng loạt các trang được viết mã cố định với đầy các đường liên kết. Bây giờ chúng tôi có các công cụ như SubjectsPlus để làm giảm nhẹ công việc nặng nhọc đó cho chúng tôi.

SubjectsPlus dễ dàng bổ sung thêm các nhân viên (hoặc những người quản lý chỉ dẫn) và các tài nguyên (in, các cơ sở dữ liệu, các đường liên kết, và hơn thế nữa) sao cho bạn có thể xuất bản chỉ dẫn đối tượng hữu ích cho các khách hàng của bạn. Ví dụ hãy kiểm tra Chỉ dẫn Khóa học về CSE 561 (Course Guide for CSE 561) của Thư viện Đại học Oakland.

LibKi

Libki là hệ thống quản lý quầy công cộng được thiết kế cho các thư viện bởi những người đang làm việc trong thư viện! Nó cho phép bạn quản lý các máy tính công cộng của bạn trong thư viện (hoặc bất kỳ cơ sở công khai nào) với thiết lập tối thiểu.

Tôi nhớ khi thư viện đầu tiên của tôi chọn một hệ thống quản lý quầy – đó từng là sự tra tấn để thiết lập và duy trì. Đó là khi tôi đi ra ngoài tìm kiếm lựa chọn thay thế và tìm thấy LibKi.

Sử dụng LibKi, thư viện có thể quản lý những người sử dụng có thể ngồi với các máy công cộng bao nhiêu thời gian, đưa ra các mã ID của người viếng thăm với các quy tắc khác nhau so với những người có thẻ thường xuyên, để dành các máy cho các khách hàng, và quản lý chung quầy sao cho bất kỳ ai cũng có được phần thời gian công bằng của họ.

BibApp

BibApp là một mạng xã hội nghiên cứu. Đây là công cụ gọn nhẹ cho các thư viện hàn lâm sử dụng để kết nối các nhà nghiên cứu trong khu trường với các chuyên gia trong lĩnh vực để hỗ trợ họ trong nghiên cứu của họ. Các nhà nghiên cứu tạo các hồ sơ và thêm các công việc của họ vào hồ sơ của họ. Điều này làm cho dễ dàng để họ thúc đẩy công việc của họ, và nó chỉ ra phần còn lại của cộng đồng trong khu trường của bạn về nhà nghiên cứu đó đang làm về điều gì. Đối với các thư viện, BibApp làm cho dễ dàng để tìm ra nghiên cứu nào đang được tiến hành trong khu trường.

Guide on the Side

Guide on the Side là công cụ đáng kinh ngạc, và nó nói ngay trên website: Biết cách sử dụng từ ư? Bạn biết rồi cách sử dụng Guide on the Side! Đây là công cụ nhỏ hữu dụng ngồi bên cạnh website hoặc catalog thư viện của bạn để hướng dẫn các khách hàng cách sử dụng hệ thống. Xem công cụ này hoạt động ở Đại học Arizona.

Về cơ bản, bạn vết sách chỉ dẫn của bạn trong giao diện của Guide on the Side và sau đó nói cho nó URL nào phải hiển thị ở bên phải màn hình. Sách chỉ dẫn của bạn thậm chí có thể bao gồm bài kiểm tra để chắc chắn mọi người đang tuân theo cùng và hiểu các chỉ dẫn của bạn. Công cụ này có thể có nhiều sử dụng bên trong thư viện.

OpenRoom

OpenRoom cho phép bạn quản lý sự đặt chỗ trước không gian công cộng trong thư viện. Một câu hỏi lặp đi lặp lại mà tôi có trong các phiên huấn luyện là ứng dụng đặt phòng nguồn mở. Thực sự có vài ứng dụng như vậy ngoài đó, nhưng OpenRoom được thiết kế bởi và cho các thư viện. Giao diện đơn giản cho phép dễ dàng tùy biến thích nghi chủ đề, tạo sự đặt chỗ trước thông qua mẫu biểu trên web, và nhanh chóng thiết lập các phòng và/hoặc các nhóm phòng. Hãy lấy OpenRoom và thử nó.

Tác giả: Lê Minh Nghĩa

Chuyện những Pull Requests trong lập trình

Nếu bạn đã trở thành một lập trình viên, làm việc theo team, hoặc bạn đã từng sử dụng qua những công cụ quản lí mã nguồn (git, svn, …), có lẽ bạn sẽ không quá xa lạ với khái niệm về những Pull Requests (PRs). Bạn làm việc với nó hằng ngày, cùng tương tác với những đồng nghiệp của mình trên những PRs, bạn tự tạo những PRs cho mình hoặc kiểm tra những PRs của người khác, … nhưng bạn có hiểu hết hoặc tận dụng hết những ý nghĩa mà nó mang lại cho bạn?

Nếu bạn chưa biết PRs là gì, thì cũng đừng quá lo lắng, mình sẽ giải thích lại khái niệm đó, cũng như những công việc lập trình viên cần phải làm từ khi tạo ra cho tới khi kết thúc PRs ngay sau đây.

Pull request (PR) là gì?

Để nói tới PR, chúng ta không thể không nhắc tới mã nguồn (source code) của chương trình. Thông thường, một phần mềm được tạo nên bởi nhiều lập trình viên, để có thể đảm bảo tính nhất quán về source code của sản phẩm, chúng ta sẽ cần sử dụng tới những phần mềm quản lí mã nguồn, ví dụ như git hoặc svn. Trong số đó, nổi tiếng và quen thuộc nhất với cộng đồng lập trình viên hiện tại có lẽ là git và ứng dụng giúp chúng ta thực thi và tương tác với nó là github.

Khi nhiều lập trình viên cùng làm việc trên cùng một tập mã nguồn (thuật ngữ chuyên ngành gọi là repository hay ngắn ngọn là repo), họ thực hiện sao chép repo gốc – được quản lí trên server github – về máy tính cá nhân, ta gọi mã nguồn ở máy tính cá nhân là local repo. Hình dung đơn giản bằng hình ảnh sau đây:

Thông thường, mã nguồn chính của sản phẩm thường được để trong nhánh (thuật ngữ là branch) có tên gọi là master. Khi phát triển một tính năng mới, nhưng lại tránh thay đổi gì mã nguồn đang có của nhánh master, lập trình viên sẽ tạo ra các nhánh con, ví dụ: nhánh feature_A, nhánh feature_B … Sau đó sẽ thêm mã nguồn mới vào các nhánh con này, trong khi họ làm tính năng mới thì nhánh master sẽ không bị thay đổi gì cả, vì thế mà trong lúc họ làm phần mềm vẫn chạy bình thường. Minh họa bằng sơ đồ sau:

Khi lập trình viên viết code xong cho những tính năng mình phụ trách, họ sẽ tạo những Pull Request (minh họa ở trên là PR-1 và PR-2) với mục đích kĩ thuật là để gộp mã nguồn mới vào mã nguồn cũ (thuật ngữ chuyên môn gọi là merge source). Bên cạnh đó, PRs cũng để thông báo với những người làm chung rằng: tôi đã làm xong và sẵn sàng gộp chung mã nguồn mới (của tính năng mới) vào phần mềm đang chạy, để bổ sung tính năng mới cho sản phẩm.

Những tác dụng của Pull Requests

Như đã giải thích ở trên, các PRs là các khái niệm hoàn toàn mang tính kĩ thuật: giúp ta gộp chung mã nguồn mới vào mã nguồn cũ. Với một khái niệm hoàn toàn mang tính kĩ thuật như vậy, chúng ta liệu có học hỏi được nhiều bài học từ nó? Nếu bạn còn thắc mắc như vậy thì để mình nói cho bạn nghe thêm vài tác dụng khác của PRs nhé.

Nhờ người khác kiểm tra lại mã nguồn (review)

Khi bạn tạo ra một PR để yêu cầu có một sự merge source, bạn mới thực hiện được một nửa quá trình, PR còn cần phải được “xác nhận” lại lần cuối trước khi lệnh merge được chính thức kích hoạt bởi phần mềm quản lí mã nguồn git. Trong github, việc “xác nhận” này được thực hiện bằng việc nhấn vào nút MERGE trên PR.

Ở bước “xác nhận” này, bạn có thể nhờ một người khác trong nhóm của bạn -người có thể có nhiều kinh nghiệm – kiểm tra lại PR đó xem coi những đoạn mã lệnh bạn viết trong tính năng mới có ổn hay không, có thực thi đúng chức năng và nhiệm vụ không, có đạt hiệu suất cao hay không, có bảo mật hay không, … Khi những tiêu chí về chất lượng mã nguồn được kiểm tra và đảm bảo, tính năng mới (hay mã nguồn mới) mới chính thức được merge vào sản phẩm. Công việc kiểm tra này được gọi bằng thuật ngữ là review.

Từ cái nhìn trên, có thể hiểu PR là một thứ thể hiện cho kiến thức và kĩ năng của bạn, việc nhờ người khác nhận xét và kiểm tra, bạn sẽ hạn chế được lỗi (nếu có) phát sinh trong quá trình viết code, cũng như sẽ rút ra được nhiều bài học mới và vấn đề mới cần cải thiện.

Lưu lại lịch sử phát triển của sản phẩm

Sau khi PRs được merge vào nhánh chính của sản phẩm, thông tin về nó sẽ không bị mất đi. Phần mềm quản lí mã nguồn sẽ tiếp tục lưu lại thông tin về những PRs trong dữ liệu của nó, những thông tin thay đổi về mã nguồn chi tiết tới từng dòng đều được lưu lại để thực hiện truy vấn lại sau này. Nói một cách khác, quá trình phát triển của sản phẩm được ghi lại một cách rõ ràng và chi tiết thông qua những PRs.

Tất cả mọi người lớn đều đã từng là những đứa trẻ, tương tự như thế, tất cả những phầm mềm dù lớn tới và phức tạp tới đâu cũng từng được tạo nên từ những thứ đơn giản ban đầu. Mỗi PR giống như một bài học bạn học được trong quá trình lớn lên và trưởng thành vậy. Bạn có thể học được rất nhiều bài học về phát triển phần mềm từ những PRs trong quá khứ.

Là cơ hội giúp bạn học hỏi từ người khác

Bạn vẫn luôn được những lập trình viên có kinh nghiệm khuyên rằng: cách tốt nhất để phát triển kĩ năng của mình là phải làm thật nhiều. Sự thật là vậy, bạn càng viết code nhiều, luyện tập thiết kế cách tính năng khác nhau thì sẽ càng mau giỏi. Nhưng vấn đề là, khi bạn còn chưa có nhiều kinh nghiệm, leader hoặc cấp trên của bạn nào dám đưa cho bạn phụ trách những tính năng lớn, những tính năng phức tạp.

Khi bạn không được trao vai trò chính trong việc phát triển và trở thành người tạo ra những PR, bạn vẫn có thể học hỏi từ nó, bằng cách đóng góp những commits nhỏ trong PR, trở thành người kiểm tra Pull Request (gọi là reviewer), hay đơn thuần chỉ là người đọc qua những sự thay đổi của mã nguồn từ những PRs.

Khi làm việc với những nhóm lớn, sẽ có rất nhiều PRs được tạo ra trong quá trình phát triển sản phẩm, những PRs chứa đựng giải pháp cho những điều bạn có thể chưa biết, tham khảo những PRs này cũng sẽ giúp bạn học thêm được rất nhiều điều mới mẻ và có ích cho sự phát triển của bạn.

Nói tóm lại

Bạn có thể thấy, PR thực chất là một khái niệm mang tính kĩ thuật của những phần mềm quản lí mã nguồn, nó giúp ta gộp những mã nguồn mới vào mã nguồn cũ để phát triển sản phẩm, nhưng không vì thế mà nó không chứa nhiều điều cho chúng ta học hỏi.

Kĩ thuật tách nhánh vào tạo những PRs giúp chúng ta tách biệt trách nhiệm của từng người, phân chia công việc lớn thành những thứ nhỏ hơn để nhiều người cùng có thể phát triển sản phẩm mà không dẫm chân lên nhau. Hãy luôn nhớ một điều là: phát triển phần mềm là công việc của cả một tập thể, bạn luôn luôn có cơ hội để học hỏi từ những người khác, ngay cả khi bạn không làm việc trực tiếp với họ. Những Pull Requests chính là thứ giúp chúng ta thực hiện điều này.

TopDev via Những dòng code vui

Vượt qua các bài phỏng vấn Javascript

 Đối với cả ngành công nghệ phần mềm hiện nay, thì số lượng việc làm có liên quan đến lĩnh vực web chiếm một tỉ trọng tương đối lớn. Lập trình viên có khả năng làm về web đang được săn tìm khá nhiều trên các trang tìm việc online đủ để minh chứng cho điều này. Và nếu đã làm web thì không thể không nhắc tới ngôn ngữ Javascript.

Kĩ năng về Javascript không chỉ cần thiết cho công việc phát triển Client-side của hệ thống, ngoài ra với sự xuất hiện của NodeJS và nhiều Framework hỗ trợ khác, bạn có thể làm việc như một Fullstack developer với chỉ 1 ngôn ngữ duy nhất là Javascript, thậm chí là ứng dụng web của bạn còn có thể được mang lên cả các thiết bị di động cũng chỉ với Javascript, thật vi diệu ^^.

Xem việc làm javascript đãi ngộ tốt trên TopDev

Tất cả những điều đó có đủ thuyết phục để bạn bỏ công sức ra tìm hiểu về Javascript chưa? Công việc có liên quan tới Javascript tràn ngập ngoài thị trường, và nếu bạn có ý định tìm một công việc nào đó có liên quan đến ngôn ngữ này, thì bạn cần phải xem lại các vấn đề cốt lõi sau đây để có thể vượt qua được vòng phỏng vấn của các công ty tuyển dụng. Càng nắm vững kiến thức, vượt qua được các câu hỏi phỏng vấn dễ dàng bao nhiêu thì cơ hội bạn nhận được mức lương tốt cũng sẽ cao tương ứng. Chúng ta cùng xem thử các vấn đề thường gặp phải trong các bài phỏng vấn Javascript thôi nào.

1. Vấn đề đầu tiên: Scope (tầm vực) của biến.

Scope trong Javascript có một chút khác biệt so với các ngôn ngữ lập trình khác, Scope trong Javascript có phạm vi nằm trong hàm (function scope):

  • Thứ 1: Biến được khai báo bên trong hàm sẽ là biến cục bộ, và biến cục bộ thì có thể được truy cập bên trong hàm (không có khái niệm scope trong 1 khối lệnh).
  • Thứ 2: Biến được khai báo bên ngoài hàm sẽ là biến toàn cục, và có thể được truy cập từ bất cứ đâu.

Chú ý: biến khai báo bên trong hàm mà không có từ khoá “var” cũng sẽ trở thành biến toàn cục. Ngoài ra, việc khai báo “var” mà lại không nằm trong function nào thì biến cũng sẽ mang tầm vực toàn cục.

Chúng ta kiểm chứng lại ngay sau đây, đầu tiên là khai báo một hàm trong Javascript

1
2
3
4
5
6
7
8
9
function testScope()
{
    var local_var_1 = global_var_1 = "inside_function";
    if(true){
        var local_var_2 = "inside IF";
    }
    console.log("Test local_var_1 inside function: " + local_var_1);
    console.log("Test local_var_2 inside function: " + local_var_2);
}

Mọi người thử trả lời xem kết quả của câu lệnh dưới đây là gì nào?

1
2
3
testScope();
console.log("Test local_var_1 outside function: " + local_var_1);
console.log("Test global_var_1 outside function: " + global_var_1);

Dưới đây là đáp án cho câu hỏi trên, các bạn nên thử tự mình trả lời rồi so sánh với kết quả bên dưới này xem như thế nào nhé:

1
2
3
4
Test local_var_1 inside function: inside_function
Test local_var_2 inside function: inside IF
undefined
Test global_var_1 outside function: inside_function

Bằng việc thực thi hàm testScope(), chúng ta sẽ kiểm tra được giá trị của biến “local_var_2” mặc dù được khai báo bên trong khối lệnh if() nhưng nó vẫn sẽ có tầm vực truy cập bên ngoài khối lệnh này. Tầm vực của biến “global_var_1” có giá trị toàn cục, do vậy ta vẫn có thể truy cập giá trị biến này bên ngoài hàm, lí do là ta đã không dùng từ khoá “var” khi khai báo biến này (chú ý là trong trường hợp này “var” chỉ có tác dụng khai báo với biến “local_var_1” mà thôi).

Vấn đề về scope trong Javascript có đôi chút nhập nhằng, do vậy mà mình khuyên mọi người luôn dùng từ khoá var để khai báo biến nhằm tránh các tình huống biến trở thành biến toàn cục có thể dẫn tới những lỗi rất khó để phát hiện. Ngoài ra nên dùng thêm từ khoá “use strict” để sử dụng Javascript với strict mode, mode này sẽ yêu cầu bạn phải khai báo tường minh tất cả mọi thứ để tránh các lỗi tiềm tàng có thể xảy ra.

2. Khái niệm hoisting

Khi code sử dụng javascript, có một khái niệm cũng khá là đặc biệt là hoisting. Với khái niệm này, javascript quy định, mọi khai báo biến đều được đưa lên trên cùng của một tầm vực. Tức là mặc kệ bạn khai báo biến ở vị trí nào trong 1 hàm, thì tự động nó sẽ kéo lên trên cùng của hàm để khai báo (javascript tự động thực hiện ngầm cho khái niệm này).

Khái niệm hoisting này cũng là một khái niệm khác biệt của Javascript, nhiều lập trình viên thường bỏ qua vấn đề này, và đây cũng là 1 trong những nguyên nhân gây ra lỗi rất khó phát hiện ở trong ngôn ngữ lập trình này. Chạy thử đoạn code sau để hiểu rõ hơn:

1
2
3
4
5
6
var hoisting_example = 'test_hoisting_AAA';
function explainHoisting(){
    console.log(hoisting_example);
    var hoisting_example = "testing_hoisting_BBB";
    console.log(hoisting_example);
}

Chắc hẳn là nhiều người sẽ nghĩ rằng kết quả là thế này:

1
2
testing_hoisting_AAA
testing_hoisting_BBB

Tuy nhiên, đáp án ở trên là SAI. Kết quả đúng phải là:

1
2
undefined
testing_hoisting_BBB

Câu hỏi đặt ra là: tại sao ở lần đầu tiên in ra, thì biến “hoisting_example” lại không có giá trị? Câu trả lời là: chính việc hoisting trong Javascript làm như thế. Như đã nói ở trên, việc khai báo biến đã được Javascript ngầm thực hiện ở trên đầu hàm, chính điều này làm mất đi giá trị của biến “hoisting_example” đã được khai báo bên ngoài hàm. Tóm lại, đoạn code ở trên có thể được hiểu một cách tường minh như sau:

1
2
3
4
5
6
7
var hoisting_example = 'test_hoisting_AAA';
function explainHoisting(){
    var hoisting_example;
    console.log(hoisting_example);
    hoisting_example = "testing_hoisting_BBB";
    console.log(hoisting_example);
}

Ngoài ra, trong phiên bản ESMAScript 6, chúng ta có them từ khoá khai báo biến mới đó là “let”. Từ khoá “let” dung để khai báo 1 biến có tầm vực trong 1 block code, tứ là nó sẽ không ảnh hưởng bởi khái niệm hoisting, mọi người có thể tìm hiểu them trên google để hiểu rõ hơn về các đặc trưng mới của phiên bản ECMAScript 6. Và hãy nhớ, để ý vấn đề hoisting khi làm việc với Javascript nha mọi người!

3. Về Native method, khái niệm Object và Prototype của Object

Chúng ta thử chạy đoạn lệnh dưới đây và giải thích kết quả xem nào:

1
2
3
4
5
var num = 5;
typeof(num);          //”number”
//chạy lệnh lấy bình phương của số đó
num.square();        // Uncaught TypeError: num.square is not a function

Mọi người thử trả lời câu hỏi tại sao lệnh lấy bình phương square() lại báo lỗi? Nếu bạn cho rằng kiểu dữ liệu number không có sẵn phương thức square() thì bạn đã trả lời đúng rùi đấy. Vậy câu hỏi đặt ra tiếp theo là: làm thế nào để ta khiến cho câu lệnh đó thực thi đúng như mong đợi? 1p suy nghĩ bắt đầu ^^

… … … … Hết giờ … … …

Có thể là giải pháp của bạn trông giống như sau:

1
2
3
4
Number.prototype.square = Number.prototype.square || function(){return this*this;};
//Gọi thử lệnh để xem kết quả xem nào:
num.square();               //25

Công việc chúng ta vừa làm ở trên là: xây dựng thêm một native method cho kiểu dữ liệu number, đây thực chất là việc thêm một phương thức prototype cho đối tượng built-in là Number.

Như bạn đã thấy, để có thể đưa ra giải pháp ở trên, chúng ta cần các kiến thức về khái niệm Object và prototype của Object trong Javascript. Những thuộc tính và phương thức trong prototype của object sẽ được các object con kế thừa. Đây chính là 1 đặc điểm hết sức khác biệt nữa của Javascript: nó là một ngôn ngữ sử dụng kế thừa kiểu object-based (không giống class-based như các ngôn ngữ OOP truyền thống).

Các bạn cần phải chuẩn bị kĩ các kiến thức về Object và khái niệm prototype của object nếu muốn trở thành một lập trình viên Javascript tốt. Hôm nào có thời gian mình cũng sẽ ôn lại các kiến thức đó qua một bài viết mới. Các bạn nhớ đón xem nhé ^^

4. Con trỏ this

Con trỏ this được sử dụng rất nhiều trong các đoạn mã JS, và nó cũng là một trong những khái niệm gây ra nhiều sự hiểu lầm (dẫn đến bug) nhất trong ngôn ngữ này. Để lập trình tốt bằng Javascript thì người lập trình viên buộc phải hiểu rõ cách mà con trỏ this vận hành.

Trong các ngôn ngữ OOP điển hình như C++, PHP, Java, … khái niệm con trỏ “this” tương đối dễ hiểu, nó gắn liền với thực thể (instance) đang được kích hoạt. Ở javascript thì mọi chuyện có vẻ phức tạp hơn, giá trị của this gắn liền với context mà nó được gọi, xét thử đoạn code sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var name = "Peter";
var Hocsinh = {
    name: "John",
    printName: function(){
        console.log(this.name);
    }
};
//Lệnh gọi đầu tiên
var printHocsinhName = Hocsinh.printName;
printHocsinhName();                          // Peter
//Lệnh gọi thứ 2
Hocsinh.printName();                         // John

Như ta đã thấy, kết quả của 2 lần gọi hàm này cho ta 2 kết quả khác nhau. Tại sao lại như vậy? Thử đưa ra câu trả lời xem nào. Cho bạn 100 giây suy nghĩ: 1 … 2 …3 …4 … 5 … 100 … hết giờ =))

Ở lần gọi đầu tiên, hàm này được kích hoạt không bởi đối tượng cụ thể nào, tức là context của hàm printName được gán là biến toàn cục window, trong khi đó đối tượng gọi hàm ở lần chạy thứ 2 là đối tượng Hocsinh, do vậy mà giá trị của this sẽ có giá thị của đối tượng Hocsinh.

Sự nhập nhằng của giá trị this trong Javascript có thể khiến lập trình viên bối rối, và nếu bạn muốn vượt qua các buổi phỏng vấn cũng như nâng cao kĩ năng viết code Javascript của mình, thì nên đầu tư tìm hiểu khái niệm này kĩ hơn.

Bind(), Call(), Apply()

Đi kèm với các hàm này là vấn đề liên quan tới giá trị của con trỏ “this”, ta xem lại ví dụ ở trên, lí do mà 2 lần gọi hàm ta được 2 kết quả khác nhau là bởi vì context của con trỏ this ở 2 tình huống là khác nhau. Nếu ta muốn kết quả in ra đúng với ý định của mình, thì ta có thể gán context cho con trỏ this một cách tường minh bằng các hàm bind(), call() hoặc apply().

Bây giờ thử trả lời câu hỏi: làm thế nào cả lệnh gọi printHocsinhName cho ta kết quả là “John”, và làm thế nào để ta có thể gọi hàm Hocsinh.printName mà lại có kết quả là “Peter”???

Chúng ta lại có thêm 100s suy nghĩ nữa nào: 1 … 2 … 3 … 99 … 100 … và … hết giờ ^^. Cùng thử so sánh đáp án xem nào:

1
2
3
4
5
6
7
8
9
10
//Cách thứ nhất
var printHocsinhName = Hocsinh.printName.bind(Hocsinh);
printHocsinhName();                                      // John
//Hoặc cách thứ 2
var printHocsinhName = Hocsinh.printName;
printHocsinhName.call(Hocsinh);                          // John
//Xử lí Hocsinh.printName
Hocsinh.printName.call(window);                           //Peter

Bản chất của câu hỏi này nhằm kiểm tra các kiến thức của bạn về khái niệm context của con trỏ this khi được gọi, và các cách thức để kiểm soát được giá trị này một cách chặt chẽ hơn. Cả 3 hàm này đều có ý nghĩa là gán giá trị của con trỏ this khi được chạy tới một giá trị cụ thể nào đó, và nếu bạn nắm được khái niệm context của con trỏ this, bạn sẽ giải quyết được câu hỏi này cách dễ dàng.

Nhắc lại 1 chút, bản thân một hàm (function) cũng là 1 object trong Javascript, vậy nên chúng ta sẽ rất hay bắt gặp các tình huống làm thay đổi context của hàm như: truyền qua object function, hàm mượn, callback, … Nắm được cách sử dụng các hàm bind(), call(), apply() sẽ giúp chúng ta kiểm soát tốt và đảm bảo được kết quả chạy của các hàm đúng với mong muốn.

Ngoài ra, bạn cũng cần coi thêm các kiến thức về cơ chế xử lí bất đồng bộ như: các thao tác gọi xử lí AJAX, các kiểu Promise hỗ trợ thực thi bất đồng bộ và giúp tránh callback hell, v.v.v Nắm được hết các vấn đề này, thì bạn có thể tự tin là mình đã biết được khá rõ về Javascript rồi đó.

TopDev via Nhungdongcodevui

Xem thêm việc làm developer trên TopDev

Migrate từ hệ thống monolithic sang microservice – part 2

Để thực hiện migrate sang microservice, thì phương pháp Domain Driven Design được sử dụng. Tuy nhiên được cải biên thành DDD Incremental Design. Phương pháp này thực chất là SA và Domain expert cùng ngồi lại với nhau để xác định Bounded Context, hiểu đơn giản là bóc tách 1 phần chức năng của hệ thống cũ và tạo ra 1 logical border quanh nó. Thật sự thì đọc giải thích trên Google về các khái niệm domain và bounded context rất khó hiểu. 

Link phần 1 đây nhé các bạn : https://topdev.vn/blog/migrate-tu-he-thong-monolithic-sang-microservice/

  • Từ hệ thống cũ phân tích nghiệp vụ, bóc ra một chức năng business cụ thể (ví dụ như order, payment)
  • Tạo 1 border bao quanh business logic và data đó, những module khác muốn truy cập thì phải qua interface

Khái niệm Big Ball of Mud

Legacy system đang theo kiến trúc monolithic, giống như một quả bóng bùn khổng lồ (gigantic ball of mud), anti-pattern. Business logic được code theo kiểu xâu chuỗi theo kiểu hàm A gọi hàm B, B lại gọi cho C qua rất nhiều level function call. Không hề có một biên giới rõ ràng giữa data và chức năng. Đó là 1 challenging khi migrate sang microservice.

Việc xác định Bounded Context trong hệ thống đòi hỏi cần có Domain Expert, những người hiểu rất sâu sắc business của hệ thống, biết được các module liên hệ qua lại như thế nào, dependency ra sao.

Domain Expert cần mô tả được hệ thống có bao nhiêu module, quan hệ giữa các module như thế nào

Ví dụ minh họa đơn giản

Những module như Order có nhiều quan hệ với module khác thì việc migrate sang microservices sẽ phức tạp hơn nhiều so với các module độc lập như Product. 

Từ các module trên sẽ bóc nhỏ thành các Bounded Context

Build model và interface

Sau khi Bounded Context được xác định, bước tiếp sẽ tạo interface. Phần lớn trường hợp thì interface được thiết kế thành Rest API. Ngoài ra thì có thể sử dụng Queue, event streams.

Các module bên ngoài sẽ được modify để access bounded context thông qua interface. Do đó mỗi khi bóc tách module thành microservice, thì những phần còn lại của hệ thống mono sẽ được sửa đổi để gọi chúng qua interface thay vì function call như trước. Quá trình bóc tách sửa chữa cứ được làm từ từ từng bước một cho đến khi toàn bộ hệ thống migrate xong. Tức là hệ thống mới và cũ vẫn cùng tồn tại (co-exist) cho đến khi hoàn thành migration. Gọi là mô hình Strangler pattern, hiểu nhanh là mô hình dây leo tầm gửi, dây leo (microservice bám quanh) cây chủ (monolithic) cắn từng miếng của cây chủ để lớn dần. cây chủ ngày càng nhỏ dần rồi chết khô

Chốt hạ là sao cho 2 hệ thống mono và microservice có thể chạy đồng thời mà ko ảnh hưởng gì đến business, user sử dụng vẫn ko cảm thấy khác biệt gì, là một challenging thứ 2. Vì quá trình migration sẽ được tính bằng năm.

Ví dụ Order Service được tách ra thành service độc lập từ monolithic ban đầu. Xác định dc bounded context Order từ monolithic tách ra thành Order microservice, phần code đang gọi legacy order qua function call được modified để switch sang gọi bằng API (order API)

Migrate data

Bước cuối cùng là làm sao break down DB monolithic ra thành db riêng own by service. 

Challenging ở đây là làm sao migrate data từ mono db sang microservice db. Vì data là tài sản của tổ chức, không phải của ứng dụng, data lên tới hàng triệu record với hàng trăm bảng quan hệ chằng chịt.

Việc break down và migrate data như thế nào, đón đọc bài sau.

TechTalk via Giaosucan

Code 101: Dành cho ai muốn học lập trình

Càng ngày lập trình trở nên càng phổ biến, cũng như Word và Excel 10–15 năm trước vậy. Để thành công với nghề kỹ sư phần mềm thì cũng cần tố chất phù hợp, nhưng để hiểu và ứng dụng trong cuộc sống thì lập trình cũng không khó hơn Word và Excel. Nếu bạn biết dùng các hàm trong Excel thì có nghĩa là bạn đã lập trình rồi đấy!

Bài viết này giới thiệu một số trò chơi và website dạy tư duy lập trình. Sau đó là các đường dẫn để học Python miễn phí. Cộng đồng VISC có nhiều bạn không làm phần mềm và muốn hiểu hơn về cryptocurrency thì hiểu biết một chút về lập trình sẽ giúp các bạn thoải mái hơn khi đọc các tài liệu kỹ thuật hoặc học các khoá nâng cao.

Lập Trình Là Gì?

Nói một cách đơn giản, lập trình là quá trình viết các lệnh và thao tác để máy tính thực hiện. Nếu bạn có thể chia nhỏ bài toán thành từng bước với các thao tác chi tiết thì bạn có thể bắt đầu lập trình. Không phải lúc nào lập trình cũng là viết ngôn ngữ gần giống tiếng Anh. Những năm 1960 đến những năm 1980, nhiều nơi các nhà khoa học hay nghiên cứu sinh, kỹ sư dùng giấy đục lỗ. Bố tôi cũng vẫn còn giữ một xấp giấy giống thế này:

Ngày nay lập trình đã được bình dân hoá và có vô vàn các ngôn ngữ gần với tiếng Anh thông dụng và thậm chí là xếp các hình khối để diễn tả các bước, các thao thác cho máy tính hiểu:

Lập trình ngày nay đã rất đơn giản và dễ nhập môn hơn ngày xưa rất nhiều. Ở phần sau chúng ta sẽ xem một số trò chơi trong xu hướng gamification để dạy lập trình

Các Trò Chơi Dạy Tư Duy Lập Trình

Trò chơi đầu tiên phải nói đề là Blocky — Do Google và MIT hợp tác sản xuất để dạy tư duy lập trình cho trẻ em và người lớn mới nhập môn:

Blockly | Google Developers
Visual programming editor. Drag and drop blocks to generate executable code. Designed for developers to embed into…developers.google.com

Blocky bắt nguồn từ dự án Scratch của MIT nhưng Scratch thì cần Flash, còn Blocky thì không. Tôi khuyến khích các bạn dùng Blocky vì nó hiện đại hơn.

Trò chơi thứ hai là Human Resource Machine:

Tomorrow Corporation : Human Resource Machine
Tomorrow Corporation is an independent game developer behind indie games Little Inferno and Human Resource Machinetomorrowcorporation.com

Trò chơi rất thú vị và ngộ nghĩnh. Bạn có thể học lập trình trên phone và chơi qua các phần của trò chơi. Cảm ơn bạn Nguyễn Lan Chi đã giới thiệu.

Sau khi làm quen với các trò chơi rèn luyện tư duy lập trình, bạn có thể học một ngôn ngữ lập trình rất hot hiện nay: Python.

Vì Sao Chọn Python?

Ngày nay, số ngôn ngữ lập trình đã lên tới hàng trăm. Theo một thống kê không đầy đủ trên Wikipedia, bạn có thể thấy hơn 700 ngôn ngữ lập trình: https://en.wikipedia.org/wiki/List_of_programming_languages . Theo thống kê của IEEE, Python nằm trong top 10 ngôn ngữ lập trình phổ biến nhất, và năm 2017 Python leo lên vị trí quán quân: https://spectrum.ieee.org/computing/software/the-2017-top-programming-languages

Python cũng rất dễ học và ứng dụng trong nhiều lĩnh vực: Web, desktop, server, công cụ cho quản trị mạng, dạy học, trí tuệ nhân tạo, xử lý ảnh, game, … Bởi vậy tôi chọn Python để giới thiệu với các bạn trong bài viết này.

Các Công Cụ và Tài Liệu Học Python Miễn Phí

Để học một ngôn ngữ lập trình hiệu quả, bạn cần có những công cụ hỗ trợ. Sau đây là trang Learn Python dành cho newbie:

Learn Python – Free Interactive Python Tutorial
LearnPython.org is a free interactive Python tutorial for people who want to learn Python, fast.www.learnpython.org

Bạn có thể chạy trực tiếp trên browser mà chưa phải cài đặt gì. Để hiểu sâu hơn về các vòng lặp, cấu trúc điều kiện, bạn có thể sử dụng công cụ diễn giải Python Tutor:

Python Tutor – Visualize Python, Java, JavaScript, TypeScript, Ruby, C, and C++ code execution
Using this tool, you can write Python 2, Python 3, Java, JavaScript, TypeScript, Ruby, C, and C++ code in your web…pythontutor.com

Sau khi nắm vững các phần cơ bản, bạn có thể tự học các khoá học miễn phí trên Coursera:

Python Courses | Coursera
Learn Python online from 164 Python courses from top institutions like University of Michigan and University of Toronto…www.coursera.org

Hoặc đọc một số tài liệu như Python Crash Course:

Python Crash Course | No Starch Press
“It has been interesting to see, over the last few years, No Starch Press, which produces this book, growing and…www.nostarch.com

Hay là cuốn sách miễn phí “Python rất là cơ bản” dành cho dân lập trình học Python của bạn Võ Duy Tuấn:

Download sách “Python rất là cơ bản”
Hiện nay, Python là một trong những ngôn ngữ lập trình đang được chú ý bởi tính đa dạng về ứng dụng, thư viện phong ph…bloghoctap.com

Tôi cũng rất khuyến khích đọc thêm cuốn “The Hitchhiker’s Guide to Python!” (hoàn toàn miễn phí):

The Hitchhiker’s Guide to Python! – The Hitchhiker’s Guide to Python
This handcrafted guide exists to provide both novice and expert Python developers a best practice handbook to the…docs.python-guide.org

Khi học Python, bạn nên dùng Jupyter Notebook để có thể chạy Python trên browser và sửa code & chạy ngay mà không phải dùng terminal/console nhằm có trải nghiệm tốt nhất. Để cho đơn giản, bạn nên cài đặt luôn trọn gói Anaconda có chứa Jupyter và các thư viện Python phổ biến nhất.

Chúc các bạn học lập trình vui vẻ, tự tin và hiệu quả!

Bài viết của anh Lê Quốc Việt trên medium.com

Muốn phát triển AI cần nuôi dưỡng được niềm đam mê

AI – Trí tuệ nhân tạo xưa và mồi lửa thiên, địa, nhân

AI của thế hệ xưa

Nếu như bạn có cơ hội tiếp xúc với máy tính từ những năm 1990, có lẽ AI chỉ được hiểu như là những đối thủ trong trò chơi điện tử, với những phương thức lập trình vô cùng đơn giản và nhàm chán, nhưng lại là một phần trò cười trong trò chơi đó. Giả dụ như phiên bản Mario trong trò chơi điện tử 4 nút (Nintendo Entertainment System – N.E.S), những con rùa xanh và những con quái vật nâu chỉ biết đi qua đi lại để cố tỏ ra nguy hiểm. Đó chính là bộ mặt điển hình của AI thời điểm đó.
Thế rồi những phim “bom tấn” Hollywood cố tô vẽ một ước mơ, một khát khao cháy bỏng của con người là biến những trò cười trong trò chơi điện tử kia thành những cỗ máy khổng lồ, siêu thông minh, và có phần đáng sợ như trong Ma Trận (Matrix), Kẻ Hủy Diệt (The Terminator). Khi đó, máy tính biết suy nghĩ độc lập, đưa ra quyết định, trợ giúp hoặc trở thành kẻ thù của con người.
Bộ phim khắc họa AI thông minh và hủy diệt.
Trước đây người ta chỉ có thể sử dụng trí tưởng tượng để khắc họa nên những cỗ máy như thế, nhưng nay không thể nói rằng những gì trên phim ảnh là hoàn toàn tưởng tượng được nữa. Những cỗ máy hiện thời đang trở nên vô cùng thông minh một cách đáng kinh ngạc.
Vậy điều gì đã khiến AI trở nên tiến bộ vượt bậc trong thập kỷ qua để tiến hóa từ những con rùa xanh thành những sản phẩm “Powered by AI” với giá trị hàng trăm triệu đô la Mỹ?
Trước khi trả lời câu hỏi đó, hãy nhìn vào một số định nghĩa. AI là một cụm từ mang hàm ý rất rộng, nói đến những cỗ máy hay thuật toán thông minh có thể xử lý các tình huống một cách nhịp nhàng tùy vào hoàn cảnh, chứ không còn là một chương trình được định sẵn để rồi mắc các sai lầm ngớ ngẩn.
Máy học (Machine Learning) là một định nghĩa nhỏ hơn nằm bên trong AI, nói về các thuật toán làm cho máy tính có thể cải thiện được độ chính xác của các công việc theo số lượng dữ liệu đầu vào. Và Học sâu (Deep Learning) là một định nghĩa nhỏ hơn nữa, nằm bên trong Máy học, nói đến một loại thuật toán cụ thể là mạng nơron nhân tạo, một cấu trúc tính toán được phát minh lấy cảm hứng từ cấu trúc não bộ con người.
Sẽ không ngoa khi nói rằng, Máy học là linh hồn của AI, và Học sâu đã đem lại thành công, sự chú ý, cũng như tiềm năng vô tận đến cho Máy học. Sự bùng nổ của các thuật toán Học sâu gần đây đến từ sự cải tiến về phần cứng của máy móc, khi các vi xử lý đồ họa (GPU) giúp tăng tốc tính toán cho các mạng nơron nhân tạo lên gấp hàng ngàn lần so với một lõi vi xử lý trung tâm (CPU). Ngoài ra, một nguyên nhân không thể thiếu đó là nguyên liệu cho các thuật toán Học sâu hoạt động chính là lượng dữ liệu chúng ta tạo ra trong những năm gần đây đã vượt xa kỳ vọng, với 90% tổng lượng dữ liệu là chỉ mới được tạo ra trong vỏn vẹn hai năm gần đây.
Thiên thời (dữ liệu lớn), địa lợi (sức mạnh tính toán cao), và nhân hòa (các tài năng trong lĩnh vực AI) chính là mồi lửa tạo nên cuộc cách mạng khiến cho các phát minh AI đang dần trở nên vô cùng quan trọng và len lỏi vào cuộc sống của con người, cũng giống như dòng điện mà Benjamin Franklin đã tìm ra vào ba thế kỷ trước đây. Vậy thì cuộc sống chúng ta sẽ thay đổi ra sao khi đồng hành cùng với AI?

Xử lý ngôn ngữ tự nhiên (Natural Language Processing)

AI đã và đang đọc hàng triệu, hàng tỉ văn bản mỗi ngày, tổng hợp và thậm chí là tóm tắt lại những kiến thức trong mớ tài liệu khổng lồ mà không một cá thể loài người nào có thể làm được. AI giúp con người trả lời câu hỏi sau khi đọc các kiến thức đó, đưa ra gợi ý, hoàn thành câu viết, và có khi là viết hộ luôn con người. Gần đây, những nhà nghiên cứu của viện Open AI, nơi mà tỉ phú Elon Musk đầu tư mạnh, đã đưa ra một mô hình AI có khả năng tạo ra văn bản với độ “thật” đến đáng sợ, khiến cho họ quyết định không xuất bản toàn bộ thuật toán vì lo sợ nguy cơ bị lạm dụng. Điều này khiến cho cả thế giới khoa học giật mình vì nó quan trọng đến mức tổ chức Open AI đã phải đi ngược lại với chữ “Open” (Mở) của họ.

Thị giác máy tính (computer vision)

Và thị giác máy tính (computer vision) là ngành được hưởng lợi nhiều nhất trong cuộc cách mạng AI. Hình ảnh là thứ con người tự hào đem lại rất nhiều thông tin mà nay đã được máy tính học và dần dần thắng thế. Từ những ứng dụng bảo mật như nhận dạng khuôn mặt, đến các thuật toán tìm ra những hình ảnh, thước phim nhạy cảm, các công ty công nghệ lớn như Apple, Facebook, hay Google đều coi AI là trái tim trong các sản phẩm công nghệ của họ.
Đơn giản rằng, nếu thiếu đi AI, các sản phẩm công nghệ của họ không thể nào phát triển (scale) đến hàng tỉ người dùng được. Và tuyệt vời thay, đến các ngành như y tế cũng đã ứng dụng công nghệ AI vào việc giúp các bác sĩ chẩn đoán các bệnh như lao, ung thư, khối u một cách chính xác hơn ngày xưa rất nhiều.

Từ Mỹ đến Nhật

Mỹ là đầu tàu của cả thế giới về lĩnh vực AI bởi vì Mỹ là cái nôi của Internet. Thành công của các công ty có công nghệ AI bậc nhất thế giới như Facebook, Google, hay Amazon đến từ lượng dữ liệu khổng lồ họ có được khi là một công ty Internet. Đây là điểm mấu chốt để thành công, bên cạnh những sự đầu tư khổng lồ về cơ sở hạ tầng tính toán và nhân tài trong lĩnh vực này.
Vậy đâu là cánh cửa cho các công ty khác, các đất nước khác muốn phát triển AI và cạnh tranh với các ông lớn này?
Làm việc tại Nhật Bản trong những năm qua cho tôi thấy cách người Nhật tạo ra lợi thế cạnh tranh của họ. Khó có đất nước nào tạo được nhiều dữ liệu về quá trình sản xuất tiên tiến và cơ sở hạ tầng thông minh như Nhật Bản. Họ lấy đó làm tiền đề để thúc đẩy ngành AI cho nước Nhật và cạnh tranh với những việc mà Facebook, hay Google không thể nào động đến họ được. Khi nghiên cứu ở Nhật, tôi đã phát minh ra thuật toán AI có thể tự động hóa quy trình lấy và xử lý nước trong một nhà máy lọc nước vô cùng hiện đại với các cảm ứng được lắp đặt ở khắp nơi.

Và đến Việt Nam

Nhìn về Việt Nam, đâu là cơ hội cho chúng ta trở thành một nước cạnh tranh về AI trên bản đồ thế giới. Giống như ở trên tôi phân tích, ba yếu tố quan trọng đó là thiên thời (dữ liệu lớn), địa lợi (sức mạnh tính toán cao), và nhân hòa (các tài năng trong lĩnh vực AI) cần phải được cân nhắc để tạo nên tính khác biệt với các nước trên thế giới.

Thứ nhất, thiên thời – dữ liệu của người Việt.

Việt Nam có số lượng người sử dụng điện thoại thông minh rất cao (lên đến 72% tỷ lệ thâm nhập theo báo cáo của Appota), một phương tiện để thu thập cũng như sản sinh ra dữ liệu rất lớn. Ngoài ra, những bộ dữ liệu “độc quyền” của người Việt có thể kể đến ngôn ngữ, văn bản, hình ảnh trong nước, hay các ngành nghề rất Việt Nam.
Việt Nam cần có một cơ sở dữ liệu của riêng mình, và tốt nhất là được mở ra cho các nhà nghiên cứu về AI có thể truy cập và sử dụng một cách an toàn. Nếu chúng ta không làm được điều này ở cấp độ nhà nước, thì chỉ còn trông đợi vào các doanh nghiệp tư nhân đua nhau thu thập dữ liệu và tạo ra thế mạnh cho riêng họ. Nhưng liệu các ông chủ tư nhân có đủ thoải mái để kết hợp với nhau, chia sẻ tài nguyên với nhau, để cùng cạnh tranh với thế giới hay không?

Thứ hai, địa lợi – cơ sở hạ tầng tính toán

Một trong các điều kiện tiên quyết để bứt phá trong ngành AI đó là sức mạnh tính toán. Các trường đại học thành công trong nghiên cứu về AI đều có cơ sở hạ tầng tính toán lớn, đủ sức để đưa ra kết quả của một thí nghiệm có quy mô lớn trong… vài ngày. Việc liên tục có được những kết quả thí nghiệm thúc đẩy vòng lặp quá trình tìm hiểu, sửa lỗi, nâng cấp diễn ra nhanh hơn.
Ở Việt Nam, ngoài một số công ty lớn về công nghệ đang nỗ lực đầu tư cơ sở hạ tầng tính toán (tuy nhiên không rõ có phải để dành cho nghiên cứu hay cho việc làm sản phẩm), thì cơ sở hạ tầng tính toán ở các trường đại học ở Việt Nam gần như không có sức cạnh tranh.

Cuối dùng, nhân hòa – tài năng trong lĩnh vực AI

Nhìn vào thành công của người Việt trên thế giới, có lẽ không quá tự kiêu khi nói rằng người Việt rất phù hợp với làm AI.
Chúng ta có những người dẫn đầu thế giới trong ngành và có những người có tầm ảnh hướng lớn trong ngành. Tuy nhiên, nên nhớ rằng họ đều được đào tạo bài bản ở môi trường giáo dục nâng cao (đại học và sau đại học) tại các nước phát triển. Đồng thời, chúng ta có một chương trình toán cơ bản (bậc dưới đại học) khá tốt.
Vậy vì đâu chúng ta lại vẫn thiếu nhân lực cao cấp trong ngành đến như vậy? Theo tôi, từ bậc đại học trở lên, còn quá ít những người có niềm đam mê với nghiên cứu cơ bản về toán, về ngành khoa học máy tính, và về AI nói riêng. Có phải chúng ta chưa nuôi dưỡng được niềm đam mê đó? Bản thân tôi, cũng bắt đầu làm việc với các học sinh cấp 3 về ngành AI để nuôi dưỡng những tài năng và đam mê cho AI Việt sau này. Nếu như không ai quan tâm, chúng ta không thể có nguồn lực dồi dào, chất lượng cho những dự án tham vọng về AI của đất nước sau này.
Phong và giáo sư Yoshua Bengio (giám đốc MILA)
Tôi từng gặp Giáo sư Yoshua Bengio, một trong những cha đẻ của ngành AI tiên tiến thời nay, tại Montreal, Canada. Ông có nói với tôi rằng, họ, những sinh viên đang nghi ngờ những điều ông giảng, chính là những người sẽ thay đổi thế giới sau này, chứ không phải là ông nữa. Đó là điều khiến tôi mong muốn được làm việc với ông trong tương lai, và đương nhiên bản thân tôi cũng mong muốn được biết thêm nhiều bạn trẻ Việt Nam như vậy.
TopDev via Giaosucan

Hướng dẫn giải bài toán phân bổ số lượng (thuật toán chia kẹo) trong sqlserver

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách giải bài toán phân bổ số lượng (bài toán chia kẹo) trong lập trình cơ sở dữ liệu sqlserver.

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách giải bài toán phân bổ số lượng (bài toán chia kẹo) trong lập trình cơ sở dữ liệu sqlserver.

Ví dụ: mình có hình database như ở bên dưới

candy_algorithm_sqlserver

Ở hình trên các bạn thấy:

+ Mình có số lượng của tổng PO là : 375 [DocEntry = 1](số lượng vào)

+ Và một bản hiển thị ở dưới cần chia cho [DocEntry] lần lượt là: 100, 200 và 200.

Nếu với số lượng như hình trên kết quả mình muốn hiển thị như hình dưới lần lượt là: 100, 200, sau khi chia hết 300 thì còn 75 chia cho column thứ 3.

Nếu số lượng vào dư lên, sẽ được cộng dồn vào cho column ở ô cuối cùng.

Kết quả khi chạy truy vấn SQL chia kẹo:

candy_sqlserver

Câu lệnh truy vấn T-SQL:

DROP TABLE #po;
DROP TABLE #inv;
DROP TABLE #temp;
CREATE TABLE #PO
(
    PO VARCHAR(10),
    DocEntry INT,
    Qty INT
);
CREATE TABLE #INV
(
    INV VARCHAR(10),
    DocEntry INT,
    Qty INT
);
INSERT INTO #PO
(
    PO,
    DocEntry,
    Qty
)
VALUES
('A123', 1, 200);
INSERT INTO #PO
(
    PO,
    DocEntry,
    Qty
)
VALUES
('A123', 1, 150);
INSERT INTO #PO
(
    PO,
    DocEntry,
    Qty
)
VALUES
('A123', 1, 25);
INSERT INTO #PO
(
    PO,
    DocEntry,
    Qty
)
VALUES
('B123', 2, 50);
INSERT INTO #PO
(
    PO,
    DocEntry,
    Qty
)
VALUES
('B123', 2, 30);
INSERT INTO #INV
(
    INV,
    DocEntry,
    Qty
)
VALUES
('IV100', 1, 100);
INSERT INTO #INV
(
    INV,
    DocEntry,
    Qty
)
VALUES
('IV102', 2, 200);
INSERT INTO #INV
(
    INV,
    DocEntry,
    Qty
)
VALUES
('IV105', 1, 200);
INSERT INTO #INV
(
    INV,
    DocEntry,
    Qty
)
VALUES
('IV106', 2, 190);
INSERT INTO #INV
(
    INV,
    DocEntry,
    Qty
)
VALUES
('IV112', 1, 200);

CREATE TABLE #temp
(
    PO VARCHAR(10),
    DocEntry INT,
    Qty INT
);
INSERT INTO #temp
(
    PO,
    DocEntry,
    Qty
)
SELECT PO,
       DocEntry,
       SUM(Qty)
FROM #PO
GROUP BY PO,
         DocEntry;
SELECT a.PO,
       a.Qty,
       a.Quantity,
       DevideCandy = CASE
                         WHEN a.conlai2 > 0
                              AND a.conlai2 >= a.Quantity THEN
                             a.Quantity
                         WHEN a.conlai2 > 0
                              AND a.conlai2 < a.Quantity THEN
                             a.Quantity
                         WHEN (a.conlai2 + a.Quantity) < 0 THEN
                             0
                         ELSE
                             a.conlai2 + a.Quantity
                     END
FROM
(
    SELECT p.DocEntry,
           p.PO,
           p.Qty,
           i.INV,
           i.Qty AS Quantity,
           conlai = IIF(
                        p.Qty -
                        (
                            SELECT SUM(rt.Qty)
                            FROM #INV rt
                            WHERE (rt.DocEntry = i.DocEntry)
                                  AND (rt.INV <= i.INV)
                        ) < 0,
                        0,
                        p.Qty -
                        (
                            SELECT SUM(rt.Qty)
                            FROM #INV rt
                            WHERE (rt.DocEntry = i.DocEntry)
                                  AND (rt.INV <= i.INV)
                        )),
           conlai2 = p.Qty -
                     (
                         SELECT SUM(rt.Qty)
                         FROM #INV rt
                         WHERE (rt.DocEntry = i.DocEntry)
                               AND (rt.INV <= i.INV)
                     )
    FROM #temp p
        LEFT JOIN #INV i
            ON (p.DocEntry = i.DocEntry)
) a
ORDER BY a.DocEntry,
         a.INV;

Các bạn có thể copy đoạn script này về để test thử.

Có thể bạn quan tâm:

Xem thêm việc làm SQL Server trên TopDev

TopDev via Laptrinhvb