Home Blog Page 53

Mobile Developer là gì? Trở thành Mobile Developer từ con số 0

mobile developer là gì

Theo thống kê từ trang Statista, đầu năm 2023, số lượng người dùng smartphone trên thế giới hiện nay là 6.92 tỷ người, nghĩa là có đến 86.34% dân số thế giới sở hữu smartphone. Thị trường phát triển ứng dụng smartphone ngày càng có nhu cầu lớn hơn, cũng chính vì thế mà lập trình viên ứng dụng di động – Mobile Developer trở thành 1 ngành nghề hot với nhu cầu tuyển dụng rất lớn. Bài viết hôm nay chúng ta cùng tìm hiểu về ngành này cũng như lộ trình để trở thành lập trình viên ứng dụng di động nhé.

Mobile Developer là gì?

Mobile Developer là những lập trình viên phát triển những ứng dụng dành cho các thiết bị di động, phổ biến hiện nay là các ứng dụng trên smartphone với 2 hệ điều hành chính là Android và iOS. Các hệ điều hành chạy trên thiết bị smartphone đều được trang bị các công cụ (SDK, IDE) và ngôn ngữ giúp các nhà phát triển tạo ra ứng dụng của mình, với Android sử dụng Java hay Kotlin; iOS sử dụng Objective-C hay Swift.

Ngoài ra có các thư viện hay framework và ngôn ngữ khác nhau giúp tạo ra ứng dụng đa nền tảng (có thể chạy trên nhiều hệ điều hành) như React Native viết bằng JavaScript, Flutter viết bằng Dart,… Nhiệm vụ của lập trình viên di động là nắm vững các kiến thức về lập trình, trang bị cho mình 1 hoặc nhiều trong số các ngôn ngữ, thư viện hay framework kể trên để có thể tạo ra những ứng dụng theo yêu cầu.

Mobile Developer là gì?

Mô tả về công việc cụ thể của 1 lập trình viên di động như sau:

  • Tham gia thiết kế xây dựng phần mềm dựa vào ý tưởng, nhu cầu của người dùng và những kinh nghiệm phát triển ứng dụng di động đã có
  • Viết code lập trình xây dựng giao diện và tính năng cho ứng dụng theo như khách hàng yêu cầu
  • Tham gia chạy, kiểm thử ứng dụng trên các thiết bị, phần mềm giả lập
  • Sửa chữa và nâng cấp các lỗi xuất hiện trong quá trình sử dụng ứng dụng
  • Publish (phát hành) ứng dụng lên các nền tảng chợ (market) như Google Play với Android hay AppStore với iOS
  • Nghiên cứu các công nghệ mới, cập nhật các bản phát hành của hệ điều hành, công cụ phát triển (SDK, IDE) tương ứng để áp dụng vào công việc, hỗ trợ cập nhật phần mềm khi có phiên bản hệ điều hành mới

  Lập trình di động và những điều cần chú ý!

Đặc thù ngành lập trình di động

Khác với lập trình Web hay Desktop, có 1 số đặc thù mà chỉ riêng ngành lập trình di động mới có và nó tác động khá lớn đến dự định trở thành 1 mobile developer của bạn:

  • Làm việc với nhiều thiết bị phần cứng khác nhau: hiện nay có vô số các thiết bị smartphone với đủ kích thước màn hình, cấu hình phần cứng khác nhau. Ứng dụng của bạn sẽ phải đối ứng với đủ các kiểu màn hình như tai thỏ, giọt nước, đục lỗ, … khiến cho ứng dụng của bạn có thể gặp nhiều vấn đề mà trên PC sẽ không bao giờ gặp phải.
  • Tương tác trực tiếp với các thiết bị cảm biến phần cứng: nếu như trên PC hay các ứng dụng Web, việc truy cập và làm việc với các thiết bị ngoại vi như camera, mic, loa mặc dù không quá thường xuyên nhưng có thể khiến bạn đau đầu; thì với smartphone hiện nay, có hàng chục các loại cảm biến khác nhau từ định vị, cảm biến con quay hồi chuyển, cảm biến gia tốc, vân tay, faceid, cảm biến tiệm cận, … với đủ các thứ quyền mà bạn cần xin phép mới có thể sử dụng.
  • Phát hành ứng dụng lên các chợ: ứng dụng của bạn nếu muốn đến tay người dùng thì không chỉ cần 1 địa chỉ website như ứng dụng Web, cũng không chỉ cần 1 bản cài đặt như ứng dụng trên Desktop; bạn cần phải phát hành chúng trên các chợ như Google Play, Appstore để người dùng tìm kiếm và có thể download về cài đặt. Việc tuân thủ tất cả các chính sách có thể khiến bạn phải đau đầu, chưa kể sự cập nhật thường xuyên về hệ điều hành cũng khiến ứng dụng của bạn cần update để đáp ứng.

Tham khảo việc làm Android Developer hấp dẫn trên TopDev

Lộ trình trở thành Mobile Developer

Với việc đặc thù là tạo ra ứng dụng chạy trên nhiều nền tảng hệ điều hành di động khác nhau, vì thế có 2 định hướng khá rõ trong lộ trình trở thành 1 lập trình viên di động.

Lộ trình trở thành Mobile Developer

Hướng thứ nhất là tập trung làm mobile trên 1 nền tảng duy nhất (single platfom):

  • iOS: sử dụng ngôn ngữ Swift, Objective-C trên IDE Xcode sử dụng iOS SDK do Apple cung cấp để viết các ứng dụng dành riêng cho nền tảng iOS, chạy trên các thiết bị iPhone, iPad, Mac, …
  • Android: sử dụng ngôn ngữ Java, Kotlin trên IDE Android Studio sử dụng Android SDK do Google cung cấp để tạo ra các ứng dụng dành riêng cho nền tảng Android, chạy trên các thiết bị di động sử dụng hệ điều hành Android

  Mình đã học kotlin như thế nào?: Phần 1: từ 1 dev IOS nhảy sang dev android

Đối với hướng này, các lập trình viên sẽ tìm hiểu sâu vào từng ngôn ngữ, từng thư viện được cung cấp sẵn trong SDK, tương tác sâu và trực tiếp với các thiết bị phần cứng.

Đặc thù của ứng dụng bạn viết ra là sẽ chỉ chạy được trên nền tảng duy nhất, bạn không thể lấy source code ứng dụng Android để tạo ra ứng dụng tương ứng cho iOS. Nhưng cũng chính đó là ưu điểm của hướng phát triển này khi bạn có thể tối ưu hóa 1 cách tốt nhất cho ứng dụng của mình.

Hướng thứ 2 là việc phát triển các ứng dụng đa nền tảng (cross platform), được hiểu là có thể tạo ra ứng dụng chạy được trên nhiều nền tảng hệ điều hành khác nhau. 2 loại kỹ thuật phát triển ứng dụng đa nền tảng là Hybrid và Native:

  • Hybrid: các ứng dụng hybrid chủ yếu được viết trên nền tảng Web sử dụng HTML, CSSJS. Bằng việc bao bọc ứng dụng bằng 1 trình duyệt để nó có thể chạy trên nền tảng di động, ứng dụng hybrid tạo ra 1 giao diện duy nhất cho nhiều nền tảng hệ điều hành khác nhau. Có thể kể đến 1 vài framework hay thư viện giúp xây dựng ứng dụng Hybrid như Cordova, Ionic, jQuery Mobile, HTML5, …
  • Native: khác với Hybrid khi chỉ tạo ra 1 ứng dụng duy nhất, các ứng dụng Native cho phép bạn viết 1 source code duy nhất và tạo ra các ứng dụng dành riêng cho từng hệ điều hành khác nhau bằng các công cụ biên dịch. Lựa chọn này giúp ứng dụng của bạn có thể tối ưu tốt hơn khi tương tác với phần cứng cụ thể của từng hệ điều hành cũng như tối ưu hóa hiệu năng. Có thể kể đến các framework như React Native, Flutter, Xamarin.

Ưu điểm của hướng thứ 2 chính là việc tiết kiệm thời gian, nguồn lực và kinh phí phát triển ứng dụng so với hướng thứ 1. Tuy vậy thì nhược điểm của nó là khả năng tạo ra các ứng dụng với trải nghiệm tốt nhất về giao diện cũng như hiệu năng dành cho người dùng.

Mobile Developer cần xác định trước lộ trình mình mong muốn trở thành ngay từ đầu để có thể lựa chọn học đúng, học đủ và học sâu những kiến thức theo lộ trình. Sau khi thành thạo 1 trong 2 hướng thì có thể chuyển qua học hướng còn lại để nâng cao khả năng lập trình của mình.

Kết bài

Như vậy qua bài viết này, mình đã cùng các bạn tìm hiểu về ngành lập trình ứng dụng di động – Mobile Developer cũng như lộ trình, các kiến thức cần thiết nếu bạn có dự định dấn thân vào ngành này. Đây là 1 ngành nghề hay và thú vị, cùng với nhu cầu lớn của thị trường sẽ là 1 lựa chọn tiềm năng dành cho bạn. Cảm ơn các bạn đã đọc và theo dõi, hẹn gặp lại trong các bài viết tiếp theo của mình.

Tác giả: Phạm Minh Khoa

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

Xem thêm các việc làm nhân viên cntt hấp dẫn tại TopDev

Những tính năng cao cấp trong Laravel mà có thể bạn chưa biết

Những tính năng cao cấp trong Laravel mà có thể bạn chưa biết

Bài viết được sự cho phép của tác giả Phạm Bình

Chào các bạn,

Laravel tuy một PHP framework mạnh mẽ khi cung cấp rất nhiều tính năng hay ho cho developer. Nhưng thực tế, nhiều bạn developer mới chỉ sử dụng Laravel như một framework MVC đơn thuần mà không biết rằng ngoài cái đó ra, Laravel còn có nhiều tính năng cao cấp khác.

Vì vậy, trong bài viết này mình sẽ chỉ ra một số tính năng hữu ích khác của Laravel (bên cạnh một MVC framework thuần túy). Hy vọng các bạn sẽ có thêm kiến thức để giải quyết các vấn đề trong dự án tốt hơn.

I. Queue

Queue – Hàng đợi trong Laravel là giải pháp để xử lý các request tốn nhiều thời gian thực thi, trong khi bạn lại không muốn user phải đợi quá lâu mới có response.

Để hiểu rõ hơn, chúng ta sẽ cùng làm một tính năng theo 2 cách, cách 1 không sử dụng queue, cách 2 sử dụng queue để xem sự khác nhau như thế nào nhé:

Xét bài toán như sau:

Xây dựng tính năng đăng ký tài khoản, sau khi đăng ký thành công, sẽ gửi tới email của user một thông báo “Chào mừng bạn đến với website … “, đồng thời hiện một thông báo lên màn hình là “Bạn đã đăng ký thành công“.

  Cách sử dụng Laravel với Socket.IO

  Tại sao nên sử dụng Laravel?

Cách 1: Thực hiện mà KHÔNG dùng queue.

Thực hiện mà không sử dụng queue, thì các bước sẽ diễn ra tuần tự như sau:

  • Bước 1: User nhập thông tin đăng ký và nhấn nút “Đăng ký”.
  • Bước 2: Thông tin đăng ký gửi tới Controller để xử lý, thông tin user được lưu vào trong database.
  • Bước 3: Thực hiện gửi mail, và đợi đến khi mail được gửi thành công.
  • Bước 4: In ra màn hình thông báo “Bạn đã đăng ký thành công”.

Cách 2: Thực hiện mà CÓ sử dụng queue.

Các bước sẽ diễn ra như sau:

  • Bước 1: User nhập thông tin đăng ký và nhấn nút “Đăng ký”. (Giống cách 1)
  • Bước 2: Thông tin đăng ký gửi tới Controller để xử lý, thông tin user được lưu vào trong database. (Giống cách 1)
  • Bước 3: Tạo ra một “job gửi email” và đưa vào queue, job này sẽ được chạy sau.
  • Bước 4: In ra màn hình thông báo “Bạn đã đăng ký thành công”. (Giống cách 1)

Tham khảo nhiều chương trình tuyển dụng Laravel hấp dẫn trên TopDev

Nhận xét:

  • Cả hai cách chỉ khác nhau ở bước 3.
  • Cách 1 yêu cầu user phải đợi cho đến khi email được gửi thành công thì mới thực hiện bước 4.
  • Cách 2 thì tạo ra một “job gửi email” và được đưa vào trong queue, job này sẽ chạy sau, nên user không cần phải đợi mà có thể chuyển sang bước 4 ngay.
  • Vì cách 2 không yêu cầu phải đợi, nên cách 2 user sẽ sớm nhận được thông báo “Bạn đã đăng ký thành công“, làm user có trải nghiệm tốt hơn.
  • Job đưa vào trong queue đúng là chạy sau, nhưng nó gần như chạy sau khi user nhận được thông báo “Bạn đã đăng ký thành công hơn“, nên user sẽ vẫn nhận được email ngay sau khi đăng ký.

Mình có một bài viết chi tiết hơn về Queue trong Laravel, bạn có thể tham khảo để hiểu rõ hơn, hoặc đọc tài liệu chính thức của Laravel về queue.

II. Task Scheduling

Laravel là PHP framework, mà ứng dụng PHP sẽ chỉ hoạt động khi có request (tức có user truy cập). Nhưng trong thực tế đôi khi sẽ có những yêu cầu mà ứng dụng PHP phải tự nó chạy mà không cần request nào được gửi đến.

Như việc backup dữ liệu vào 12h đêm mỗi ngày chẳng hạn, không lẽ bạn cứ phải căn đúng 12h đêm để vào website, nhấn nút “backup” sao. Thật ra nếu muốn thì bạn cũng có thể làm như vậy, nhưng có cách khác tiện hơn nhiều, đó chính là Task scheduling.

Task scheduling là tính năng cho phép bạn lập lịch chạy một tác vụ nào đó.

Quay trở lại ví dụ backup database ở trên, mình sẽ tạo ra một task mà cứ đúng 12h đêm nó sẽ tự động được chạy, để rồi sáng hôm sau mình sẽ chỉ việc download file database đã được backup về máy, mà không cần phải thức đêm để nhấn nút “backup”.

Cách sử dụng Laravel task scheduling

Laravel task scheduling hoạt động dựa trên crontab, vì thể để sử dụng được tính năng này bạn cần phải cấu hình một cronjob như sau:

Crontab là chương trình lập lịch chạy trên Linux, mỗi một tác vụ được lập lịch chạy được gọi là một cronjob.

Chỉnh sửa crontab:

crontab -e

Thêm vào một cronjob như sau:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Cronjob trên có ý nghĩa là “Cứ mỗi phút thì thực hiện lệnh cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1 một lần”. Bạn có thể tìm hiểu thêm về cú pháp của Crontab tại đây.

Sau khi cấu hình crontab, giờ bạn có thể cấu hình task scheduling trong file app/Console/Kernel.php.

// app/Console/Kernel.php // ... protected function schedule(Schedule $schedule) {     $schedule         ->call(function () {             // Task làm gì sẽ được định nghĩa ở đây         })         // daily() nghĩa là task này sẽ được chạy mỗi ngày ngày.         // ngoài daily() thì còn nhiều phương thức khác nữa         // chi tiết tìm hiểu trên docs của Laravel bạn nhé         ->daily(); }

Về cách khai báo task, cũng như lập lịch task (mỗi ngày, mỗi tuần, chạy lúc mấy giờ,…) thì tài liệu Laravel đã viết rất rõ, nên mình lười không muốn viết lại nữa, bạn có thể đọc thêm ở đây.

III. Compiling Assets

Là một PHP framework, nhưng Laravel cũng chú trọng cả frontend, điều này được thể hiện qua tính năng “Compiling assets” (Biên dịch các file assets như scss, js). Ở phiên bản hiện tại (Laravel 8), Laravel thực hiện compiling assets thông qua gói Laravel Mix.

Nếu bạn đã từng sử dụng các tool build frontend như webpackgulp thì Laravel Mix cũng là cái gì đó tương tự như vậy.

Frontend của các dự án web ngày càng phức tạp, trong khi đó kiểu lập trình web truyền thống thì chưa tập trung nhiều vào tối ưu frontend. Ví dụ, để viết CSS cho website, chúng ta thường tạo một file style.css và nhúng nó vào phần head của trang web. Nhưng khi các trang web ngày càng trở nên phức tạp (ngày càng nhiều trang, ngày càng nhiều css) thì cách làm này dần phát sinh nhiều nhược điểm:

  • File style.css quá nặng.
  • Không tối ưu css: do toàn bộ css đều được viết trong một file, và không phải trang nào cũng sử dụng hết các class được khai báo trong đó, thậm chí có những đoạn css đã không còn dùng tới.
  • Khó quản lý các class: các class mới thì ngày càng được bổ sung, và có thể bị trùng lặp, hoặc xung đột với các class trước đó.

Đứng trước các nhược điểm trên, người ta đã tạo ra các công cụ giúp để tối code frontend, giúp việc code và quản lý các file css, js trở nên đơn giản hơn gấp bội phần. Webpack hiện đang là công cụ được sử dụng nhiều nhất, và Laravel Mix thì được xây dựng dựa trên Webpack.

Về cơ bản Laravel Mix sẽ giúp bạn viết css bằng các css preprocessor, đóng gói (bundle) các file js và minify chúng.

Laravel Mix đã được tích hợp mặc định trong source code Laravel, để sử dụng Laravel Mix, bạn chỉ cần chạy lệnh npm install để cài đặt.

Chi tiết về cách sử dụng Laravel Mix, bạn có thể đọc tại tài liệu chính thức của Laravel.

IV. Tạm kết

Điểm danh trước 3 tính năng “Premium” trong Laravel mà chưa hẳn ai cũng biết, các tính năng còn lại mình sẽ tổng hợp và chia sẻ với các bạn qua Phần 2, Phần 3, … Phần N nhé.

Chúc các bạn học tập hiệu quả. Hẹn gặp lại.

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

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

Tham khảo thêm các vị trí tuyển dụng ngành IT tại Topdev

Hướng dẫn Java Design Pattern – Proxy

Hướng dẫn Java Design Pattern – Proxy

Bài viết được sự cho phép của tác giả Giang Phan

Khi cần điều khiển truy nhập tới một đối tượng được thực hiện từ quá trình khởi tạo nó cho tới khi thực sự cần sử dụng nó. Hoặc cần bảo vệ quyền truy xuất vào các phương thức của object thực. Trong trường hợp như vậy, ta nên dùng mẫu thiết kế Proxy.

Proxy Pattern là gì?

Provide a surrogate or placeholder for another object to control access to it.

Proxy Pattern là một trong những Pattern thuộc nhóm cấu trúc (Structural Pattern).

Proxy có nghĩa là “ủy quyền” hay “đại diện”. Mục đích xây dựng Proxy pattern cũng chính vì muốn tạo ra một đối tượng sẽ ủy quyền, thay thế cho một đối tượng khác.

Proxy Pattern là mẫu thiết kế mà ở đó tất cả các truy cập trực tiếp đến một đối tượng nào đó sẽ được chuyển hướng vào một đối tượng trung gian (Proxy Class). Mẫu Proxy (người đại diện) đại diện cho một đối tượng khác thực thi các phương thức, phương thức đó có thể được định nghĩa lại cho phù hợp với múc đích sử dụng.

Để đơn giản hơn bạn có thể nghĩ đến khái niệm HTTP proxy trong mạng máy tính, nó là một gateway giữa trình duyệt (client) và máy chủ (server). HTTP proxy giúp nâng cao trải nghiệm người dùng, tăng tốc với lưu đệm các dữ liệu, loại bỏ các trang quảng cáo, giới hạn các vùng thông tin được xem… Proxy Pattern cũng có chung một mục đích như với HTTP proxy.

Proxy Pattern còn được gọi là Surrogate (thay thế) hoặc Placeholder (trình giữ chỗ).

  Hệ thống 23 mẫu Design Patterns

  Design pattern là gì? Tại sao nên sử dụng Design pattern?

Phân loại Proxy

  • Virtual Proxy : Virtual Proxy tạo ra một đối tượng trung gian mỗi khi có yêu cầu tại thời điểm thực thi ứng dụng, nhờ đó làm tăng hiệu suất của ứng dụng.
  • Protection Proxy : Phạm vi truy cập của các client khác nhau sẽ khác nhau. Protection proxy sẽ kiểm tra các quyền truy cập của client khi có một dịch vụ được yêu cầu.
  • Remote Proxy : Client truy cập qua Remote Proxy để chiếu tới một đối tượng được bảo về nằm bên ngoài ứng dụng (trên cùng máy hoặc máy khác).
  • Monitor Proxy : Monitor Proxy sẽ thiết lập các bảo mật trên đối tượng cần bảo vệ, ngăn không cho client truy cập một số trường quan trọng của đối tượng. Có thể theo dõi, giám sát, ghi log việc truy cập, sử dụng đối tượng.
  • Firewall Proxy : bảo vệ đối tượng từ chối các yêu cầu xuất xứ từ các client không tín nhiệm.
  • Cache Proxy : Cung cấp không gian lưu trữ tạm thời cho các kết quả trả về từ đối tượng nào đó, kết quả này sẽ được tái sử dụng cho các client chia sẻ chung một yêu cầu gửi đến. Loại Proxy này hoạt động tương tự như Flyweight Pattern.
  • Smart Reference Proxy : Là nơi kiểm soát các hoạt động bổ sung mỗi khi đối tượng được tham chiếu.
  • Synchronization Proxy : Đảm bảo nhiều client có thể truy cập vào cùng một đối tượng mà không gây ra xung đột. Khi một client nào đó chiếm dụng khóa khá lâu khiến cho số lượng các client trong danh sách hàng đợi cứ tăng lên, và do đó hoạt động của hệ thống bị ngừng trệ, có thể dẫn đến hiện tượng “tắc nghẽn”.
  • Copy-On-Write Proxy : Loại này đảm bảo rằng sẽ không có client nào phải chờ vô thời hạn. Copy-On-Write Proxy là một thiết kế rất phức tạp.

Tìm kiếm việc làm FrontEnd Hồ Chí Minh mới nhất tại TopDev!

Cài đặt Proxy Pattern như thế nào?

Proxy Pattern có những đặc điểm chung sau đây:

  • Cung cấp mức truy cập gián tiếp vào một đối tượng.
  • Tham chiếu vào đối tượng đích và chuyển tiếp các yêu cầu đến đối tượng đó.
  • Cả Proxy và đối tượng đích đều kế thừa hoặc thực thi chung một lớp giao diện. Mã máy dịch cho lớp giao diện thường “nhẹ” hơn các lớp cụ thể và do đó có thể giảm được thời gian tải dữ liệu giữa server và client.design patterns proxy diagram

Các thành phần tham gia vào mẫu Proxy Pattern:

  • Subject : là một interface định nghĩa các phương thực để giao tiếp với client. Đối tượng này xác định giao diện chung cho RealSubject và Proxy để Proxy có thể được sử dụng bất cứ nơi nào mà RealSubject mong đợi.
  • Proxy : là một class sẽ thực hiện các bước kiểm tra và gọi tới đối tượng của class service thật để thực hiện các thao tác sau khi kiểm tra. Nó duy trì một tham chiếu đến RealSubject để Proxy có thể truy cập nó. Nó cũng thực hiện các giao diện tương tự như RealSubject để Proxy có thể được sử dụng thay cho RealSubject. Proxy cũng điều khiển truy cập vào RealSubject và có thể tạo hoặc xóa đối tượng này.
  • RealSubject : là một class service sẽ thực hiện các thao tác thực sự. Đây là đối tượng chính mà proxy đại diện.
  • Client : Đối tượng cần sử dụng RealSubject nhưng thông qua Proxy.

Ứng tuyển các vị trí việc làm Java lương cao trên TopDev

Ví dụ Virtual Proxy

Trì hoãn việc tạo ra real subject bên trong proxy class. Chỉ đến khi cần, proxy class mới thật sự khởi tạo real class. Loại Proxy này làm việc theo cơ chế Lazy Loading.

Lazy Loading là một khái niệm mà ứng dụng trì hoãn việc tải các đối tượng cho đến thời điểm mà người dùng cần nó. Nói một cách đơn giản là tải theo yêu cầu của người dùng chứ không phải tải đối tượng không cần thiết. Lợi ích của việc này là giảm thiểu số lượng yêu cầu, giảm thiểu số lượng tài nguyên thừa cần tải cho tới khi người dùng cần đến chúng thực sự. Chúng ta đã thấy điều này qua cơ chế Lazy load của Hibernate.

