Bài viết được sự cho phép của tác giả Tô Thị Vân Anh
TestNG là một nền tảng được sử dụng để giúp chúng ta thiết kế tự động test chức năng hoặc unit test trong Java. Eclipse là một trong những IDE rất phổ biến cho phát triển các test trong Java. Và để sử dụng testNG, không phải là bạn sẽ tải về và cài đặt như một cái tool, mà sẽ giống như một cái phần mềm nho nhỏ được cài đặt tích hợp trong Eclipse nha.
Ngày xưa còn chưa biết đến automation, hóng được testNG, thì cứ nghĩ nó là một cái tool độc lập phải cài vào máy mới dùng được. Giờ thì thông tin nhiều hơn rồi nên chắc không ai bị như mình ngày đấy đâu! hihi
Hôm nay thì mình sẽ hướng dẫn các bạn các bước để cài đặt testNG trong Eclipse nhé!
1. Mở Eclipse IDE. Chọn Help > Install new software… -> Trên màn hình sẽ hiển thị một cửa sổ có tên Install:
2. Nhấn nút Add, màn hình lúc này sẽ hiển thị một popup nho nhỏ, bạn sẽ điền thông tin này vào từng trường tương ứng nhé:
Name: TestNg ( Bạn có thể đặt tên tùy ý chỗ này)
Location: http://beust.com/eclipse/ (Link này thì lấy chính xác nhé! :D)
Nhấn OK
3. Check vào checkbox TestNG vừa hiển thị, sau đó nhấn Next
4. Check đồng ý vào điều khoản liên quan đến bản quyền
5. Lúc này quá trình download diễn ra, và TestNG sẽ được cài đặt sau đó
6. Sau khi quá trình cài đặt ở bước trên đã xong, sẽ có một cửa sổ hiển thị yêu cầu bạn sẽ khởi động lại Eclipse để cập nhật những cài đặt vừa rồi. Bạn chọn Yes để hoàn tất việc cài đặt TestNG.
Rất đơn giản đúng không nào!
Có một cách khác mà bạn cũng có thể sử dụng để cài đặt TestNG cho Eclipse đó là:
Click Help > Eclipse Marketplace…
Gõ TestNG và nhấn Go để tìm kiếm framework
Nhấn Install để cài đặt
Chờ cho đến khi cài đặt xong và khởi động lại TestNG là được
Hi vọng là với các bước đơn giản phía trên bạn có thể cài đặt TestNg một cách dễ dàng và nhanh chóng hơn.
Hãy nhớ rằng 1 observable sẽ không làm gì cho đến khi nó nhận được đăng ký(subscription). Một đăng ký kích hoạt nó phát ra các sự kiện, cho đến khi nó tạo ra 1 sự kiện .error hoặc .completed để kết thúc. Bạn có thể đăng ký nó và chấm dứt nó. Cùng xem ví dụ sau:
example(of: "dispose") {
// 1
let observable = Observable.of("A", "B", "C")
// 2
let subscription = observable.subscribe { event in
// 3
print(event)
}
}
Tạo 1 observable gồm các string
Đăng ký vào observable, phát ra các sự kiện
Hiển thị các sự kiện phát ra
Kết quả:
--- Example of: dispose ---
next(A)
next(B)
next(C)
completed
Để hủy 1 subscribe, ta thêm dispose() cho nó. Và nó ngừng phát ra sự kiện. Thêm đoạn code này vào cuối chương trình:
subscription.dispose()
Quản lý hủy đăng ký rất tẻ nhạt, cho nên RxSwift cung cấp cho chúng ta công cụ để hủy là hàm .disposed(by:), và sẽ tự động gọi dispose mỗi khi đăng ký bị hủy. Cùng xem đoạn code sau:
Đây là mẫu mà bạn sẽ sử dụng thường xuyên nhất, tạo và đăng ký 1 observable đồng thời thêm đăng ký vào xử lý disposeBag. Khi bạn quên đăng ký disposeBag cho nó có thể gây rò rỉ bộ nhớ. Tuy nhiên đừng lo lắng, trình biên dịch sẽ cảnh báo cho bạn.
Trong các ví dụ trước, bạn quan sát các sự kiện thông qua sự kiện .next. Cùng xem ví dụ sau:
Vì sự kiện complete đã phát ra cho nên sự kiện 3 không thể phát ra nữa. Điều gì sẽ xảy ra khi bạn thêm 1 sự kiện error cho nó? Cùng thêm đoạn code sau vào đầu file:
enum MyError: Error {
case anError
}
Và thêm đoạn code sau vào giữa .onNext và .onCompleted:
observer.onError(MyError.anError)
Kết quả như sau:
--- Example of: create ---
1
anError
Disposed
Điều gì sẽ xảy ra khi chúng ta không emit ra sự kiện onCompleted và .error cũng như không đăng ký với disposeBag? Sửa lại đoạn code như sau:
Machine learning là một chủ đề được nhắc đến rất nhiều trong thời gian trở lại đây bên cạnh trí tuệ nhân tạo, nó được ứng dụng cực kỳ nhiều ở thời điểm hiện tại trong hầu hết tất cả các lĩnh vực. Trong bài viết hôm nay, chúng ta sẽ cùng tìm hiểu xem machine learning là gì, các khái niệm cơ bản và vì sao nó lại được ứng dụng rỗng rãi như vậy?
Lưu ý trước khi đọc bài: mình mới vừa tìm hiểu về machine learning không lâu nên sai sót là điều không thể tránh khỏi. Các bạn đọc bài nếu thấy sai đừng quên góp ý dưới phần comment để mình hoàn thiện bài viết tốt hơn nha!
Machine learning là gì?
Tính đến thời điểm hiện tại, có rất nhiều định nghĩa về machine learning, nếu bạn nào từng google thì hẳn các bạn sẽ biết. Mình đã đọc và tổng hợp lại sau đó rút ra khái niệm như sau:
Machine learning (ML) hay máy học là một nhánh của trí tuệ nhân tạo (AI), nó là một lĩnh vực nghiên cứu cho phép máy tính có 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ó thể tự dự đoán hoặc đưa ra quyết định mà không cần được lập trình cụ thể.
Bài toán machine learning thường được chia làm hai loại là dự đoán (prediction) và phân loại (classification). Các bài toán dự đoán như dự đoán giá nhà, giá xe… Các bài toán phân loại như nhận diện chữ viết tay, nhận diện đồ vật…
Machine learning workflow sẽ cho bạn thấy quy trình để làm việc với machine learning như thế nào. Hãy nhìn vào sơ đồ bên dưới:
Cụ thể từng bước trong machine learning workflow như sau như sau:
Data collection – thu thập dữ liệu: để máy tính có thể học được bạn cần có một bộ dữ liệu (dataset), bạn có thể tự thu thập chúng hoặc lấy các bộ dữ liệu đã được công bố trước đó. Lưu ý là bạn phải thu thập từ nguồn chính thống, có như vậy dữ liệu mới chính xác và máy có thể học một cách đúng đắng và đạt hiệu quả cao hơn.
Preprocessing – tiền xử lý: bước này dùng để chuẩn hóa dữ liệu, loại bỏ các thuộc tính không cần thiết, gán nhãn dữ liệu, mã hóa một số đặc trưng, trích xuất đặc trưng, rút gọn dữ liệu nhưng vẫn đảm bảo kết quả… Bước này tốn thời gian nhất tỉ lệ thuận với số lượng dữ liệu bạn có. Bước 1 và 2 thường chiếm hơn 70% tổng thời gian thực hiện.
Training model – huấn luyện mô hình: bước này là bước bạn huấn luyện cho mô hình hay chính là cho nó học trên dữ liệu bạn đã thu thập và xử lý ở hai bước đầu.
Evaluating model – đánh giá mô hình: sau khi đã huấn luyện mô hình xong, chúng ta cần dùng các độ đo để đánh giá mô hình, tùy vào từng độ đo khác nhau mà mô hình cũng được đánh giá tốt hay không khác nhau. Độ chính xác của mô hình đạt trên 80% được cho là tốt.
Improve – cải thiện: sau khi đã đánh giá mô hình, các mô hình đạt độ chính xác không tốt thì cần được train lại, chúng ta sẽ lặp lại từ bước 3, cho đến khi đạt độ chính xác như kỳ vọng. Tổng thời gian của 3 bước cuối rơi vào khoảng 30% tổng thời gian thực hiện.
Có rất nhiều cách phân loại machine learning, thông thường thì machine learning sẽ được phân làm hai loại chính sau:
Supervised learning: học có giám sát
Unsupervised learning: học không giám sát
Ngoài ra, machine learning còn có thể phân làm các loại sau:
Semi-supervised learning: học bán giám sát
Deep learning: học sâu (về một vấn đề nào đó)
Reinforce learning: học củng cố/tăng cường
Mình sẽ chỉ đề cập đến cách phân loại phổ biến nhất là phân làm hai nhóm: học có giám sát và học không giám sát.
Supervised learning
Supervised learning là việc cho máy tính học trên dữ liệu đã được gán nhãn (label), hay nói cách khác, với mỗi đầu vào Xi, chúng ta sẽ có nhãn Yi tương ứng.
Unsupervised learning
Unsupervised learning là cho máy tính học trên dữ liệu mà không được gán nhãn, các thuật toán machine learning sẽ tìm ra sự tương quan dữ liệu, mô hình hóa dữ liệu hay chính là làm cho máy tính có kiến thức, hiểu về dữ liệu, từ đó chúng có thể phân loại các dữ liệu về sau thành các nhóm, lớp (clustering) giống nhau mà chúng đã được học hoặc giảm số chiều dữ liệu (dimension reduction).
Môt số khái niệm cơ bản
Dataset (còn gọi là data corpus hay data stock): là tập dữ liệu ở dạng nguyên thủy chưa qua xử lý mà bạn đã thu thập được ở bước data collection. Một dataset sẽ bao gồm nhiều data point.
Data point: là điểm dữ liệu, mỗi điểm dữ liệu biểu diễn cho một quan sát. Mỗi data point có nhiều đặc trưng hay thuộc tính khác nhau, được chia làm hai loại: dữ liệu số (numerical) và dữ liệu không phải số (ví dụ như chuỗi) (non-numerical/categorical). Data point được biểu diễn thành dòng tương ứng, mỗi dòng có thể có 1 hoặc nhiều dữ liệu (chính là các đặc trưng).
Training data và test data: dataset thường sẽ được chia làm 2 tập này, training data dùng để huấn luyện cho mô hình, test data dùng để dự đoán kết quả và đánh giá mô hình. Có bài toán người ta sẽ cho sẵn hai tập này thì bạn không cần phải chia nữa, đối với bài toán chỉ cho mỗi dataset thôi thì phải chia ra. Thường tỷ lệ giữa tập train và test sẽ là 8/2.
Features vector: là vector đặc trưng, mỗi vector này sẽ biểu diễn cho một điểm dữ liệu trong dataset. Mỗi vector có n chiều biểu diễn các đặc trưng của điểm dữ liệu, mỗi đặc trưng là một chiều và phải là dữ liệu số. Các mô hình chỉ có thể huấn luyện được từ các vector đặc trưng này, do đó dataset cần phải chuyển về dạng một tập các vector đặc trưng (features vectors).
Model: là các mô hình được dùng để training trên một training data theo thuật toán của mô hình đó. Sau đó mô hình có thể dự đoán hoặc đưa ra các quyết định dựa trên những gì chúng đã được học.
Ứng dụng của Machine learning
Machine learning được ứng dụng cực kỳ nhiều trong đời sống hiện nay trong mọi lĩnh vực:
Tài chính – ngân hàng
Sinh học
Nông nghiệp
Tìm kiếm, trích xuất thông tin
Tự động hóa
Robotics
Hóa học
Mạng máy tính
Khoa học vũ trụ
Quảng cáo
Xử lý ngôn ngữ tự nhiên
Thị giác máy tính
Và còn rất rất nhiều lĩnh vực mà machine learning có thể được áp dụng, machine learning tỏ ra cực kỳ hiệu quả, hơn hẳn con người trong cụ thể các lĩnh vực mà chúng được áp dụng.
Ví dụ đơn giản như dự báo thời tiết, người ta sẽ dùng các phép tính và những quan sát, ghi nhận về thời tiết trong quá khứ để dự báo về thời tiết của những ngày kế tiếp. Tuy nhiên sẽ thế nào nếu như có cực kỳ nhiều quan sát được thực hiện, có thể lên đến hàng triệu, hàng tỉ quan sát, lúc đó con người không thể nào thực hiện được việc tính toán trên dữ liệu lớn như vậy. Hơn nữa, việc tính toán với dữ liệu lớn như vậy có thể gặp sai sót và dẫn đến kết quả dự đoán bị sai.
Khi này, việc áp dụng machine learning vào để cho máy tính học các quan sát được ghi nhận trong quá khứ, chúng có thể dự đoán được thời tiết trong tương lai với độ chính xác cao hơn rất nhiều so với con người dự đoán.
Chính vì sự phổ biến và hiệu quả của machine learning, việc bạn biết và học về machine learning chắc chắn là một lợi thế lớn trong thời đại công nghệ 4.0 như ngày nay.
Tổng kết
Vậy là trong bài này, mình đã cùng các bạn tìm hiểu qua về machine learning là gì, các khái niệm cơ bản và ứng dụng của nó. Nếu như bạn thấy bài viết này hay hoặc có đóng góp về bài viết, đừng quên bình luận phía bên dưới để giúp mình hoàn thiện bài viết tốt hơn nha.
Odoo is a suite of web based open source business apps. The main Odoo Apps include an Open Source CRM, Website Builder, eCommerce, Warehouse Management, Project Management, Billing & Accounting, Point of Sale, Human Resources, Marketing, Manufacturing, Purchase Management, … Odoo Apps can be used as stand-alone applications, but they also integrate seamlessly so you get a full-featured Open Source ERP when you install several Apps.
Nó là một bộ các web app phục vụ các công việc trong kinh doanh như quản lý quan hệ khách hàng, quản lý dự án, tính tiền/kế toán, tuyển dụng… đầy đủ đến mức nó là một giải pháp “ERP” cho doanh nghiệp. Odoo là tên mới từ bản 8.0 (giờ đang là 10.0) của phần mềm OpenERP.
Đứng ở góc độ của lập trình viên, việc phát triển một “module/addon” cho Odoo không có gì quá khác biệt hay cao siêu so với viết một web app bằng bất cứ framework nào (Django, Flask…), ngoài chuyện clone 1.6GB git repo.
Cài đặt và chạy thử
Code Python cài từ source có một số thư viện yêu cầu lập trình viên phải cài thêm các thư viện C (bằng apt trên Ubuntu):
Mặc dù dùng qweb template engine, Odoo vẫn có vài chỗ dùng jinja2 hay Mako template engine:
[2] although it uses a few others, either for historical reasons or because they remain better fits for the use case. Odoo 9.0 still depends on Jinja and Mako.
Sau khi cài
Giao diện quản lý dự án
Cảm nhận chung là Odoo vẫn chậm như thời OpenERP, khá ngốn RAM, 180MB cho process Python chạy Odoo, chưa làm gì cả + một đống process chạy postgres.
Khi vận hành trang tổng hợp việc Python của PyMi, những tin tuyển lập trình viên Odoo hiện lên hàng ngày, lặp đi lặp lại, với mức lương phổ biến trong khoảng 6-10 triệu.
Các nhà tuyển dụng thì lại bắt buộc lập trình viên phải có sẵn kinh nghiệm với Odoo… NOOOOOO!
Chẳng có lập trình viên web Python nào đầu tư vào 1 framework không dùng ở đâu ngoài để phát triển chính Odoo module/addon, họ học Django, Flask. Một lập trình viên Django hay Flask có thể viết Odoo webapp chỉ sau vài tiếng chuyển đổi những kiến thức tương tự sang những thư viện của Odoo framework.
Tại sao anh đòi hỏi thứ không ai có, mà lại trả lương thấp?
Theo như kết quả nghiên cứu của Stack Overflow trong năm 2020, JavaScript là ngôn ngữ lập trình phổ biến nhất trên thế giới, với hơn 63% các nhà phát triển đã và đang sử dụng nó. JavaScript có kho lưu trữ gói mã nguồn mở lớn nhất trên thế giới (npm) và cũng có nhiều khung và thư viện khác nhau được xây dựng cùng với nó. JavaScript rất dễ bắt đầu vì nó không yêu cầu bất kỳ cài đặt nào để bắt đầu coding.
JavaScript có thể làm nhiều việc hơn so với những gì bạn biết
Phát triển Front-end Web
Front-end web là một hình thức phát triển giao diện người dùng liên quan mà người dùng có thể xem và tương tác được. Có 3 ngôn ngữ chính hiện nay có thể dùng để phát triển front-end: HTML, CSS và JavaScript.
HTML (Ngôn ngữ đánh dấu siêu văn bản) liên quan đến cấu trúc và nội dung của trang web, CSS (Trang tính kiểu xếp tầng) xử lý kiểu dáng.
Và cuối cùng, JavaScript làm cho trang web mang các hiệu ứng động, dễ nhìn hơn. Và điều này có thể được thực hiện theo nhiều cách khác nhau, chẳng hạn như:
Thuyết trình
Bạn có thể tạo băng chuyền và thanh trượt trên trang web một cách dễ dàng bằng cách sử dụng một số thư viện JavaScript như Reveal JS, Swiper JS và Owl JS
Với các thư viện này, bạn có thể tùy chỉnh cách trình bày trang web của mình một cách nhanh chóng và không quá phiền phức.
Một trong những cách bạn có thể làm cho trang web của mình trở nên sinh động và hấp dẫn hơn là sử dụng hình ảnh động. Bạn có thể sử dụng chúng trên một trang web theo nhiều cách khác nhau, chẳng hạn như thông qua các chuyển động, sự biến đổi của các đối tượng và rất nhiều điều tuyệt vời khác.
Có một số thư viện ảnh gif để bạn lựa chọn, chẳng hạn như Anime JS, Greensock JS, Mo JS và Animate On Scroll. Đây là tất cả các thư viện được xây dựng bằng ngôn ngữ JavaScript giúp tạo hoạt ảnh của bạn dễ dàng hơn bằng cách sử dụng các khối mã nhỏ hơn.
Phát triển back-end liên quan đến phần phía sau của trang web mà người dùng không tương tác trực quan. Đây còn được gọi là phát triển ở phía máy chủ. Phát triển back-end liên quan đến việc tạo cơ sở dữ liệu, API, máy chủ tệp, dịch vụ đám mây, v.v.
Và với việc tạo ra Node.js, một công cụ thời gian chạy JavaScript, giờ đây bạn cũng có thể sử dụng JavaScript để phát triển web back-end. Các khung JavaScript khác nhau đã được xây dựng để đơn giản hóa quá trình phát triển web back-end. Một số trong số đó bao gồm:
Express Js: Express là một Web Application framework nổi tiếng nhất dựa trên Node.js. Nó chủ yếu được sử dụng để phát triển Web Applications và API REST.
Fastify: Đây là một Server-Side Web Framework tối giản, tập trung nhiều vào trải nghiệm của nhà phát triển và hiệu suất ứng dụng.
Koa: Đây là một framework trung gian hiện đại và mạnh mẽ cho các Web Applications và APIs.
Game là một trong những dự án thú vị nhất mà bạn có thể tạo, vì cả bạn và người dùng cuối đều có thể tận hưởng chúng. Có nhiều cách khác nhau để sáng tạo game mới với ngôn ngữ JavaScript, tùy thuộc vào độ phức tạp của trò chơi.
Để xây dựng các game có thiết kế phức tạp, cũng như các trò chơi mang tính hiệu quả hơn và nhanh hơn, bạn có thể sử dụng công cụ trò chơi JavaScript để làm cho quá trình này dễ dàng hơn. Một số engines này là Phaser Js, Blyon Js và Lime Js có thể giúp bạn làm việc dễ dàng hơn.
Phát triển ứng dụng dành cho thiết bị di động đề cập đến quá trình viết phần mềm hoạt động trên thiết bị di động. Nó liên quan đến việc phát triển các ứng dụng có thể được sử dụng trên thiết bị di động.
Bạn có thể sử dụng JavaScript để phát triển các mobile app. Các khung và thư viện Javascript khác nhau đã được xây dựng để tạo các ứng dụng gốc, đa nền tảng và kết hợp bằng JavaScript. Một số trong số đó là:
React Native: React Native là một framework mã nguồn mở có thể được sử dụng để xây dựng các cross-platform native apps – ứng dụng gốc đa nền tảng. React Native sử dụng phong cách lập trình khai báo và các thành phần có thể sử dụng lại cho giao diện người dùng.
NativeScript: NativeScript là một trong những framework đa nền tảng nổi tiếng nhất giúp bạn phát triển các mobile app cho các nền tảng Android và iOS. Vì nó là một khuôn khổ mã nguồn mở, các nhà phát triển có thể điều chỉnh giao diện người dùng cho nhiều màn hình và thiết bị, đồng thời cũng sử dụng các biến phụ thuộc khác nhau.
Ionic: Ionic là một JavaScript framework phổ biến khác để xây dựng các ứng dụng kết hợp. Đối với các nhà phát triển quen thuộc với công nghệ web và phát triển ứng dụng web, việc hiểu cấu trúc của một ứng dụng Ionic rất đơn giản.
Việc chọn JavaScript framework phù hợp cho dự án của bạn phụ thuộc vào ứng dụng bạn đang xây dựng và cũng như nền tảng mà nó dành cho. Vì vậy, hãy chắc chắn chọn một cái dựa trên trường hợp sử dụng của bạn nếu bạn có thể.
JavaScript là một ngôn ngữ đa dụng và có thể được ứng dụng trong nhiều lĩnh vực công nghệ khác nhau. Cá nhân tôi rất đề cao nó và thật sự khuyên bạn nên học JavaScript như một ngôn ngữ lập trình nếu bạn quan tâm đến bất kỳ lĩnh vực nào mà tôi đã chia sẻ ở trên.
Phỏng dịch dựa trên bài viết gốc được đăng tải tại freecodecamp.org
Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh
Vậy là bạn đã đọc qua về phần detail của khóa học rồi đúng không? Nếu chưa hãy đọc nó tại menu lập trình IOS nhé. Dù sao, chúng ta nên nhắc lại mục đích của hàng loạt bài viết liên quan tới Rx và MVVM trước. Để chúng ta biết chúng ta sẽ đạt được gì sau khi học.
Vậy là có tổng 10 thư mục. Chúng ta hãy tìm hiểu lần lượt từng thư mục nhé
1. Thư mục Application
Thư mục này có 3 file:
File AppDelegate.swift:
Hãy để ý dòng code này:
let libsManager = LibsManager.shared
Ở đây tác giả tạo 1 singleton có tên là LibsManager. Nếu ai chưa biết về singleton, thì nôm na nó là 1 lớp được khởi tạo duy nhất 1 lần, và cho dù có gọi hàm tạo đi bao lần nữa nó cũng chỉ tạo có 1 lần thôi. Người ta hay dùng singleton cho những thứ chỉ được tạo 1 lần duy nhất, như quản lý AppDelegate, loading app… Ai chưa hiểu hãy giành 30 phút để google singleton là gì?
Vậy lớp LibsManager dùng để làm gì? Chúng ta hãy vào class này xem nhé:
Để ý đoạn code này:
if UserDefaults.standard.object(forKey: Configs.UserDefaultsKeys.bannersEnabled) == nil {
bannersEnabled.accept(true)
}
lúc mới chạy app lần đầu
Bạn chạy app lần đầu, hình ảnh này sẽ xuất hiện. Còn các lần tiếp theo, nó không xuất hiện nữa. Và chính dòng code trên điều khiển việc đó.
Bắt đầu mù tịt vì đụng đến Rx rồi. Bắt đầu khó nha. Đến đây thì chúng ta bắt buộc phải đọc về Rx để hiểu nó đang làm gì. Vậy thì hãy để ý tới biến bannersEnabled. Nó được khởi tạo dạng Rx chứ không phải biến thông thường bằng câu lệnh:
let bannersEnabled = BehaviorRelay(value: UserDefaults.standard.bool(forKey: Configs.UserDefaultsKeys.bannersEnabled))
Chúng ta thấy, BehaviorRelay là 1 hàm, có value phía trong là 1 giá trị kiểu boolean. Đọc về help của Xcode như sau:
Summary
BehaviorRelay is a wrapper for BehaviorSubject.
Discussion
Unlike BehaviorSubject it can’t terminate with error or completed.
Đến đây thì đọc không hiểu mô tê gì cả. Bắt buộc chúng ta phải đọc sample ở đâu đó trên mạng. OK, vậy chúng ta cùng tìm hiểu nhé.
Sau đó các bạn mở file RxSample.xcworkspace và xem code trong file ViewController
let bag = DisposeBag() //0
let bannersEnabled = BehaviorRelay<String>(value: "code")//1
bannersEnabled.accept("toan")//2
bannersEnabled.accept("bug")//3
let subscriber = bannersEnabled.subscribe { (event) in
print("event = \(event)")
} //4
bannersEnabled.accept("viet")//5
bannersEnabled.accept("nam")//6
subscriber.disposed(by: bag)//7
Giải thích từng dòng:
Dòng 1: Các bạn khởi tạo 1 biến bannersEnabled có kiểu là BehaviorRelay. Đúng ra cái này không phải biến thông thường như các bạn đã quen, là nó có giá trị kiểu số 1,2 hay là kiểu string abc.. Mà thằng này có 1 đặc điểm là biến có thẻ phát ra 1 giá trị nào đó theo thời gian thực, cụ thể mình cho nó phát ra được các giá trị string. Giá trị khởi đầu là “code”
Dòng 2, 3: Mình đang ném 2 cái giá trị string “toan” và “bug” vào biến này để nó phát ra – nó như 1 cái đài phát thanh đang nói ra 2 câu đó.
Dòng 4: Mình khởi tạo biến subscriber, biến này dùng để lắng nghe các sự kiện phát ra từ biến bannersEnabled, giống như bạn chọn đúng kênh của đài phát thanh để nghe âm thanh trên kênh. này. Và câu lệnh print để hiển thị những gì mà nó nghe được.
Dòng 5, 6: tương tự dòng 2,3 mình lại phát ra 2 câu nói “viet” và “nam”.
Dòng 7: Các bạn hiểu nôm na là quy tắc dọn dẹp bộ nhớ tự động. Nó dựa vào biến dòng số 0 để dọn dẹp lại, và nôm na nó bắt buộc luôn khi các bạn khởi tạo các subscriber thì đều phải nhờ ông bag này dọn dẹp bộ nhớ khi không dùng nữa. Hiểu thế cho đơn giản.
Tại sao chúng ta chỉ nghe được 3 câu trên. Đơn giản do thằng bannersEnabled nó bắt đầu nghe tính từ thời điểm cách thời điểm nó đăng ký trước đó 1 tín hiệu, nghĩa là bắt đầu nghe từ từ bug trở đi về sau.
Vậy làm sao ta chỉ muốn nghe mỗi 2 từ viet nam thôi, cách đơn giản là thêm dòng lệnh này thay thế:
let subscriber = bannersEnabled.skip(1).subscribe { (event) in
print("event = \(event)")
}
skip(n) ở đây nghĩa là bỏ đi n giá trị phát ra tính từ thời điểm trước đăng ký 1 sự kiện cho đến về sau. Các bạn có thể thay đổi con số để loại bỏ. Ví dụ skip(2) thì nó bỏ từ bug và từ viet, còn nghe được mỗi từ nam.
Ồ! Vậy bạn đã hiểu các biến trên làm gì chưa? Bọn nó phát ra sự kiến, xử lý sự kiện trong hàm subscribe.
Quay trở lại hàm trong dự án của chúng ta, đoạn code trên:
let bannersEnabled = BehaviorRelay(value: UserDefaults.standard.bool(forKey: Configs.UserDefaultsKeys.bannersEnabled))//0
if UserDefaults.standard.object(forKey: Configs.UserDefaultsKeys.bannersEnabled) == nil {//1
bannersEnabled.accept(true)//2
}
bannersEnabled.skip(1).subscribe(onNext: { (enabled) in
UserDefaults.standard.set(enabled, forKey: Configs.UserDefaultsKeys.bannersEnabled)//3
analytics.set(.adsEnabled(value: enabled))//4
}).disposed(by: rx.disposeBag)//5
Dòng 1: lệnh if nếu như kiểm tra cái bannersEnabled chưa có giá trị(app chưa được mở bao giờ) thì gán giá trị bannersEnabled.accept(true) để phát ra tín hiệu rằng nó chưa mở banner bao giờ(dòng 2).
Dòng 3: Nó đăng ký 1 subscriber và bỏ đi 1 skip để loại bỏ giá trị khởi tao ban đầu(dòng 0), chỉ bắt đầu nghe ngóng từ dòng số 2 trở đi.
Vậy khi dòng 2 phát ra sự kiện thì các dòng 3, 4 được thực thi, và nếu mình đoán không nhầm thì nó làm 2 hành động: 1 là gán giá trị để bật banner lên, và chắc chắn ở đâu đó có 1 thằng lắng nghe khi giá trị này thay đổi, để hiển thị UI như hình trên. 2 là nó bật quảng cáo lên, và cũng tương tự, ở đâu đó nhiều thằng subscriber cũng lắng nghe sự thay đổi của biến này để hiển thị UI quảng cáo(adsEnabled nghĩa là bật quảng cáo, từ ads là quảng cáo, enabled là bật lên).
Vậy chúng ta đã hiểu hết logic đống loằng ngoằng trên rồi đúng không? Các bạn bắt đầu hình dung được là Rx sẽ là công cụ giúp chúng ta phát tín hiệu và lắng nghe tín hiệu. Vậy nó có ưu điểm gì:
Ví dụ khi chúng ta bật ads lên, thì mọi UI ở khắp mọi nơi khi hiển thị cho người dùng không cần quan tâm bạn thay đổi ở màn hình nào, đều đồng bộ được giá trị. Nếu bạn làm UIKit thuần, bạn sẽ phải vất vả dùng NSNotificationCenter hay là Protocol hay là closure function để báo hiệu giá trị thay đổi cho các màn khác. Và giả sử bạn có 5 cái màn khác nhau, sub view có, parrent view có, thì câu chuyện đồng bộ hóa dữ liệu trở nên khủng khiếp biết nhường nào
OK, Rx đáng để học đúng không nào? Vậy chúng ta cùng xem các đoạn code khác nhé.
CocoaLumberjack is a fast & simple, yet powerful & flexible logging framework for Mac and iOS.
Vậy nó là 1 thư viện log, chức năng là ghi lại những hoạt động của người dùng trong ứng dụng. Ví dụ người dùng bấm nút, chuyển màn hình, gõ text… bất cứ action nào trên ứng dụng của mình. Điều này nhằm cho developer đánh giá được người dùng hay xem phần nào, màn nào bị crash không, … rất nhiều thứ hay ho mà chúng ta có thể thống kê được qua thư viện này. Nhằm cải thiện app tốt hơn hay triển khai các hoạt động marketing cho app…
setupAnalytics là gì? Ở đây chúng ta đang nói đến Firebase của Google. Nó có nhiều chức năng lắm, và cụ thể là làm server, realtime, bắn notification cho app, tracking app, quảng cáo… Rất nhiều tính năng mà Google cung cấp cho chúng ta. Và tất nhiên như thông lệ, Google vẫn hay bài cho dùng thử giới hạn, dùng quá thì phải pay Đúng là ông lớn nên biết làm kinh tế quá ha.
Cụ thể nó như nào, chúng ta sẽ nghiên cứ 1 topic sâu về Firebase sau các bạn nhé.
setupAds là gì? cái tên tiếng Anh cũng nói rằng nó là cài đặt cho phần quảng cáo trong app rồi đúng không. Và ở đây chúng ta dùng quảng cáo của Google.
setupTheme – phần này khá mới trong thời gian gần đây, khi mà các ứng dụng bắt đầu quan tâm tới thị giác của người dùng nhiều hơn. Làm sao mà họ dùng app đỡ hại mắt, và dùng trong đêm tối sẽ theo 1 chế độ màu khác với dùng ban ngày. Người ta đẻ ra dark-mode và light-mode, chính ông lớn apple cũng chơi cuộc chơi này rồi. Nếu bạn đang cầm trên tay 1 thiết bị IOS 13, bạn sẽ hiểu được vào ban đêm, nhiều ứng dụng tự nhiên chuyển màu tối, đễ đơ hại mắt hơn. Hay thậm chí facebook cũng đã bật chế độ này trên appweb của họ rồi. Nó rất nhiều thứ hay ho để học, và trong ứng dụng này chúng ta chỉ cần bấm nút switch đơn giản để chuyển qua lại giữa 2 chế độ.
setupKafkaRefresh – Cái này là gì? Thư viện ở đây:
Như readme mà họ viết, thì nó đơn giản là dạng loading khi bạn vuốt xuống ở table để cập nhật data mới, hay gọi là pull to refresh mà các bạn hay thấy trên nhiều ứng dụng. Trông cũng cool ngầu đấy chứ:
FLEX (Flipboard Explorer) is a set of in-app debugging and exploration tools for iOS development. When presented, FLEX shows a toolbar that lives in a window above your application. From this toolbar, you can view and modify nearly every piece of state in your running application.
Chi tiết, bạn đọc readme tiếng Anh, còn ai không thích tiếng anh thì mình tìm thấy 1 bài viết khá đầy đủ ở đây. Nôm na nó là thư viện cho phép xem thông tin mọi thứ của app mà ta đang làm, bao gồm view, thông số biến, hàm, log hay database…
setupKeyboardManager – nghe tên cũng biết là quản lý bàn phím rồi đúng không?
Như readme viết, thường khi chúng ta build ứng dụng sẽ hay gặp tình trạng bàn phím che mất chữ, không nhìn thấy được. Và thư viện này giúp chúng ta giải quyết vấn đề đó mà không phải viết bất kỳ 1 dòng code nào. Nghe ra gì phết. Okie vậy chúng ta cứ dùng thôi.
setupActivityView – vào phần chi tiết chúng ta thấy 1 đối tượng NVActivityIndicatorView.
Vậy là chúng ta đã dạo qua 1 vòng về file LibsManager – quản lý toàn bộ library của App. Theo mình đây là cách rất thông minh để có thể tập trung lại các thư viện, dễ quản lý và dễ sửa lỗi khi cần.
2. Thư mục Managers
Chúng ta cùng nghiên cứu về cách quản lý các thư viện của tác giả ở bài viết tiếp theo.
Trong lập trình C/C++, Enum hay Enumeration là kiểu dữ liệu cố định, chỉ cho phép biến nhận số số giá trị nhất định nào đó.
Các giá trị enum có thể coi là một hằng số. Việc sử dụng enum giúp đảm bảo giá trị các biến chỉ nhận các giá trị mong đợi.
Ví dụ: Mình định nghĩa kiểu Enum là dayOfWeek và chỉ nhận các giá trị là ngày trong tuần (từ thứ 2 đến chủ nhật). Mỗi lần có tính toán tới ngày trong tuần thì mình dùng dayOfWeek sẽ giúp tránh các giá trị nằm ngoài khoảng từ thứ hai đến chủ nhât.
Trường hợp bạn không truyền giá trị cho các trạng thái trong enum thì nó sẽ tự nhận các giá trị tăng dần từ 0. Hoặc tăng dần theo giá trị của trạng thái trước đó.
Sự khác biệt map và weakmap luôn là một phần kiến thức cần nắm vững đối với lập trình viên Javascript. Nắm rõ sự khác biệt còn phải hiểu lúc nào nên sử dụng loại nào nữa. Đấy, vô vàn vấn đề cần tìm hiểu.
Tuy nhiên, khó cũng phải hiểu. Vì Data Structure không phải muốn dùng sao cũng được. Ở các System lớn, chỉ cần thay đổi một kiểu của DS thôi cũng gây ra hàng tá vấn đề.
Dữ liệu lớn, request xử lý hàng đống. Memory là thứ cần kiểm soát chặt chẽ để đảm bảo hệ thống luôn vận hành trơn tru. Kieblog hân hạnh giới thiệu bài viết sự khác biệt map và weakmap. Bắt đầu ngay thôi nào!
The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.
Đối tượng Map lưu cặp key-value (khoá – giá trị) theo thứ tự chèn vào của khoá. Bất kỳ giá trị nào (cả đối tượng (objects) và primitive values) đều có thể sử dụng làm key hoặc value.
WeakMap thì bản thân bao gồm 2 chữ. Weak và Map, hẳn là phải có cái gì đó “yếu hơn” rồi.
The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced. The keys must be objects and the values can be arbitrary values.
Đối tượng WeakMap là collection của các cặp key/value với các key được tham chiếu yếu ớt. Các key phải là đối tượng và các value có thể là bất kỳ giá trị nào.
Cả Map và WeakMap đều cho phép lưu trữ theo kiểu key-value. Key và uniques và một loạt Value đi kèm. Tuy nhiên vẫn tồn tại một số sự khác biệt map và weakmap.
Weak không có nghĩa là yếu. Chỉ “lỏng lẻo” hơn một vài điểm thôi
2. Sự khác biệt Map và Weak Map
2.1 Key Store
Cùng là cơ chế lưu trữ key-value. Nhưng có sự khác biệt rõ ràng về tiêu chuẩn của key.
A WeakMap accepts only objects as keys whereas a Map,in addition to objects, accepts primitive datatype such as strings, numbers etc.
WeakMap chỉ chấp nhận kiểu objects đóng vai trò như là key. Trong khi Map, ngoài kiểu Objects, nó còn chấp nhận cả các kiểu nguyên thủy như Strings, Numbers,…
JavaScript
map.set(44, 12);
// Lỗi
weakmap.set(44, 13);
// Lỗi. Không thể tạo WeakMap từ 2D array.
var map_1 = new WeakMap([[1, 2], [4, 5]]);
Mà cái thằng WeakMap này cũng dị. Mấy function hay methods dùng được với map thì không dùng được với Weakmap.
JavaScript
console.log(weakmap.size); //undefined
//loop through the keys in an map
for(var i of map)
{
console.log(i);
}
//loop through the keys in an weakmap doesn't work
for(var i of weakmap)
{
console.log(i);
}
//delete all keys
map.clear();
weakmap.clear(); //but this works
Ngoài chuyện Primitive Type thì còn một vấn đề khác nữa là Memory Leak. Cái này là “cốt lõi”. Có nó mới có chữ Weak trong WeakMap. Khác biệt cốt lõi nhất!
Memory thì từ xưa đến nay đã luôn là vấn đề cố hữu của Map. Một Map được tạo ra cũng đồng nghĩa với một phần memory được cấp phát. Cấp thì dễ, nhưng đôi khi mấy anh dev lại quên lấy lại phần đó (mặc dù đã sử dụng xong Map).
Sự khác biệt giữa Map và WeakMap lại là vấn đề này. Đây cũng là điểm khác biệt cần nắm rõ để có lựa chọn sáng suốt khi lựa chọn Map hay WeakMap.
Để dễ hiểu hơn thì ta có thể xem xét ví dụ sau:
JavaScript
var map = new Map();
var weakmap = new WeakMap();
(function(){
var a = {x: 12};
var b = {y: 12};
map.set(a, 1);
weakmap.set(b, 2);
})()
Xét như ví dụ phía trên, function tóm gọn lại từ dòng 4 đến dòng 10. Tuy nhiên để access được b = {y: 12}; bên ngoài function scope thực sự là không thể.
Mặc dù cả Map và Weakmap đều là global access variable. Tuy nhiên cơ chế của WeakMap cho phép Garbage collector xóa pointer tới b của chính nó. Bản thân chữa weak mang nghĩa là yếu, liên kết của weak map tới chính đứa con mà nó set vào là liên kết lỏng lẻo.
So “Map” can cause more garbages in memory. We can say that “Map” references are strong pointer whereas “WeakMap” references are weak pointers.
Chính vì vậy Map có thể chiếm dụng khá nhiều về mặt memory. Cũng có thể nói “map” tham chiếu mạnh hơn so với “WeakMap”. Tham chiếu ở đây được hiểu là tham chiếu tới memory được cấp phát.
3. Lúc nào nên xài cái gì?
Không phải ngẫu nhiên mà Javascript ES6 bổ sung thêm WeakMap. Rõ ràng Map luôn có sự bất tiện khi sử dụng.
Rõ ràng có sự bất tiện khi sử dụng Map
Vấn đề memory có được dọn dẹp hay không đã là sự khác biệt map và weakmap. Vậy lúc nào ta nên dùng WeakMap?
Đầu tiên, ta cần một Map để chứa key-value. Tuy nhiên thời gian sử dụng chỉ gói gọn trong một vài dòng code. Tính toán, mapping xong lại không xài tới Map nữa -> Ưu tiên sử dụng WeakMap.
Keeping private data about a specific object and only giving access to it to people with a reference to the Map. A more ad-hoc approach is coming with the private-symbols proposal but that’s a long time from now. Đảm bảo an toàn cho dữ liệu, chỉ cho phép access đối với các đối tượng có tham chiếu và cần sử dụng tới WeakMap.
Chắc sẽ còn một vài trường hợp khác WeakMap trở nên hữu ích. Tui sẽ bổ sung cho mấy ông sau.
Chúng mình xin chia sẻ với bạn kỹ thuật bảo mật tiên tiến, mạnh mẽ dành cho Java web sử dụng Spring Security. Bài viết hội tụ các best-practice, các kỹ thuật tối tân nhất hiện nay. Nội dung sẽ hay và khó.
Công nghệ sử dụng (technology-stack)
Spring Security
Spring Boot
Spring Web MVC
Gradle (build system)
Thymeleaf (template engine)
Công cụ sử dụng
IntelliJ IDEA 2016.1.3
Apache Tomcat 8.0.35
Trước khi bắt tay thực hiện, Bạn nên đọc các bài viết trên SmartJob:
Giới thiệu Spring Boot (để hiểu về Spring Boot)
Kiểm tra tính hợp lệ của dữ liệu đầu vào form Spring Web MVC bởi Hibernate Validator (để hiểu về luồng đi của Spring Web MVC)
Spring Security [1] là bộ khung bảo mật ứng dụng Java web cung cấp cơ chế cấp phép quyền (authorization) và xác thực người dùng (authentication). Sức mạnh của Spring Security thể hiện ở sự dễ dùng, dễ cấu hình, khả năng mở rộng, và khả năng bảo mật ứng dụng mạnh mẽ. Spring Security chống được các kỹ thuật hacking tinh vi:
Session fixation (Tấn công chiếm quyền điều khiển session của người dùng) [2]
Clickjacking (click chuột tự động, ví dụ click vào nút Like Facebook mà không xin phép người dùng)
CSRF (Cross-site request forgery: Tạo truy vấn (request) giả mạo truyền từ trang này sang trang khác)
Mục tiêu
Chúng ta sẽ xây dựng ứng dụng Java web có trang chủ, trang đăng nhập, khu vực bảo mật (chỉ truy cập được sau khi người dùng hợp lệ đăng nhập). Cấu trúc project sau khi hoàn tất sẽ như thế này
Bạn sẽ phải tạo/chỉnh sửa 7 file:
Application.java
MvcConfig.java
WebSecurityConfig.java
dang_nhap.html
khu_vuc_bao_mat.html
trang_chu.html
build.gradle
Sử dụng IntelliJ IDEA để khởi tạo project:
Bộ khung project được dựng trên nền Spring Boot. Bấm chọn Spring Initializr, rồi bấm Next.
Bạn điền thông tin, các tùy chọn vào 10 mục như ảnh chụp màn hình. Bước thứ 11 là bấm nút Next
Chọn và nhặt vào thư viện cần dùng. 3 thành phần tham gia mở rộng ứng dụng Spring Boot là:
Security
Web
Thymeleaf
Phiên bản Spring Boot ổn định, mới nhất tại thời điểm viết bài là 1.3.5.RELEASE
Đặt tên project, chọn vị trí lưu mã nguồn project
Cấu hình cho Gradle build system
InteliJ IDEA và Spring Initializer tự động sinh ra cho bạn cấu trúc thư mục của project. Tìm file build.gradle sửa lại nội dung như sau:
Dòng 10, 29 cho phép chúng ta đóng gói ứng dụng Spring Boot thành file WAR truyền thống. (Nếu để theo mặc định, Spring Boot sẽ đóng gói ứng dụng web thành file JAR thực thi dùng Apache Tomcat nhúng, run trực tiếp, rất đặc sắc. Tuy nhiên theo cách này việc deploy sẽ quá đơn giản đến mức khiến bạn đọc khó hiểu, tại sao không có file WAR mà ứng dụng Java web vẫn chạy).
Tạo thêm thư mục java trong thư mục src/main, rồi tạo thêm package vn.smartjob.demo_spring.demo_security . Tạo class Application.java
package vn.smartjob.demo_spring.demo_security;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
/**
* Điểm đi vào của ứng dụng Spring Boot.
*/
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
Mã nguồn dưới đây thực chất đã chuyển đổi (convert) ứng dụng Spring Boot nguyên bản (tạo ra file JAR có thể run được) thành ứng dụng web Java truyền thống (đóng gói thành file WAR) bằng cách:
– Dòng 12, class Application được extends từ class org.springframework.boot.context.web.SpringBootServletInitializer
– Dòng 14 đến 17, phải Override method configure để đóng gói ứng dụng Spring Boot thành file WAR truyền thống.
Tạo thêm thư mục resources bên trong thư mục src\main. Tạo thư mục templates bên trong thư mục resources.. Sau đó tạo 3 tập tin giao diện (sử dụng Thymeleaf template engine). Các file giao diện sử dụng Thymeleaf. Ở đâu Thymeleaf xử lý (render) ra giao diện, sẽ sử dụng HTML element mà trong đó chứa thuộc tính th:____ . Các thẻ security chèn vào trong giao diện sẽ do Spring Security xử lý.
File trang_chu.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://wwww.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Trang chủ</title>
</head>
<body>
<h1>Ứng dụng minh họa Spring Security</h1>
<p>Bấm vào <a th:href="@{/hello}">link này</a> để đăng nhập.</p>
</body>
</html>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Đây là khu vực bảo mật</title>
</head>
<body>
<h2>Đây là khu vực chỉ dành cho thành viên đã đăng nhập</h2>
Bí quyết công nghệ sử dụng trong ứng dụng này:<br/>
<ol>
<li>Spring Web MVC</li>
<li>Spring Boot</li>
<li>Spring Security</li>
</ol>
<h1 th:inline="text">Xin chào bạn [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Đăng xuất"/>
</form>
</body>
</html>
File MvcConfig.java . 4 dòng code từ 12 đến 15, là việc ánh xạ (mapping) đường dẫn truy cập với file giao diện tương ứng (đó chính là tên các file html không bao gồm đuôi file).
package vn.smartjob.demo_spring.demo_security;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("trang_chu");
registry.addViewController("/").setViewName("trang_chu");
registry.addViewController("/hello").setViewName("khu_vuc_bao_mat");
registry.addViewController("/login").setViewName("dang_nhap");
}
}
File WebSecurityConfig.java . Cấu hình bảo mật sử dụng hoàn toàn bằng method và class Java. Bạn để ý bên trên class có annotation @Configuration và @EnableWebSecurity để ứng dụng nhận diện thông số bảo mật nằm trong đoạn mã nguồn này. Để cho đơn giản, chúng ta cấp phép 1 người dùng có tên smartjob cùng mật khẩu 4321 . Chúng ta có thể cấu hình các quy tắc bảo mật tinh tế sau này trong các ví dụ sau.
package vn.smartjob.demo_spring.demo_security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* Cấu hình bảo mật
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* Cấu hình xác thực người dùng (authentication).
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
/**
* Cấu hình cấp phép (quyền) người dùng (authorization).
*
* @param auth
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("smartjob").password("4321").roles("USER");
}
}
Dòng 26: Cấp phép truy cập, khởi tạo luồng lo-gic bảo mật.
Dòng 27: Cho phép tất cả người dùng (đã đăng nhập, hay chưa đăng nhập) đều được truy cập trang chủ.
Dòng 30: Nếu người dùng có nhu cầu, đưa người dùng đến trang Đăng nhập.
Dòng 31: Tất cả mọi người dùng đều có quyền tiếp cận (truy cập) trang Đăng nhập.
Dòng 34: Sau khi đăng nhập, người dùng đã được xác thực có thể Đăng xuất.
Dòng 48: Cấp phép người dùng có tên đăng nhập smartjob, mật khẩu 4321, với vai trò (role) là người dùng thông thường (USER). Trên một hệ thống sẽ có nhiều role khác nhau.
Chạy ứng dụng trên Apache Tomcat 8
Chúng ta cố tình nhập sai tên đăng nhập hoặc mật khẩu để kiểm tra thông báo lỗi và kiểm tra khả năng ngăn chặn của Spring Security:
Khi nhập đúng tên đăng nhập: smartjob và mật khẩu: 4321 thì người dùng sẽ truy cập được khu vực bảo mật:
Đăng nhập thành công, người dùng truy cập được khu vực đặc quyền riêng. Thậm chí Trình duyệt web còn hỏi bạn có muốn lưu tên đăng nhập, mật khẩu ứng dụng trong trình duyệt hay không. Để sử dụng tính năng đăng xuất (do Spring Security cung cấp), bạn bấm nút Đăng xuất để kiểm tra việc vận hành của việc xóa thông tin người dùng trên trình duyệt.
Mẹo: Trong quá trình phát triển ứng dụng, có thể bạn phải xóa thông tin đăng nhập lưu trong trình duyệt đi để test khả năng bảo mật. Bạn làm như sau: Trình duyệt Google Chrome, chọn Setting, gõ từ khóa tìm kiếm pri (privacy)
Chọn Content settings… rồi tìm
Chọn All cookies and site data…
Nhớ bấm nút X rồi sau đó Done để xóa thông tin bảo mật lưu trên trình duyệt, nhằm mục đích chuẩn bị môi trường test ứng dụng Spring Security.
Người dùng cuối thường sẽ không phân biệt được những điểm giống và khác nhau của website và web application. Họ chỉ việc nhập URL và sử dụng kết quả tìm kiếm là được. Nhưng với các dev, bạn chính là người build nên các nền tảng này cho người dùng sử dụng. Do đó việc nắm bắt được sự khác nhau này chắc chắn sẽ giúp ích rất nhiều cho công việc.
Web Application còn hay được gọi tắt là web app là một phần của phần mềm có thể được truy cập bởi trình duyệt. Nói cách khác, web app là website có chức năng và các yếu tố tương tác.
Các web app có khả năng tùy biến cực cao và có thể thực hiện nhiều tác vụ và chức năng khác nhau. Chúng thường phức tạp hơn và khó xây dựng hơn, đồng thời chúng cần một đội ngũ phát triển phần mềm có kinh nghiệm để tạo ra chúng.
Một số web apps phổ biến hiện nay như Twitter, Facebook, Gmail, Adobe CC và Youtube.
Web Application là gì?
Đặc điểm của Web Application
Đa nền tảng
Dễ dàng test với các bài kiểm tra automated
Được lưu trữ trên đám mây
Bạn sử dụng Web Application để làm gì?
Có thể sử dụng trên mọi nền tảng vì chúng hỗ trợ tất cả các trình duyệt hiện đại
Bạn không cần phê duyệt từ cửa hàng ứng dụng để có một web app
Người dùng có thể truy cập chúng bất kỳ lúc nào, từ bất kỳ đâu
Có thể sử dụng trên cả thiết bị di động hoặc máy tính để bàn để truy cập dữ liệu
Dễ hiểu hơn vì sử dụng cùng một bộ mã trong toàn bộ ứng dụng
Website là một tập hợp các trang web có liên quan chứa hình ảnh, văn bản, âm thanh, video và hơn thế nữa. Nó có thể bao gồm một trang hoặc nhiều trang và nó cung cấp cả nội dung trực quan và văn bản. Có rất nhiều loại website khác nhau hiện tại trang web giáo dục, cộng đồng, tìm kiếm, viết blog,…
Một số website phổ biến như Wikipedia, Google, Amazon và Craigslist.
Website là gì
Đặc điểm của một Website
Thân thiện với người dùng
Có thể dễ dàng tìm kiếm bằng công cụ tìm kiếm
Hiển thị nội dung chất lượng
Có một bố cục dễ điều hướng
Khi nào bạn cần dùng đến website?
Bạn có thể cần một trang web để giới thiệu sản phẩm của mình
Trang web giúp bạn thiết lập thương hiệu cho doanh nghiệp
Giúp tạo ra bằng chứng xã hội để người khác có thể thấy những gì bạn đã và đang làm
Sử dụng nó để quảng cáo và nâng cao nhận thức về thương hiệu của mình
Sự khác biệt chính giữa Website và Web Application
Sự tương tác của người dùng
Website cung cấp nội dung văn bản và hình ảnh mà người dùng có thể xem và đọc, nhưng điều này không ảnh hưởng đến hoạt động của trang web.
Với web app, người dùng không chỉ xem nội dung trên trang mà còn thao tác dữ liệu. Người dùng có thể tương tác từng người một bằng cách điền vào biểu mẫu hoặc cung cấp dữ liệu cần thiết để tương tác với ứng dụng.
Vấn đề xác thực
Xác thực không phải lúc nào cũng cần thiết cho các website dựa trên thông tin. Người dùng có thể được yêu cầu đăng ký nhận các bản cập nhật thường xuyên để truy cập các tùy chọn bổ sung, và thế là xong.
Các web app cần xác thực vì chúng cung cấp phạm vi tùy chọn và chức năng/tương tác rộng hơn nhiều so với một trang web. Điều này có nghĩa là bạn phải có tên người dùng và mật khẩu để truy cập vào tài khoản của mình.
Một số khác biệt cơ bản giữa website với web application
Tasks và sự linh hoạt
Một website sẽ chỉ hiển thị dữ liệu và thông tin được thu thập trên một trang cụ thể khi người dùng đã tìm kiếm.
Trong một web app, các chức năng cao hơn và phức tạp hơn so với các chức năng của một trang web.
Mục đích sáng tạo
Một website chủ yếu bao gồm nội dung tĩnh. Điều này có nghĩa là thông tin có thể truy cập công khai cho tất cả khách truy cập.
Web app được thiết kế để tương tác với người dùng cuối. Điều này có nghĩa là nếu không có thông tin đăng nhập bắt buộc, bạn có thể không truy cập được vào bất kỳ dữ liệu nào.
Khi xử lý một website, những thay đổi nhỏ không bao giờ yêu cầu biên dịch lại và triển khai đầy đủ. Bạn chỉ cần cập nhật mã HTML và mọi thứ sẽ được cập nhật.
Trong khi với web app, bạn cần phải biên dịch lại và triển khai lại ứng dụng bất cứ khi nào bạn thực hiện thay đổi.
Phát triển một website là một quá trình tương đối đơn giản. Nhưng việc tạo một web app đòi hỏi kiến thức sâu hơn, nhiều kinh nghiệm hơn và lập kế hoạch nhiều hơn. Do đó, nắm rõ sự khác biệt của chúng giúp bạn hiểu rõ mình cần làm gì và phát triển như thế nào.
Bài viết được sự cho phép của tác giả Kien Dang Chung
Video trong bài viết
Chúng ta có quy trình 3 bước để máy có thể học nhưng trước khi đi đến phần thuật toán, tôi muốn giới thiệu với các bạn một chút về môi trường chúng ta sẽ thực hành viết code Python.
Jupyter Notebook là công cụ thực hiện code Python, không những thế bạn có thể đưa vào văn bản, hình ảnh giúp cho các đoạn code dễ hiểu và có thể chia sẻ với mọi người.
Phần văn bản của Jupyter Notebook có thể đưa vào nội dung rất phong phú với các cú pháp Markdown và LaTex:
Markdown là một cú pháp sẽ được phân tích cú pháp thành HTML, nó có thể đưa vào tất các các phần tử của HTML, do đó Notebook của bạn sẽ không khác gì một trang web cả.
LaTex là công cụ đánh dấu và hiển thị cho các công thức toán học và khoa học. Bạn thử xem hai hàm số này, cái nào dễ nhìn hơn: y = x^2 + 2x + 1 và y=x2+2x+1y=x2+2x+1.
Trang web bạn đang xem All Laravel được chúng tôi xây dựng trên nền tảng OctoberCMS cũng đang sử dụng các công cụ như Markdown và LaTex để biên soạn nội dung các bài viết mà bạn đang xem.
1.1 Cú pháp Markdown
Có khá nhiều cú pháp trong Markdown nhưng tôi sẽ giới thiệu sơ qua một số cú pháp hay dùng nhất:
Tiêu đề: Trong HTML chúng ta có các thẻ tiêu đề từ H1 đến H6 thì trong Markdown, chúng ta thực hiện định dạng một câu thành tiêu đề bằng dấu # ở trước. Ví dụ:
# Đây là tiêu đề H1
nó sẽ tương ứng với
<h1>Đây là tiêu đề H1</h1>
Muốn có tiêu đề H2 chúng ta sử dụng hai dấu ##, H3 tương ứng với ###…
Định dạng văn bản: Một số định dạng phổ biến như viết đậm, viết nghiêng trong Markdown sẽ như sau:
**Đoạn này chữ đậm**
nó sẽ tương ứng với
<strong>Đoạn này chữ đậm</strong>
*Đoạn này chữ nghiêng*
nó sẽ tương ứng với
<em>Đoạn này chữ đậm</em>
Danh sách: Có hai loại danh sách là danh sách có thứ tự với số ở đầu (ol) và danh sách không có thứ tự (ul). Trong Markdown các danh sách được viết khá dễ dàng:
* Python
* C#
* PHP
Tương đương với
<ul><li>Python</li><li>C#</li><li>PHP</li></ul>
Kết quả thực tế như sau:
Python
C#
PHP
Tương tự với danh sách có thứ tự, chúng ta chỉ cần viết như khi đánh văn bản hay dùng:
1. Python
2. C#
3. PHP
Tương đương với
<ol><li>Python</li><li>C#</li><li>PHP</li></ol>
Kết quả thực tế như sau:
Python
C#
PHP
Có rất nhiều các cú pháp trong Markdown, bạn có thể tìm hiểu thêm trên mạng với từ khóa Markdown syntax, ở đây tôi chỉ giới thiệu để bạn hiểu được Markdown là gì? Bản chất Markdown là một ngôn ngữ đánh dấu trung gian, nó khá tiện dụng khi viết nội dung đặc biệt với các tài liệu khoa học. Các hệ thống hỗ trợ Markdown sẽ thực hiện theo thứ tự như sau:
Markdown -> HTML -> Hiển thị nội dung cho người dùng.
1.2 Cú pháp LaTex
LaTex nhận dạng nội dung bên trong một đoạn văn bản là công thức hay không thông qua thẻ $ và $$.
Với $, nội dung bên trong sẽ là biểu thức nằm trên cùng một dòng với văn bản ở ngoài.
Với $$ nội dung bên trong là biểu thức sẽ được trình bày ở giữa một dòng mới.
Ví dụ: Phương trình hàm parabol y=3x2+2x+1y=3×2+2x+1 là dạng cùng dòng (inline) với thẻ $ trong LaTex. Nhưng biểu thức sau đây lại sử dụng $$:
∑i=0ni2=(n2+n)(2n+1)6∑i=0ni2=(n2+n)(2n+1)6
Chỉ số trên và chỉ số dưới: sử dụng _ cho chỉ số dưới và ^ cho chỉ số trên. Ví dụ: $x^2$ sẽ có kết quả là x2x2, $n_i$ sẽ có kết quả là nini và kết hợp cả hai $\theta_0^{(i)}$ sẽ cho kết quả là θ(i)0θ0(i). Các biểu thức toán sẽ rất đẹp phải không bạn.
Tổng, tích phân: Với tổng chúng ta sử dụng \sum, tích phân là \int với các chỉ số trên và chỉ số dưới giống như ở phần trên. Ví dụ: $\sum_{i=0}^ni^2$ cho kết quả ∑ni=0i2∑i=0ni2. Ví dụ khác về tích phân $$\int_0^{\frac{\pi}{4}}\sqrt{1-x^2}dx$$ cho kết quả
∫π401−x2−−−−−√dx∫0π41−x2dx
Phân số: Phân số trong LaTex sử dụng cú pháp $\frac{a}{b}$, ví dụ $\frac{(n^2+n)(2n+1)}{6}$ cho kết quả (n2+n)(2n+1)6(n2+n)(2n+1)6.
Trên đây là một số cú pháp cơ bản khi biểu diễn các biểu thức toán học với LaTex, bạn có thể xem nhiều các công thức toán học khác có thể được biểu diễn bằng LaTex ở đây.
1.3 Đệ nhất lẩu Jupyter, Markdown và LaTex
Với sự kết hợp của Markdown và LaTex chúng ta có thể biểu diễn các thuật toán với các biểu thức toán học kết hợp với các nội dung diễn giải tuyệt vời. Không chỉ có vậy, Jupyter Notebook là một tài liệu có chứa cả các cell có code Python có thể thực thi được, bạn thấy đấy, giờ đây chúng ta chỉ cần 1 chỗ vừa có thể xem các diễn giải các công thức và dưới đó là các phần code thực hiện và xem các kết quả chương trình đưa ra. Có thể nói ĐỆ NHẤT LẨU JML (Jupyter-Markdown-LaTex) đã mang lại cho chúng ta những lồi nẩu cực cực cực … cực kỳ hấp dẫn.
2. Vẽ đồ thị trong Python
Các cụ nhà ta có câu:
Trăm nghe không bằng một thấy.
Cho thấy tầm quan trọng của việc biểu diễn dữ liệu bằng các biểu đồ, đồ thị. Trong phần này, chúng ta sẽ thực hiện vẽ đồ thị các hàm số trong Python, nó giúp cho các thuật toán lằng nhằng có thể được diễn tả bằng hình ảnh một cách dễ hiểu nhất.
Trong hệ sinh thái Python, có rất nhiều các thư viện bên thứ 3 được phát triển dưới dạng mã nguồn mở, rất phổ biến và cực hữu ích khi làm việc với Python. Trong phần này tôi giới thiệu với bạn hai thư viện được dùng khá nhiều trong Khóa học Machine Learning này đó là Numpy và Matplotlib.
Numpy: giúp thao tác với các mảng đa chiều, sinh dữ liệu và thực hiện các phép biến đổi dữ liệu dễ dàng hơn.
Matplotlib: thư viện giúp bạn mô phỏng dữ liệu thành các biểu đồ, đồ thị, thư viện không thể thiếu khi bạn thực hiện phân tích dữ liệu.
Nói thì nghe cao siêu vậy thôi, chúng ta cùng bắt tay vào một ví dụ vẽ đồ thị, bạn sẽ thấy các thư viện này rất dễ sử dụng. Trong bài trước, bạn đã nghe đến khái niệm về hàm chi phí hay hàm mất mát (từ giờ tôi sẽ chỉ dùng tên gọi Hàm chi phí), đó là cơ sở để tính toán các sai lệch khi đưa ra các giá trị khởi tạo trong bước 1 của Quy trình 3 bước trong Machine Learning. Chúng ta cần vẽ đồ thị của hàm chi phí để có thể tìm được các điểm cực tiểu mà tại đó là lời giải của thuật toán Grandient Descent.
2.1 Phương thức plot()
Giả sử chúng ta có một hàm chi phí y=x2+x+1y=x2+x+1, chúng ta sẽ vẽ hàm chi phí này để có thể tìm hiểu về điểm cực tiểu, nơi mà chi phí thấp nhất (Chi phí – cost, ở đây không có nghĩa là mất mát về tiền, chi phí ở đây với ý nghĩa là …). Bắt đầu thôi:
Đầu tiên, chúng ta thực hiện import các thư viện cần thiết:
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
Hai dòng đầu tiên là import các thư viện matplotlib và numpy, dòng %matplotlib inline là một câu lệnh của Jupyter Notebook, nó giúp vẽ các đồ thị bên trong các cell. Tiếp đó, để vẽ được hàm y=x2+x+1y=x2+x+1 chúng ta sẽ sử dụng phương thức plot() của pyplot là một module trong matplotlib mà ta đã đặt tên ngắn gọn là plt.
Phương thức plot() giúp vẽ một danh sách các điểm thành một đồ thị, phương thức này có nhiều tham số nhưng chúng ta chỉ quan tâm đến tham số x và y là hai danh sách (Python List) với giá trị là tọa độ x và y.
Chú ý, phương thức plot() trả về một đối tượng Python do đó để thực sự vẽ ra đồ thị, chúng ta cần gọi phương thức show().
2.2 Tạo dữ liệu mẫu với numpy
Bạn thấy đấy, chúng ta có 3 điểm là (0,1) (2,8) và (7,9), ở đây chúng ta đưa hết giá trị trên tọa độ x vào biến x_list và trên tọa độ y vào y_list. plot() đã vẽ ra ba điểm này và giữa hai điểm liên tiếp nó vẽ một đường thẳng. Ok, vậy chúng ta có thể vẽ phương trình y=x2+x+1y=x2+x+1 như thế nào? Chẳng lẽ chúng ta phải tự tạo ra dữ liệu là danh sách các tọa độ x, y này, như thế thì thật mất nhiều công sức, chưa kể là giữa hai điểm ở đây là một đường thẳng, như vậy đồ thị vẽ ra cũng không trơn tru vì chỉ là một đường nối các điểm với nhau.
Không có vấn đề gì, chúng ta vẫn còn Numpy, bạn nhớ chứ, chúng ta đã import thư viện này vào nhưng chưa sử dụng đến. Trong numpy có phương thức linspace() cho phép tạo ra một mảng số với số lượng phần tử cho trước và nằm trong một phạm vi cho trước.
x_1 = np.linspace(start=-3, stop=3, num=100)
Dòng code này sẽ tạo ra một mảng gồm 100 phần tử chạy trong khoảng [-3,3] với giá trị các phần tử cách đều nhau.
2.3 Vẽ đồ thị hàm parabol
Ok, chúng ta đã tạo ra được dữ liệu mẫu cho trục x trong khoảng từ [-3, 3], giờ là lúc cần định nghĩa hàm y=x2+x+1y=x2+x+1 trong Python và tính ra các giá trị cho trục y tương ứng với các giá trị trục x.
def f(x):return x**2+ x +1
y_1 =f(x_1)
Kết quả ta có biến y_1 là một mảng các giá trị hàm số y=x2+x+1y=x2+x+1 tương ứng với x tại các giá trị trong mảng x_1.
Ok, dữ liệu cho các trục x, y đã chuẩn bị xong, giờ chúng ta sẽ vẽ đồ thị y=x2+x+1y=x2+x+1.
plt.plot(x_1, y_1)
plt.show()
Kết quả chúng ta có đồ thị y=x2+x+1y=x2+x+1 như hình dưới đây:
Đồ thị đã rất đẹp, nhưng chúng ta vẫn cần định dạng lại chút, ví dụ thêm nhãn cho các trục tọa độ, giới hạn tọa độ hiển thị:
Trong đoạn code trên, xlim() và ylim() để giới hạn vùng tọa độ sẽ hiển thị trên trục x và y, xlabel() và ylabel() để gán nhãn cho các trục tọa độ, kết quả chúng ta được đồ thị mới như sau:
2.4 Vài lời tâm sự
Đồ thị hàm parabol y=x2+x+1y=x2+x+1 rất đẹp được vẽ lên từ 100 điểm nối với nhau. Chúng ta thấy đường parabol rất trơn tru vì trong một khoảng ngắn có tới 100 điểm thì các điểm gần như sát với nhau do đó chúng ta không cảm nhận được những đoạn thẳng nối từng hai điểm liên tiếp.
Bạn sẽ đặt câu hỏi, tại sao tôi chọn khoảng [-3, 3] để vẽ đồ thị, thực ra khi vẽ chúng ta sẽ phải dò dẫm chút, đưa ra một khoảng bất kỳ và chỉnh dần về khoảng sao cho đồ thị có những điểm đặc biệt nằm chọn trong đó. Khi vẽ bạn cũng chọn số điểm vừa phải, nếu thấy chưa trơn tru thì tăng dần lên tránh việc máy tính phải tính toán nhiều, đó là thói quen cần thiết của những người làm về khoa học dữ liệu.
Một thực tế nữa là khi làm việc với data science, chúng ta chỉ luôn tính xấp xỉ chứ không thể có những con số tuyệt đối như khi học toán học. Những con số xấp xỉ đã có một giá trị rất cao mặc dù nếu khi thi toán, giải kết quả xấp xỉ là bạn bị điểm 0 liền. Ví dụ, khi tính toán một phương án đầu tư, chỉ cần cho kết quả cỡ 60-70% là đã coi như 100% chứ không như trong toán, lúc nào cũng phải 1+1=21+1=2.
3. Bài tập
Nhân tiện về chủ đề vẽ đồ thị và khảo sát hàm số, một chủ đề rất thích hợp với chương trình toán trong Phổ thông trung học. Mình đưa ra một số bài tập ở đây để mọi người vẽ và hồi tưởng về một thời mài đít quần trên ghế nhà trường :D.
Bài tập: Soạn một notebook trên Jupyter bao gồm cả đề bài, vẽ đồ thị với Python.
Cho đồ thị hàm số y=14x3−32x2+5y=14×3−32×2+5
Khảo sát sự biến thiên, vẽ đồ thị đã cho.
Tìm giá trị của m để phương trình x3−6x2+m=0x3−6×2+m=0 có 3 nghiệm phân biệt.
Hehe, giải kiểu gì cũng được nhé, miễn là ra kết quả, kể cả kết quả gần đúng. Lời giải có trong bài tiếp theo nhé.
Dead Letter là một tin nhắn không thể gửi đến người nhận. Dead Letter Queue (DLQ), là hàng đợi chứa tin nhắn chưa được gửi, không thể được gửi đến đích của chúng vì lý do này hay lý do khác.
Trong hàng đợi tin nhắn, DLQ là một dịch vụ được cài đặt để lưu trữ các tin nhắn đáp ứng một hoặc nhiều sự kiện sau:
Tin nhắn bị từ chối (rejected) bởi một Queue Exchange.
Message hết hạn (expire) do Time to live (TTL).
Vượt quá giới hạn chiều dài hàng đợi (length limit).
Đoạn code trên đơn giản tạo một Exchange mới gọi là gpcoder.exchange.name và Exchange mới này là Dead Letter Exchange cho hàng đợi mới được tạo. Lưu ý rằng Exchange không phải được khai báo khi hàng đợi được khai báo, nhưng nó phải tồn tại tại thời điểm các Message được Dead Letter, nếu không thì các Message sẽ bị hủy bỏ.
Theo mặc định RabbitMQ sẽ lấy khoá định tuyến từ Message ban đầu được gửi đến Exchange. Chúng ta cũng có thể chỉ định một khóa định tuyến sẽ được sử dụng khi Dead Letter Message nếu muốn.
Dead-lettered message được định tuyến tới Dead Letter Exchange theo thứ tự ưu tiên sau:
Theo khoá định tuyến được chỉ định cho hàng đợi Dead Letter Message được chỉ định.
Theo khoá định tuyến ban đầu Message được publish.
Ví dụ: Nếu một Message ban đầu được publish đến Exchange với khoá định tuyến foo. Sau đó Message này bị reject và nó trở thành một Dead Letter Message. Và nó được publish đến Dead Letter Exchange với khoá định tuyến foo. Giả sử chúng ta đã chỉ định một khóa định tuyến sẽ được sử dụng khi Dead Letter Message là bar, lúc này Message được publish đến Dead Letter Exchange với khoá định tuyến bar.
Dead-lettered message được re-published với tính năng publisher confirm được bật mặc định để đảm bảo rằng Dead-letter queue phải gửi xác nhận Message (ack) đã được lưu trữ trước khi nó bị xoá ở Queue gốc.
Message bị thay đổi như thế nào khi chuyển sang Dead-Lettered Message?
Header bị thay đổi:
Exchange name bị thay thế bởi Dead-letter exchange name.
Routing key có thể bị bởi một Routing key khác.
Nếu điều trên xảy ra, thì CC và BCC header cũng sẽ bị remove.
Thêm header x-death, với một mảng các giá trị:
queue: tên của Queue mà Message được publish trước khi nó trở thành Dead-Lettered Message.
reason: lý do xảy ra Dead-Lettered Message. Có thể là: rejected, expired, maxlen.
time: thời gian Message bị dead lettered.
exchange: tên Exchange mà Message được publish, nó có thể là dead letter exchange nếu Message bị dead lettered nhiều lần.
routing-keys: là routing key (bao gồm CC keys nhưng không bao gồm BCC keys) của Message được publish.
count: số lần mà Message bị dead-lettered trong Queue này vì lý do này.
original-expiration: nếu Message bị dead-lettered vì lý do TTL, nào là giá trị của thuộc tính expiration ban đầu của Message. Thuộc tính expiration sẽ bị remove từ dead-lettering message để ngăn việc expiring lần nữa trong Queue mà nó được định tuyến đến.
3 header được thêm cho mỗi dead-lettering event đầu tiên:
x-first-death-reason
x-first-death-queue
x-first-death-exchange
Chúng có cùng các giá trị như reason, queue, và exchange của event xảy ra Dead-Lettered ban đầu. Sau khi thêm, các header này không bao giờ được sửa đổi.
Lưu ý rằng: mảng giá trị x-death được sắp xếp gần đây nhất trước, do đó, Dead-Lettered gần đây nhất sẽ được ghi lại trong mục đầu tiên.
Ví dụ sử dụng Dead Letter Exchange trong RabbitMQ
Trong ví dụ này tôi sử dụng Dead Letter Exchange để mô phỏng trường hợp Retry xử lý sau mỗi 300 millisecond nếu ngay lần nhận Message đó không thể xử lý thành công.
Tạo một WorkQueue và bind đến WorkExchange.
Tạo một RetryQueue và bind đến RetryExchange.
Gán agruments: x-dead-letter-exchange đến WorkExchange
Gán agruments: x-message-ttl là 300 ms.
Producer publish một Message đến WorkExchange. Sau đó, WorkExchange sẽ chuyển Message đến WorkQueue.
Consumer nhận Message từ WorkQueue và cố gắng xử lý nó.
Trường hợp xử lý thất bại, Consumer sẽ publish Message đó đến RetryExchange. Sau đó, RetryExchange sẽ chuyển Message đến RetryQueue.
Message sẽ lưu tại RetryQueue trong 300 ms.
Khi Message bị expire, nó sẽ được chuyển đến WorkExchange và được chuyển đến WorkQueue.
Khi đó Consumer có thể nhận lại Message từ WorkQueue và xử lý lại.
Như bạn thấy, Message được tự động chuyển từ WorkQueue sang RetryQueue sau mỗi 300 ms nhờ vào Dead Letter Message. Đây là ví dụ cho trường hợp một Message hết hạn (expire) do Time to live (TTL).
Tương tự các bạn có thể set agruments là agruments.put(“x-max-length”, 10) để test trường hợp số lượng Message trong Queue vượt quá giới hạn chiều dài hàng đợi (length limit).
Ở bài viết trước, ta đã phân tích về Load Balancer và bài toán “Server nào sẽ handle request nào?“, ở bài viết này, ta sẽ bàn tiếp về một khía cạnh khác của Load Balancer là Stateful App Servers.
Qua bài viết, phần nào ta đã hiểu được rằng tại sao App Servers không hề quan tâm tới User State. Tuy nhiên, với những Servers được thiết kế Stateful App Servers, bằng cách nào ta có thể áp dụng Load Balancer thành công?.
Bản thân nó luôn đối đãi như nhau với các request từ phía client. Công bằng và văn minh vcl.
Sự công bằng này đảm bảo cho mô hình Load Balancer hoạt động hiệu quả, server nào trống sẽ được phân công làm nhiệm vụ ngay. Nếu một server quan tâm tới user state, nó sẽ bị kẹt không biết tới khi nào (ví dụ như một chị đi shopping 3 tiếng mới thêm một món vào giỏ hàng). Server nếu hold cứ hold mãi không biết tới lúc nào.
Bản thân kiến trúc Load Balancer cũng cần giải pháp để kết nối những công việc còn “chưa xong” ở phía client. Kiến trúc này thường được biết tới như Stateful App Servers. Lúc này mỗi machine trong kiến trúc balancer sẽ giữ một số thông tin phía client. Bản thân những thông tin này cho phép Server có thể tùy ý tracking client đã làm việc với server nào
Những yếu tố có thể giúp việc stateful dễ dàng hơn:
Với những application đã được thiết kế theo hướng Stateful App Servers thì điều quan tâm tới state hiện tại của user để có cách handle hợp lý. Trường hợp có Load Balancer, bằng cách nào ta có thể đáp ứng được “stateful”, mà vẫn đảm bảo “load balancer” thành công.
2.1 IP Address
IP address là một cách khả phố biến để phán định xem server nào sẽ tiếp tục xử lý request từ phía client. Tracking IP sẽ được thực hiện ngay từ lần đầu tiên User request tới server.
Ví dụ client A send request tới Server B. Ở các request tiếp theo, khi server phát hiện địa chỉ IP nó đã handle trước đó. Sử dụng IP Address thường đi kèm thêm lớp Network Load Balancer, có trách nhiệm phân giải IP, block các IP đến từ khu vực không cho phép thiết lập trước đó.
Kiến trúc Application Load Balancer với IP Address. Nguồn ảnh / Source: aws.amazon.com
Sử dụng IP Address cũng là giải pháp thường biết tới với tên “Layer 4”. Bản thân Layer 4 ở đây là Transport Layer trong kiến trúc 7 tầng của mạng máy tính (7 layers OSI Model). Sử dụng IP Address cũng là biện pháp khá phổ biến cho các Stateful App Servers
2.2 Web Application
NgoàimLayer 4, ta cũng có thể sử dụng một số kỹ thuật thường được sử dụng ở phía Application như:
Session Id
Session Id SSL
Cookies
để phán định server sẽ handle request còn dang dở. Session và Cookies từ đâu đã là thành phần không thể thiếu của Stateful App Servers. Tuy nhiên để handle session trong kiến trúc Load Balancer, ta cần biết tới một khái niệm mới là Sticky Session.
Với Session stickiness, request được điều phối đi đúng server để tiếp tục handle
Session stickiness, a.k.a., session persistence, is a process in which a load balancer creates an affinity between a client and a specific network server for the duration of a session, (i.e., the time a specific IP spends on a website). Using sticky sessions can help improve user experience and optimize network resource usage.
Session Stickiness là quá trình load balancer khởi tạo mối quan hệ giữa client và server trong thời gian của một phiên (session). Sử dụng sticky session cải thiện performance và user experienced, tối ưu tài nguyên server được sử dụng.
Dựa vào session id được cấp phát, Session stickiness sẽ lựa chọn đúng Server đã handle các request còn dang dở. Ở các request tiếp theo, nó cũng điều động các request đi đúng hướng, trỏ về đúng server mục tiêu.
Không những thay đổi lớn về performance, không thể chê được vào đâu khi bổ sung hàng loạt tính năng mới, nhưng kích thước của Vue 3 cũng chỉ bằng Vue 2 (12KB).
Cải tiến đáng giá được nhắc tới trong bài viết này bao gồm:
Composition API
Multiple root elements
Suspense
Multiple v-models
Sơ bộ anh em có thể xem qua video này để nắm bắt thêm Vue 3 có gì mới nha!.
2. Composition API
Kể từ khi Vue 2 nổi lên như là ngôi sáng sáng giữa bầu trời, rất nhiều dự án lớn đã sử dụng Vue. Một khi dự án lớn (cỡ vài trăm component), vấn đề tái sử dụng (reusable code) và scability (mở rộng) trở nên quan trọng hơn bao giờ hết.
Ok, Composition API là câu trả lời đầu tiên cho Vue 3 có gì mới?. Vậy Composition API là gì?
Composition API as a reactive API coupled with the ability to register lifecycle hooks using globally imported functions.
Composition API là thành phần của Reactive API, với khả năng đăng kí các lifecycle hooks sử dụng các import global cho functions.
Quất thêm cái nữa khó hiểu hơn:
The main point is that the Composition API provides a different way to manage reactivity at all points in an application, without compromising organization and readability.
Điểm mấu chốt mà Composition API cung cấp là một “cách khác” để quản lý reactivity tất cả các điểm trong application, mà không ảnh hưởng tới tổ chức code và khả năng đọc hiểu.
Vãi nồi khó hiểu, đọc vậy mông lung như một trò đùa.
2.1 Dễ hiểu hơn được không?
Thực chất Composition API cho phép ta đóng gói một loạt các method trong life cycle. Ví dụ, trước kia ở Vue 2, created tính toán, chuẩn bị dữ liệu cho object A, watch theo dõi object A khi thay đổi, … Vô vàn thứ cần làm với A. Source code trở nên mất kiểm soát, khó hiểu nếu bạn không phải là người viết ra component đó.
Các vùng có màu khác nhau thì độc lập với nhau. Nội đủ hết method trong life cycle cũng đã là nhiều với component.
Chính bởi khi có quá nhiều Component và nhiều logic phức tạp. Khó maintain và scale, nên ta cần tới Composition API.
Với Composition API, tất cả các đoạn code xử lý liên quan tới Object A có thể được gom lại duy nhất ở setup.
Tuy nhiên, đừng quên là Vue 3 vẫn hỗ trợ Options API, nên nếu muốn, không có vấn đề gì khi cứ viết các method theo Life Cycle của Vue nha. Với Options API, cùng lướt qua component vô cùng đơn giản với Options API.
Because the component instance is not yet created when setup is executed, there is no this inside a setup option. This means, with the exception of props, you won’t be able to access any properties declared in the component – local state, computed properties or methods.
Bởi vì Component instance chưa hề được tạo ra khi method setup được thực thi, nên this chắc chắn không work. Ngoại trừ cái thằng props ra, tuyệt nhiên ta không thể access tới bất cứ properties nào khai báo trong component, local state, computed properties hoặc methods cũng không là ngoại lệ.
3. Multiple root elements
Multi root elements ở đây được hiểu là component không cần phải thuộc về duy nhất một node cha nữa. Câu trả lời thứ 2 cho Vue 3 có cái gì mới xem ra dễ hiểu hơn nhiều!.
Bai bai cái lỗi khó chịu quỷ tha ma bắt này. Bắt đầu từ Vue 3, một component có thể có nhiều hơn một node cha.
Tha hồ, mặc sức mà tạo node con trong template với Vue 3. Việc bỏ đi một node cha cũng bớt phiền phức khi làm việc với css. Trước đây 2 tag p nếu bắt buộc chung nhau 1 div phải viết css parent child mệt mỏi. Tuy nhiên, giờ mạnh ai người đó xài css của mình.
Suspense là cái tiến mới ở Vue 3 liên quan tới Asynchorous (Bất đồng bộ). Trước đây khi làm việc với API, do việc xử lý call API là bất đồng bộ, nên cần chờ tới khi có response trả về mới thực hiện render.
Thông thường sử dụng v-if, tuy nhiên với Suspense, mọi việc trở nên đơn giản hơn nhiều.
Suspense is a special component that renders a fallback content instead of your component until a condition is met.
Suspense là component dặc biệt render nội dung dự phòng thay vì component chính (lúc này chưa có data), cho tới khi condition (điều kiện để render component) được xác lập.
Sử dụng Suspense cũng khá đơn giản, chỉ cần lưu ý tới 2 từ khóa default và fallback. Cùng xem xét ví dụ sau:
Vue.js Component
<template>
<Suspense>
// Sau khi đã có response từ API, nội dung template này sẽ render sau.
<template #default>
<div v-for="item in articleList" :key="item.id">
<article>
<h2>{{ item.title }}</h2>
<p>{{ item.body }}</p>
</article>
</div>
</template>
// Trước khi có data từ API, nội dung trong template này sẽ tải trước
<template #fallback>
Articles loading...
</template>
</Suspense>
</template>
<script>
import axios from 'axios'
export default {
async setup() {
let articleList = await axios
.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response)
return response.data
})
return {
articleList
}
}
}
</script>
5. Multiple V-models
Làm việc với Vue 2 chắc chắn đã biết tới v-models. V-models là two way binding. Dữ liệu binding 2 chiều, thường được sử dụng với form trên component.
Hữu dụng là thế, tuy nhiên Vue 2 chỉ cho phép một component có duy nhất một v-models. Vue 3 thì khác, cho phép không giới hạn số lượng v-model trong component.
Vue.js Component
<template>
<Suspense>
// Sau khi đã có response từ API, nội dung template này sẽ render sau.
<template #default>
<div v-for="item in articleList" :key="item.id">
<article>
<h2>{{ item.title }}</h2>
<p>{{ item.body }}</p>
</article>
</div>
</template>
// Trước khi có data từ API, nội dung trong template này sẽ tải trước
<template #fallback>
Articles loading...
</template>
</Suspense>
</template>
<script>
import axios from 'axios'
export default {
async setup() {
let articleList = await axios
.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response)
return response.data
})
return {
articleList
}
}
}
</script>
Đến thời điểm hiện nay, tôi thường yêu cầu các dự án của mình phải có CI. Nếu viết bằng script như nodejs thì CI sẽ có nhiệm vụ check syntax, để các thành viên trong nhóm cùng một kiểu viết giống nhau, và chạy các mức test khác nhau như unit test, CDC test.
Điểu tuyệt vời của gitlab là nó đi kèm với bộ CI miễn phí cho cả dự án private (yay). Blog này sẽ trình bày chiến lược để thiết lập ENV test trên Gitlab CI để build docker image, và upload nó lên gitlab registry.
Là nơi chương trình test của bạn sẽ được chạy. Bạn có thể có một PC riêng biệt cho việc build và test. Gitlab cung cấp một chương trình khá tiện https://gitlab.com/gitlab-org/gitlab-ci-multi-runner để thiết lập runner cục bộ. Cá nhân tôi chỉ sử dụng multi runner này khi chương trình cần tài nguyên lớn.
Shared runner chạy trên docker, nên có thể khai báo các docker có sẵn khá tiện (yay).
.gitlab-ci.yml
Là file cấu hình cho gitlab CI. Dưới đây là một ví dụ trong đó khai báo một trạng thái của test pipeline là unit test. Phần sau dựa trên giả thuyết tôi đang xây dựng một web app với nodejs, và chạy unit test với npm run test.
image: node:boron-alpine
stages:
- unit_test
unit_test_job:
stage: unit_test
script:
- npm install
- npm run test
Với mỗi git push lên CI được trigger. CI sẽ pull về docker image node:boron-alpine giống với docker chạy trong staging và production environment của web app này. Stages khai báo các bước của CI. Trong trường hợp này, tôi chỉ có một bước duy nhất là unit test khai báo trong unit_test_job.
Nhưng tôi tin vào 12factor, và tôi muốn có quá trình build trước. CI hay staging hay production sẽ khác nhau ở ENV truyền vào docker như trình bày ở https://12factor.net/build-release-run. Tôi sẽ tạo một job để tạo artifact, và chạy test trên artifact này.
image: docker:1.12
services:
- docker:dind
stages:
- build
variables:
CONTAINER_TEST_IMAGE: registry.gitlab.com/company/project:$CI_BUILD_REF_NAME
before_script:
- docker info
build_image_job:
stage: build
script:
- docker build -t $CONTAINER_TEST_IMAGE .
- docker run $CONTAINER_TEST_IMAGE npm run test
Setup này sử dụng docker in docker (dind) để build docker image trong một docker (nơi CI đang chạy). Đều này đạt được do shared runner chạy với privileged enable.
Như vậy lúc này CI sẽ tạo một docker có tên biến CONTAINER_TEST_IMAGE , và chạy test trong image này.
Tôi muốn tiến thêm một bước nữa, pipeline bao gồm: build, test, và release. Quá trình release xảy ra khi tôi tag git tag -a version, nó sẽ tạo ra tag latest và upload lên gitlab registry.
Khoa, gitlab registry? Đúng vậy, gitlab cho phép bạn lưu các image lên host của họ. Bạn sẽ có CI, và registry (miễn phí).
Gitlab rất hào phóng khi cung cấp đầy đủ các công cụ và dịch vụ để bạn có thể xây dựng một quá trình CI khá hoàn chính, từ việc chạy các test đến việc lưu trữ các image của bạn.
Hy vọng bạn sẽ tìm thấy sự hữu dụng trong ecosystem của gitlab.
Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng
Julia là ngôn ngữ lập trình mới, trông rất giống code Python, chạy nhanh hơn Python3 ít nhất 2 lần và có nhiều tính năng hấp dẫn. Bạn không cần phải từ bỏ Python hay ngôn ngữ XYZ để học Julia, Julia chỉ đơn giản là một bông hoa đẹp mà ai thích… thì múc.
Julia là ngôn ngữ lập trình “làm gì cũng được”, nhưng được tập trung vào lĩnh vực tính toán khoa học và muốn thế chỗ Python (nhưng đường còn dài, và còn nhiều hơn chông gai).
Tại thời điểm viết bài (2019 tháng 4), Julia ở bản 1.1.0 – đã ổn định hơn trước rất nhiều, ít bug hơn, chạy nhanh hơn.
Từ Python ngó sang
Julia trông rất giống Python, cách dùng các học, cách code cũng tương tự, nên nếu biết Python thì việc viết được code để làm công việc thường ngày (của 1 DevOps) chỉ trong vòng vài tiếng.
REPL
Gõ lệnh trực tiếp bằng lệnh julia trên Linux/MacOS
julia>1+12###### gõ ? xong , biến từ julia> thành help?>help?>sumsearch:sumsum!summarycumsumcumsum!isnumericVersionNumberissubnormalget_zero_subnormals...sum(itr)Returnsthesumofallelementsinacollection.
Màu mè (syntax highlight) cũng tự có sẵn rồi.
Chạy file code
File code Julia có đuôi .jl, ví dụ hello.jl. Chạy file code bằng cách gõ lệnh: julia hello.jl
Cài đặt package
Để cài các package trên mạng, sử dụng package manager CÓ SẴN của Julia. Chuyện về virtualenv tạm chưa bàn tới ở đây vì khá rõ ràng là không cần thiết (cài package không cần gõ sudo gì cả).
Việc cài đặt package trong Julia thực hiện hơi khác so với Python Pip hay NodeJS NPM một chút. Sẽ không có câu lệnh nào để gõ cả, không có chương trình thêm nào hết. Julia thực hiện cài đặt package khi một đoạn code Julia được chạy (gọi function thực hiện cài đặt).
|> gọi là Piping operator, lấy đầu ra của function này làm đầu vào cho function khác. Giúp việc goi funciton liên tục (và đọc nó) dễ dàng hơn. Giống UNIX command.
Nhanh
Julia thường nhanh hơn Python ít nhất 2 lần
Không quan trọng indentation
Dù bạn thụt ra thụt vào 2 3 4 5 ký tự, hay dùng tab đều không quan trọng. Chuyện này vốn gây đau đầu cho không ít người dùng Python.
Julia dùng từ end để kết thúc if hay for, nên không cần thiết sử dụng dấu cách hay tab để thụt dòng. Thậm chí có thể dùng ; để phân cách các phần, và viết trên 1 dòng (bạn KHÔNG THỂ làm điều này với Python khi có for):
Một điều gây khó chịu với người mới code Python là phần kết thúc của range không được tính. Tức nếu viết range(1,1000) thì chỉ có từ 1 đến 999. Trong đầu luôn phải nhớ bớt đi 1. Julia 1:999 nghĩa là 1 đến 999, không thêm bớt gì.
Do chữ Đ trong Unicode UTF-8 được biểu diễn bằng 2 byte, ta chỉ có thể truy cập được index 1, không truy cập được index 2. Và chữ i ngay sau Đ sẽ là index 3.
Exception
TBD
Chú ý
Julia khởi động mất 0.2-0.4 giây, Python khởi động nhanh gấp 10.
String trong Julia phải dùng double quote "", single quote '' dành cho ký tự (Char).
Nối string dùng * chứ không phải +.
Sẽ không có method gắn liền vào các object như string hay list trong Python, thay vào đó là các function có sẵn (thường không cần import, gọi là trong Base)
Ví dụ 1 chương trình CLI nhận argument, gọi HTTP với JSON
importHTTPimportJSONusingDocOpt# import docopt functionfunctionmain()doc="""Fist Julia program which makes HTTP requests to httpbin endpoint Usage: main.jl request <endpoint> Options: -h --help Show this screen. --version Show version. """args=docopt(doc,version=v"0.0.1")endpoint=args["<endpoint>"]url="https://httpbin.org/$endpoint"println("Accessing $url")resp=HTTP.get(url)d=JSON.Parser.parse(String(resp.body))println("My IP is "*d["origin"])println("Now also send post")r=HTTP.request("POST","https://httpbin.org/post",["Content-Type"=>"application/json"],JSON.json(Dict('a'=>2,'b'=>3)))data=JSON.Parser.parse(String(r.body))open("/tmp/data.json","w")dofwrite(f,JSON.json(data["json"]))endopen("/tmp/data.json","r")dofd=JSON.Parser.parse(String(read(f)))println(d)endopen(`ls -l`)doioforlineineachline(io)if!isa(match(r".*\.jl",line),Nothing)println(line)endendendendmain()
Chạy
$ julia main.jl -h
Fist Julia program which makes HTTP requests to httpbin endpoint
Usage:
main.jl request <endpoint>
Options:
-h --help Show this screen.
--version Show version.
$ julia main.jl request ip
Accessing https://httpbin.org/ip
My IP is 3.117.2.254, 3.117.2.254
Now also send post
Dict{String,Any}("b"=>3,"a"=>2)
-rw-r--r-- 1 viethung.nguyen viethung.nguyen 1189 Apr 1208:38 main.jl
Code hoàn toàn tương đương với code Python.
Kết luận
Còn chờ gì nữa? Làm tí Julia thôi.
Phần tiếp theo (nếu có) sẽ đi vào các tính năng của Julia sử dụng trong tính toán khoa học.
Bài viết được sự cho phép của tác giả Trần Hữu Cương
Trong lập trình, việc xử lý các giá trị đúng/sai là điều thường xuyên phải thực hiện, đặc biệt trong các câu lệnh điều kiện, vòng lặp và kiểm tra logic. Kiểu dữ liệu Boolean được sử dụng để biểu diễn hai trạng thái logic cơ bản này. Cùng tìm hiểu về Bool trong C/C++ được sử dụng như thế nào, cú pháp ra sao trong bài viết của TopDev.
Bool trong C/C++ là gì?
Trong C++, kiểu dữ liệu boolean được sử dụng để biểu diễn hai trạng thái logic: đúng hoặc sai. Kiểu dữ liệu này được gọi là bool, và nó có thể chứa một trong hai giá trị:
true: Đại diện cho giá trị đúng.
false: Đại diện cho giá trị sai.
Kiểu dữ liệu bool được sử dụng rộng rãi trong các câu lệnh điều kiện như if, while, for, và các phép toán logic khác. Khi một giá trị bool được sử dụng trong điều kiện, giá trị true được coi là 1 và false được coi là 0.
Ban đầu, ngôn ngữ C không hỗ trợ kiểu bool, mà nó dùng số integer để biểu thị true/false (0 tức là false, khác 0 tức là true). Bắt đầu từ phiên bản C99 standard for C language thì mới bắt đầu hỗ trợ kiểu bool.
Thư viện <stdbool.h> là một phần của C99, cung cấp định nghĩa cho kiểu bool, cũng như các hằng số true và false. Thư viện này thường được sử dụng trong C hơn là trong C++.
Với cách này ta sử dụng kiểu bool của C (với C++ thì mặc định không cần khai báo thư viện <stdbool.h>)
Ví dụ:
#include<stdio.h>#include <stdbool.h>intmain(){bool value = false;if(value){ // tương đương với kiểm tra value == trueprintf("value is true"); }else{printf("value is false");}return0; }
Nếu bạn không muốn sử dụng kiểu bool tích hợp sẵn, bạn có thể tự định nghĩa nó bằng cách sử dụng enum (liệt kê). Điều này giúp bạn tạo ra kiểu dữ liệu bool của riêng mình với các giá trị true và false.
#include<stdio.h>typedef enum {false,true} bool;int main(){ bool value =false;if(value){ // tuong duong v?i ki?m tra value == true printf("value is true");}else{ printf("value is false");}return0;}
Cách 3: Định nghĩa kiểu bool với integer
Một cách khác để mô phỏng kiểu bool là sử dụng một số nguyên (integer). Trong cách này, bạn quy ước rằng 0 đại diện cho false và 1 (hoặc bất kỳ giá trị khác 0) đại diện cho true.
typedefintbool;
#define true 1#define false 0intmain(){
bool isTrue = true; // isTrue = 1bool isFalse = false; // isFalse = 0if (isTrue) {
// Thực hiện một số hành động khi isTrue là true
}
return0;
}
Cách 4: Khai báo hằng số true/false
Bạn cũng có thể tự định nghĩa các hằng số true và false mà không cần phải tạo kiểu dữ liệu mới. Điều này thường được sử dụng trong các ngôn ngữ hoặc môi trường không hỗ trợ kiểu bool một cách tự nhiên.
#define true 1#define false 0intmain(){
int isTrue = true; // isTrue = 1int isFalse = false; // isFalse = 0if (isTrue) {
// Thực hiện một số hành động khi isTrue là true
}
return0;
}
Cách 1 chỉ chạy được từ phiên bản C99 standard for C language. Tuy nhiên hầu hết các bản compiler C/C++ đều đã update cho nên các bạn nên dùng cách này. Cách 2,3,4: thì hoạt động giống nhau.
Nhìn chung thì kiểu bool vẫn là kiểu integer, nên cho dù dùng cách nào thì bạn vẫn có thể gán bool bằng một giá trị integer bất kì (0 tức là false, khác 0 tức là true).
Các ứng dụng thực tiễn của Bool C++
Kiểu dữ liệu boolean có rất nhiều ứng dụng trong lập trình, từ việc kiểm tra điều kiện trong câu lệnh if, vòng lặp while, for, đến việc sử dụng trong các phép toán logic phức tạp.
Kiểm tra điều kiện trong câu lệnh if
Câu lệnh if là một trong những câu lệnh điều kiện phổ biến nhất trong lập trình, và boolean đóng vai trò quan trọng trong việc xác định các điều kiện đúng hoặc sai.
Ví dụ:
#include<iostream>intmain(){
bool isLoggedIn = true;
if (isLoggedIn) {
std::cout << "User is logged in." << std::endl;
} else {
std::cout << "User is not logged in." << std::endl;
}
return0;
}
Sử dụng trong vòng lặp while
Vòng lặp while sử dụng boolean để xác định khi nào vòng lặp sẽ tiếp tục chạy và khi nào sẽ dừng.
Boolean cũng được sử dụng trong các phép toán logic, như AND (&&), OR (||), và NOT (!), giúp thực hiện các kiểm tra điều kiện phức tạp.
Ví dụ:
#include<iostream>intmain(){
bool isAdmin = true;
bool isLoggedIn = true;
if (isAdmin && isLoggedIn) {
std::cout << "User is an admin and is logged in." << std::endl;
} else {
std::cout << "Access denied." << std::endl;
}
return0;
}
Kiểu dữ liệu boolean là một phần quan trọng và không thể thiếu trong lập trình, giúp lập trình viên thực hiện các kiểm tra điều kiện và các phép toán logic một cách dễ dàng và hiệu quả. Dù là trong ngôn ngữ C với sự thiếu hụt ban đầu của kiểu boolean hay trong C++ với kiểu dữ liệu boolean tích hợp sẵn, việc hiểu và sử dụng đúng cách kiểu boolean là kỹ năng quan trọng mà mỗi lập trình viên cần nắm vững.
Qua bài viết này, hy vọng bạn đã có cái nhìn sâu hơn về cách sử dụng kiểu boolean trong C và C++, cũng như biết cách áp dụng nó vào các tình huống thực tế trong lập trình.
Thư trả lời kết quả phỏng vấn được xem được đánh giá là khá quan trọng đối với các ứng viên. Vì thực tế, bất kỳ ứng viên nào cũng đều mong muốn nhận được phản hồi về kết quả phỏng vấn; dù có trúng tuyển hay không?
Nếu là một doanh nghiệp có công tác chuyên nghiệp trong tuyển dụng, thì việc gửi email hay gọi điện phản hồi kết quả phỏng vấn là điều nên hiển nhiên cần thực hiện. Đây cũng thể hiện doanh nghiệp có một quy trình chặt chẽ; đảm bảo tính lịch sự và để lại ấn tượng đẹp trong lòng nhiều ứng viên. Cùng TopDev tìm hiểu xem đâu là cách thức viết thư trả lời phỏng vấn hiệu quả và chuẩn nhất!
Từ chối ứng viên một cách lịch sự – Cần hay không?
Tất nhiên là có! Và đó cũng là điều mà nhiều doanh nghiệp cần phải quan tâm. Việc tìm ra cách thức để từ chối ứng viên một cách lịch sử cũng trở nên quan trọng hơn.
Và sẽ tùy thuộc vào cách xử lý của mỗi công ty cũng như phòng nhân sự; các giải pháp cụ thể dễ dàng nhất sẽ được diễn ra. Có nhiều cách thức từ chối được thông báo đến ứng viên. Đó có thể là bằng văn bản, bằng email hay bằng liên hệ qua điện thoại thông báo trực tiếp đến từng người,… Tuy vậy, cách chuyển tải nội dung thông báo kết quả qua văn bản. Cụ thể là thư trả lời kết quả phỏng vấn được xem là ưa chuộng nhất.
Có nên cần hay không?
Cùng tham khảo các mẫu trả lời ứng viên dưới đây khi ứng viên của bạn chưa may mắn trúng tuyển nhé!
Mẫu thư trả lời kết quả phỏng vấn cho ứng viên không trúng tuyển
Mẫu email trả lời lịch sự
THÔNG BÁO
V/v …………………………
Kính gửi: ………………………………………………………………………………………………..
Trước hết Công ty xin trân trọng cảm ơn Anh/Chị đã tham gia vào chương trình tuyển dụng của công ty chúng tôi.
Sau khi kiểm tra kiến thức chuyên môn, kỹ năng và phỏng vấn, Công ty xin thông báo: Anh/Chị không trúng tuyển vào vị trí: ………………………………………………………………..
Trường hợp Anh/Chị muốn nhận lại hồ sơ, xin vui lòng liên hệ Anh/Chị ………………………..
Phòng Nhân sự. Nếu Anh/Chị không lấy lại hồ sơ, chúng tôi sẽ chuyển hồ sơ Anh/Chị vào hồ sơ lưu (ứng viên tiềm năng).
Trân trọng kính chào!
TP. NHÂN SỰ
(Ký và ghi rõ họ tên)
Mẫu thư trả lời kết quả chuẩn
THƯ CẢM ƠN
V/v …………………………
Kính gửi:
Lời đầu tiên thay mặt Tập thể công ty xin trân trọng cảm ơn Anh/Chị đã tham gia vào chương trình tuyển dụng của công ty chúng tôi.
Sau khi kiểm tra kiến thức chuyên môn, kỹ năng và phỏng vấn, Công ty xin thông báo: Anh/Chị không trúng tuyển vào vị trí:
Ban tuyển dụng đánh giá cao thời gian bạn dành để ứng tuyển. Chúc bạn may mắn trong quá trình tìm việc và mong rằng có thể hợp tác với bạn ở những vị trí việc làm khác trong tương lai.
Trân trọng kính chào!
NHÂN SỰ
(Ký và ghi rõ họ tên)
Lưu ý về cách viết thư trả lời kết quả sau phỏng vấn ứng viên
Số lượng ứng viên cho một vị trí rất nhiều. Do vậy, sức cạnh tranh là vô cùng lớn. Và việc lưu ý về cách thức viết thư trả lời kết quả của buổi phỏng vấn cũng có thể giúp bạn tối ưu hóa vấn đề thời gian. Đồng thời, vẫn đảm bảo tính chuyên nghiệp, tính lịch sự,… Hãy lưu tâm đến những vấn đề sau đây:
Về thông tin cá nhân của ứng viên
Dù đó là thư từ chối ứng viên; hay thư báo kết quả ứng viên thì cũng cần đảm bảo những thông tin cá nhân cho ứng viên. Điều này minh chứng cho sự chuyên nghiệp của tổ/doanh nghiệp đó.
Lời cảm ơn rất quan trọng!
thư trả lời kết quả phỏng vấn
Một lời cảm ơn chân thành là điều mà mọi ứng viên đều mong muốn nhận được từ doanh nghiệp. Đừng quên dành lời cảm ơn đến ứng viên bởi họ đã quan tâm đến công ty cũng như vị trí mà họ ứng tuyển; dành thời gian của mình để nộp hồ sơ cũng như tham gia cuộc phỏng vấn. Đây thể hiện sự trân trọng lớn với những cố gắng mà họ đã bỏ ra.
Thư phản hồi ứng viên sau phỏng vấn cần được trình bày một cách rõ ràng; rành mạch về lý do. Không nên viết quá dài dòng và lan man. Hãy tập trung vào những yếu tố mang tính xây dựng; khuyến khích tạo động lực thay vì chỉ chia sẻ về việc ứng viên thiếu những gì và không phù hợp ở đâu.
Mời ứng tuyển lại
Đây thật sự là một điểm sáng cho thư trả lời kết quả sau phỏng vấn. Vì nếu công ty thấy ứng viên chưa phù hợp với vị trí hiện tại, hãy lưu hồ sơ của họ. Có thể sẽ có những vị trí phù hợp hơn. Việc thông báo ấy cũng tạo động lực; khích lệ tinh thần của họ một cách tốt hơn.
Lời kết
Thư trả lời kết quả phỏng vấn là một lá thư quan trọng đối với ứng viên. Và quả thật, ai trong số họ cũng quan tâm đến nó. Đó cũng là cơ sở để họ biết được tình trạng kết quả phỏng vấn của mình thế nào.
Mong rằng, với bài viết này, TopDev đã chia sẻ với các bạn các mẫu thư trả lời phỏng vấn cơ bản; cùng những lưu ý giúp thư trả lời kết quả của bạn trở nên chỉn chu; chuyên nghiệp hơn.
Tuyển Dụng Nhân Tài IT Cùng TopDev Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products
Tự hào là nhà phân phối chính thức các thiết bị tin học tại thị trường Việt Nam, ADVN Computer đang dần chiếm ưu thế trong mối quan hệ hợp tác với các thương hiệu công nghệ hàng đầu. Với sự phát triển mạnh mẽ trong lĩnh vực outsource, ADVN Computer luôn tìm kiếm nhân tài công nghệ và sẵn sàng trao tay những cơ hội tuyệt vời.
ADVN Computer và sự tín nhiệm bởi các doanh nghiệp hàng đầu về công nghệ
Ruby on Rails Developer
Vươn lên từ sự thành công của công ty mẹ – AceCom tại Singapore, ADVN Software hình thành năm 2014 với nền tảng ban đầu là nhà phân phối Công nghệ thông tin. Đến nay, ADVN Computer đã trở thành một trong những Công ty phần mềm cung cấp ứng dụng Website, Mobile App, Quảng cáo Google… được ưa chuộng nhất tại thị trường Việt Nam.
Từ năm 2016, ADVN Computer trở thành nhà phân phối chính thức các thiết bị tin học mang thương hiệu tầm cỡ thế giới tại Việt Nam, khẳng định vị thế của mình bởi sự tín nhiệm từ các thương hiệu công nghệ hàng đầu như MSI, Sony, Hitachi, InFocus, Prolink…
Với mục tiêu tập trung phát triển các dự án outsource, thương mại điện tử và quảng cáo chất lượng, công ty luôn nỗ lực tìm tòi, áp dụng công nghệ hiện đại, đồng thời từ đó đáp ứng tối đa và tối ưu các yêu cầu từ khách hàng.
Hoạt động với phương châm “Chuyên nghiệp, sáng tạo, chất lượng” và sự tin cậy từ các Nhà sản xuất, ADVN Computer được chỉ định là Trung Tâm Bảo Hành Ủy Quyền Chính Thức tại Việt Nam cho tất cả các thương hiệu nhằm đảm bảo quyền lợi tuyệt đối về chất lượng, giá cả, kỹ thuật, chế độ hậu mãi (Motorola).
Và để đạt được thành tựu to lớn đó, ADVN Computer luôn ghi nhận tài năng và công sức của đội ngũ “chiến binh” công nghệ – những “phần tử” tài năng luôn cố gắng hết sức mình cho sự phát triển của công ty.
Con đường sự nghiệp rộng mở dành cho Ruby on Rails Developer khi gia nhập ADVN Computer
Ruby on Rails Developer
Ở thời điểm hiện tại, Team Dev nhà ADVN Computer đang tìm kiếm “nhân tố” tài năng cho vị trí Ruby on Rails Developer, với nhiệm vụ hỗ trợ công ty phát triển trang web, trang thương mại điện tử và ứng dụng di động, đáp ứng các nhu cầu từ phía khách hàng.
Và nếu bạn đã nhen nhóm dự định lựa chọn ADVN Computer làm “điểm đến” để phát triển sự nghiệp, đừng ngại gửi CV ứng tuyển ngay hôm nay. ADVN Computer sẵn sàng mang đến cho bạn điều kiện tốt nhất về không gian làm việc, đi kèm với mức lương thưởng và đãi ngộ xứng đáng:
Mức lương hấp dẫn $1,000 – $1,500;
Review lương hàng năm, nâng cao chất lượng sống;
Được đảm bảo mọi quyền lợi các chế độ (ngày phép năm, gói bảo hiểm) đầy đủ theo luật Việt Nam;
Được thử sức mình với các dự án đầy tính thử thách, cải thiện và trau dồi kỹ năng làm việc theo nhóm;
Cơ hội phát triển mạnh mẽ với sự hướng dẫn tận tình, giúp đỡ từ “đàn anh” trong công ty;
Được làm việc trong môi trường quốc tế chuyên nghiệp, thân thiện với đầy đủ tiện nghi và không gian tuyệt vời cho bạn thỏa sức đam mê;
Cùng nhiều hoạt động tập thể, team building, sự kiện thú vị khác.