Nó giải quyết vấn đề rất lớn về hiệu suất, lý do là vì proxy class có chi phí khởi tạo rất ít, việc duy trì nó không mất nhiều tài nguyên hệ thống. Trong khi đó Real class thường rất tốn chi phí , vì thế với virtual proxies, chỉ khi nào cần thiết, real class mới được khởi tạo.

Ví dụ một website hiển thị ảnh, có thể có rất nhều ảnh trên một trang hay một ảnh được hiển thị nhiều lần. Trường hợp này chúng ta chỉ cần load ảnh khi nó cần hiển thị (khi ta scroll tới nơi đặt image) hoặc là nó chưa được load (không như các website truyền thống là load hình ngay khi load website, nó rất tốn tài nguyên và đôi khi không cần thiết do người dùng không scroll tới nơi đặt image, có thể load 1 ảnh nhiều lần).

design-patterns-proxy-example1

Image.java

package com.gpcoder.patterns.structural.proxy.virtual;

public interface Image {

    void showImage();

}

RealImage.java

package com.gpcoder.patterns.structural.proxy.virtual;

public class RealImage implements Image {
    private String url;

    public RealImage(String url) {
        this.url = url;
        System.out.println("Image loaded: " + this.url);
    }

    @Override
    public void showImage() {
        System.out.println("Image showed: " + this.url);
    }
}

ProxyImage.java

package com.gpcoder.patterns.structural.proxy.virtual;

public class ProxyImage implements Image {
    private Image realImage;
    private String url;

    public ProxyImage(String url) {
        this.url = url;
        System.out.println("Image unloaded: " + this.url);
    }

    @Override
    public void showImage() {
        if (realImage == null) {
            realImage = new RealImage(this.url);
        } else {
            System.out.println("Image already existed: " + this.url);
        }
        realImage.showImage();
    }
}

Client.java

package com.gpcoder.patterns.structural.proxy.virtual;

public class Client {
    public static void main(String[] args) {
        System.out.println("Init proxy image: ");
        ProxyImage proxyImage = new ProxyImage("http://gpcoder.com/favicon.ico");

        System.out.println("---");
        System.out.println("Call real service 1st: ");
        proxyImage.showImage();

        System.out.println("---");
        System.out.println("Call real service 2nd: ");
        proxyImage.showImage();
    }
}

Output của chương trình:

Init proxy image: 
Image unloaded: http://gpcoder.com/favicon.ico
---
Call real service 1st: 
Image loaded: http://gpcoder.com/favicon.ico
Image showed: http://gpcoder.com/favicon.ico
---
Call real service 2nd: 
Image already existed: http://gpcoder.com/favicon.ico
Image showed: http://gpcoder.com/favicon.ico

Như bạn thấy image chỉ thật sử được load lên khi proxy class gọi hàm.

Ví dụ Protection proxy

Yêu cầu người gọi proxy class phải chứng thực trước khi proxy class truy xuất vào real class. Cái này rất hữu dụng khi bạn bạn viết library cho một bên khác sử dụng và yêu cầu họ xác thực trước khi gọi hàm.

design-patterns-proxy-example2

UserService.java

package com.gpcoder.patterns.structural.proxy.protection;

public interface UserService {

    void load();

    void insert();
}

UserServiceImpl.java

package com.gpcoder.patterns.structural.proxy.protection;

public class UserServiceImpl implements UserService {

    private String name;

    public UserServiceImpl(String name) {
        this.name = name;
    }

    @Override
    public void load() {
        System.out.println(name + " loaded");
    }

    @Override
    public void insert() {
        System.out.println(name + " inserted");
    }

}

UserServiceProxy.java

package com.gpcoder.patterns.structural.proxy.protection;

public class UserServiceProxy implements UserService {

    private String role;
    private UserService userService;

    public UserServiceProxy(String name, String role) {
        this.role = role;
        userService = new UserServiceImpl(name);
    }

    @Override
    public void load() {
        userService.load();
    }

    @Override
    public void insert() {
        if (isAdmin()) {
            userService.insert();
        } else {
            throw new IllegalAccessError("Access denied");
        }
    }

    private boolean isAdmin() {
        return "admin".equalsIgnoreCase(this.role);
    }
}

Client.java

package com.gpcoder.patterns.structural.proxy.protection;

public class Client {
    public static void main(String[] args) {
        UserService admin = new UserServiceProxy("gpcoder", "admin");
        admin.load();
        admin.insert();

        UserService customer = new UserServiceProxy("customer", "guest");
        customer.load();
        customer.insert();
    }
}

Output của chương trình:

gpcoder loaded
gpcoder inserted
customer loaded
Exception in thread "main"
java.lang.IllegalAccessError: Access denied
    at com.gpcoder.patterns.structural.proxy.rotection.UserServiceProxy.insert(UserServiceProxy.java:23)
    at com.gpcoder.patterns.structural.proxy.rotection.Client.main(Client.java:11)

Các bạn thấy khi Client muốn gọi hàm insert(), trong Proxy luôn xác thực quyền của user trước khi thực hiện nó.

Ví dụ Remote Proxy

Với Remote Proxy, proxy class và real class nằm ở 2 địa chỉ khác nhau. Thông qua network, proxy class sẽ encode và gửi request tới real class để khởi tạo, truy xuất, …

Chúng ta có thể thấy remote Proxy khi implements Java RMI hoặc thông dụng nhất là ở WebService. Bên phía client sẽ có 1 proxy class, client sẽ khởi tạo proxy class và gọi tới real class nằm ở 1 địa chỉ khác.

Ví dụ Smart Proxy

Proxy Class sẽ thay đổi hoặc thêm 1 số thao tác trước khi gọi tới real class. Một số trường hợp thường thấy là:

  • Ở lần đâu tiên khởi tạo real class, Proxy class sẽ lưu lại thông tin của real class vào cache và hữu dụng cho lần tái sử dụng sau. Ta có thể thấy việc xuất hiện ở lazy-load ở các connection xuống database.
  • Trước khi gọi real class, ta có thể lock real class lại và không cho các thread khác phải chờ cho tới khi thread hiện tại release real class.
  • Đếm số lượng reference tới real class.

Ở Virtual Proxy, mình cũng có lồng 1 ví dụ của Smart Proxy vào. Khi ta khởi tạo RealImage, mình đã lưu cache RealImage lại và lần sau gọi hàm ShowImage(), ta không phải khởi tạo lại RealImage.

Lợi ích của Proxy Pattern là gì?

  • Cãi thiện Performance thông qua lazy loading, chỉ tải các tài nguyên khi chúng được yêu cầu.
  • Nó cung cấp sự bảo vệ cho đối tượng thực từ thế giới bên ngoài.
  • Giảm chi phí khi có nhiều truy cập vào đối tượng có chi phí khởi tạo ban đầu lớn.
  • Dễ nâng cấp, bảo trì.

Sử dụng Proxy Pattern khi nào?

  • Khi muốn bảo vệ quyền truy xuất vào các phương thức của object thực.
  • Khi cần một số thao tác bổ sung trước khi thực hiện phương thức của object thực.
  • Khi tạo đối tượng ban đầu là theo yêu cầu hoặc hệ thống yêu cầu sự chậm trễ khi tải một số tài nguyên nhất định (lazy loading).
  • Khi có nhiều truy cập vào đối tượng có chi phí khởi tạo ban đầu lớn.
  • Khi đối tượng gốc tồn tại trong môi trường từ xa (remote).
  • Khi đối tượng gốc nằm trong một hệ thống cũ hoặc thư viện của bên thứ ba.
  • Khi muốn theo dõi trạng thái và vòng đời đối tượng.

So sánh Proxy Pattern với Decorator Pattern

Cấu trúc của Proxy Pattern và Decorator Pattern là tương tự nhau (bạn có thể coi ở class diagram). Hai Pattern này đều Wrap một đối tượng thực bên trong nó. Tuy nhiên, khác nhau thật sự giữa Proxy Pattern và Decorator Pattern nằm ở mục đích sử dụng. Với Decorator Pattern, người sử dụng sẽ nhắm tới mục tiêu là có thể thêm tính năng động vào một đối tượng có trước, trong khi đó Proxy Pattern cho phép ta tạo ra một đại diện cho một đối tượng khác.

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

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

Xem thêm Việc làm IT hấp dẫn trên TopDev

Các lưu ý về strategy của GeneratedValue khi sử dụng hibernate

Các lưu ý về strategy của GeneratedValue khi sử dụng hibernate

Bài viết được sự cho phép của tác giả Trần Văn Dem

Hiện nay việc tìm kiếm các hướng dẫn về sử dụng hibernate, spring jpa là rất dễ. Tuy nhiên các hướng dẫn này thường chỉ giới thiệu cách sử dụng, quản lý Id của Entity thông qua strategy : AUTO,TABLE,SEQUENCE,IDENTITY. Nhưng rất ít hoặc rất khó tìm bài hướng dẫn nào nói cụ thể về các kiểu strategy này và cách sử dụng hiệu trong dự án. Bài viết này tôi sẽ giúp các bạn hiểu rõ hơn về các loại strategy này từ đó có thể tự tin lựa chọn trong project tránh các lỗi không đáng có.

Trước khi tìm hiểu về các loại strategy thì chúng ta nên phân biệt các loại dữ liệu này. Trước tiên thì 2 loại này sẽ là cách cơ sở dữ liệu của bạn dùng để tạo id cho bảng lưu trữ dữ liệu.

Cách sử dụng auto_increment

create table user
(
    id   int auto_increment
        primary key,
    name varchar(255) null,
    age  int          null
);


insert into user (age, name) values (104, 'mai4')
insert into user (age, name values (103, 'mai3')

SELECT * FROM user;

+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | mai4 |  104 |
|  2 | mai3 |  103 |
+----+------+------+
2 rows in set (0,00 sec)

Kiểu dữ liệu này chắc hầu hết mọi người đều đã biết và sử dụng thường xuyên kiểu này. Các loại database sau hỗ trợ: mysqlmariadb,…

  Cấu hình Spring Data JPA với @EnableJpaRepositories annotation

  Các Annotation của Hibernate

Cách sử dụng sequence với mariadb. Chi tiết về sequece của mariadb mọi người tham khảo tại link

CREATE SEQUENCE serial START WITH 1 INCREMENT BY 10;
insert into user (age, name,id) values (104, 'mai4',nextval(serial));
insert into user (age, name,id) values (103, 'mai3',nextval(serial));

SELECT * FROM user;

+----+------+------+
| id | name | age  |
+----+------+------+
|  1 | mai4 |  104 |
| 11 | mai3 |  103 |
+----+------+------+
2 rows in set (0,00 sec)

Các loại database sau hỗ trợ : postgresqlmariadb,oracle,… Nhìn sơ qua thì khi sử dụng sequence câu lệnh insert sẽ dài và khó nhớ hơn.

Tham khảo việc làm JavaScript hấp dẫn trên TopDev

Tạo 1 entity đơn giản như bên dưới lưu ý allocationSize phải đúng với giá trị INCREMENT BY khi tạo sequence. Loại strategy này sẽ hỗ trợ việc batch insert. Ví dụ bên dưới thực hiện với mariadb.

import lombok.Data;

import javax.persistence.*;

@Entity
@Table(name = "user")
@Data
public class User {
    @Id
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "serial"
    )
    @SequenceGenerator(
            name = "serial",
            sequenceName = "serial",
            allocationSize = 10
    )
    private int id;

    private String name;

    private int age;

}

Tạo 1 router để save vào database sau:

    @PutMapping("/multi/user")
    String insertUser() {
        List<User> savedUser = new ArrayList<>();

        for (int i =0 ; i < 5 ; i ++){
            User user = new User();
            int index = count.addAndGet(1);
            user.setName("demtv" + index);
            user.setAge(index);
            savedUser.add(user);
        }
        repository.saveAll(savedUser);
        return "done";
    }

Chỉnh sửa config của spring boot để kết nối với mariadb.

spring:
  application:
    name: user-service
    url: jdbc:mariadb://127.0.0.1:3307/blog?characterEncoding=utf8
    driver-class-name: org.mariadb.jdbc.Driver
    username: root
    password: demtv
  jpa:
    properties:
      hibernate:
        jdbc:
             batch_size : 5
        order_inserts : true

    show-sql : true

Để sử dụng được mariadb chúng ta nên sử dụng mariadb client sau.

        <!-- https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client -->
        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
            <version>2.7.3</version>
        </dependency>

Chúng ta cần ghi đè lại phương thức log của hibernate để biết được có sử dụng batch process hay không? Tham khảo tại link

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;


import javax.sql.DataSource;
import java.lang.reflect.Method;

@Component
public class DatasourceProxyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
        if (bean instanceof DataSource) {
            ProxyFactory factory = new ProxyFactory(bean);
            factory.setProxyTargetClass(true);
            factory.addAdvice(new ProxyDataSourceInterceptor((DataSource) bean));
            return factory.getProxy();
        }

        return bean;
    }

    private static class ProxyDataSourceInterceptor implements MethodInterceptor {

        private final DataSource dataSource;

        public ProxyDataSourceInterceptor(final DataSource dataSource) {
            this.dataSource = ProxyDataSourceBuilder.create(dataSource).name("Batch-Insert-Logger").asJson().countQuery().logQueryToSysOut().build();
        }

        @Override
        public Object invoke(final MethodInvocation invocation) throws Throwable {
            Method proxyMethod = ReflectionUtils.findMethod(dataSource.getClass(), invocation.getMethod().getName());
            if (proxyMethod != null) {
                return proxyMethod.invoke(dataSource, invocation.getArguments());
            }
            return invocation.proceed();
        }
    }
}

Thực hiện gọi đến route và chúng ta check log trên service ta được kết quả sau :

Hibernate: select nextval(serial)
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select nextval(serial)"], "params":[[]]}
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
{"name":"Batch-Insert-Logger", "time":2, "success":true, "type":"Prepared", "batch":true, "querySize":1, "batchSize":5, "query":["insert into user (age, name, id) values (?, ?, ?)"], "params":[["1","demtv1","12"],["2","demtv2","13"],["3","demtv3","14"],["4","demtv4","15"],["5","demtv5","16"]]}

Check log của mariadb ta được kết quả:

SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';
select * from mysql.general_log a  order by event_time desc;

+----------------------------+----------------------------+-----------+-----------+--------------+----------------------------------------------------------------------------------------------------------------+
| event_time                 | user_host                  | thread_id | server_id | command_type | argument                                                                                                       |
+----------------------------+----------------------------+-----------+-----------+--------------+----------------------------------------------------------------------------------------------------------------+
| 2021-07-18 08:52:07.774988 | root[root] @  [172.17.0.1] |        49 |         1 | Query        | SHOW WARNINGS                                                                                                  |
| 2021-07-18 08:52:07.773198 | root[root] @  [172.17.0.1] |        49 |         1 | Query        | SELECT @@session.tx_isolation                                                                                  |
| 2021-07-18 08:51:56.061139 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | set autocommit=1                                                                                               |
| 2021-07-18 08:51:56.057017 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | COMMIT                                                                                                         |
| 2021-07-18 08:51:56.055347 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | insert into user (age, name, id) values (5, 'demtv5', 16)                                                      |
| 2021-07-18 08:51:56.055283 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | insert into user (age, name, id) values (4, 'demtv4', 15)                                                      |
| 2021-07-18 08:51:56.055213 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | insert into user (age, name, id) values (3, 'demtv3', 14)                                                      |
| 2021-07-18 08:51:56.055135 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | insert into user (age, name, id) values (2, 'demtv2', 13)                                                      |
| 2021-07-18 08:51:56.054717 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | insert into user (age, name, id) values (1, 'demtv1', 12)                                                      |
| 2021-07-18 08:51:56.031163 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | select nextval(serial)                                                                                         |
+----------------------------+----------------------------+-----------+-----------+--------------+----------------------------------------------------------------------------------------------------------------+

select * from user;

+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | mai4   |  104 |
| 11 | mai3   |  103 |
| 12 | demtv1 |    1 |
| 13 | demtv2 |    2 |
| 14 | demtv3 |    3 |
| 15 | demtv4 |    4 |
| 16 | demtv5 |    5 |
+----+--------+------+

Ta thấy các id được service tạo ra nó có thứ tự liên tiếp khác với những id được chúng ta tạo với 2 câu lệnh insert đầu tiên. Hình ảnh bên dưới mô tả cơ chế GenerationType.SEQUENCE của hibernate.

Pooled

Đầu tiên hibernate sẽ gọi vào database để lấy nextVal của sequece lưu lại nextVal này và tiếp tự generate id của entity từ nextVal – allocateSize-1 đến nextVal hoạt động tạo id này sẽ không cần truy cập vào database nên sẽ tối ưu về mặt tốc độ. Mặt khác vì kiểu sequence là kiểu đặc biệt nên 2 service cùng gọi để lấy nextVal tại 1 thời điểm thì kết quả trả về cho 2 service là khác nhau cho nên sẽ không có trường hợp bị trùng id giữa các service khác nhau sử dụng cùng một sequence để tạo id.

Chúng ta sẽ sử dụng loại strategy này với mysql, strategy này ứng với dạng auto_increment. Chỉnh sửa một chút về file config, Entity, thư viện.

Modify Entity

import lombok.Data;

import javax.persistence.*;

@Entity
@Table(name = "user")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)

    private int id;

    private String name;

    private int age;

}

Modify Config và thư viện kết nối

spring:
  application:
    name: user-service
  config:
    import : optional:configserver:http://localhost:8888/
  profiles:
    active: dev
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/blog?characterEncoding=utf8
    driver-class-name: com.mysql.jdbc.Driver
    username: demtv
    password: Anhdem96!@
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 5
        order_inserts : true

    show-sql : true

server:
  port: 8082
        <dependency> 
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>

Vì trong hibernate khi batch insert chúng ta bắt buộc phải truyền theo Id, nhưng dạng này lại dựa vào cơ chế auto_increment của database nên lúc insert chúng ta chưa biết được id của nó là gì khiến cho dạng này hibernate sẽ không hỗ trợ batch insert mặc dù chúng ta vẫn cấu hình batch insert cho nó. Thực hiện gọi đến route và ta được kết quả.

Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["1","demtv1"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["2","demtv2"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["3","demtv3"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["4","demtv4"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["5","demtv5"]]}

Check kết quả trong mysql ta được:

select * from user;
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | mai3   |  103 |
|  2 | demtv1 |    1 |
|  3 | demtv2 |    2 |
|  4 | demtv3 |    3 |
|  5 | demtv4 |    4 |
|  6 | demtv5 |    5 |
+----+--------+------+

Bằng các cách tạo id hiện nay, các service của chúng ta không cần phải trọc vào database vẫn có thể tạo ra các id khác nhau (Mình sẽ viết phương pháp này trong bài tiếp) . Ngay cả khi chúng ta thực hiện truyền id này vào trong entity sử dụng strategy GenerationType.IDENTITY hibernate cũng không thực hiện batch insert, thậm trí khi truyền Id chúng ta lại có một hiệu năng còn tệ hơn.


    @PutMapping("/multi/user")
    String insertMultiUser() {
        List<User> savedUser = new ArrayList<>();
        for (int i = 1; i < 6; i++) {
            User user = new User();
            user.setId(1000 * i);
            int index = count.addAndGet(1);
            user.setName("demtv" + index);
            user.setAge(index);
            savedUser.add(user);
        }
        repository.saveAll(savedUser);
        return "done";
    }

Thực hiện gọi route ta có kết quả

{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["1000"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["1","demtv1"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["2000"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["2","demtv2"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["3000"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["3","demtv3"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["4000"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["4","demtv4"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["5000"]]}
Hibernate: insert into user (age, name) values (?, ?)
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["insert into user (age, name) values (?, ?)"], "params":[["5","demtv5"]]}

Theo kết quả query của hibernate bên trên thì trước mỗi câu insert chúng ta đều phải có một câu select để kiểm tra id của chúng ta truyền vào đã tồn tại trong bảng hay chưa? Rồi mới đến bước insert vào database. Điều đó khiến hiệu năng giảm xuống. Tiếp theo check kết quả mysql chúng ta mới thấy sự bất ngờ.

mysql> select * from user;
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | mai3   |  103 |
|  2 | demtv1 |    1 |
|  3 | demtv2 |    2 |
|  4 | demtv3 |    3 |
|  5 | demtv4 |    4 |
|  6 | demtv5 |    5 |
|  7 | demtv1 |    1 |
|  8 | demtv2 |    2 |
|  9 | demtv3 |    3 |
| 10 | demtv4 |    4 |
| 11 | demtv5 |    5 |
+----+--------+------+
11 rows in set (0,00 sec)

Bất ngờ là id chúng ta truyền vào không hề xuất hiện trong bảng khi sử dụng strategy này.

import lombok.Data;

import javax.persistence.*;

@Entity
@Table(name = "user")
@Data
public class User {
    @Id
    @GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "serial"
    )
    @SequenceGenerator(
            name = "serial",
            sequenceName = "serial",
            allocationSize = 10
    )
    private int id;

    private String name;

    private int age;

}


config
spring:
  application:
    name: user-service
  config:
    import : optional:configserver:http://localhost:8888/
  profiles:
    active: dev
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/blog?characterEncoding=utf8
    driver-class-name: com.mysql.jdbc.Driver
    username: demtv
    password: Anhdem96!@
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 5
        order_inserts : true
        ddl-auto : create
    generate-ddl : true
    show-sql : true
Hibernate: select next_val as id_val from serial for update
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select next_val as id_val from serial for update"], "params":[[]]}
Hibernate: update serial set next_val= ? where next_val=?
{"name":"Batch-Insert-Logger", "time":1, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["update serial set next_val= ? where next_val=?"], "params":[["11","1"]]}
Hibernate: select next_val as id_val from serial for update
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select next_val as id_val from serial for update"], "params":[[]]}
Hibernate: update serial set next_val= ? where next_val=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["update serial set next_val= ? where next_val=?"], "params":[["21","11"]]}
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
{"name":"Batch-Insert-Logger", "time":2, "success":true, "type":"Prepared", "batch":true, "querySize":1, "batchSize":5, "query":["insert into user (age, name, id) values (?, ?, ?)"], "params":[["1","demtv1","1"],["2","demtv2","2"],["3","demtv3","3"],["4","demtv4","4"],["5","demtv5","5"]]}

Chúc mừng chúng ta cuối cùng đã thực hiện được batch insert với mysql. Nhưng sự thật có đáng để vui hay không? Theo như log bên trên mỗi lần thực hiện insert hibernate lại vào bảng serial lấy ra id tiếp theo Hibernate: select next_val as id_val from serial for update Cơ chế này sẽ làm giảm hiệu năng chương trình đi rất nhiều. Tiếp đến câu lệnh hibernate dùng để lấy id cũng gây lock table serial lại khiến hiệu năng lại giảm thêm. Cơ chế này không phải cơ chế SEQUENCE mà là cơ chế “TABLE” một trong các cơ chế mọi người nên tránh sử dụng. Chỉ sủ dụng khi loại database của mọi người không hỗ trọ cơ chế “auto_increment” và “sequence”. Với mysql hibernate chỉ sử dụng tốt nhất với strategy = GenerationType.IDENTITY

Giả sử với phương pháp tạo Id, chúng ta không cần thiết phải dựa vào database để tạo id. Chúng ta dùng id tự tạo ra để insert vào database.

import lombok.Data;

import javax.persistence.*;

@Entity
@Table(name = "user")
@Data
public class User {
    @Id
    private int id;

    private String name;

    private int age;

}
    @PutMapping("/multi/user")
    String insertMultiUser() {
        List<User> savedUser = new ArrayList<>();
        for (int i = 1; i < 6; i++) {
            User user = new User();
            user.setId(1000 * (i + 1));
            int index = count.addAndGet(1);
            user.setName("demtv" + index);
            user.setAge(index);
            savedUser.add(user);
        }
        repository.saveAll(savedUser);
        return "done";
    }

Chúng ta gọi đến route và check log

Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["2000"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["3000"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["4000"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["5000"]]}
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?
{"name":"Batch-Insert-Logger", "time":0, "success":true, "type":"Prepared", "batch":false, "querySize":1, "batchSize":0, "query":["select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.name as name3_0_0_ from user user0_ where user0_.id=?"], "params":[["6000"]]}
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
Hibernate: insert into user (age, name, id) values (?, ?, ?)
{"name":"Batch-Insert-Logger", "time":2, "success":true, "type":"Prepared", "batch":true, "querySize":1, "batchSize":5, "query":["insert into user (age, name, id) values (?, ?, ?)"], "params":[["1","demtv1","2000"],["2","demtv2","3000"],["3","demtv3","4000"],["4","demtv4","5000"],["5","demtv5","6000"]]}

Cách này cũng giống như khi sử dụng strategy=IDENTITY cũng gây hiệu năng giảm sút vì cần các câu select trước các câu insert.

Các bạn có thể biết cách batch insert không phải là cách insert nhanh nhất khi thực hiện insert dữ liệu vào database. Nó chỉ tiết kiệm được IO truyền qua mạng bằng cách gửi nhiều lệnh insert lên database thực hiện một lần. Kiểu insert nhanh nhất vào database phải là bulk insert rất tiếp hibernate không hỗ trợ kiểu này. Nhưng với mariadb và mysql chúng ta có config rewriteBatchedStatements nếu set config này rewriteBatchedStatements=true thì jdbc sẽ viết lại các câu lệnh batch insert thành bulk insert.

spring:
  application:
    name: user-service
    url: jdbc:mariadb://127.0.0.1:3307/blog?characterEncoding=utf8&rewriteBatchedStatements=true
    driver-class-name: org.mariadb.jdbc.Driver
    username: root
    password: demtv
  jpa:
    properties:
      hibernate:
        jdbc:
             batch_size : 5
        order_inserts : true

    show-sql : true

Gọi đến route và check lại log trên server mariadb ta được như sau

select * from mysql.general_log a  order by event_time desc;

+----------------------------+----------------------------+-----------+-----------+--------------+----------------------------------------------------------------------------------------------------------------+
| event_time                 | user_host                  | thread_id | server_id | command_type | argument                                                                                                       |
+----------------------------+----------------------------+-----------+-----------+--------------+----------------------------------------------------------------------------------------------------------------+
| 2021-07-18 08:52:07.774988 | root[root] @  [172.17.0.1] |        49 |         1 | Query        | SHOW WARNINGS                                                                                                  |
| 2021-07-18 08:52:07.773198 | root[root] @  [172.17.0.1] |        49 |         1 | Query        | SELECT @@session.tx_isolation                                                                                  |
| 2021-07-18 08:51:56.061139 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | set autocommit=1                                                                                               |
| 2021-07-18 08:51:56.057017 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | COMMIT                                                                                                         |
| 2021-07-18 08:51:56.055347 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | insert into user (age, name, id) values (5, 'demtv5', 16),(4, 'demtv4', 15) ,(3, 'demtv3', 14),(2, 'demtv2', 13),(1, 'demtv1', 12)|
| 2021-07-18 08:51:56.031163 | root[root] @  [172.17.0.1] |        71 |         1 | Query        | select nextval(serial)                                                                                         |
+----------------------------+----------------------------+-----------+-----------+--------------+----------------------------------------------------------------------------------------------------------------+

Chú ý phần argument của câu lệnh insert nó đã được viết lại thành bulk insert điều này tăng hiệu năng của chương trình.

Sau khi thử nghiệm các loại strategy khác nhau chúng ta có kết luận sau:

  • Sử dụng SEQUENCE khi database hỗ trợ dạng này. Kể cả hỗ trợ SEQUENCE lẫn IDENTITY thì vẫn chọn dạng SEQUENCE vì hibernate hỗ trợ tốt nhất với dạng này.
  • Nếu database hỗ trợ IDENTITY thì chỉ nên dùng IDENTITY đùng sử dụng các loại khác
  • Không sử dụng loại TABLE trừ khi database của bạn không hỗ trợ “auto_increment” hoặc “sequence”
  • Không nên truyền id khi thực hiện insert trong hibernate nếu không hiệu năng chương trình của bạn sẽ có vấn đề
  • Sử dụng config “rewriteBatchedStatements” với mariadb, mysql để tăng hiệu năng của chương trình.

Bài viết gốc được đăng tải tại demtv.hashnode.dev

Xem thêm:

Xem thêm Việc làm IT hấp dẫn trên TopDev

Cấu hình Laravel Queue trên môi trường production

Cấu hình Laravel Queue trên môi trường production

Bài viết được sự cho phép của tác giả Phạm Bình

Chào các bạn,

Trên môi trường local, chúng ta khởi động queue bằng cách chạy command:

php artisan queue:work

Nhưng trên môi trường production thì không ai rảnh mà lúc nào cũng bật một terminal để chạy command trên cả, mà sẽ có cách khác, và trong bài viết ngắn gọn này mình sẽ chỉ bạn điều đó.

I. Supervisor

1.1 Cấu hình supervisor để chạy queue

Supervisor là một chương trình giám sát tiến trình trên hệ điều hành Linux, mặt khác Laravel thường được deploy trên các server Linux, vì thế mình sẽ sử dụng Supervisor để giám sát việc chạy queue Laravel.

Hiểu nôm na, Supervisor sẽ giúp chúng ta chạy ngầm cái command
php artisan queue:work ngay cả khi tắt terminal.

Để sử dụng supervisor làm “giám sát viên” cho queue, ta thực hiện các bước sau:

Bước 1: Cài đặt Supervisor trên Linux (ở đây mình sử dụng Ubuntu)

sudo apt-get install supervisor

Bước 2: Cấu hình supervisor

Mỗi một tiến trình do Supervisor giám sát sẽ được cấu hình ở một file dạng *.conf nằm trong thư mục /etc/supervisor/conf.d. Nên mình sẽ tạo ra một file có tên là laravel-workder.conf để cấu hình tiến trình chạy queue của Laravel.

sudo vim /etc/supervisor/conf.d/laravel-workder.conf

Nội dung của file laravel-workder.conf như sau:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/your/project/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true

# user thực hiện command 'php artisan queue:work'
# nhớ thay bằng user có quyền thực hiện command trên nhé
user=forge

numprocs=8
redirect_stderr=true

# Các vấn đề sẽ được log vào đây
stdout_logfile=/path/to/your/project/worker.log

Nhớ thay các đoạn bôi đỏ thành thông tin phù hợp với dự án của bạn, sau đó lưu file lại.

  Cài đặt Rust trên Arch Linux

  Todo List: Cập nhật dữ liệu ứng dụng trong Laravel

Bước 3: Khởi động queue

Mỗi khi thay đổi các thông tin cấu hình Supervisor, bạn cần phải khởi động lại Supervisor bằng các command sau:

sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start laravel-worker:*

Bạn cũng có thể tìm hiểu thêm thông tin về Supervisor qua tài liệu chính thức.

Vậy là xong, Supervisor đã thay bạn chạy command php artisan queue:work, và queue bây giờ đã sẵn sàng hoạt động.

Xem thêm nhiều chương trình tuyển dụng Laravel hấp dẫn trên TopDev

2.2 Một số command hay sử dụng của supervisor

Tặng bạn một số thao tác phổ biến với Supervisor:

Command Mô tả
sudo service supervisor restart Khởi động lại toàn bộ supervisor
sudo supervisorctl stop laravel-worker:* Dừng worker laravel-worker:*
sudo supervisorctl start laravel-worker:* Khởi động worker laravel-worker:*
sudo supervisorctl restart laravel-worker:* Khởi động lại worker laravel-worker:*

2.3 Một số vấn đề thường gặp với supervisor

Khi sử dụng Supervisor để chạy queue Laravel, thường có một số vấn đề (lỗi) kèm hướng khắc phục như sau:

Queue không chạy

Có rất nhiều nguyên nhân dẫn đến queue không chạy, vì thế hãy đọc file log worker.log để biết thêm thông tin (cũng nên kết hợp đọc cả file storage/logs/laravel.log nữa).

Vẫn chạy “job cũ

Code trong job được update, thế nhưng nó không chạy theo code mới, mà lại chạy theo code cũ. Gặp trường hợp này, hãy thử khởi động lại supervisor:

sudo service supervisor restart

II. Queue Driver

Queue đã tự động chạy với Supervisor, giờ chúng ta tìm hiểu kỹ hơn về các queue driver có trong Laravel.

Queue driver là các “loại queue” có trong Laravel, chúng đều có mục đích là giúp queue có thể hoạt động, nhưng mỗi loại queue lại có các tính chất (hiệu năng, cách cài đặt, cách chạy) khác nhau, và tùy từng dự án mà chúng ta sẽ sử dụng các loại queue khác nhau.

Từ Laravel 6.x, Queue driver được gọi là Queue connection, chỉ là đổi cách gọi tên, còn chúng vẫn là một.

2.1 Sync

Queue sync là queue mà … dùng như không dùng. Các job khi đưa vào queue sẽ được thực hiện ngay lập tức. Cũng có thể hiểu, khi cấu hình queue driver là sync tức là bạn đã tắt queue trong Laravel.

Queue sync chỉ nên sử dụng để dev trên local, không nên để trên production.

Cách cài đặt

Mở file .env, tìm dòng QUEUE_DRIVER=XXX, đổi thành QUEUE_DRIVER=sync.

Lưu ý: với Laravel 6.x trở nên thì QUEUE_DRIVER đổi thành QUEUE_CONNECTION.

2.2 Database

Với queue database, các job sẽ được lưu vào trong database để chạy dần dần. Vì lưu trữ job trong database, nên chúng ta sẽ cần tạo một vài table mới để lưu trữ, nhưng không sao, laravel đã tạo sẵn cho bạn command để cài đặt rồi.

Cách cài đặt

Chạy command sau để tạo bảng lưu trữ các job:

php artisan queue:table php artisan migrate

Cấu hình .env

QUEUE_DRIVER=database

Queue database cũng phù hợp để sử dụng trên production.

2.3 Redis

Redis là một dạng database lưu trữ trên RAM, đặc điểm của nó là tốc độ đọc – ghi rất nhanh, rất phù hợp để làm nơi lưu trữ các job của queue. Để sử dụng queue driver là redis, trước tiên bạn cần cấu hình thông tin kết nối tới redis ở config/database.php trước đã:

// config/database.php

// ...
'redis' => [
    'client' => 'predis',

    // Hãy đảm bảo các thông tin kết nối tới redis là chính xác
    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,
     ],

],

Bạn có thể tìm hiểu thêm về cách cài đặt và cấu hình redis database theo tài liệu của Laravel.

Cách cài đặt

Về cơ bản, bạn chỉ cần cấu hình thông tin kết nối tớ redis ở file config/database.php là đủ, nhưng bạn cũng nên xem qua file config/queue.php

// config/queue.php

// ...
'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => '{default}',
    'retry_after' => 90,
],

Cấu hình lại thông tin trong .env

QUEUE_DRIVER=redis

Redis rất phù hợp để làm driver cho queue trên môi trường production của Laravel.

III. Tổng kết

Một bài viết ngắn gọn ghi chú lại các kiến thức và kinh nghiệm cấu hình Queue Laravel trên production, hy vọng sẽ giúp ích cho nhiều bạn.

Xin chào, hẹn gặp lại.

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

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

Tham khảo thêm các vị trí tuyển dụng ngành IT tại Topdev

Công nghệ Blockchain là gì? Tiềm năng & ứng dụng thực tế 

Công nghệ Blockchain là gì?

Công nghệ Blockchain mang một tiềm năng to lớn, được xem là “chìa khóa” cho chuyển đổi số và mở ra một xu hướng mới cho nhiều lĩnh vực trong tương lai. Vậy công nghệ blockchain là gì? Các đặc điểm nổi bật của blockchain? Và ứng dụng nó như thế nào?

Công nghệ Blockchain là gì?

Blockchain là công nghệ chuỗi khối, cho phép chia sẻ thông tin một cách minh bạchan toàn dựa trên hệ thống mã hóa vô cùng phức tạp. Dữ liệu sẽ được lưu trữ trong các khối, liên kết với nhau trong một chuỗi và được mở rộng theo thời gian.

Mỗi khối sẽ chứa đựng các thông tin về dữ liệu giao dịch và liên kết với khối trước đó nên việc can thiệp thay đổi thông tin là điều không thể xảy ra.

Công nghệ Blockchain là gì?

Một điều khác biệt của blockchain so với các công nghệ khác là thông tin không nằm tập trung ở một máy chủ nào cả, cũng không ai kiểm soát được nó, mọi thông tin sẽ được sao lưu trên nhiều máy chủ khác nhau. Thiết kế của mạng lưới này giúp chống lại sự thay đổi của dữ liệu và quản lý dưới mạng lưới phi tập trung. Ngay cả khi một phần của hệ thống blockchain sụp đổ thì các nút khác vẫn sẽ tiếp tục lưu trữ và giữ cho mạng lưới hoạt động bình thường.

  Thông não về các khái niệm Web1, Web2, Web3

Công nghệ blockchain – sự kết hợp giữa 3 loại công nghệ nào?

Blockchain là sự kết hợp giữa 3 loại công nghệ:

  • Mật mã học: Blockchain đã sử dụng public key và hàm hash function để đảm bảo tính minh bạch, toàn vẹn và riêng tư.
  • Mạng ngang hàng: Mỗi một nút trong mạng được xem như một client và cũng là server để lưu trữ bản sao ứng dụng.
  • Lý thuyết trò chơi: Các nút tham gia vào hệ thống đều phải tuân theo giao thức đồng thuận (PoS, PoW,…) và được thúc đẩy bởi động lực kinh tế.

Tham khảo việc làm Blockchain hấp dẫn trên TopDev

Các đặc điểm nổi bật của công nghệ blockchain

Các chuỗi blockchain không thể làm giả và phá hủy: Chỉ khi máy Internet trên toàn cầu biến mất blockchain mới bị phá hủy.

  • Bất biến: Dữ liệu không thể được sửa chữa nếu giao dịch đã xảy ra.
  • Bảo mật: Các thông tin và dữ liệu về các chuỗi blockchain được phân tán và an toàn tuyệt đối.
  • Minh bạch: AI sẽ theo dõi đườngđi của blockchain từ địa chỉ này qua địa chỉ khác và ghi lại toàn bộ lịch sử đó.
  • Hợp đồng thông minh: Đây là một dạng hợp đồng kỹ thuật số được nhúng vào đoạn code if-this-then-that (IFTTT) cho phép chúng tự động thực thi khi đáp ứng các điều kiện đã định sẵn mà không cần can thiệp bởi bên thứ ba.

Các đặc điểm nổi bật của công nghệ blockchain

Công nghệ blockchain và ứng dụng

Blockchain là một công nghệ mới và ngày càng chứng minh được khả năng ứng dụng tuyệt vời của nó vào thực tiễn. Dưới đây là một số ứng dụng điển hình của công nghệ blockchain trong nhiều lĩnh vực.

Truyền thông và viễn thông: Blockchain sẽ giúp các nhà cung cấp dịch vụ truyền thông tối ưu hóa quy trình, tăng cường khả năng bảo mật mạng cũng như quản lý danh tính trong mô hình kinh doanh của mình. 

Sản xuất: Công nghệ blockchain mang đến các giải pháp giúp theo dõi quá trình sản xuất, quản lý hàng tồn kho, truy xuất nguồn gốc sản phẩm qua các khâu, theo dõi nguồn cung cấp nguyên liệu sản xuất, ghi nhận thông tin giao dịch,…

Y tế: Blockchain được sử dụng để quản lý tài sản và lưu trữ thông tin sức khỏe bệnh nhân, quản lý chuỗi cung ứng thuốc, thiết bị y tế (nguồn gốc, hạn sử dụng,…), tăng cường tính minh bạch và tự động hóa trong các giao dịch khám chữa bệnh,…

Giáo dục: Công nghệ blockchain giúp lưu trữ các thông tin về quá trình học, các kinh nghiệm thực tế, trình độ học vấn, kỷ luật,… tránh tình trạng ứng viên gian lận trong quá trình xin học bổng, thăng tiến. Blockchain còn giúp thực hiện các khoản nội quy đào tạo của nhà trường, xử lý các trường hợp vi phạm và cải thiện quy trình làm việc.

Tài chính & ngân hàng: Khả năng tạo hợp đồng thông minh của blockchain sẽ giải quyết được các rủi ro khi giao dịch, loại bỏ tình trạng tập trung quyền lực, cho phép giao dịch ngay cả khi không có trung gian xác minh. Người dùng sẽ tiết kiệm được chi phí, tăng tốc độ giao dịch và hạn chế rủi ro trong quá trình thanh toán.

ứng dụng của blockchain

Thương mại điện tử: Công nghệ blockchain sẽ giải quyết các vấn đề liên quan đến nguồn gốc sản phẩm, quá trình vận chuyển bằng các hợp đồng thông minh, tạo điều kiện cho các doanh nghiệp đa quốc gia dễ dàng ký kết. 

Nông nghiệp: Blockchain được ứng dụng trong nông nghiệp giúp lưu trữ thông tin giao dịch, tăng tính minh bạch của thông tin trong quá trình vận chuyển sản phẩm từ cơ sở sản xuất đến cơ sở chế biến, nhà phân phối, cửa hàng hay siêu thị. Điều này giúp truy xuất nguồn gốc hiệu quả, nâng cao lòng tin cho người tiêu dùng.

Ngoài ra, công nghệ blockchain còn được ứng dụng ở nhiều lĩnh vực khác như vận tải và logistics, ngành bán lẻ, du lịch, bảo hiểm, năng lượng, xây dựng,… 

  Ethereum là gì? Tìm hiểu cơ bản về Blockchain (P1)

Tương lai của công nghệ blockchain

Thành công lớn nhất của công nghệ blockchain là tạo ra “hợp đồng thông minh”, các giao dịch thỏa thuận trong hợp đồng sẽ được xác nhận mà không cần thông qua bên trung gian. Mọi giao dịch đều an toàn và minh bạch, khó có thể làm giả và nếu có chắc chắn sẽ để lại dấu vết.

Công nghệ blockchain đã mở ra một xu hướng mới cho các lĩnh vực như tài chính ngân hàng, bảo hiểm,  kế toán kiểm toán, y tế, game,… Kéo theo cơn khát nhân sự blockchain nóng hơn bao giờ hết.

Trong thời đại công nghệ, nhu cầu bảo mật, kết nối và tiện lợi của khách hàng ngày càng cao, việc nắm bắt xu hướng công nghệ mới sẽ tạo lợi thế khác biệt để thương hiệu vươn lên trước đối thủ cạnh tranh. Hiện nay đã có rất nhiều công ty và tập đoàn lớn bắt tay vào xây dựng blockchain như Facebook, Apple, Alibaba, Ford,… tạo nên một làn sóng công nghệ mới cho tương lai.

Tóm lại, công nghệ blockchain ra đời đã và đang trở thành một điểm sáng trong nền khoa học 4.0 của thế kỷ 21. Đây là thời điểm thích hợp để các công ty/doanh nghiệp khai thác và tận dụng công nghệ mới này một các tối ưu và hiệu quả nhất. Hy vọng bài viết này đã giúp bạn hiểu rõ hơn về công nghệ blockchain, chúc bạn có những định hướng tốt trong trong tương lai.

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

Đừng bỏ lỡ Top việc làm IT mới nhất trên TopDev!

Những cái “khó” khi mới học lập trình

Những cái “khó” khi mới học lập trình

Bài viết được sự cho phép của tác giả Phạm Bình

Chào các bạn,

Vạn sự khởi đầu nan, câu nói này chưa bao giờ sai, kể cả trong việc học lập trình cũng vậy. Bài viết này mình sẽ kể ra những cái “khó” mà mình gặp phải trong những ngày đầu tiên học lập trình, để xem giữa mình và bạn có đặc điểm chung nào không nhé.

I. Nản do phải học nhiều thứ

Trước khi học lập trình, mình có ước mơ là sẽ tạo ra một phần mềm gì đó thật ngầu, làm thay đổi thế giới, và trở nên giàu có nhờ phần mềm đó. Nhưng khi bắt đầu học, thì mới thấy cái ước mơ đầu quá xa vời. Vì để tạo ra một phần mềm vĩ đại như thế, mình cần phải học rất nhiều thứ (cho tới bây giờ cũng chưa học hết). Khi biết được điều này, thật sự mình cảm thấy nản và muốn bỏ cuộc. Nhưng nghĩ kỹ thì lại thấy làm gì có gì dễ dàng đâu, thôi thì giảm mục tiêu xuống vậy.

  Python là gì? Tổng hợp kiến thức cho người mới bắt đầu

Tâm lý của một lập trình viên qua từng giai đoạn

– Trước khi học lập trình: Mình sẽ tạo ra một con game làm “điên đảo” game thủ thế giới
– Khi học được 1 năm: Mình sẽ tạo ra một cổng thông tin về game lớn nhất Việt Nam
– Khi học được 2 năm: Mình sẽ tạo ra một blog và tự tay viết các tin về game
– Khi học được 3 năm: Mình sẽ dùng một nền tảng blog có sẵn để viết bài thay vì tự code
– Khi học xong: Code gì cũng được, miễn là code
– Khi đi làm: Ai đó fix giúp tôi cái bug này

Nếu bạn có rơi vào trường hợp này giống mình, thì cũng hãy thử giảm mục tiêu xuống xem sao. Giảm mục tiêu không phải là sợ mình không làm được việc lớn, mà là biết lượng sức mình. Hoàn thiện nhiều việc nhỏ giúp mình có kiến thức và kinh nghiệm để sau này làm việc lớn.

Việc làm IT Fresher dành cho bạn

II. Càng học càng thấy mình “ngu”

Khi học lập trình, mình gặp rất nhiều kiến thức được gắn mác “cơ bản”, nhưng khi học mình lại khó vô cùng (nhất là kiến thức về giải thuật), làm mình có suy nghĩ “có phải mình quá ngu để học lập trình hay không”, và lại bắt đầu chán nản lần 2.

Nhưng một người khác đã nói với mình “cơ bản không có nghĩa là dễ học dù phần lớn kiến thức cơ bản đều dễ học“. Nghĩ thì thấy đúng thật.

kiến thức cơ bản là những kiến thức mang tính cơ sở để học các kiến thức khác, và nó không có “nghĩa vụ” là phải dễ học. Nếu một kiến thức gắn mác “cơ bản”, nghĩa là mình phải học nó, chứ không có nghĩa là mình có thể học nó một cách dễ dàng. Quan điểm này đã giúp mình thay đổi suy nghĩ và tiếp tục học một cách nghiêm túc.

  Lời khuyên tốt nhất cho một lập trình viên mới vào nghề là gì?

III. Học được, nhưng … không làm được

Mình đã bỏ thời gian học hành nghiêm túc, mình đã học hết các kiến thức cơ bản, mình đã có thể tạo ra một giao diện web hoặc một phần mềm giả lập máy tính bỏ túi, và mình cũng tự tin là nắm rõ một vài ngôn ngữ lập trình. Nhưng mình vẫn không thể tạo ra một phần mềm ưng ý. Phần mềm mình tạo ra rất khó sử dụng, thường xuyên gặp lỗi, bố cục lộn xộn, giao diện xấu xí, và mình còn chẳng muốn sử dụng nó chứ đừng nói là cho người khác sử dụng – nói chung là “Học được nhưng làm không được”.

Nhưng mà kệ, đâm lao thì phải theo lao thôi, học được đến đây rồi không lẽ bỏ cuộc.

Mình cũng cho rằng việc “học được nhưng làm không được” là do thiếu kinh nghiệm, nên mình cố gắng code nhiều hơn, cải tiến các dự án cũ cho bớt lỗi và dễ sử dụng hơn, cũng như tham khảo các dự án opensource được tạo ra bởi các developer có kinh nghiệm để học tập.

Mình chẳng nhớ là đã làm bao nhiêu dự án cá nhân (pet project) nữa, chắc phải đến cả trăm cái, qua mỗi dự án như vậy, mình lại rút ra được một chút kinh nghiệm. Lâu dần, tích tiểu thành đại, mình đã nâng cao khả năng code đáng kể.

IV. Một vài khó khăn khác

Một vài khó khăn khác nhỏ hơn, nhưng vẫn đáng nói:

  • Không quen “mặt bug”: Khi mới học lập trình, có những lỗi rất khó hiểu, mặc dù trình biên dịch hiển thị lỗi rất cụ thể, nhưng đọc vẫn không hiểu. Đành copy lên google xem có ai gặp phải hay chưa rồi xem cách khắc phục của họ. Lâu ngày, bug cũ lặp đi lặp lại thì thành ra “quen mặt”, nên cũng dễ fix hơn.
  • Không quen “mặt code”: Mỗi ngôn ngữ lập trình lại có cú pháp khác nhau, cái dài cái ngắn, cái có dấu chấm phẩy cái lại không có. Nên thời gian đầu đọc hơi khó hiểu, nên đành phải code nhiều, nhìn nhiều cho quen.
  • Chọn cách giải nào: Cùng một vấn đề, nhưng có thể có nhiều cách giải, và mình phải tốn khá nhiều thời gian và chất xám để tìm ra cách giải nào là tốt nhất.

V. Lời kết

Bài viết này không chỉ mang tính chất “kể khổ”, mà còn muốn nhắn nhủ tới các bạn newbie rằng “vạn sự khởi đầu nan”. Dù khó khăn của bạn có giống của mình hay không, thì thời gian đầu chắc chắn khó học, nhưng khó ở đây là khó chung chứ không riêng gì bạn, vì thế hãy cố gắng vượt qua nhé. Chúc các bạn thành công.

Hẹn gặp lại.

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

Xem thêm:

Đừng bỏ qua việc làm IT tất cả level có trên TopDev nhé!

Phiên bản LTS là gì? Khi nào nên sử dụng phiên bản LTS

Phiên bản LTS là gì? Khi nào nên sử dụng phiên bản LTS

Bài viết được sự cho phép của tác giả Phạm Bình

I. LTS là gì?

Trong thế giới công nghệ, thỉnh thoảng chúng ta thường bắt gặp cụm từ “LTS“. Ví dụ như Ubuntu 16.04 LTS, Ubuntu 18.04 LTS, Laravel 6 LTS,… Vậy LTS có nghĩa là gì?

LTS là viết tắt của Long Term Support có nghĩa là Hỗ trợ dài hạn.

Như định nghĩa trên:

các phiên bản có gắn mác LTS sẽ là phiên bản được hỗ trợ dài hạn. Tức là cho dù đã phát hành được một thời gian và kể cả đã có phiên bản khác mới hơn được phát hành thì phiên bản có gắn mác LTS sẽ vẫn được hỗ trợ bảo trì như bình thường.

Ví dụ một ứng dụng A phát hành phiên bản 4.0 LTS vào năm 2020, hỗ trợ bảo trì tới năm 2024. Thì trong khoảng thời gian từ năm 2020 tới năm 2024 có thể ứng dụng A đã phát hành thêm các phiên bản 5.0, 6.0 khác, nhưng phiên bản 4.0 vẫn sẽ được cập nhật các bản vá lỗi và vá lỗi bảo mật một như bình thường.

  Hướng dẫn tạo certificate SSL trên ubuntu (file key, pem)

II. Nên sử dụng phiên bản LTS khi nào?

Việc sử dụng phiên bản LTS sẽ đem lại một số lợi thế sau:

Phiên bản LTS thường là các phiên bản hoạt động ổn định, có cộng đồng sử dụng đông đảo.

Không tốn thời gian, chi phí cho việc phải thường xuyên cập nhật phiên bản mới mà vẫn nhận được sự hỗ trợ từ chính tổ chức phát hành.

Trên là hai lý do cơ bản nhất khiến bạn nên sử dụng phiên bản có gắn mác LTS thay vì các phiên bản thông thường khác. Tuy nhiên bạn vẫn nên sử dụng các phiên bản thông thường (hoặc phiên bản mới nhất) nếu như 2 lợi thế kể trên không đặc biệt quan trọng với bạn.

Tham khảo việc làm CSS hấp dẫn trên TopDev

Công ty mình đang làm hiện tại luôn ưu tiên sử dụng các phiên bản LTS thay vì các phiên bản khác (kể cả phiên bản mới nhất), vì sản phẩm của công ty luôn yêu cầu tính ổn định cao. Hơn nữa mọi người cũng muốn tập trung nguồn lực để phát triển các business của sản phẩm thay vì chỉ trực có phiên bản mới là update.

Còn với cá nhân mình, trong các dự án dạng “làm chơi cho vui” thì cứ phiên bản mới nhất là mình quất. Cốt lõi là muốn trải nghiệm các tính năng mới, bởi các phiên bản hỗ trợ dài hạn cũng thường đi với sự lỗi thời.

  Xử lý SSL Certificate trong Selenium WebDriver

III. Tổng kết

Tổng kết lại thì có một số luận điểm sau:

  • LTS là Long Term Support – Hỗ trợ dài hạn, ám chỉ phiên bản được hỗ trợ dài hạn cho dù đã có phiên bản khác mới hơn.
  • Phiên bản LTS có tính ổn định cao.
  • Phiên bản LTS nên được sử dụng trong các sản phẩm của cơ quan tổ chức cần tính ổn định cao.

Trên là một số quan điểm, kiến thức của mình về các phiên bản dạng LTS, hy vọng sẽ giúp ích được cho các bạn.

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

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

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Thiết kế service có tải ghi cao không gây tranh chấp tài nguyên

Thiết kế service có tải ghi cao không gây tranh chấp tài nguyên

Để đảm bảo một hệ thống chạy tốt và ổn định, các việc thiết kế hệ thống như : chọn mô hình (micromonolithic), loại database, cách truyền tải dữ liệu (message queuehttpsocket,..), cách load balancing,… là việc rất quan trọng đánh dấu sự thành công của hệ thống. Song song với đó việc chúng ta thiết kế một service cũng là một mấu chốt quan trọng. Service bạn chịu trách nhiệm thiết kế có thể có các thao tác đọc ghi trên một dữ liệu tranh chấp. Khi 2 luồng của service của bạn cùng sửa một tài nguyên bị tranh chấp sẽ gây ra sự sai sót của hệ thống. Vậy khi thiết kế chúng ta cần có các kỹ thuật tránh điều này. Trong bài viết này tôi sẽ chia sẻ kinh nghiệm của mình khi thiết kế các service như vậy. Đây là phần một của bài viết sẽ nói về cách các bạn xử lý dữ liệu khi đến service chưa nói đến phân tải khi bạn có nhiều service cùng thực hiện một việc cũng như các service cùng một việc sẽ đồng bộ với nhau như thế nào.

Giả sử chúng ta cần thiết kế một service cho phép khách hàng thực hiện rút tiền. Chúng ta có một bảng đơn giản lưu lại thông tin của khách hàng như sau.

CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `total_money` int DEFAULT NULL,
  `version` int DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6028 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Tôi sẽ insert trước vài dữ liệu vào bảng này.

mysql> select * from users;
+----+--------+------+-------------+---------+
| id | name   | age  | total_money | version |
+----+--------+------+-------------+---------+
|  1 | demtv1 |    1 |           0 |       1 |
|  2 | demtv2 |    2 |          10 |       1 |
|  3 | demtv3 |    3 |          90 |       1 |
|  4 | demtv4 |    4 |          50 |       1 |
|  5 | demtv5 |    5 |          70 |       1 |
+----+--------+------+-------------+---------+

Yêu cầu của service là khi khách hàng rút tiền số dư sẽ được thay đổi và được lưu lại trong database. Trong đề bài này phần tài nguyên tranh chấp là số tiền của khách hàng. Chúng ta sẽ thiết kế theo mô hình đơn giản sau

simpleService.png

  Lưu ý cho Lock trong Java

  Hướng dẫn Java Design Pattern – State

Cách đơn giản để tránh tranh chấp các loại tài nguyên này là bạn chỉ cho phép một luồng được thực hiện với thao tác với tài nguyên tranh chấp. Trong java chúng ta có thể dùng synchronized hoặc lock.

      public synchronized User doUpdate(int amount){
        //...
        user.setTotalMoney(user.getTotalMoney() - withDrawRequest.getAmount());
        user = service.updateUser(user);
        CacheManager.user.put(user.getId(), user);
        response.setMsg("ok");

        //...
    }

    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.WriteLock lock = readWriteLock.writeLock();
    public  User doUpdate(int amount){
        lock.lock();
        try{
            //...
            user.setTotalMoney(user.getTotalMoney() - withDrawRequest.getAmount());
            user = service.updateUser(user);
            CacheManager.user.put(user.getId(), user);
            response.setMsg("ok");

            //...
        }finally {
            lock.unlock();
        }
    }
  • Dễ implement không cần database để xử lý tranh chấp
  • Không thể phục vụ nhiều khách hàng cùng lúc được.
  • Khó triển khai trên nhiều node service với các cách phân tải hay dùng hiện nay ví dụ : roundrobin, ip, WeightedResponseTimeRule … Phải có bộ phân tải hợp lý sao cho mỗi một node service chỉ phục vụ một số lượng user nhất định.

Tham khảo việc làm Java hấp dẫn trên TopDev

Với thiết kế này trên database sẽ có 1 trường mang đánh dấu là version của dữ liệu khi 2 luồng cùng thực hiện update trên cùng một dữ liệu trên database thì chỉ có 1 luồng thực hiện update thành công. Kỹ thuật đó là optimistic locking chi tiết mọi người xem tại link. Với spring boot các bạn có thể tham khảo tại link. Hoặc tham khảo đoạn code dưới đây

import lombok.Data;

import javax.persistence.*;

@Entity
@Table(name = "users")
@Data
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    private int age;

    private int totalMoney;

    @Version
    private int version;

}

// thao tác với database
   try {
      user = service.updateUser(user);
      CacheManager.user.put(user.getId(), user);
      response.setMsg("ok");
   } catch (IllegalStateException exception) {
      exception.printStackTrace();
      response.setMsg("version is not ok");
   }
  • Phương pháp này có thể phục vụ nhiều khách hàng khác nhau cùng thực hiện thao tác rút tiền.
  • Nếu bạn có nhiều node service phương pháp này vẫn phục vụ tốt cho bạn không sợ sai lệch dữ liệu
  • Rất dễ dàng để implement với tất cả developer
  • Phương pháp phải dùng database để bảo vệ tài nguyên tranh chấp gây lên cao tải cho database. Khi database cao tải bạn tăng số lượng service cũng không làm hệ thống bạn chạy tốt hơn.

Ý tưởng của request rất đơn giản thay vì mỗi request đến chúng ta có một luồng không xác định xử lý và thao tác với database. Giờ chúng ta sẽ tạo trước một số lượng luồng xử lý với database nhất định. Sau đó mỗi request đến ta sẽ lần lượt chia vào từng luồng này để xử lý. Điều này dẫn đến chúng ta sẽ ít sảy ra trường hợp insert fail vào database hơn vì với cùng request của một user chúng ta đã chỉ có 1 luồng duy nhất thao tác với nó nên trong cùng một node service sẽ không gây ra tranh chấp tài nguyên.

sharding_request.png

  • Không cần dùng đến database để xử lý tài nguyên tranh chấp cho nên không gây cao tải nên database khiến hệ thống chạy nhanh hơn. Khi bị hệ thống cao tải có thể add thêm service để phục vụ.
  • Nếu database bị cao tải ta có thể sử dụng phương pháp acsync insert/update vào database không gây ảnh hưởng đến trải nghiệm khách hàng.
  • Khó implement với những developer mới code. Mọi người có thể tham khảo link github sau được implement bằng springboot. Nếu nó có ích cho tôi xin 1 sao nhé. :))
  • Khi có nhiều node service thì cách này sẽ không thực sự hiệu quả với các cách load balacing thông thường như : roundrobin, ip, WeightedResponseTimeRule,… Vì như thế chúng ta sẽ không biết được cùng một user có rơi vào 2 node khác nhau không. Chúng ta nên sử dụng thêm version trong database.
  • Khi triển khai nhiều node service chúng ta cần có phương pháp phân tải thích hợp cho mỗi user sẽ chỉ vào một node nhất định. Khi node đó bị chết thì request của user đó sẽ chỉ chuyển sang một node khác. Có cơ hội sẽ trình bài ở các phần sau.

Ở đây tôi đã trình bày xong các cách giúp mọi người có thể thực hiện để tránh tranh chấp tài nguyên khi lập trình vào các request phải thay đổi dữ liệu hy vọng sẽ giúp ích được cho mọi người.

Tất cả các phương pháp đều có thể kết hợp với cache để tăng tốc độ khi không cần thực hiện giao tiếp nhiều với database. Ở các phần sau tôi sẽ giới thiệu một cách phân tải khá thông minh để áp dụng với cách thứ 3 trong bài này và nếu mọi người thấy việc implement cách thứ 3 khá khó thì tôi cũng sẽ có bài hướng dẫn mọi người implement tùy xem Hà Nội cách ly bao ngày nữa :))

Bài viết gốc được đăng tải tại demtv.hashnode.dev

Xem thêm:

Tuyển dụng IT lương cao, đãi ngộ hấp dẫn. Ứng tuyển ngay!

Đồng bộ dữ liệu giữa MongoDB với Elasticsearch bằng Transporter

Đồng bộ dữ liệu giữa MongoDB với Elasticsearch bằng Transporter

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Trong bài này mình sẽ làm ví dụ chuyển data từ MongoDB sang Elasticsearch bằng Transport.

1. Transporter là gì? Cài đặt transporter trên ubuntu

Transporter là một phần mềm mã nguồn mở để di chuyển / đồng bộ dữ liệu trên các kho dữ liệu khác nhau.

Các kho dữ liệu được đồng bộ ở đây có thể là database, files…

Dữ liệu được đọc từ kho dữ liệu nguồn (source) sau đó được chỉnh sửa, tách lọc… (transformer) rồi chuyển tới kho dữ liệu đích (sink) thông qua pipeline do bạn định nghĩa.

  Truy vấn dữ liệu MongoDB

Cài đặt transport trên ubuntu

Download transporter:

wget https://github.com/compose/transporter/releases/download/v0.5.2/transporter-0.5.2-linux-amd64

(Download các phiên bản khác tại đây)

Chuyển các file vừa tải về vào folder /usr/local/bin/transporter hoặc folder nào đó bạn thích.

sudo mv transporter-*-linux-amd64 /usr/local/bin/transporter

Run transporter

chmod +x /usr/local/bin/transporter

Kiểm tra transport sau khi cài đặt bằng lệnh transporterĐồng bộ dữ liệu giữa MongoDB với Elasticsearch bằng Transporter

Tham khảo việc làm MongoDB hấp dẫn trên TopDev

2. Chuyển dữ liệu từ MongoDB sang Elasticsearch

(Xem lại: Hướng dẫn cài đặt MongoDB)

(Xem lại: Hướng dẫn cài đặt Elasticsearch)

Trong ví dụ này mình sẽ chuyển dữ liệu trong database demo sang elasticsearch.

B1: Tạo dữ liệu cho database demo:

db.player.insert({'name':'ronaldo','position':'striker'})
db.player.insert({'name':'buffon','position':'goalkeeper'})

tạo dữ liệu trên database mongo tạo dữ liệu trên database mongo

B2: Tạo pipeline để chuyển dữ liệu từ MongoDB sang Elasticsearch bằng lệnh:

transporter init mongodb elasticsearch

Tạo pipeline để chuyển dữ liệu từ MongoDB sang Elasticsearch

Kết quả là file pipeline.js được tạo ra, file này sẽ chứa các thông tin nguồn, đích của dữ liệu:

var source = mongodb({
  "uri": "${MONGODB_URI}"
  // "timeout": "30s",
  // "tail": false,
  // "ssl": false,
  // "cacerts": ["/path/to/cert.pem"],
  // "wc": 1,
  // "fsync": false,
  // "bulk": false,
  // "collection_filters": "{}",
  // "read_preference": "Primary"
})

var sink = elasticsearch({
  "uri": "${ELASTICSEARCH_URI}"
  // "timeout": "10s", // defaults to 30s
  // "aws_access_key": "ABCDEF", // used for signing requests to AWS Elasticsearch service
  // "aws_access_secret": "ABCDEF" // used for signing requests to AWS Elasticsearch service
  // "parent_id": "elastic_parent" // defaults to "elastic_parent" parent identifier for Elasticsearch
})

t.Source("source", source, "/.*/").Save("sink", sink, "/.*/")

Các bạn có thể tạo biến môi trường MONGODB_URI và ELASTICSEARCH_URI tương ứng hoặc có thể sửa trực tiếp vào file pipeline.js.

Ở đây mình tạo biến môi trường:

MONGODB_URI sẽ là uri tới database demo trên mongodb

export MONGODB_URI='mongodb://localhost/demo'

ELASTICSEARCH_URI sẽ là uri đích để chứa dữ liệu trên elasticsearch:

export ELASTICSEARCH_URI='http://localhost:9200/demo'
  MongoDB là gì? Cơ sở dữ liệu phi quan hệ

B3: chạy file pipeline.js để chuyển dữ liệu từ mongodb sang elasticsearch

transporter run pipeline.js

Kết quả:chạy file pipeline.js để chuyển dữ liệu từ mongodb sang elasticsearch

Kiểm tra lại dữ liệu trên elasticsearch bằng lệnh:

curl $ELASTICSEARCH_URI/_search?pretty=true

Kiểm tra lại dữ liệu trên elasticsearch bằng lệnh:

Đó, tất cả dữ liệu trên database demo đã được chuyển sang elasticsearch.

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

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

Xem thêm tuyển dụng nhân viên it hấp dẫn trên TopDev

Chat GPT là gì? Ứng dụng tuyệt vời và cách chatGPT hoạt động

Chat GPT là gì

ChatGPT là gì mà khiến anh em bà con không chỉ trong mà còn cả ngoài ngành phải thử ít nhất một lần? Điều gì khiến Chat GPT trở nên hot như vậy?

Trong thế giới công nghệ hiện nay, trí tuệ nhân tạo (AI) đang dần trở thành một phần không thể thiếu của cuộc sống. Một trong những công nghệ AI đang thu hút sự chú ý là ChatGPT. Vậy Chat GPT là gì? Nó có thể làm gì và ứng dụng như thế nào? Hãy cùng tìm hiểu trong bài viết này

Chat GPT là gì? Ứng dụng tuyệt vời và cách chatGPT hoạt động
Chat GPT là gì? Ứng dụng tuyệt vời và cách chatGPT hoạt động

Chat GPT là gì?

Chat GPT hay chatGPT, viết tắt của Chat Generative Pre-trained Transformer là một mô hình AI được phát triển bởi OpenAI. Nó sử dụng các thuật toán deep learning để hiểu và tạo ra văn bản tự nhiên giống như con người. Chat GPT có khả năng trả lời câu hỏi, viết văn bản, dịch ngôn ngữ, và thậm chí tham gia vào các cuộc trò chuyện phức tạp.

ChatGPT là mô hình được đào tạo để có thể tương tác theo cách đàm thoại. Ở định dạng đối thoại, Chat GPT có thể trả lời các câu hỏi tiếp theo (có tính kế tiếp), thừa nhận lỗi nếu nó có lỗi. Từ chối các yêu cầu không phù hợp. Chat GPT là mô hình anh em với InstructGPT, được đào tạo để làm theo hướng dẫn ngay lập tức và cung cấp phản hồi chi tiết.

OpenAI, một công ty nghiên cứu và phát triển về AI có trụ sở ở San Francisco đã ra mắt ChatGPT vào ngày 30 tháng 11 năm 2022. Bản chất của chatGPT vẫn đang là một mô hình sử dụng trí tuệ nhân tạo. Hằng ngày vẫn đang học hỏi chứ không phải là đã hoàn thành.

Chat GPT
ChatGPT là gì?

Chat GPT cho phép người dùng đặt câu hỏi hoặc kể lại một câu chuyện. Từ đó BOT sẽ trả lời bằng câu chuyện hoặc câu trả lời có liên quan. Giao diện được thiết kế cho gần giống nhất với cuộc trò chuyện giữa con người với con người.

Các phiên bản chatGPT hiện nay

Kể từ khi ra mắt, Chat GPT đã trải qua nhiều phiên bản nâng cấp để cải thiện hiệu suất và khả năng xử lý. Các phiên bản chính bao gồm:

GPT-1

  • Giới thiệu: GPT-1 là phiên bản đầu tiên của mô hình GPT được phát triển bởi OpenAI và ra mắt vào năm 2018. Đây là bước đầu tiên trong việc sử dụng kiến trúc Transformer để xử lý ngôn ngữ tự nhiên.
  • Cải tiến chính: GPT-1 sử dụng 117 triệu tham số, đánh dấu sự chuyển đổi từ các mô hình truyền thống sang kiến trúc Transformer, giúp cải thiện đáng kể hiệu suất xử lý ngôn ngữ.

GPT-2

  • Giới thiệu: Ra mắt vào năm 2019, GPT-2 là phiên bản cải tiến của GPT-1 với khả năng xử lý ngôn ngữ mạnh mẽ hơn.
  • Cải tiến chính: GPT-2 có 1,5 tỷ tham số, lớn hơn nhiều so với GPT-1, cho phép mô hình tạo ra văn bản tự nhiên hơn và phản hồi phức tạp hơn. GPT-2 có khả năng hoàn thành các nhiệm vụ như viết tiếp câu, trả lời câu hỏi, và thậm chí tạo ra đoạn văn từ một số gợi ý ban đầu.

GPT-3

  • Giới thiệu: GPT-3 được ra mắt vào năm 2020 và là phiên bản phổ biến nhất hiện nay của OpenAI.
  • Cải tiến chính: GPT-3 sử dụng tới 175 tỷ tham số, một bước nhảy vọt lớn so với GPT-2. Điều này giúp GPT-3 có khả năng hiểu và tạo ra văn bản với mức độ phức tạp và chính xác cao hơn nhiều. Nó có thể thực hiện nhiều tác vụ phức tạp như dịch ngôn ngữ, viết bài, sáng tác nhạc, và tham gia vào các cuộc trò chuyện dài và chi tiết.

GPT-4

    • Giới thiệu: GPT-4 là phiên bản mới nhất, ra mắt vào năm 2023.
    • Cải tiến chính: GPT-4 tiếp tục nâng cao khả năng xử lý ngôn ngữ và tích hợp nhiều cải tiến về hiệu suất và độ chính xác. Mặc dù OpenAI không tiết lộ chính xác số lượng tham số của GPT-4, nhưng nó được cho là lớn hơn và hiệu quả hơn GPT-3. GPT-4 có khả năng hiểu ngữ cảnh tốt hơn, giảm thiểu lỗi và cung cấp các phản hồi mượt mà và tự nhiên hơn.

Tìm hiểu thêm về các phiên bản GPT-4 phát hành mới nhất: GPT-4oGPT-4o mini

GPT-5

Chat GPT-5 dự kiến được ra mắt vào cuối năm 2025 hoặc đầu năm 2026 (theo Giám đốc công nghệ (CTO) của OpenAI – Mira Murati cho biết). Bà Mira tiết lộ rằng GPT-5 sẽ là thế hệ có thể đạt được trí thông minh của một tiến sĩ trong một số lĩnh vực nghiên cứu cụ thể. Để so sánh, GPT-3 tương đương với mức độ thông minh của một đứa trẻ, trong khi GPT-4 giống với mức độ thông minh của học sinh trung học.

Chat GPT hoạt động ra sao?

Chat GPT hoạt động ra sao?
Chat GPT hoạt động ra sao?

Chat GPT hoạt động dựa trên mô hình học máy tiên tiến gọi là Transformer, được huấn luyện trên lượng lớn dữ liệu văn bản để hiểu và tạo ra văn bản tự nhiên. Dưới đây là mô tả chi tiết về cách thức hoạt động của Chat GPT:

Kiến trúc Transformer

Kiến trúc Transformer là nền tảng của Chat GPT, được giới thiệu trong bài báo “Attention is All You Need” bởi Vaswani et al. vào năm 2017. Transformer sử dụng cơ chế Attention, cho phép mô hình tập trung vào các phần quan trọng của văn bản đầu vào trong quá trình xử lý.

Quá trình huấn luyện

Chat GPT được huấn luyện thông qua hai giai đoạn chính: tiền huấn luyện (pre-training) và tinh chỉnh (fine-tuning).

  1. Tiền huấn luyện (Pre-training)

Trong giai đoạn này, mô hình được huấn luyện trên một lượng lớn dữ liệu văn bản từ internet. Mục tiêu là giúp mô hình học cách dự đoán từ tiếp theo trong một câu. Cụ thể, GPT sử dụng phương pháp học máy không giám sát để huấn luyện trên các cặp câu liên tiếp, qua đó học được các cấu trúc ngữ pháp, ngữ nghĩa và thông tin ngữ cảnh từ dữ liệu đầu vào.

  1. Tinh chỉnh (Fine-tuning)

Sau khi hoàn thành giai đoạn tiền huấn luyện, mô hình được tinh chỉnh trên một tập dữ liệu nhỏ hơn, có giám sát, để cải thiện độ chính xác và khả năng đáp ứng cho các tác vụ cụ thể. Giai đoạn này sử dụng các dữ liệu đã được gán nhãn, bao gồm các câu hỏi và câu trả lời hoặc các đoạn văn bản có chủ đề nhất định. Điều này giúp mô hình hiểu rõ hơn về các yêu cầu cụ thể và cải thiện khả năng phản hồi chính xác.

Cơ chế Attention

Cơ chế Attention là một phần quan trọng của Transformer, cho phép mô hình tập trung vào các từ quan trọng trong câu để hiểu ngữ cảnh và mối quan hệ giữa các từ. Attention giúp mô hình xác định và tập trung vào các từ có liên quan trực tiếp đến từ đang được dự đoán, qua đó cải thiện độ chính xác của phản hồi.

Tạo văn bản

Khi nhận được đầu vào từ người dùng, Chat GPT sử dụng các kiến thức đã học trong quá trình huấn luyện để tạo ra văn bản đầu ra. Quá trình này bao gồm các bước sau:

  1. Tiếp nhận đầu vào: Chat GPT nhận một câu hỏi hoặc yêu cầu từ người dùng.
  2. Phân tích ngữ cảnh: Mô hình sử dụng các kiến thức đã học để phân tích ngữ cảnh và hiểu yêu cầu của người dùng.
  3. Tạo văn bản: Sử dụng cơ chế Attention và các tham số đã được huấn luyện, Chat GPT dự đoán từ tiếp theo và tạo ra câu trả lời phù hợp.
  4. Phản hồi: Mô hình gửi câu trả lời trở lại cho người dùng.

Tham khảo việc làm AI hấp dẫn trên TopDev!

Chúng ta có thể sử dụng Chat GPT như thế nào?

ChatGPT cũng có thể được sử dụng để tạo trải nghiệm kể chuyện tương tác, cho phép người dùng khám phá và học hỏi từ thế giới ảo.

Với Chat GPT, anh em có thể sử dụng vào các mục đích dưới đây:

  • Tạo phản hồi trong chatbot hoặc trợ lý ảo để cung cấp tương tác tự nhiên và hấp dẫn hơn với người dùng (kiểu con bot này nói chuyện như thật zậy chời).
  • Lên ý tưởng nội dung về từ khóa hoặc chủ đề (thời đại viết bài bằng AI tới đây rồi đấy thôi)
  • Tạo thông tin liên lạc được cá nhân hóa, chẳng hạn như phản hồi email hoặc đề xuất sản phẩm (hỏi phát biết ngay bố mày là ai)?

Ngoài ra, một số nghề có thể biến mất nếu Chat GPT hoạt động xuất sắc.

  • Tạo nội dung tiếp thị như bài đăng trên blog hoặc cập nhật trên mạng xã hội (nghề content writer có thể ra đi).
  • Dịch văn bản từ ngôn ngữ này sang ngôn ngữ khác (học nhiều học lâu có khi google dịch cũng ra đi luôn).
  • Tóm tắt tài liệu dài bằng cách cung cấp toàn văn và yêu cầu ChatGPT tạo bản tóm tắt ngắn hơn (rồi nhà báo ngày viết trăm bài lun)
  • Sử dụng câu trả lời do chatbot tạo ra để tạo công cụ chăm sóc khách hàng tự động (rồi mẹ chăm sóc khách hàng hoạt động năm 365 ngày lun)

Hạn chế của ChatGPT

Mặc dù Chat GPT có nhiều ưu điểm và ứng dụng hữu ích, nó cũng gặp phải một số hạn chế đáng kể. Dưới đây là các hạn chế chính của Chat GPT:

1. Thiếu hiểu biết ngữ cảnh sâu

Chat GPT, dù có khả năng xử lý và tạo ra văn bản tự nhiên, đôi khi vẫn gặp khó khăn trong việc hiểu ngữ cảnh phức tạp hoặc đa nghĩa. Nó có thể đưa ra các phản hồi không chính xác hoặc không phù hợp nếu ngữ cảnh không được xác định rõ ràng từ đầu.

2. Phụ thuộc vào dữ liệu huấn luyện

Chất lượng và độ chính xác của Chat GPT phụ thuộc rất nhiều vào dữ liệu huấn luyện. Nếu dữ liệu đầu vào có sai sót hoặc thiên lệch, kết quả đầu ra của mô hình cũng sẽ bị ảnh hưởng. Điều này có thể dẫn đến việc mô hình tạo ra thông tin không chính xác hoặc phản ánh các thiên lệch có trong dữ liệu.

3. Rủi ro bảo mật

Chat GPT có thể bị lợi dụng để tạo ra thông tin sai lệch, spam, hoặc thực hiện các hành vi lừa đảo. Khả năng tạo ra văn bản giống như con người khiến nó trở thành công cụ tiềm năng cho các hoạt động không lành mạnh nếu không được kiểm soát chặt chẽ.

4. Thiếu tính sáng tạo thực sự

Mặc dù Chat GPT có thể tạo ra văn bản mới từ dữ liệu đã học, nó vẫn dựa vào các mẫu và thông tin đã có trong dữ liệu huấn luyện. Điều này nghĩa là mô hình có thể thiếu tính sáng tạo thực sự và khó có thể đưa ra các ý tưởng hoàn toàn mới mẻ hoặc khác biệt.

5. Hiệu suất không ổn định

Hiệu suất của Chat GPT có thể không nhất quán trong các tình huống khác nhau. Đôi khi, mô hình có thể cung cấp các phản hồi xuất sắc, nhưng trong những trường hợp khác, nó lại có thể tạo ra các câu trả lời thiếu logic hoặc không liên quan.

6. Giới hạn về kiến thức cập nhật

Chat GPT không thể truy cập trực tiếp vào các sự kiện hoặc thông tin mới nhất sau khi quá trình huấn luyện kết thúc. Điều này có nghĩa là nó có thể không biết về các sự kiện hiện tại hoặc những thay đổi gần đây trong các lĩnh vực khác nhau.

7. Khả năng xử lý đa ngôn ngữ hạn chế

Mặc dù Chat GPT có thể xử lý nhiều ngôn ngữ, khả năng hiểu và tạo văn bản có thể không đồng đều giữa các ngôn ngữ khác nhau. Ngôn ngữ nào có ít dữ liệu huấn luyện hơn sẽ dẫn đến hiệu suất thấp hơn trong việc tạo ra các phản hồi chất lượng.

9. Thiếu khả năng tương tác đa phương thức

Hiện tại, Chat GPT chủ yếu xử lý văn bản. Nó không thể dễ dàng tương tác hoặc hiểu các dạng dữ liệu khác như hình ảnh, âm thanh, hoặc video, hạn chế khả năng ứng dụng trong các tình huống yêu cầu tương tác đa phương thức.

10. Phản hồi quá mức (Overfitting)

Trong một số trường hợp, Chat GPT có thể phản hồi quá mức, tạo ra văn bản dài hơn hoặc phức tạp hơn mức cần thiết. Điều này có thể dẫn đến sự mất mạch lạc và gây khó khăn cho người dùng trong việc hiểu rõ ý nghĩa của phản hồi.

Chat GPT là một công cụ mạnh mẽ nhưng cũng có những hạn chế cần được cân nhắc khi sử dụng. Việc nhận thức và hiểu rõ những hạn chế này sẽ giúp người dùng áp dụng Chat GPT một cách hiệu quả và tránh các rủi ro tiềm ẩn.

Chat GPT có khả dụng ở Việt Nam không?

Ứng dụng chat GPT đã có mặt ở Việt Nam
Ứng dụng chat GPT đã có mặt ở Việt Nam

Ngày đầu ra mắt, chatGPT chỉ truy cập và đăng kí tài khoản sử dụng ở một số quốc gia, và Việt Nam không nằm trong danh sách đó, nếu muốn sử dụng chúng ta phải mua tài khoản được đăng kí ở quốc gia khác.

Tuy nhiên vào ngày 02/11/2023, chat GPT đã chính thức có mặt ở Việt Nam, bạn có thể đăng ký và sử dụng miễn phí ChatGPT tại Việt Nam trên nền tảng website chat.openai.com, ứng dụng ChatGPT trên Android, iOS.

Chat GPT vs Google – nên dùng cái nào?

Chat GPT và Google là hai công cụ mạnh mẽ được sử dụng rộng rãi trên toàn thế giới. Tuy nhiên, mỗi công cụ có những ưu điểm và hạn chế riêng biệt, phục vụ cho các mục đích khác nhau. Dưới đây là sự so sánh chi tiết giữa Chat GPT và Google để giúp bạn quyết định nên sử dụng công cụ nào trong từng tình huống cụ thể.

  Chat GPT Google

Mục đích sử dụng

  • Tạo văn bản tự nhiên: Chat GPT được thiết kế để tạo ra văn bản tự nhiên giống như con người. Nó có thể tham gia vào các cuộc trò chuyện, trả lời câu hỏi, viết bài, sáng tác và dịch ngôn ngữ.
  • Hỗ trợ khách hàng: Chat GPT có thể được tích hợp vào các hệ thống hỗ trợ khách hàng để trả lời câu hỏi và giải quyết các vấn đề của người dùng.
  • Giáo dục và học tập: Chat GPT có thể cung cấp thông tin học thuật, giải đáp thắc mắc và giúp học sinh, sinh viên trong việc học tập.
  • Tìm kiếm thông tin: Google là công cụ tìm kiếm thông tin mạnh mẽ nhất thế giới, giúp người dùng tìm kiếm thông tin trên internet một cách nhanh chóng và hiệu quả.
  • Dịch vụ trực tuyến: Google cung cấp nhiều dịch vụ trực tuyến khác nhau như Gmail, Google Docs, Google Drive, Google Maps và YouTube.
  • Quảng cáo và kinh doanh: Google Ads và Google Analytics là công cụ quan trọng giúp doanh nghiệp quảng cáo sản phẩm và phân tích dữ liệu khách hàng.
Cách thức hoạt động
  • Xử lý ngôn ngữ tự nhiên (NLP): Sử dụng mô hình học máy và kiến trúc Transformer để hiểu và tạo ra văn bản tự nhiên dựa trên ngữ cảnh của câu hỏi hoặc yêu cầu.
  • Tương tác theo ngữ cảnh: Có khả năng duy trì ngữ cảnh trong cuộc trò chuyện, giúp phản hồi một cách mạch lạc và logic.
  • Thu thập và lập chỉ mục dữ liệu: Sử dụng các thuật toán tìm kiếm để thu thập, lập chỉ mục và xếp hạng hàng tỷ trang web trên internet.
  • Cung cấp kết quả tìm kiếm: Trả về danh sách các liên kết web liên quan đến từ khóa mà người dùng tìm kiếm, thường kèm theo các đoạn trích dẫn và thông tin bổ sung.
Ưu điểm
  • Tương tác tự nhiên: Có khả năng tạo ra văn bản tự nhiên và tham gia vào các cuộc trò chuyện phức tạp.
  • Linh hoạt: Ứng dụng trong nhiều lĩnh vực khác nhau từ hỗ trợ khách hàng đến sáng tác nghệ thuật.
  • Không yêu cầu từ khóa chính xác: Có thể hiểu và phản hồi dựa trên ngữ cảnh mà không cần từ khóa chính xác.
  • Tìm kiếm thông tin nhanh chóng: Có thể tìm kiếm thông tin từ hàng tỷ trang web chỉ trong vài giây.
  • Kiến thức cập nhật: Kết quả tìm kiếm thường xuyên được cập nhật, đảm bảo người dùng nhận được thông tin mới nhất.
  • Nhiều dịch vụ hỗ trợ: Cung cấp nhiều dịch vụ trực tuyến hữu ích cho cả cá nhân và doanh nghiệp.
Hạn chế
  • Thiếu kiến thức cập nhật: Kiến thức bị giới hạn trong phạm vi dữ liệu huấn luyện và không thể cập nhật theo thời gian thực.
  • Chi phí sử dụng cao: Việc sử dụng mô hình lớn như GPT-3 hoặc GPT-4 có thể tốn kém, đặc biệt khi sử dụng API
  • Phụ thuộc vào từ khóa: Cần sử dụng từ khóa chính xác để nhận được kết quả tìm kiếm phù hợp.
  • Không tương tác theo ngữ cảnh: Không thể duy trì ngữ cảnh cuộc trò chuyện và cung cấp phản hồi như con người.

 

Cập nhật và chỉnh sửa từ bài viết của tác giả: Kiên Nguyễn

Xem thêm:

Tìm kiếm việc làm IT mới nhất tại TopDev!

 

Hướng dẫn kết nối PHP với SQL Server

kết nối php với sql server

Kết nối hệ cơ sở dữ liệu với hệ thống backend là điều bắt buộc phải làm trước khi viết API hoặc thực hiện một số thao tác liên quan tới hệ cơ sở dữ liệu, bài viết này mình sẽ đi từng bước giúp anh em kết nối PHP với SQL Server ở local.

1. Cài đặt SQL Server

Kết nối php với SQL server sẽ đi qua 2 bước, anh em cứ từ từ nha. Không có gì nóng vội, ta cứ cài đặt đã. Đầu tiên, anh em truy cập trang web của microsoft về SQL Server tại link này. Kéo xuống bên dưới chỗ phía cho developer.

Sau khi đã tải về file exe để cài đặt, anh em double click lên. Mở ra trình cài đặt của SQL server

  Thói quen viết code an toàn trong khi xây dựng ứng dụng PHP

Ở bước lựa chọn có 3 lựa chọn cho anh em cài đặt SQL Server

  • 1. Basic: cài một phát xong luôn với tất cả thiết lập đều là thiết lập mặc định (khuyên dùng nếu không có gì đặc biệt)
  • 2. Custom: Cho phép custom một số thiết lập default ban đầu
  • 3. Download media: Tải về trước và cài đặt sau, tiết kiệm thời gian sau không cần phải tải nữa.

Không có gì thì anh em cứ chọn basic rồi next. Tới trình cài đặt.

Có thời gian thì đọc thêm license terms rồi next nha.

kết nối php với sql server

1 là đường dẫn mặc định cài SQL server, ấn vào 2 browser nếu anh em muốn thiết lập đường dẫn khác.

Xem thêm tuyển dụng PHP lương cao trên TopDev

2. Mở extension kết nối Php với SQL server

Để mở kết nối Php với SQL server, anh em cần chỉnh sửa file php.ini. File này mặc định sẽ comment một số extension kết nối tới hệ cơ sở dữ liệu

Anh em cài bản php nào sẽ mở kết nối tới bản php đó theo như đường dẫn dưới đây

kết nối php với sql server

Nếu anh em dùng Php XAMPP thì có thể đi thẳng tới php.ini thông qua lựa chọn dưới đây.

kết nối php với sql server

Sau khi đã đi tới thư mục có php.ini, anh em mở file lên và tìm tới dòng (trên windows)

extension=php_sqlsrv_72_ts.dll

Trên linux thì anh em tìm tới dòng này

extension=php_sqlsrv_72_nts.so

Sau khi đã mở comment các dòng này. Anh em tìm tới pdo, để PDO_SQLSRV có thể hoạt động, ta cần mở thêm pdo. Mở thêm comment của dòng này.

extension=php_pdo.dll

Trên linux

extension=pdo_sqlsrv.so

  Mẹo tối ưu câu lệnh truy vấn (query) SQL

3. Code PHP kết nối với SQL server.

Sau khi đã mở extension php.ini, anh em lưu lại, nếu cần có thể start lại XAMPP. Lúc này anh em đã sẵn sàng để kết nối PHP với SQL server.

Trước khi làm gì với Database đều cần phải mở kết nối. Đoạn code dưới đây giúp mở kết nối từ Php

 function OpenConnection()
    {
        $serverName = "tcp:myserver.database.windows.net,1433";
        $connectionOptions = array("Database"=>"AdventureWorks",
            "Uid"=>"MyUser", "PWD"=>"MyPassword");
        $conn = sqlsrv_connect($serverName, $connectionOptions);
        if($conn == false)
            die(FormatErrors(sqlsrv_errors()));

        return $conn;
    }

Phần serverName nếu anh em sử dụng local thì nó là localhost. Phần connectionOptions là các thông tin liên quan tới DB, Uid (tài khoản) và mật khẩu. Anh em chú ý là lưu ở array.

Sau khi đã mở kết nối tới database, anh em có thể thực hiện các câu truy vấn.

   function ReadData()
    {
        try
        {
            $conn = OpenConnection();
            $tsql = "SELECT [CompanyName] FROM SalesLT.Customer";
            $getProducts = sqlsrv_query($conn, $tsql);
            if ($getProducts == FALSE)
                die(FormatErrors(sqlsrv_errors()));
            $productCount = 0;
            while($row = sqlsrv_fetch_array($getProducts, SQLSRV_FETCH_ASSOC))
            {
                echo($row['CompanyName']);
                echo("<br/>");
                $productCount++;
            }
            sqlsrv_free_stmt($getProducts);
            sqlsrv_close($conn);
        }
        catch(Exception $e)
        {
            echo("Error!");
        }
    }

Câu truy vấn này thực hiện lấy companyName từ bảng Customer.

4. Tham khảo

Cảm ơn anh em đã đón đọc – Mong sẽ bổ ích cho anh em – Happy coding!

Tác giả: Kiên Nguyễn

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

Truy cập ngay việc làm IT đãi ngộ tốt trên TopDev

Các vai trò trong một team phát triển phần mềm

vai trò team phát triển phần mềm

Bài viết được sự cho phép của tác giả Phạm Bình

Chào các bạn,

Có phải để tạo ra một sản phẩm phần mềm thì chỉ cần các bạn developer thôi là đủ không? Câu trả lời là vừa có … vừa không. Vì một team bao gồm những ai thì phụ thuộc rất nhiều vào quy mô, cũng như tốc tốc độ phát triển của dự án đó.

Để các bạn hiểu rõ về các vai trò trong một team phát triển sản phẩm, thì mình sẽ mô tả quá trình thay đổi của một team dự án, từ lúc nó bé xíu, cho tới lúc đã có tương đối đủ thành viên, như vậy bạn sẽ dễ hiểu hơn về vai trò của từng thành viên trong team.

Lưu ý: 
Không phải tất cả các dự án phần mềm đều có sự phát triển giống như trong bài viết này. Mình chỉ lấy ví dụ để các bạn dễ hình dung ra vai trò của từng bộ phận trong team hơn thôi nhé.

Vai trò của Developer

Developer là dân kỹ thuật chính hiệu, kỹ năng mạnh nhất của họ chính là viết code để tạo ra phần mềm.

Thời điểm này, dự án chỉ bao gồm 3 developer. Họ có chung ý tưởng, và quyết định hợp tác với nhau để cùng biến ý tưởng đó thành một sản phẩm thực tế. Họ phác thảo ý tưởng ra giấy, rồi phân chia công việc. Họ cũng bầu ra một leader (gọi là developer leader) để chịu trách nhiệm điều phối, và đảm bảo chất lượng sản phẩm.

Giai đoạn này, công việc chủ yếu là code, đôi khi phát sinh một số công việc khác nhưng không nhiều, cũng không quá khó, họ vẫn có thể tự chia nhau hoàn thành.

Sau một thời gian phát triển, họ đã có phiên bản đầu tiên, sẵn sàng ra mắt khách hàng, và hy vọng là sẽ có nhiều khách hàng sử dụng.

  Tech Lead là gì? Nhiệm vụ, vai trò của Tech Lead trong team

Vai trò của Product Owner (PO)

Sau khi ra mắt sản phẩm, cũng có một vài bug, nhưng nó không nghiêm trọng lắm, các developer vẫn làm việc bình thường, và sản phẩm cũng đã “nhen nhúm” có khách hàng sử dụng. Tuy nhiên, ý tưởng ban đầu của họ đã được khai thác hết, tất cả các tính năng cần thiết đều đã xuất hiện trên sản phẩm, họ bắt đầu cạn ý tưởng và không biết phải làm gì tiếp theo.

Các developer cũng bắt đầu ý thức được rằng, việc đưa ra một ý tưởng thì không khó, nhưng đưa ra một ý tưởng thiết thực thì lại rất khó. Trong khi họ là các developer, nên việc tìm ra một ý tưởng như vậy không phải là điều dễ dàng.

Họ bắt đầu đi tìm kiếm một product owner – người sẽ chịu trách nhiệm tìm ra các ý tưởng, sao cho các ý tưởng đó là hay, là thiết thực, vừa đem lại giá trị cho khách hàng, lại vừa đem lại lợi ích cho sản phẩm (gọi chung là tối ưu hóa sản phẩm).

Có Product Owner, các ý tưởng hay liên tục được đưa ra, nhờ đó mà sản phẩm phát triển nhanh hơn rất nhiều so với trước kia – cả về mặt tính năng lẫn số lượng khách hàng sử dụng.

Tham khảo Job FrontEnd HOT trên TopDev!

Vai trò của Business Analyst (BA)

Ban đầu, PO và các developer phối hợp với nhau rất tốt, công việc rất trôi chảy, suôn sẻ. Nhưng càng về sau, thì càng xuất hiện nhiều vấn đề, chủ yếu xoay quanh:

  • Sản phẩm đã trở nên khá phức tạp, và không một ai trong team có thể nhớ rõ chính xác nó hoạt động như thế nào. Nên các ý tưởng của PO khi đưa ra tuy rất phù hợp về mặt hướng đi, nhưng lại xung đột nhiều với các tính năng đã có.
  • Các ý tưởng mà PO đưa ra ngày càng phức tạp, và các developers sẽ không thể “nghe một lần rồi hiểu ngay”, nên họ thường xuyên code “lệch” so với ý tưởng của PO.
  • Các developer trễ deadline, do việc việc triển khai ý tưởng mới phải gánh thêm việc giải quyết xung đột với tính năng cũ, trong khi đó, không ai biết chính việc sửa tính năng cũ tốn bao nhiêu thời gian, có thể rất nhiều, hoặc rất ít.

Vì vậy, cả team quyết định sẽ phân tích kỹ lưỡng, đồng thời mô tả sử thay đổi của sản phẩm ra văn bản, coi nó là tài liệu mô tả yêu cầu trước khi code. Tuy nhiên, không biết nên để công việc này cho ai vì:

  • Vai trò của PO là người đi tìm các ý tưởng, và chứng minh là đó là ý tưởng thiết thực mà sản phẩm nên có. Đây là công việc cực kỳ quan trọng, PO không nên tốn thời gian vào việc mô tả chi tiết yêu cầu.
  • Nếu PO không làm công việc trên, thì developer lại càng không. Vì trò của developer chủ yếu là về mặt công nghệ – đây cũng là một công việc rất quan trọng, không nên để developer tốn thời gian vào việc viết mô tả chi tiết yêu cầu. Mặt khác, chính các developer sẽ là người chuyển yêu cầu thành code, nếu để họ để họ viết yêu cầu, thì không khác gì bảo họ viết hai lần, một lần bằng ngôn ngữ tự nhiên, và một lần viết bằng code.

Vì thế, team quyết định tìm thêm một bạn làm về business analyst (BA) – Chuyên viên phân tích nghiệp vụ.

BA sẽ đảm nhiệm phân tích ý tưởng ban đầu của PO thành các yêu cầu cụ thể trên sản phẩm (như sản phẩm cần thêm, sửa, xóa tính năng gì), đồng thời văn bản hóa các yêu cầu đó thành tài liệu SRS (*), trực tiếp giải thích cho các developer hiểu. Nếu yêu cầu tính năng quá khó để miêu tả bằng văn bản, thì BA sẽ vẽ các bản mockup (*)prototype (*) để dễ hình dung hơn.

  Team Leader là gì? Những kỹ năng nào mà một Team Leader cần có?

Vai trò của UI/UX Designer

Kể từ khi có BA, công việc lại trở nên ổn định, deadline đã chính xác hơn trước, PO cũng tự tin đưa khi đưa ý tưởng mới mà không lo các developer than “Ui nó ảnh hưởng nhiều lắm, code phức tạp lắm“. Số lượng tính năng mới, và khách hàng vẫn liên tục tăng lên.

Về mặt team phát triển, cơ bản là không có vấn đề gì, nhưng vấn đề lúc này lại đến từ khía khách hàng. Ngoại trừ việc sản phẩm có một vài lỗi nhỏ, thì còn một vấn đề lớn nữa đó là “các tính năng quá khó để sử dụng”. Khách hàng đã tiếp cận với sản phẩm, nhưng rồi lại lặng lẽ đi ra vì … không biết dùng như thế nào.

Cả team từng cho rằng BA sẽ cần phân tích thêm cả việc sản phẩm nên thể hiện như thế nào với khách hàng, nhưng không, BA đang rất bận rộn với việc phân tích yêu cầu của PO. Mặt khác, BA sẽ tập trung trả lời cho câu hỏi “sản phẩm sẽ cần thay đổi những gì về mặt tính năng?“, chứ ít khi trả lời câu hỏi “sản phẩm phải làm thế nào để đẹp hơn và dễ dùng hơn“.

Vì thế, để sản phẩm thu hút hơn, và đem lại trải nghiệm tốt hơn với khách hàng, team đã tìm thêm một bạn UI/UX designer. Bạn này sẽ đảm nhiệm việc thiết kế giao diện (màu sắc, bố cục), và các luồng sử dụng trên sản phẩm, sao cho thân thiết, đẹp mắt, dễ tiếp cận và dễ dàng sử dụng với khách hàng, ngay cả khi họ là người mới.

Sau khi có UI/UX designer, sản phẩm như được lột xác. Bố cục rõ ràng, màu sắc hài hòa, cùng với một tính năng, trước kia khách hàng phải tốn 10 click, thì giờ chỉ tốn 3 click. Tóm lại trải nghiệm được tăng lên đáng kể.

Vai trò của Tester

Số lượng khách hàng sử dụng bây giờ đã rất nhiều, và các bug ngày trước được coi là nhỏ, thì bây giờ sẽ được coi là lớn, các bug ngày trước được coi là lớn, thì bây giờ không được phép xuất hiện trên sản phẩm.

Mặc dù các developer không cố tình tạo ra bug, họ cũng đã kiểm tra lại kỹ càng các tính năng trước khi đưa cho khách hàng sử dụng. Nhưng suy cho cùng, họ vẫn là con người, không thể tránh được thiếu sót, và các bug “không thể chấp nhận được” vẫn đôi lúc xuất hiện.

Vì vậy, team quyết định tìm thêm một bạn tester – người sẽ đảm bảo chất lượng sản phẩm trước khi nó tới tay khách hàng.

Từ khi có tester, các đợt cập nhật phiên bản mới đều được kiểm tra kỹ càng rồi mới đưa đến tay khách hàng, các bug “không thể chấp nhận được” đã không còn xuất hiện nữa.

Vai trò của team Manager

Điểm lại một chút, lúc này team đã có khá nhiều vai trò: developer, PO, UI/UX designer, tester. Và các bộ phận này này đang gặp một số vấn đề như sau:

  • Không biết cách phối hợp với nhau thế nào cho hiệu quả.
  • Lúc thì bộ phận này bận SML, còn bộ phận kia thì rảnh và ngược lại.
  • Đôi khi có các công việc “không tên”, thì không ai muốn nhận nó về mình, ai có lý do từ chối hợp lý.

Hiện tại thì team vẫn đang có một leader (chính là bạn developer được bầu ra ở level 1). Nhưng suy cho cùng đó là kiêm nhiệm vị trí, và bạn đó vẫn đang làm việc ở vị trí developer nhiều hơn.

Để team hoạt động hiệu quả hơn, team quyết định để bạn developer leader kia lên làm team manager – bạn này chịu trách nhiệm điều phối công việc trong team, cân bằng khối lượng công việc giữa các bộ phận, tìm ra quy trình phù hợp và áp dụng vào team.

Trong thực tế, nếu team không bầu được ai, thì có thể tuyển người mới. Tuy nhiên vị trí này ít khi được tuyển mới mà thường được cất nhắc từ người trong team hiện tại – nhất là với các team nhỏ.

Kể từ khi có team manager, công việc lại trôi chảy hơn nhiều, mọi người đi làm cảm thấy vui vẻ, không còn lo quá nhiều hoặc quá ít việc. Các bộ phận cũng phối hợp hiệu quả hơn do có quy trình làm việc rõ ràng.

Tạm kết câu chuyện của team tới đây, vì nếu mình viết tiếp thì sẽ rất dài, thậm chí không có hồi kết. Cũng như mình chia sẻ ở đầu bài viết, quy mô của dự án sẽ quyết định các vai trò trong team, tuy nhiên, đều tuân theo một quy luật là “nghẽn ở đâu, thì giãn nở ở đó”. Khi dự án phát triển tới mức độ được coi là lớn, thì bất kỳ một công việc nhỏ nào trước kia đều có thể trở nên cực kỳ phức tạp, và cần một bộ phận chuyên trách để xử lý – đó là lúc team cần bổ sung thêm một vai trò mới.

Ngoài các vai trò đã được nếu phía trên, thì dưới đây mình bổ sung thêm một số vai trò điển hình khác:

  • Vai trò của DevOps Developer: Chịu trách nhiệm về hạ tầng sản phẩm (server, mạng,…), giúp sản phẩm chạy ổn định với khách hàng.
  • Vai trò của Security: Đảm bảo hệ thống an toàn, không bị xâm nhập trái phép.
  • Vai trò của Software Architecture: Thiết kế kiến trúc của phần mềm, để sản phẩm có tính mở rộng cao, dễ dàng thay đổi, và ít để lại nợ công nghệ
  • SRS: Viết tắt của Software Requirement Specification, được dịch ra tiếng việt là Tài liệu đặc tả yêu cầu. SRS là tài liệu được sử dụng để mô tả chi tiết các yêu cầu chức năng và phi chức năng của hệ thống.
  • Prototype, mockup: Ám chỉ các bản vẽ mô tả về sản phẩm.

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

Những bài viết liên quan:

Xem thêm Việc làm IT hấp dẫn trên TopDev

Top 7 câu hỏi phỏng vấn Backend Developer

phỏng vấn backend developer

Backend Developer chưa bao giờ hết hot là vị trí được tuyển dụng nhiều và trả lương cao chót vót, phỏng vấn Backend Developer cũng không hề dễ. Nói thì không phải troll chứ Frontend Developer luôn tạo ra những thứ hoa mỹ bóng bẩy. Ngược lại, Backend Developer luôn gồng gánh phần nặng nhất, chịu trách nhiệm cho hệ thống hoạt động ổn định.

Mà làm source code đẹp hay không ai biết, chỉ toàn meme chế backend là một đống hỗ độn, che dấu đằng sau cái vẻ đẹp lồng lộn của Frontend.

backend

Quả không điêu khi Backend Developer đòi hỏi một lượng kiến thức khổng lồ khi tham gia phỏng vấn. Mà có phải là code không đẹp đâu. Tí nữa rồi anh em sẽ rõ thông qua 1,2 câu hỏi về clean architecture. Code đẹp, structure đẹp cho bọn meme nó bớt chế.

Kiến thức cần có ở Backend Developer trải dài từ hệ cơ sở dữ liệu qua tới kinh nghiệm làm việc với API. Ở mức độ cao hơn, Backend Developer có kinh nghiệm còn cần có giải pháp cho những vấn đề hóc búa xảy ra trong quá trình làm việc.

Những kinh nghiệm này là kinh nghiệm thực tế, tức là trong quá trình làm việc xảy ra những vấn đề hóc búa ở phía Backend, tìm tòi xử lý các vấn đề. Tích luỹ thành kinh nghiệm.

  Lập trình Backend là gì? Backend Developer cần các kỹ năng nào?
  Mô tả công việc - Vị trí lập trình Backend

1. CAP Theorem là gì?

Bắt đầu danh sách câu hỏi phỏng vấn Backend Developer bằng một câu hỏi lý thuyết. Bắt đầu bằng câu hỏi này bởi vì đi thẳng vào từng ngôn ngữ lập trình thì sẽ có series phỏng vấn Java, Python sau cho anh em thoải mái focus vào từng ngôn ngữ.

Quay lại với câu hỏi đầu tiên, CAP Theorem là định lý ban đầu được tạo ra cho hệ thống phân tán (distributed computer system) bởi Eric Brewer. C,A,P là viết tắt của 3 yếu tố cần có. Kiến thức này khá là quan trọng với Backend Developer, người thường xuyên làm việc với hệ thống phân tán.

Bắt đầu với C – Consistency (tính nhất quán). Tính nhất quán ở đây mang ý nghĩ client luôn thấy cùng một data. Bất kể client đang được liên kết tới node nào. Để được vậy, phải thực hiện đồng bộ dữ liệu cho tất cả. Lặp lại cho tất cả các nốt.

Thứ hai là A – Availability – tính sẵn sàng. Tính sẵn sàng được hiểu rằng bất cứ khi nào client gửi request. Họ đều sẽ nhận được response. Thậm chí một hoặc vài node bị down.

Thứ ba là P (Partition tolerance). Phía bên hệ thống phân tán, lúc thiết kế phải đảm bảo sao cho khi một số node die, cả hệ thống vẫn hoạt động bình thường.

Nhiều tin tuyển dụng Backend lương cao trên TopDev

Phỏng vấn backend developer

Về câu hỏi này anh em có thể tham khảo qua bài viết này. Đây là câu hỏi lý thuyết cơ bản cho anh em học vừa mới ra trường hoặc đã nhiều năm kinh nghiệm đều cần phải nắm vững. CAP theorem tuy đơn giản nhưng là tiêu chuẩn cho tất cả các hệ thống lớn ở Amazon, Google. Anh em chú ý.

2. Tại sao bạn lại chọn kiến trúc micro services?

Câu hỏi thứ hai khi phỏng vấn Backend Developer là kiến trúc phổ biến đối với các hệ thống Microservices. Nhưng tại sao và lúc nào ta nên lựa chọn microservices?

Trả lời cho câu hỏi này, trước tiên là kiến trúc micro services có rất nhiều ưu điểm. Một số câu trả lời cho anh em có thể tham khảo

  • Microservices can adapt easily to other frameworks or technologies. – Microservices có thể dễ dàng thích ứng với các framework hoặc công nghệ khác.
  • Failure of a single process does not affect the entire system. – Việc một microservices bị fail có thể không ảnh hưởng tới toàn bộ hệ thống.
  • Provides support to big enterprises as well as small teams. – Microservices phù hợp cho cả doanh nghiệp lớn và các đội nhóm nhỏ hơn.
  • Can be deployed independently and in relatively less time – Có thể triển khai độc lập trong một thời gian ngắn hơn các kiến trúc thông thường.

Lý thuyết là vậy nhưng trong quá trình phỏng vấn, anh em có thể nêu thêm các ví dụ để làm rõ ý của mình. Ví dụ như deploy độc lập dùng docker hay kubenetes?. Trường hợp một microservices down tại sao lại không ảnh hưởng tới các services khác?.

3. SQL Injection là gì?

Câu hỏi này tập trung chủ yếu vào Web Security. Làm backend mà không biết hoặc không chú trọng tới security thì nguy hiểm lắm. Khái niệm và những lỗ hổng đã được phát hiện trước đây nếu anh em biết thêm thì quá tuyệt.

Chính vì vậy, câu hỏi thứ 3 trong bộ câu hỏi phỏng vấn backend developer là câu hỏi liên quan tới một lỗ hổng đã phát hiện từ lâu SQL Injection.

SQL Injection

Trả lời cho câu hỏi này anh em cần biết bản chất của Injection (chèn vào, tiêm chích vào). Bản chất phương thức tấn công này nhắm vào việc chèn các đoạn mã SQL không được phép. Thực hiện các câu SQL độc hại thông qua lỗ hổng. Biết tất nhiên cần có cách phòng tránh.

  • Prepared statements with parameterized queries – Các truy vấn cần được chuẩn hoá.
  • Input validation – blacklist validation and whitelist validation – Thực hiện validation chặt chẽ đầu vào
  • Principle of least privilege – Application accounts shouldn’t assign DBA or admin type access onto the database server. – Đặt quyền tối thiểu, tài khoản ứng dụng tất nhiên không thể có quyền truy cập vào dữ liệu nhạy cảm.

4. Điểm yếu của REST web services là gì?

Câu hỏi thứ 4 trong bộ câu hỏi phỏng vấn backend developer là câu hỏi liên quan tới API design. Để trả lời được câu hỏi này. Anh em cần có kinh nghiệm ở REST. Không những chỉ REST mà còn ở các kiến trúc API khác.

Khi đã có kinh nghiệm kha khá hoặc có cơ hội khác tiếp xúc với GraphQL chẳng hạn. Anh em sẽ có cái nhìn rõ hơn về điểm yếu của REST web services.

Để trả lời cho câu hỏi này, anh em có thể liệt kê ra một số nhược điểm của REST bao gồm:

  • Trường hợp không có API contract giữa client và server. Nên REST cần có tài liệu đi kèm để giải thích cụ thể những gì được viết hoặc thực hiện ở API.
  • REST web services hoạt động dựa trên HTTP nên không thể có các request bất đồng bộ (asynchronous)
  • Với kiến trúc REST, session can’t be maintained (không được duy trì lâu).

5. Giải thích API Gateway Pattern

Với backend developer ở trình độ cao, bộ câu hỏi phỏng vấn không thể không có các câu hỏi liên quan tới Software Architecture. Gateway là một trong các câu hỏi đó, trong bộ các câu hỏi phỏng vấn backend developer.

Để trả lời câu hỏi này, anh em có thể tham khảo:

An API Gateway is a server that is the single entry point into the system. It is similar to the Facade pattern from object‑oriented design. The API Gateway encapsulates the internal system architecture and provides an API that is tailored to each client. It might have other responsibilities such as authentication, monitoring, load balancing, caching, request shaping and management, and static response handling. API gateway là server và nó là điểm vào duy nhất của hệ thống. Nó tương tự như Facade Pattern trong lập trình hướng đối tượng. API Gateway đóng gói kiến trúc nội bộ và cung cấp API phù hợp cho từng client. Ngoài ra API Gateway có thể có các chức năng khác như xác thực, giám sát, cân bằng tải, cache đóng gói và quản lý các response.

API Gateway

Kieblog có bài viết cụ thể và giải thích rõ ràng hơn về API gateway ở đây. Anh em có thể đọc để hiểu sâu hơn

Tìm việc làm Backend Intern HCM trên TopDev ngay!

6. B-tree index trong hệ cơ sở dữ liệu hoạt động như thế nào?

Câu hỏi thứ 6 trong bộ câu hỏi phỏng vấn backend developer liên quan tới hệ cơ sở dữ liệu (database). Tất nhiên rồi, đã làm backend mà không biết hoặc không một lần đụng tới index thì quả thật là hết sức vô lý.

Đối với anh em có nhiều thời gian làm việc với database, với cơ sở dữ liệu lớn hoặc ít nhất là các task liên quan tới tối ưu SQL sẽ biết tới index. Tuy nhiên biết là một chuyện, nhưng nó hoạt động ra sao lại đòi hỏi thời gian để tìm tòi.

Trả lời cho câu hỏi này anh em cần biết về cây nhị phân (binary tree). B-tree tốt hơn cây nhị phân ở chỗ dữ liệu được lưu trữ trên đĩa. Việc truy cập để lấy dữ liệu trên đĩa thực sự chậm hơn so với bộ nhớ (memory). B-tree được hình dung như việc lấy hoặc tìm kiếm thông tin một cuốn sách ở trong thư viện.

Bản thân cuốn sách đó đã được đánh dấu hoặc sắp xếp các câu hỏi bắt đầu bằng A,B,C và D,E,F. Nếu cần D, ta sẽ bỏ qua một khoảng tương đối dài của A,B,C. Việc này giúp tối ưu hiệu quả tìm kiếm. B-tree cần tới logB N

7. Sự khác biệt giữa Acceptance Test và Functional Test?

Sẽ thật sự là thiếu sót to lớn nếu bỏ qua Software Testing khi phỏng vấn Backend Developer. Testing từ lâu đã là một kỹ năng cần có của mọi lập trình viên. Bất kể Front hay là Back, tất cả đều yêu cầu có kiến thức về Software Testing. Testing là công đoạn không thể thiếu giúp tạo ra một sản phẩm phần mềm tốt.

Trả lời cho câu hỏi này:

Functional testing: This is a verification activity; did we build a correctly working product? Does the software meet the business requirements? A functional test verifies that the product actually works as you (the developer) think it does. Test tính năng; Đây là hoạt động xác minh. Thông thường với các câu hỏi, chúng tôi đã xây dựng một sản phẩm chính xác chưa?. Phần mềm có đáp ứng được yêu cầu nghiệp vụ không? Sản phẩm đã đáp ứng được yêu cầu thực tế hay chỉ như người lập trình viên nghĩ?

Tiếp đến là kiểm thử chấp nhận (khác với kiểm tra tính năng)

Acceptance testing: This is a validation activity; did we build the right thing? Is this what the customer really needs? Acceptance tests verify the product actually solves the problem it was made to solve. This can best be done by the user (customer), for instance performing his/her tasks that the software assists with. Test xác nhận. Thường bắt đầu với các câu hỏi, thứ chúng ta xây dựng ra đã đúng chưa?. Đây có phải thật sự là những gì khách hàng cần tới?. Acceptance testing xác định rằng sản phẩm thực sử giải quyết được vấn đề. Việc này tốt nhất nên được thực hiện bởi khách hàng (các tác vụ của họ được phần mềm hỗ trợ)

8. Tham khảo thêm câu hỏi khác phỏng vấn backend developer

Qua bài viết này, anh em backend phần nào cũng hiểu ra rằng phỏng vấn backend developer không hề đơn giản. Trải qua nhiều các topics, các nội dung cần nắm, các kiến thức cần tìm hiểu thêm.

Mong rằng một số câu hỏi liên quan tới API Design, Software Architecture và Software Testing phần nào giúp đỡ anh em trong các đợt phỏng vấn.

Cảm ơn anh em đã đọc bài – Thank you for your time – Happy coding!

Tác giả: Kiên Nguyễn

Bạn có thể quan tâm:

Tìm việc làm IT lương cao, đãi ngộ hấp dẫn trên TopDev!

Scratch là gì? Lập trình Scratch có gì thú vị?

Lập trình Scratch

Lập trình Scratch từ lâu đã là ngôn ngữ lập trình phổ biến cho học sinh, sinh viên và các em nhỏ. Với Scratch, việc lập trình từ ban đầu được gán cho cái mác khó nhằn, khó hiểu, đơn điệu và tẻ nhạt bỗng trở thành ngôn ngữ lập trình được các em nhỏ không cần cha mẹ nói cũng vào học.

Quả không sai, cách thức tiếp cận là tất cả. Vậy điều gì làm nên sức hút của Scratch. Ví dụ tạo project với scratch như thế nào? Tất cả sẽ có trong bài viết này.

1. Lập tình Scratch là gì?

Bắt đầu với định nghĩa về lập trình Scratch, bài viết này dành cho học sinh sinh viên nên định nghĩa cũng được giải thích rõ ràng dễ hiểu hơn.

Scratch is a visual programming language that allows students to create their own interactive stories, games and animations Scratch là ngôn ngữ lập trình trực quan cho phép học sinh tạo ra các câu chuyện của họ, trò chơi và các hoạt hình tương tác của bản thân mình.

Lập trình scratch vô cùng thú vị
Nghe thôi đã thấy hấp dẫn rồi. Với lập trình Scratch, học sinh được học cách thiết kế, suy nghĩ sáng tạo, lập luận có hệ thống và cùng nhau làm việc để tạo ra dự án riêng. Scratch được tạo ra bởi nhóm Lifelong Kindergarten tại phòng thí nghiệm của MIT.

Các bạn có thể tải miễn phí Scratch tại https://scratch.mit.edu/.

  Cách tự học lập trình tốt nhất

2. Từng bước với lập trình Scratch

Để bắt đầu với lập trình scratch, truy cập trang chủ và ấn vào start creating. Các bạn cũng có thể signup (tạo tài khoản để lưu trữ các project của cá nhân mình).

lập trình scratch
Truy cập trang chủ và ấn vào Start Creating
Scratch sẽ chuyển hướng ta tới trang bắt đầu để lập trình với Scratch.

Lập trình scratch
Giao diện sau khi đã khởi tạo project tại Scratch
Trước khi bắt đầu, các bạn nên xem qua video hướng dẫn một số thao tác cơ bản và thành phần của scratch.

Lập trình scratch
Video hướng dẫn cụ thể và rõ ràng
Lập trình scratch chú trọng tới các đối tượng và lập trình animations cho các đối tượng. Đối tượng ban đầu và mặc định là chú mèo scratch. Để thêm các đối tượng khác. Ấn vào góc bên dưới bên phải màn hình.

Tham khảo việc làm Front-end hấp dẫn trên TopDev

Lập trình scratch
Góc dưới bên phải cho phép thêm nhiều hơn các đối tượng.

Sau khi đã có các đối tượng, bước tiếp theo là các thao tác, âm thanh được tuỳ chọn để lập trình. Việc lựa chọn đúng các thao tác giúp đối tượng trở nên sinh động hơn.

  50 keywords mà mọi lập trình viên java nên biết

Scratch hiện tại hỗ trợ code (trực quan không code), costumes (tuỳ chỉnh cao hơn) và Sounds (phần âm thanh cho các đối tượng)

Lập trình scratch

2.1 Các đối tượng trong Scratch

Về mặt code, hiện tại scratch hỗ trợ danh sách sau:

  • Motion (di chuyển 10 bước, xoay ngang dọc, di chuyển tới vị trí có toạ độ x và y)
  • Looks (xin chào, thay đổi kích thước, ẩn (hide), hiện (show), …
  • Sounds (âm thanh bắt đầu tới lúc kết thúc, thay đổi volume tăng hoặc giảm, …)
  • Events (khi ấn vào thì sao?, khi nhận được tin nhắn, …)
  • Control (kiểm soát, các câu lệnh cơ bản của lập trình, nếu a thì b, nếu như thế này thì thế kia, …)
  • Sensing (các sự kiện của chuột, các sự kiện chờ cho câu hỏi, câu trả lời, …)
  • Operators (các phép cộng trừ, so sánh, tính toán độ dài, …)
  • Variables (các biến tuỳ chỉnh, thiết lập dữ liệu, thay đổi các biến, …)

lập trình scratch
Các đối tượng được hỗ trợ trong khối Variables

3. Tuỳ biến, tuỳ chỉnh cao hơn với lập trình Scratch

Sau khi đã hiểu rõ và thực hành một số thành phần code được hỗ trợ bởi Scratch. Nếu các animations và lập trình cần tới tuỳ chỉnh các đối tượng. Việc tuỳ chỉnh đối tượng cho phép làm ra các đoạn code sinh động hơn, phù hợp hơn với yêu cầu.

lập trình scratchMục consumes dành cho các đối tượng tuỳ chỉnh. Cho phép chỉnh sửa màu sắc, hình dạng, kích thước các đối tượng.

Lập trình scratchThay đổi màu sắc quần của đối tượng sang màu tím.

Một thành phần khác giúp cho các video animations được lập trình trở nên tuyệt vời hơn là âm thanh. Âm thanh cũng có thể tuỳ chỉnh ở mục Sounds.

lập trình scratch

Nếu hình ảnh trong bộ sưu tập có sẵn của Scratch không phù hợp hoặc chưa đáp ứng được nhu cầu của bạn. Các bạn có thể tự tải lên các hình ảnh riêng của mình bằng nút nhấn phía bên dưới phải màn hình.

lập trình scratch
Tải lên các hình ảnh cá nhân hoặc tự xây dựng là hoàn toàn khả thi với scratch

4. Các tuỳ chỉnh khác

Scratch giúp tăng tư duy toán tức IQ, kỹ năng giải quyết tình cảm tức EQ, ngôn ngữ, sáng tạo và hợp tác với bạn bè và máy tính. Scratch luôn luôn miễn phí và được thông dịch qua hơn 70 ngôn ngữ. Các bạn có thể lựa chọn ngôn ngữ tiếng việt giúp dễ dàng hơn khi bắt đầu với Scratch

lập trình scratch
Nút nhấn quả địa cầu là khu vực để lựa chọn ngôn ngữ
lập trình scratch
Có sẵn ngôn ngữ tiếng việt giúp dễ dàng hơn khi lập trình với Scratch

Khả năng lập trình máy tính là một phần quan trọng trong học vấn của xã hội ngày nay. Khi mọi người học cách lập trình bằng Scratch, bản thân họ sẽ học được những chiến thuật quan trọng để giải quyết vấn đề, thiết kế các chương trình và truyền đạt những ý tưởng.

Chính vì vậy, không chỉ riêng tập lớp trẻ em, học sinh là nên tiếp thu với lập trình scratch. Người già, các đối tượng khác trong xã hội nếu có điều kiện cũng có thể thử sức, sáng tạo với lập trình scratch

5. Tham khảo thêm

Cảm ơn anh em đã dành thời gian – Thank you for your time to read – Happy coding!

Tác giả: Kiên Nguyễn

Xem thêm:

Xem thêm các việc làm công nghệ hấp dẫn trên TopDev

 

Giới thiệu Aspect Oriented Programming (AOP)

Aspect Oriented Programming

Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh

AOP là gì?

Trong khi xây dựng các chương trình ứng dụng, có rất nhiều những vấn đề liên quan đến phần mềm mà chúng ta cần quan tâm. Chẳng hạn, chúng ta xây dựng một hệ thống đăng ký tạo tài khoản cho một ngân hàng. Ngoài công việc chính cho phép người dùng có thể tạo tài khoản (core concern), hệ thống còn phải đảm bảo các vấn đề khác (cross-cutting concern) như chứng thực người dùng, kiểm tra ràng buộc, quản lý transaction, xử lý ngoại lệ, ghi log, debug, đo hiệu năng của ứng dụng,…

Logger logger = Logger.getLogger(...);
TransactionManager tm = getTransactionManager();
public void addAccount(Account account) {
    logger.info("Creating (" + account + ") Account");
    try {
        tm.beginTransaction();
        db.add(account);
        tm.commit();
    } catch (Exception) {
        tm.rollback();
        logger.error("Account creation failed");
    }
}

Như bạn thấy, logic của chương trình của chúng ta phải làm rất nhiều việc như ghi log, mở/ đóng transaction, xử lý ngoại lệ, … Khi có nhiều phương thức tương tự vậy trong ứng dụng, code chúng ta bị liên kết chặt vào nhau, duplicate code, phân mảnh nhiều nơi, khó khăn khi sửa đổi thay thêm logic mới, … Để giải quyết vấn đề này, chúng ta có thể sử dụng kỹ thuật AOP.

Aspect Oriented Programming

AOP là từ viết tắt của Aspect Oriented Programming, dịch ra tiếng Việt là “phương pháp lập trình hướng khía cạnh”. AOP là một kỹ thuật lập trình cho phép phân tách chương trình thành cách module riêng rẽ, không phụ thuộc nhau. Khi hoạt động, chương trình sẽ kết hợp các module lại để thực hiện các chức năng nhưng khi sửa đổi chức năng thì chỉ cần sửa đổi trên một module cụ thể.

AOP còn được gọi là Aspect Oriented Software Development (AOSD) là một nguyên tắc thiết kế, giúp tách rời các yêu cầu hay các vấn đề được quan tâm (separation of concerns) trong chương trình thành các thành phần độc lập và từ đó tăng tính uyển chuyển cho chương trình. Trong Separation of concerns, người ta cho rằng những vấn đề tương tự nhau nên được giải quyết trong một unit of code. Khi lập trình thủ tục (functional programming), một unit of code là một function/ method, còn trong lập trình hướng đối tượng (OOP) thì unit of code là một class.

  Lập trình hướng đối tượng (OOPs) trong Java

  Javascript Prototype là gì?

aspect orientedprogramming aop in java

Trong AOP, chương trình của chúng ta được chia thành 2 loại concern:

  • Core concern/ Primary concern: là requirement, logic xử lý chính của chương trình.
  • Cross-cutting concern: là những logic xử lý phụ cần được thực hiện của chương trình khi core concern được gọi như security, logging, tracing, monitoring, …

Một số thuật ngữ khác trong AOP:

  • Joinpoint: là một điểm trong chương trình, là những nơi có thể được chèn những cross-cutting concern. Chẳng hạn chúng ta cần ghi log lại sau khi chạy method nào đó thì điểm ngay sau method đó được thực thi gọi là một Jointpoint. Một Jointpoint có thể là một phương thức được gọi, một ngoại lệ được throw ra, hay một field được thay đổi.
  • Pointcut: có nhiều cách để xác định Joinpoint, những cách như thế được gọi là Pointcut. Nó là các biểu thức được sử dụng để kiểm tra nó có khớp với các Jointpoint để xác định xem Advice có cần được thực hiện hay không.
  • Advice: những xử lý phụ (crosscutting concern) được thêm vào xử lý chính (core concern), code để thực hiện các xử lý đó được gọi Advice. Advice được chia thành các loại sau:
    • Before: được thực hiện trước join point.
    • After: được thực hiện sau join point.
    • Around: được thực hiện trước và sau join point.
    • After returning : được thực hiện sau join point hoàn thành một cách bình thường.
    • After throwing : được thực hiện sau khi join point được kết thúc bằng một Exception.
  • Aspect: tương tự như một Java class. Một Aspect đóng gói toàn bộ cross-cutting concern và có thể chứa các JointPoint, PointCut, Advice.
  • Target Object : là những đối tượng mà advice được áp dụng.

Xem thêm việc làm JavaScript hấp dẫn lương cao tại TopDev!

Một vài cross-cutting concern thường thấy trong ứng dụng:

  • Logging
  • Monitor
  • Access control
  • Error handling
  • Transaction management
  • Session management
  • Input/output validation

Weaving là gì?

Weaving là gì?

Về cơ bản Weaving (đan/ dệt) là quá trình liên kết các thành phần aspect và non-aspect của một chương trình để tạo ra đầu ra mong muốn.

Có một vài cách khác nhau giữa các hệ thống AOP về cách tạo ra Weaving. Có thể chia làm các loại Weaving: Compile-time weaving (static weaving), Load-Time Weaving và Run-time weaving (dynamic weaving).

  • Compile-time weaving :
    • Pre-Compile Weaving : sử dụng bộ tiền xử lý (pre-processor) để combine code của aspect và code non-aspect lại với nhau trước khi code được biên dịch thành byte code Java (.class).
    • Post-Compile Weaving / Binary weaving : cách này dùng để inject code của aspect vào những tập tin .class của Java đã được compile.
  • Load-Time Weaving : cách này dùng để inject code của aspect khi class cần sử dụng aspect được load vào JVM, nghĩa là trong khi ứng dụng đang chạy.
  • Run-time weaving: thực hiện weaving và unweaving code của aspect và non-aspect tại run-time.

Static weaving

Static weaving là quá trình combine code của aspect và code non-aspect lại với nhau trước khi code được biên dịch thành Java byte code (.class) bằng cách sử dụng bộ tiền xử lý (pre-processor). Do đó, code gốc chỉ được thay đổi một lần tại thời gian biên dịch (compile). Hiệu suất của code được combine này tương đương với code được viết theo truyền thống.

Hạn chế của phương pháp Static weaving là khó khăn trong việc xác định code của aspect sau này hoặc thực hiện thay đổi đối với code của aspect. Mỗi khi code của aspect bị thay đổi, tất cả tất cả code sử dụng aspect phải được biên dịch lại.

Dynamic weaving

Dynamic weaving khắc phục một số hạn chế gặp phải khi weaving được thực hiện tại thời gian biên dịch (Compile-time weaving/ Static weaving). Có thể tránh được yêu cầu biên dịch lại (recompilation), triển khai lại (redeployment) và khởi động lại (restart) bằng cách thực hiện quy trình weaving trong thời gian chạy (run-time weaving).

Có một chút khác biệt giữa load-time và run-time weaving.

  • Load-time weaving chỉ đơn giản là trì hoãn quá trình weaving cho đến khi các lớp được nạp bởi class loader. Cách tiếp cận này yêu cầu sử dụng một weaving class loader hoặc thay thế class loader bằng một loader khác. Hạn chế là load-time tăng lên và thiếu quyền truy cập vào các aspect trong khi chạy.
  • Run-time weaving là quá trình weaving và unweaving tại run-time. Cách tiếp cận này yêu cầu các cơ chế mới để can thiệp vào việc tính toán chạy.

Các AOP Framework khác nhau có cách thực hiện dynamic weaving khác nhau. Trong khi AspectWerkz sử dụng sửa đổi byte code thông qua chức năng cấp JVM và kiến ​​trúc “hotswap” để thực hiện weaving các lớp tại run-time, thì Spring AOP Framework dựa trên các proxy thay vì các class loader hoặc dựa vào các đối số JVM.

Dynamic weaving cho phép tăng tốc các giai đoạn thiết kế và kiểm thử trong phát triển phần mềm, vì các aspect mới có thể được thêm vào hoặc các aspect hiện tại có thể được thay đổi mà không cần biên dịch lại và triển khai lại các ứng dụng. Tuy nhiên, một nhược điểm lớn là hiệu suất giảm, vì weaving xảy ra tại run-time.

Cài đặt AOP trong Java như thế nào?

Một vài ý tưởng để implement AOP trong chương trình của chúng ta:

  • Class-weaving : như đã đề cập ở phần trên.
  • Proxy-based : bạn có thể tưởng tượng nó như là một ví dụ sử dụng >Decorator Pattern. Sử dụng công cụ mã hóa byte code của một số thư viện như JDK proxy, CGLib proxy, chúng ta có thể chặn các lệnh gọi hàm và thêm code của riêng mình để được thực thi trước.
    • JDK proxy : đây là cách đơn giản nhất, nhưng chỉ có thể xử lý với các phương thức public được gọi, không thể xử lý các cuộc gọi nội bộ (các cuộc gọi bắt nguồn từ chính lớp đó).
    • CGLib proxy : yêu cầu chỉnh sửa byte code bị giới hạn và có thể xử lý các lời gọi phương thức private, nhưng vẫn không thể xử lý truy cập thuộc tính trực tiếp.
  • Sử dụng các thư viện sau: Google Guice, AspectJ, Spring AOP.
spring aop process

Ví dụ tự xây dựng một AOP framework

Trong ví dụ bên dưới chúng ta sẽ tự viết code để tạo AOP Framework sử dụng JDK Proxy mà không cần sử dụng bất cứ một thư viện thứ ba nào (third-party libraries).

Để xử dụng JDK Proxy chúng ta thực hiện các bước sau:

  • Tạo Invocation Handler: class này phải implemenet java.lang.reflect.InvocationHandler. InvocationHandler là interface được thực hiện bởi trình xử lý lời gọi (invocation handler) của một proxy instance. Khi một phương thức được gọi trên một proxy instance, lời gọi phương thức được mã hóa và gửi đến phương thức gọi của invocation handler của nó.
  • Tạo Proxy Instance : sử dụng phương thức Proxy.newProxyInstance() được cung cấp bởi factory method java.lang.reflect.Proxy.

Ví dụ: chúng ta cần thêm một vài xử lý trước và sau khi các phương thức trong class AccountService được gọi.

aspect orientedprogramming aop

Account.java

package com.gpcoder.aop.account;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Account {

    private String owner;
    private String currency;
    private int balance;
}

AccountService.java

package com.gpcoder.aop.account;

public interface AccountService {

    void addAccount(Account account);

    void removeAccount(Account account);

    int getSize();
}

AccountServiceImpl.java

package com.gpcoder.aop.account;

import java.util.ArrayList;
import java.util.List;

public class AccountServiceImpl implements AccountService {

    private List<Account> accounts = new ArrayList<>();

    @Override
    public void addAccount(Account account) {
        System.out.println("addAccount: " + account);
        accounts.add(account);
    }

    @Override
    public void removeAccount(Account account) {
        System.out.println("removeAccount: " + account);
        accounts.remove(account);
    }

    @Override
    public int getSize() {
        System.out.println("getSize: " + accounts.size());
        return accounts.size();
    }
}

AbstractHandler.java

package com.gpcoder.aop.handler;

import java.lang.reflect.InvocationHandler;

public abstract class AbstractHandler implements InvocationHandler {

    private Object targetObject;

    public void setTargetObject(Object targetObject) {
        this.targetObject = targetObject;
    }

    public Object getTargetObject() {
        return targetObject;
    }
}

BeforeHandler.java

package com.gpcoder.aop.handler;

import java.lang.reflect.Method;

/**
* The class BeforeHandler provides a template for the before execution
*/
public abstract class BeforeHandler extends AbstractHandler {

    /**
     * Handles before execution of actual method.
     */
    public abstract void handleBefore(Object proxy, Method method, Object[] args);

    /*
     * (non-Javadoc)
     *
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
     * java.lang.reflect.Method, java.lang.Object[])
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        handleBefore(proxy, method, args);
        return method.invoke(getTargetObject(), args);
    }
}

BeforeHandlerImpl.java

package com.gpcoder.aop.handler.impl;

import java.lang.reflect.Method;

import com.gpcoder.aop.handler.BeforeHandler;

/**
 * This class provides implementation before actual execution of method.
 */
public class BeforeHandlerImpl extends BeforeHandler {

    @Override
    public void handleBefore(Object proxy, Method method, Object[] args) {
        // Provide your own cross cutting concern
        System.out.println("Handling before actual method execution");
    }
}

AfterHandler.java

package com.gpcoder.aop.handler;

import java.lang.reflect.Method;

public abstract class AfterHandler extends AbstractHandler {

    /**
     * Handles after the execution of method.
     */
    public abstract void handleAfter(Object proxy, Method method, Object[] args);

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(getTargetObject(), args);
        handleAfter(proxy, method, args);
        return result;
    }
}

AfterHandlerImpl.java

package com.gpcoder.aop.handler.impl;

import java.lang.reflect.Method;

import com.gpcoder.aop.handler.AfterHandler;

/**
 * This class provides an implementation of business logic which will be
 * executed after the actual method execution.
 */
public class AfterHandlerImpl extends AfterHandler {

    @Override
    public void handleAfter(Object proxy, Method method, Object[] args) {
        // Provide your own cross cutting concern
        System.out.println("Handling after actual method execution");
        System.out.println("---");
     }
}

ProxyFactory.java

package com.gpcoder.aop.handler;

import java.lang.reflect.Proxy;
import java.util.List;

/**
 * A factory for creating Proxy objects.
 */
public class ProxyFactory {

    private ProxyFactory() {
        throw new UnsupportedOperationException();
    }

    public static Object getProxy(Object targetObject, List<AbstractHandler> handlers) {
        if (handlers != null && !handlers.isEmpty()) {
            Object proxyObject = targetObject;
            for (AbstractHandler handler : handlers) {
                handler.setTargetObject(proxyObject);
                proxyObject = Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                        targetObject.getClass().getInterfaces(), handler);
            }
            return proxyObject;
        }

        return targetObject;
    }
}

AspectOrientedProgrammingInJdkExample.java

package com.gpcoder.aop;

import java.util.ArrayList;
import java.util.List;

import com.gpcoder.aop.account.Account;
import com.gpcoder.aop.account.AccountService;
import com.gpcoder.aop.account.AccountServiceImpl;
import com.gpcoder.aop.handler.AbstractHandler;
import com.gpcoder.aop.handler.ProxyFactory;
import com.gpcoder.aop.handler.impl.AfterHandlerImpl;
import com.gpcoder.aop.handler.impl.BeforeHandlerImpl;

/**
 * This class to verify an AOP example using JDK proxy.
 */
public class AspectOrientedProgrammingInJdkExample {

    public static void main(String[] args) {

        List<AbstractHandler> handlers = new ArrayList<>();
        handlers.add(new BeforeHandlerImpl());
        handlers.add(new AfterHandlerImpl());

        AccountService proxy = (AccountService) ProxyFactory.getProxy(new AccountServiceImpl(), handlers);
        Account account = new Account("gpcoder", "USD", 100);
        proxy.addAccount(account);
        proxy.getSize();
        proxy.removeAccount(account);
        proxy.getSize();
    }
}

Output của chương trình:

Handling before actual method execution
addAccount: Account(owner=gpcoder, currency=USD, balance=100)
Handling after actual method execution
---
Handling before actual method execution
getSize: 1
Handling after actual method execution
---
Handling before actual method execution
removeAccount: Account(owner=gpcoder, currency=USD, balance=100)
Handling after actual method execution
---
Handling before actual method execution
getSize: 0
Handling after actual method execution
---

Lợi ích của AOP là gì?

  • Tăng hiệu quả của Object-orented programming (OOP).
  • AOP không phải dùng để thay thế OOP mà để bổ sung cho OOP, nơi mà OOP còn thiếu sót trong việc tạo những ứng dụng thuộc loại phức tạp.
  • Tăng cường tối đa khả năng tái sử dụng của mã nguồn.
  • Đảm bảo >Single responsibility principle: mỗi một module chỉ làm cái mà nó cần phải làm.
  • Tuân thủ nguyên tắc “You aren’t gonna need it – >YAGNI” – chúng ta chỉ cài đặt những thứ chúng ta thực sự cần, không bao giờ làm trước.
  • Module hóa ở mức tiến trình/ chức năng.
  • Code gọn gàng hơn do tách biệt phần xử lý chính và phần xử lý liên quan.
  • Chức năng chính của chương trình không cần biết đến các chức năng phụ khác.
  • Các chức năng phụ có thể được thêm thắt, bật tắt tại thời điểm run-time tùy theo yêu cầu.
  • Các thay đổi nếu có đối với các chức năng phụ sẽ không ảnh hưởng đến chương trình chính.
  • Hệ thống sẽ uyển chuyển và giảm thiểu tính phụ thuộc lẫn nhau của các module.
Bài viết gốc được đăng tải tại gpcoder.com

Xem thêm:

Xem thêm công việc CNTT hấp dẫn trên TopDev

Xử lý bất đồng bộ với Promise.all trong JavaScript

promise in java

Anh em lập trình viên JavaScript chắc không xa lạ gì với Promise hay async/await trong việc xử lý các tác vụ bất đồng độ trong ứng dụng của mình; tuy vậy trong thực tế dự án có nhiều bài toán cần không chỉ 1 Promise và cần handle (xử lý) kết quả trả về trong từng Promise con, lúc này thứ chúng ta cần là Promise.all và 1 vài thứ tốt hơn thế. Bài viết này mình sẽ chia sẻ cùng các bạn cách sử dụng Promise.all trong những bài toán cụ thể ở dự án mình từng trải qua.

Nhắc lại cú pháp Promise

Trước hết cùng nhắc lại cú pháp Promise cũng như async/await cho các bạn đỡ quên nhé (lưu ý là async/await được thêm vào từ ES8 nhé).

let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("done!"), 1000);

});
// resolve runs the first function in .then
promise.then(
  result => alert(result), // shows "done!" after 1 second
  error => alert(error) // doesn't run
);
async function f() {

  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });

  let result = await promise; // wait until the promise resolves (*)

  alert(result); // "done!"
}

2 ví dụ trên là cách sử dụng Promise hay async/await để thực hiện việc chờ 1 xử lý bất đồng bộ thực hiện xong, nhận kết quả trả về để thực hiện 1 hành động nào đó – cũng khá dễ hiểu đúng không. Vậy nếu bài toán của chúng ta là cần chờ 2 hành động bất đồng bộ (ví dụ như cần call 2 API lên server) thực hiện xong để lấy kết quả thì sẽ cần làm gì? JS cung cấp cho chúng ta Promise.all.

  5 thủ thuật hay với Javascript Promise bạn cần biết!

Promise.all

Promise.all([Promise1, Promise2, Promise3])
  .then((result) => {
    console.log(result);
  })
  .catch((error) => console.log(`Error in promises ${error}`));

Promise1, Promise2 và Promise3 là những promise, bản thân Promise.all cũng là 1 promise. Vậy nó khác gì với việc chạy riêng lẻ 3 promise từ 1-3 một cách độc lập. Đầu tiên thì trong Promise.all, cả 3 Promise1-3 sẽ được thực hiện đồng thời, không cái nào cần chờ cái nào, vì thế giảm được thời gian chờ đợi và đương nhiên là tăng performance. Tiếp theo chúng ta cần lưu ý, nếu 1 trong 3 Promise1-3 đẩy ra lỗi (reject) thì Promise sẽ ngay lập tức dừng lại và nhảy vào catch chứ không thực hiện tiếp các promise khác. Trong trường hợp các task con thực hiện thành công thì Promise.all cũng sẽ trả về resolve với kết quả là 1 mảng chứa tất cả các resolve của task con.

Việc làm JavaScript Hồ Chí Minh dành cho bạn!

Đến đây chúng ta vẫn thấy quen thuộc đúng không, thực tế Promise.all được sử dụng thường xuyên trong các bài toán thực tế dự án. Mặc dù vậy sẽ có 1 số vấn đề khi sử dụng Promise.all như sau:

  • Làm sao để tạo 1 mảng Promise sử dụng map
  • Nếu muốn tất cả các Promise con thực hiện xong mà không bị dừng bị 1 trong các Promise khác thì làm sao?
  • Nếu muốn chỉ 1 trong các Promise con thực hiện xong (resolve) là hủy các Promise còn lại thì làm sao?
  • Nếu muốn chỉ 1 trong các Promise con trả về (bất kể resolve hay reject) là hủy các Promise còn lại thì làm sao?

Chúng ta cùng đi giải quyết các câu hỏi trên nhé.

Promise.all với map()

Một bài toán cũng hay gặp với Promise.all là việc sử dụng nó kết với với map nhằm tạo ra 1 group các xử lý bất đồng bộ theo mảng đầu vào. Chẳng hạn như bạn cần gửi email cho n users có sẵn trong 1 mảng dữ liệu; lúc này chúng ta có thể sử dụng hàm map() để tạo ra mảng promise con làm tham số đầu vào cho Promise.all. Ví dụ như dưới đây:

const timeOut = (t) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Completed in ${t}`);
    }, t);
  });
};

const durations = [1000, 2000, 3000];

Promise.all(durations.map((duration) => timeOut(duration))).then((response) =>
  console.log(response)
);

Tham khảo tuyển dụng javascript lương cao trên TopDev

Promise.allSettled

Promise.allSettled([
  Promise.reject("This failed."),
  Promise.reject("This failed too."),
  Promise.resolve("Ok I did it."),
  Promise.reject("Oopps, error is coming."),
]).then((res) => {
  console.log(`Here's the result: `, res);
});

Kết quả trả về:

[
  { status: "rejected", reason: "This failed." },
  { status: "rejected", reason: "This failed too." },
  { status: "fulfilled", value: "Ok I did it." },
  { status: "rejected", reason: "Oopps, error is coming." },
];

JavaScript cung cấp cho chúng ta Promise.allSettled để giải quyết vấn đề đầu tiên của Promise.all. Promise.allSettled trả về 1 Promise mới mà ở đó nó sẽ chờ tất cả các task con thực hiện xong, không kể có hoàn thành (resolve) hay bị reject. Kết quả trả về là 1 mảng theo thứ tự các Promise con truyền vào, mỗi object chứa status (trạng thái) của promise cùng giá trị trả về value hay reason (lí do) khi bị reject. Tất nhiên Promise.allSettled sẽ cần nhiều thời gian xử lý hơn so với Promise.all, tuy nhiên nó đảm bảo tất cả Promise được thực hiện.

>>> Xem thêm: Tìm hiểu phương thức slice của mảng trong JavaScript

Promise.race và Promise.any

Giả sử chúng ta có 2 bài toán như sau, các bạn hãy xem và lựa chọn các dùng nào của Promise nhé.

  • Bài toán 1: có 3 API get thông tin thời tiết và trả về kết quả như nhau, do vậy chỉ cần gọi 1 trong 3 API, cái nào có kết quả là được; không cần gọi tất cả 3 cái. Chúng ta sẽ làm thế nào?
  • Bài toán 2: chức năng upload cần upload file lên 3 server khác nhau và phải đảm bảo việc upload thực hiện thành công trên cả 3 server, nếu 1 trong 3 task fail thì dừng luôn 2 task còn lại.

Để giải quyết 2 bài toán trên, JavaScript cung cấp thêm cho chúng ta 2 function nữa là Promise.race và Promise.any. Promise.race và Promise.any có điểm chung là đều sẽ hoàn thành (resolve) khi 1 trong các promise con được thực hiện xong. Như ví dụ bài toán 1, nếu có 1 API get thông tin thời tiết hoàn thành xong thì nếu dùng Promise.race hoặc Promise.any, 2 API get thông tin thời tiết còn lại sẽ không cần thực hiện nữa.

Điểm khác nhau giữa race và any là ở trường hợp reject: any sẽ chỉ reject khi tất cả các promise con reject (hay không có promise nào trả về resolve); còn race sẽ reject khi chỉ cần 1 promise con reject. Điều này giúp Promise.race giải quyết bài toán thứ 2 ở trên. Khi có 1 trong 3 task upload file lên server thất bại thì sẽ dừng luôn 2 task còn lại.

Chúng ta có thể tổng kết họ hàng nhà Promise.all như sau:

Promise

Kết bài

Như vậy chúng ta đã đi qua hết được các phương thức xử lý bất đồng bộ Promise.all cùng cách sử dụng chúng trong từng bài toán cụ thể. Trong thực tế dự án sẽ có nhiều trường hợp các bạn sẽ vận dụng kết hợp các function khác nhau, có thể là Promise.all trong Promise.all chẳng hạn. Vì thế hãy nắm vững cách case sử dụng từng function trên nhé. Hy vọng bài viết của mình hữu ích dành cho các bạn.

Tác giả: Phạm Minh Khoa

Xem thêm:

Tìm việc làm IT mới nhất trên TopDev

Kiến trúc hệ thống là gì?

kiến trúc hệ thống

Với 1 hệ thống bất kỳ, việc xây dựng kiến trúc luôn là bước đầu tiên và quan trọng nhất quyết định tính khả thi của cả hệ thống. Đầu ra của bước thiết kế hệ thống sẽ giải quyết nhu cầu đề ra của người dùng, đồng thời là bước quan trọng để bắt đầu việc xây dựng các ứng dụng cũng như cách giao tiếp giữa các phần trong hệ thống. Bài viết hôm nay mình sẽ cùng các bạn tìm hiểu Kiến trúc hệ thống là gì và tại sao nó lại có vai trò quyết định sự thành công của 1 dự án nhé.

Kiến trúc hệ thống là gì?

1 hệ thống bất kỳ nào đó sẽ luôn có 1 kiến trúc vật lý của riêng mình, từ những website đến các ứng dụng trên thiết bị di động, hầu hết chúng đều cần phải giao tiếp với server để thực hiện các thao tác lấy dữ liệu, cập nhật chỉnh sửa thông tin dữ liệu.

Để dễ hình dung trong bài viết này mình sẽ nhắc đến 1 hệ thống web và ứng dụng mobile sử dụng mô hình client-server như hình dưới đây.

kiến trúc hệ thống

Kiến trúc hệ thống, hiểu đơn giản đó là cách tổ chức của 1 hệ thống, bao gồm tất cả các thành phần, cách chúng tương tác với nhau, môi trường mà chúng hoạt động và các nguyên tắc được sử dụng để thiết kế ra phần mềm trong hệ thống. Như ở hệ thống trên, chúng ta có thể dễ thấy 2 phần chính là CLIENT và SERVER, trong đó:

  • CLIENT: các trình duyệt web, các ứng dụng trên desktop hay smartphone truy cập để lấy và update dữ liệu bằng cách tương tác với SERVER (thông qua API)
  • SERVER: máy chủ, hiểu đơn giản đó là 1 máy tính với CPU, RAM, ổ cứng và các phần mềm phục vụ cho việc phát triển web.

  [Update] 5 xu hướng dẫn dắt “làn sóng” công nghệ trong năm 2024

  Giới thiệu về JAMstack – kiến trúc phát triển web hiện đại

Vai trò của kiến trúc hệ thống

Kiến trúc hệ thống như 1 bản thiết kế cho 1 ngôi nhà, nó cung cấp 1 sự trừu tượng để quản lý độ phức tạp của hệ thống và thiết lập 1 cơ chế giao tiếp giữa các thành phần. Vai trò của kiến trúc hệ thống có thể được list ra như sau:

  • Xác định 1 giải pháp có cấu trúc để đáp ứng tất cả các yêu cầu kỹ thuật và vận hành
  • Tối ưu hóa về mặt hiệu suất và bảo mật
  • Tác động đến chất lượng, hiệu suất và sự thành công chung của sản phẩm cuối cùng
  • Quyết định đến cách xây dựng và phát triển phần mềm bao gồm việc lựa chọn ngôn ngữ, thư viện, framework sử dụng hay kể cả giao diện người dùng.

Xem thêm việc làm Back-end hấp dẫn trên TopDev

kiến trúc hệ thống

Một số kiến trúc hệ thống hay sử dụng

Kiến trúc nguyên khối (Monolith)

Kiến trúc này tạo ra 1 đơn vị phần mềm không thể chia tách, các thành phần khác nhau của ứng dụng được kết hợp thành 1 chương trình duy nhất trên 1 nền tảng duy nhất. Các thành phần trong kiến trúc nguyên khối thường bao gồm: cơ sở dữ liệu (database), giao diện phía người dùng (client) và ứng dụng phía máy chủ (server)

kiến trúc hệ thống

Một kiến trúc nguyên khối (Monolith) sẽ thích hợp thực hiện cho các công ty nhỏ, các thành phần được kết nối với nhau và phụ thuộc nhau giúp phần mềm được khép kín. Ưu điểm của nó là tiết kiệm được thời gian phát triển và triển khai 1 cách đơn giản; hiệu suất ứng dụng cũng cao hơn do các thành phần giao tiếp với nhau 1 cách trực tiếp, đồng thời bộ nhớ được chia sẻ. Tuy vậy, nhược điểm của kiến trúc này là càng theo thời gian, khi lượng code, chức năng càng lớn thì hệ thống càng trở lên cồng kềnh và kém linh hoạt; chưa kể nếu 1 thành phần nhỏ trong cả hệ thống bị lỗi sẽ kéo theo việc toàn bộ hệ thống không thể hoạt động được.

Kiến trúc Microservice

Như hình ở trên, kiến trúc microservice thường được đưa ra so sánh với Monolith cho việc giải quyết các vấn đề mà kiến trúc nguyên khối gặp phải. Microservice là 1 loại kiến trúc hệ thống hướng dịch vụ, tập trung vào việc xây dựng 1 loạt các thành phần có khả năng tự quản lý tạo nên ứng dụng. Cách tiếp cận microservice đã trở thành 1 xu hướng trong những năm gần đây khi ngày càng có nhiều công ty áp dụng, sử dụng nhiều công nghệ DevOps. Các công ty lớn như Netflix, Amazon, Twitter, Paypal là những công ty đã phát triển chuyển đổi từ cách tiếp cận Monolith sang Microservice.

Ưu điểm lớn nhất của microservice chính là việc có thể dễ dàng triển khai, thử nghiệm các ứng dụng nhỏ 1 cách độc lập mà không làm ảnh hưởng đến hệ thống hiện có. Các service khác nhau cũng không bị tình trạng phải chờ đợi nhau hoàn thành mới có thể triển khai và chạy được, nhờ đó rủi ro khi triển khai cũng được giảm xuống trên đơn vị 1 service con. Với microservice, hệ thống của chúng ta có khả năng mở rộng theo chiều ngang, tức là dễ dàng nâng cấp, bổ sung phần cứng cho từng service với chi phí vừa phải, không cần đầu tư vào 1 máy có cấu hình cao như kiến trúc monolith để chạy hệ thống.

Tuy vậy thì hệ thống nào cũng có nhược điểm, với microservice đó là sự phức tạp khi chia ứng dụng thành các service nhỏ độc lập khiến cần nhiều công việc quản lý hơn cho từng service đó. Ngoài ra tính bảo mật cũng là 1 vấn đề khi giờ đây các API sẽ phải public ra bên ngoài để các service khác có thể gọi tới, điều đó khiến nguy cơ bị tấn công cũng cao hơn.

kiến trúc hệ thống

Kiến trúc hướng dịch vụ (SOA)

SOA – Service-Oriented Architecture là kiểu kiến trúc phần mềm dùng để chỉ ứng dụng bao gồm các tác nhân phần mềm rời rạc và lỏng lẻo thực hiện 1 chức năng cần thiết.

Ứng dụng trong SOA có thể được thiết kế và xây dựng theo kiểu module hóa , tích hợp dễ dàng và có thể sử dụng lại.

kiến trúc hệ thống

SOA có thể xem như 1 là kiến trúc nằm giữa Monolith và Microservice, khi nó được tạo thành từ các thành phần độc lập nhưng gần như không giao tiếp (hoặc rất ít) với các thành phần khác kiểu trong microservice. Cách chia module của SOA cũng sẽ khác với cách tiếp cận dạng service trong microservice. 

Kết bài

Như vậy chúng ta đã cùng đi qua khái niệm cơ bản về kiến trúc hệ thống cũng như 1 số kiến trúc hệ thống thường được áp dụng hiện nay. Đây là 1 phần khó trong lĩnh vực kỹ thuật lập trình nói riêng và kỹ sư công nghệ nói chung, vì thế nếu bạn yêu thích phần này, hãy tìm hiểu sâu thêm về các kiến trúc hệ thống mà các công ty đang áp dụng nhé. Hy vọng bài viết hữu ích dành cho bạn và hẹn gặp lại trong các bài viết tiếp theo của mình.

Tác giả: Phạm Minh Khoa

Xem thêm:

Cập nhật it jobs Developer lương cao mới nhất TopDev

[Update] 5 xu hướng dẫn dắt “làn sóng” công nghệ trong năm 2024

Tổng hợp 5 xu hướng dẫn dắt “làn sóng” công nghệ trong năm 2023

Công nghệ ngày càng phát triển với nhịp độ nhanh và cải tiến không ngừng. Cập nhật và đón đầu các xu hướng công nghệ mới là cơ hội cho các developer lên kế hoạch, nắm bắt thời cơ, để vươn lên mạnh mẽ trên con đường sự nghiệp. Hãy cùng TopDev điểm qua 5 công nghệ chính sẽ dẫn dắt “làn sóng” công nghệ trong năm 2024 này nhé!

Blockchain & Web3

Các hệ sinh thái phi tập trung Blockchain & Web3 sẽ phát triển mạnh mẽ hơn trong năm 2024 bởi những trải nghiệm an toàn, minh bạch mà chúng mang lại. 

Blockchain sẽ giúp người dùng tin tưởng vào những thứ được lưu trữ trên mạng lưới và ngăn chặn việc thay đổi hay giả mạo thông tin. Cùng với đó, Web3 sẽ cho phép người dùng trao đổi thông tin và giao dịch dựa trên công nghệ blockchain, ngoài ra nó còn giúp ngăn chặn sự phụ thuộc của người dùng vào các cá nhân hay tổ chức trung gian.

Tuy vẫn còn nhiều tranh cãi xung quanh khả năng ứng dụng và tính minh bạch của blockchain & web3, nhưng không thể phủ nhận những giải pháp mà chúng có thể mang lại cho người dùng. Dự đoán năm 2024 sẽ là một năm phát triển mạnh mẽ hơn nữa của công nghệ này.

>>> Bạn có thể tham khảo thêm về tiềm năng ứng dụng thực tế của blockchain & web3

Tham khảo việc làm Blockchain hấp dẫn trên TopDev

5G & IoT

Các công nghệ như blockchain, metaverse sẽ không phát triển hết mức do khả năng kết nối hạn chế. Các công nghệ này cần phải truyền tải một lượng thông tin khổng lồ cùng một lúc, vậy nên sự phát triển của 5G là vô cùng cần thiết. Cùng với đó, IoT (Internet of Thing) sẽ kết nối tất cả mọi thứ lại với nhau dễ dàng nhờ vào mạng lưới cảm biến, thiết bị và cơ sở hạ tầng thông minh. 

>>> Đón đầu xu hướng với bài viết về tình hình hiện tại và tương lai của IoT trong năm 2023

5G & IoT

Cùng với sự phát triển của IoT, một khái niệm mới cũng được cho ra đời có tên là IoV (Internet of vehicle). IoV là mạng lưới kết nối người đi bộ, người đi ô tô, và các bộ phận khác của cơ sở hạ tầng đô thị, nó là một phần của thành phố thông minh. IoV cố gắng làm cho giao thông trở nên tự chủ, an toàn, nhanh chóng và hiệu quả hơn, giảm thiểu tài nguyên sử dụng và tác động tiêu cực tới môi trường.

>>> Bạn có thể tìm hiểu sâu hơn về IoV qua bài viết IoV (Internet of vehicle) là gì? Kiến trúc IoV

Trí tuệ nhân tạo (AI) và máy học (ML)

Trí tuệ nhân tạo AI sẽ tiếp tục bùng nổ trong năm 2024 nhờ khả năng thích ứng nhanh chóng với nhu cầu phát triển không ngừng trong bối cảnh kinh doanh hiện nay. Doanh nghiệp có thể tận dụng AI để tạo ra các sản phẩm, dịch vụ thông minh hơn, cải tiến quy trình sản xuất và làm được nhiều điều hơn nữa.

Song song với đó, Machine Learning (ML) hay máy học là một nhánh của trí tuệ nhân tạo. Hoạt động bằng khả năng cải thiện chính bản thân chúng dựa trên dữ liệu mẫu (training data) hoặc dựa vào kinh nghiệm (những gì đã được học). Machine Learning được áp dụng trong mọi lĩnh vực và vượt trội hơn hẳn con người.

>>> Tìm hiểu sâu hơn về Machine Learning trong bài viết Machine Learning là gì? Và những ứng dụng của AI vào trong lĩnh vực y tế

Thực tế ảo (VR) và Thực tế ảo tăng cường (AR)

ar vr

Công nghệ Thực tế ảo (VR) và Thực tế ảo tăng cường (AR) sẽ mở đường cho các mô hình kinh doanh mới nhờ khả năng độc đáo “thực tế không giới hạn”. Bắt đầu từ lĩnh vực game sau đó đến việc ứng dụng trong các mô hình giáo dục, chăm sóc sức khỏe và tiến xa hơn là tạo môi trường tương tác mở rộng với thực tế hỗn hợp.

Đây chắc chắn sẽ là những công nghệ cốt lõi định hình thế giới trong tương lai.

>>> Xem thêm bài viết về Thực tế ảo (VR) và Thực tế ảo tăng cường (AR) tại đây.

Điện toán đám mây (Cloud Computing)

Trong tương lai, điện toán đám mây sẽ là “đầu tàu” tiên phong trong lĩnh vực công nghệ bên cạnh các công nghệ như metaverse, AI, 5G & IoT. Với dịch vụ điện toán đám mây, người dùng có thể truy cập thông tin từ bất cứ đâu và bất cứ khi nào mà chỉ thông qua một trung tâm kỹ thuật số. 

Điện toán đám mây sẽ giúp ích rất nhiều cho doanh nghiệp trong việc phát triển trí tuệ nhân tạo (AI) và máy học (ML). Vấn đề không gian lưu trữ cho các thuật toán phức tạp sẽ được giải quyết triệt để với công nghệ này. 

Hãy cùng TopDev xem qua những cải tiến của Google trên nền tảng Google Cloud để hướng tới hỗ trợ tất cả dữ liệu phi cấu trúc qua bài viết: Google Cloud hướng tới hỗ trợ tất cả dữ liệu phi cấu trúc

Đây là top 5 xu hướng sẽ dẫn dắt “làn sóng” công nghệ trong năm 2024 mà TopDev đã tổng hợp được. Hy vọng anh em Dev sẽ nắm bắt thật tốt để khai thác và chuẩn bị cho các chiến lược tốt hơn trong năm sau.

Xem thêm:

Tìm kiếm việc làm IT mới nhất tại TopDev!

Embedded Developer là gì? Cần học gì để trở thành Embedded Developer

Embedded Developer là gì? Cần học gì để trở thành Embedded Developer

Những năm trở lại đây, cứ nhắc đến công nghệ là người ta lại nhắc đến 4.0, nhắc đến IoT, smartthing, … Với lĩnh vực lập trình, cộng đồng Dev hiện nay cũng có nhiều lĩnh vực để học và phát triển hơn liên quan trực tiếp đến phần cứng và 1 trong những vị trí đang hot hiện nay là kỹ sư lập trình nhúng – Embedded Developer. Vậy thì công việc của kỹ sư lập trình nhúng là gì và tại sao nó lại hot trong hiện tại là thời gian sắp tới, bài viết này mình sẽ cùng các bạn đi tìm hiểu sâu hơn về ngành này nhé.

Hệ thống nhúng (Embedded System) là gì?

Embedded System

Trước tiên chúng ta cùng tìm hiểu về khái niệm hệ thống nhúng (Embedded System).

Embedded System là tập hợp bao gồm phần cứng và 1 phần mềm viết riêng để điều khiển, tương tác với phần cứng đó được gọi là phần mềm nhúng (Embedded Software). Đặc điểm của hệ thống nhúng là chúng có thể tự điều hành (hoạt động) với 1 mục đích cụ thể và được thiết kế để có thể tích hợp vào hệ thống lớn hơn tùy theo mục đích sử dụng.

Hiện nay các hệ thống nhúng đang có vai trò quan trọng và hữu ích trong nhiều ngành công nghiệp cũng như đời sống của chúng ta, có thể kể vài ví dụ như sau:

  • Ngành công nghiệp chế tạo máy: hầu hết các dây chuyền lắp ráp, sản xuất máy móc hiện đại ngày nay đều là những hệ thống nhúng với quy mô từ nhỏ đến lớn. Chúng có khả năng tự vận hành, thiết kế chuyên biệt để sử dụng tùy theo mục đích.
  • Ngành công nghiệp ô tô: Hộp số tự động, hệ thống phanh, cảm biến lùi, … đều là những hệ thống nhúng mà các hãng sản xuất xe trang bị và cũng được quảng cáo là những tính năng mới của họ.
  • Smarthome, Smartcity: cái này có lẽ là gần gũi nhất với anh em lập trình khi có rất nhiều dự án liên quan với mục đích tạo ra các ứng dụng điều khiển thiết bị điện, điện tử trong gia đình. Đấy cũng chính là những hệ thống nhúng, 1 phần quan trọng trong lĩnh vực IoT nói chung ngày nay.

  Một số mẹo cho việc phát triển ứng dụng hệ thống nhúng

Công việc của kỹ sư lập trình nhúng là gì?

Công việc của kỹ sư lập trình nhúng là gì?

Xưa nay anh em lập trình viên vẫn hay than vãn rằng: em chỉ là lập trình viên, em không biết sửa máy tính, máy in hay máy giặt. Tuy vậy thì câu nói này không hẳn đúng với anh em làm lập trình nhúng nhé. Mặc dù trong lĩnh vực lập trình nhúng vẫn thường chia ra mảng chuyên lập trình và mảng chuyên thiết kế phần cứng, dù vậy thì với việc phải làm trực tiếp trên thiết bị phần cứng đặc thù thì các Embedded Developer hầu như sẽ đều phải trang bị kiến thức về phần cứng. Cụ thể thì trong 1 hệ thống nhúng, chúng ta cần nắm được các thành phần cơ bản như sau:

  • ROM: Chứa chương trình, các dữ liệu được fix hoặc các constant data.
  • RAM: Chứa chương trình thực thi và các biến tạm
  • MCU: bộ xử lý tính toán trung tâm
  • Ngoài ra là các thiết bị ngoại vi khác để giao tiếp hay điều khiển phần cứng.

Xem ngay tin tuyển dụng Embedded lương cao trên TopDev

Thêm 1 khái niệm mà chúng ta cần nắm đó là firmware.

firmware là 1 chương trình hướng dẫn được ghi vào bộ nhớ của 1 thiết bị điện tử đơn với mục đích cụ thể và thực hiện các chức năng cấp thấp, ví dụ như chuyển đổi tín hiệu cảm biến. Firmware được viết bằng ngôn ngữ cấp thấp và sau đó được dịch sang mã máy để phần cứng của thiết bị có thể đọc và thực thi nó.

Như vậy, công việc của 1 kỹ sư lập trình nhúng bao gồm:

  • Viết và lập trình firmware
  • Phân tích để lựa chọn những giải pháp hợp lý nhất cho toàn hệ thống nhúng: điều này cực kỳ quan trọng liên quan đến việc tối ưu chi phí phần cứng mà vẫn đáp ứng được nhu cầu hệ thống.
  • Viết code, test, document, tài liệu liên quan cho sản phẩm của mình
  • Phối hợp với các team phát triển phần mềm khác để xây dựng các ứng dụng điều khiển cho thiết bị di động, trên các hệ điều hành, driver, …

  Áp dụng quy trình hiện đại khi làm phần mềm cho hệ thống nhúng

Cần học gì để trở thành Embedded Developer?

Như đề cập ở phần trên thì việc viết code vẫn là 1 phần quan trọng với kỹ sư lập trình nhúng, vì thế cũng giống như nghề lập trình viên nói chung, bạn cần trang bị khả năng lập trình, khả năng đọc hiểu tài liệu đa phần bằng tiếng Anh (vì hầu hết các thiết bị phần cứng sẽ được nhập về lắp ráp). Ngoài ra, 1 số kiến thức đặc thù mà bạn cần trang bị thêm trong mảng này như sau:

  • Lập trình C: C là ngôn ngữ quan trọng nhất trong lập trình nhúng, bạn cần nắm vững và thậm chí cần chuyên sâu về C.
  • Kiến thức về điện tử: các kiến thức về logic, vi điều khiển, vi xử lý, …
  • Kiến thức về hệ điều hành: kiến trúc máy tính, hệ điều hành Linux (phần lớn sẽ sử dụng hệ điều hành này), hệ điều hành thời gian thực (Realtime OS)
  • Memory (bộ nhớ): RAM, DRAM, SRAM, NOR, NAND, …
  • Cấu trúc dữ liệu và giải thuật: cái này thì thật ra lập trình nào cũng cần
  • Các loại giao tiếp: USB, SATA, PCIE, UART,…

Về kiến thức chuyên ngành, hãy bổ sung các mục dưới đây:

  • Lập trình driver thiết bị sử dụng ngôn ngữ C
  • Ngôn ngữ script: Perl, Python, Shell Script trên Linux
  • Thiết kế mạch PCB: Allegro hay Antinum
  • Thiết kế sơ đồ – Schematic Design
  • Build Environments: Makefile, Cmake
  • Ngoài ra cần học cách tương tác với phần cứng như sử dụng các công cụ đo, test board, hay thậm chí là hàn mạch sửa mạch nếu cần
  • Một số tool mà bạn có thể tham khảo trước: Cross ToolChains (Linux), Keil Embedded Tool (Windows), Putty (Windows)

Tham khảo tuyển dụng embedded Hà Nội lương cao trên TopDev

Định hướng nghề nghiệp

Như đã nhắc ở trên, có 2 hướng đi lâu dài dành cho lập trình viên nhúng.

1 là trở thành 1 lập trình viên chuyên viết phần mềm cho hệ thống nhúng (Embedded software). Công việc của bạn sẽ tập trung vào việc viết code, test, viết tài liệu cho sản phẩm mà bạn tạo ra bao gồm các driver, firmware, hệ điều hành hay các ứng dụng khác chạy trên hệ thống nhúng hoặc chạy trên các nền tảng web, mobile, PC điều khiển thiết bị.

Hướng thứ 2 thì nếu có sở thích về phần cứng nhiều hơn, hãy lựa chọn trở thành 1 người chuyên thiết kế bo mạch (board) hay còn gọi là thiết kế PCB. Hướng này đòi hỏi bạn cần trang bị kiến thức sâu về phần cứng cũng như điện tử.

Cả 2 hướng đều có tương lai phát triển rất lớn vì hiện nay nhu cầu về mảng lập trình nhúng là rất cao, ngoài ra không dễ để học và hiểu sâu được, vì thế cần có sự tìm tòi, tìm hiểu và nắm vững chuyên môn mới có thể tiến xa được trong nghề này.

Kết bài

Như vậy mình đã cùng các bạn tìm hiểu về những khái niệm cơ bản nhất trong nghề lập trình viên nhúng – Embedded Developer. Qua bài viết này hy vọng các bạn có cái nhìn tổng quát hơn về lĩnh vực lập trình này cũng như định hướng rõ ràng hơn nếu các bạn có sở thích về mảng nhúng nói riêng và IoT nói chung. Cảm ơn các bạn đã đọc bài, hẹn gặp lại các bạn trong các bài viết tiếp theo của mình.

Tác giả: Phạm Minh Khoa

Xem thêm:

Tham khảo việc làm IT lương cao tại TopDev