Các thuật ngữ như Internet of Things hay M2M có lẽ không quá xa lạ với dân IT. Có rất nhiều cách định nghĩa về IoT và trên thực tế đây là một cụm từ khá trừu tượng nên không ít người không biết IoT hoạt động thế nào. Chúng ta hãy cùng đi tìm lời giải đáp.
MVC được hình thành bởi các nghiên cứu của Trygve Reenskaug vào khoảng các năm 1978-1979. Sau đó nó được điều chỉnh và được cài đặt lần đầu tiên vào các lớp của thư viện Xerox PARC Smalltalk-80. Mô hình MVC cổ điển hiện tại ít được sử dụng trong môi trường lập trình desktop như trước đây nhưng hiện tại nó vẫn được sử dụng cực kì rộng rãi như là kiến trúc cơ bản trong các môi trường lập trình web.
Tổng quan mô hình MVC
Tổng quan mô hình MVC
MVC là gì?
Mô hình MVC – Model-View-Controller là phương pháp chia nhỏ các các thành phần dữ liệu (data), trình bày (output) và dữ liệu nhập từ người dùng (input) thành những thành phần riêng biệt.
MVC hoạt động như thế nào?
Thông thường, chúng ta biết rằng mô hình MVC gồm 3 thành phần: Model, View và Controller
View – Nơi người dùng tương tác.
Controller – Xử lý yêu cầu và gửi phản hồi đến view.
Model – Middleware xử lý các thao tác cơ sở dữ liệu.
Mô hình MVC hoạt động như thế nào?
View
Về cơ bản, View đại diện cho cách dữ liệu được trình bày trong ứng dụng (UI). Các view được tạo ra dựa trên dữ liệu thu thập từ model. Bằng cách yêu cầu thông tin từ model, sau đó sẽ trả kết quả tới người dùng. Ngoài việc hiển thị dữ liệu từ các biểu đồ, sơ đồ và bảng, view còn hiển thị dữ liệu từ các nguồn khác. Tất cả các thành phần giao diện người dùng, chẳng hạn như hộp văn bản, menu thả xuống, v.v., sẽ xuất hiện trong bất kỳ view nào của khách hàng.
Controller
Controller là thành phần xử lý tương tác của người dùng. Dữ liệu đầu vào của người dùng được controller phân tích và xử lí, khi người dùng thao tác bất kì với hệ thống controller sẽ gửi thông tin đến model để xử lí và sau đó trả về kết quả view
Người dùng -tương tác-> Controller => Model => View (output) -trả kết quả-> Người dùng
Bằng cách giao tiếp với view liên quan của controller, người dùng có thể thay đổi giao diện của view (ví dụ: cuộn qua một tài liệu) và cập nhật trạng thái của model liên quan (ví dụ: lưu một tài liệu).
Model
Model là nơi lưu trữ dữ liệu và logic. Ví dụ, khi Controller truy xuất thông tin khách hàng từ cơ sở dữ liệu, dữ liệu được chuyển đổi giữa các thành phần controller hoặc giữa các yếu tố logic nghiệp vụ. Nó thao tác dữ liệu và gửi lại cơ sở dữ liệu, hoặc được sử dụng để hiển thị thông tin tương tự.
Ngoài ra, nó phản hồi các yêu cầu từ view và có các chỉ thị từ controller cho phép nó tự cập nhật. Nó cũng là mức thấp nhất của mô hình chịu trách nhiệm duy trì dữ liệu.
Ứng tuyển ngay các vị trí PHP tuyển dụng mới nhất trên TopDev
Ví dụ thực tiễn về mô hình MVC
Khi bạn đến quán trà đá và gọi 1 cốc trà đá. Lúc này:
Bạn là “người dùng” và “cốc trà đá” là “yêu cầu từ phía người dùng”.
Đối với bà chủ quán, cốc trà đá là một quy trình gồm các bước:
Lấy cái cốc
Cho đá vào
Cho trà vào
Cho thêm nước lọc cho trà loãng bớt
Khuấy đều lên
Đưa cốc trà cho bạn
Thanh toán
Bộ não của bà chủ quán lúc này đóng vai trò Controller. Kể từ thời điểm bạn nói “một cốc trà đá” bằng tiếng Việt và bà chủ quán hiểu được, công việc bắt đầu. Trà đá, nước mía hay cocktail thì cũng như nhau, nhưng nguyên liệu thì hoàn toàn khác biệt. Bà chủ quán chỉ có thể sử dụng những công cụ và nguyên liệu của quán, và những công cụ đó sẽ đóng vai trò Model, bao gồm:
Đôi tay của bà chủ
Các nguyên liệu pha chế (trà, nước …)
Đá lạnh
Bia, nước ngọt, thuốc lá…
Chanh, sấu, gừng…
Các ly cốc để đựng đồ uống
Những nguyên liệu và công cụ này, thông qua một loạt các bước, đã trở thành cốc trà đá mát lạnh đến tay bạn. Cốc trà đá lúc này đóng vai trò View. “View” được làm nên từ những công cụ, nguyên liệu trong “Model”, được chế biến và bàn giao tới tay bạn thông qua “Controller” (chính là bộ não của bà chủ quán).
Mô hình MVC ra đời giúp các lập trình viên giải quyết nhiều vấn đề lúc bấy giờ, cùng điểm qua các ưu điểm của MVC:
Mã nguồn dễ bảo trì và mở rộng: Kiến trúc MVC giúp mã nguồn dễ bảo trì, có thể mở rộng và phát triển một cách dễ dàng.
Các thành phần có thể kiểm tra độc lập: Các thành phần của nó có thể được kiểm tra riêng biệt từ các thành phần người dùng.
Hỗ trợ các loại khách hàng mới dễ dàng hơn: Kiến trúc này hỗ trợ việc thêm các loại khách hàng mới một cách dễ dàng.
Phát triển song song các thành phần: Có thể phân chia phát triển các thành phần khác nhau một cách song song.
Giảm bớt độ phức tạp: Bằng cách chia ứng dụng thành ba phần, bạn có thể tránh được sự phức tạp.
Sử dụng mô hình Front Controller: Chỉ sử dụng mô hình Front Controller, trong đó mỗi yêu cầu được xử lý bởi một bộ điều khiển duy nhất.
Hỗ trợ phát triển theo hướng kiểm thử tối đa: Hỗ trợ phát triển theo hướng kiểm thử (TDD) một cách tối đa.
Dễ dàng cho các nhóm phát triển lớn: Một nhóm lớn các nhà thiết kế và phát triển web có thể tạo và duy trì các ứng dụng web với nó.
Kiểm tra từng lớp và đối tượng riêng biệt: Bạn có thể kiểm tra tất cả các lớp và đối tượng riêng lẻ vì chúng đều độc lập với nhau.
Hành động của bộ điều khiển có thể nhóm logic: Các hành động của bộ điều khiển có thể được nhóm lại một cách logic bằng cách sử dụng các mẫu thiết kế MVC.
Nhược điểm của Kiến trúc MVC
Bên cạnh ưu điểm MVC cũng tồn tại một số nhược điểm:
Khó đọc, thay đổi và kiểm thử đơn vị: Khó đọc, thay đổi và kiểm thử đơn vị mô hình này vì không có thành phần riêng biệt để xử lý giao diện người dùng (UI). Tất cả phải được thực hiện trên lớp view. Vì vậy, cần phải phụ thuộc vào một framework khác để làm điều đó.
Không hỗ trợ xác thực chính thức: Kiến trúc MVC không cung cấp hỗ trợ xác thực chính thức. Vì vậy, việc xác thực cần phải được thực hiện rõ ràng.
Xử lý dữ liệu có thể không hiệu quả: Có thể dẫn đến quá trình xử lý dữ liệu không hiệu quả vì nó làm cho logic thực thi trở nên phức tạp.
Khó sử dụng với giao diện người dùng hiện nay: Việc sử dụng MVC khó khăn với giao diện người dùng hiện đại. Hầu hết các framework UI phổ biến hiện nay đều có kiến trúc triển khai riêng của chúng và không thể nhúng vào MVC.
Cần duy trì nhiều mã trong bộ điều khiển: Cần duy trì nhiều mã trong các bộ điều khiển, gần như cho mỗi hành động khác nhau trên trang, chúng ta cần khai báo các phương thức Action riêng biệt.
Nhầm lẫn về MVC
Một nhầm lẫn thường gặp trong quan hệ giữa các thành phần MVC là khi xem mục đích của Controller như là thành phần trung gian để tách rời View khỏi Model. Trong khi thực tế, kiến trúc MVC tách rời dữ liệu và xử lý trung tâm khỏi phần trình bày thông qua cơ chế là Observer Pattern chứ không phải Controller. Nhiệm vụ của Controller là cần nối giữa người dùng là ứng dụng, không phải giữa View và Model.
Trong khi mục đích chính của MVC là tách rời trình bày và các xử lý bên trong. Việc phân rõ vai trò xử lý ouput (View) và input (Controller) là một hệ quả nhằm hoàn thiện cơ chế cho ý tưởng trên. Hiện nay trong nhiều môi trường lập trình hiện đại, nhiều control được cung cấp và hoàn thiện hơn (nhiều xử lý sự kiện cơ bản đã được hỗ trợ sẵn) so với trước đây nên việc khoáng tất cả các xử lý sự kiện cho một thành phần độc lập như Controller không còn là vấn đề quan trọng nữa.
Trong khi đó, những cơ chế như Observer Pattern cũng có vấn đề của riêng chúng. Trong khi được dùng như phương tiện hiệu quả để loại bỏ sự phụ thuộc của Model vào các thành phần khác, nó có một vấn đề lớn là tại một thời điểm, chúng ta khó có thể xác định điều gì sẽ xảy ra bằng cách đọc code và việc thực hiện các testing cũng khó khăn hơn. Hơn nữa, do Model chỉ liên kết gián tiếp đến View thông qua Observer Pattern, khi sự thay đổi trạng thái của Model cần đến một vài thao tác xử lý phức tạp để áp dụng lên giao diện thì với mô hình cổ điển sẽ gặp khó khăn.
Một vấn đề khác là chúng ta cần lưu trữ tình trạng hiện tại của UI (UI state), ví dụ trong danh sách sinh viên thì chúng ta cần biết sinh viên nào đang được chọn. Trong khi thành phần UI nắm giữ dữ liệu trình bày đang được chọn thì dữ liệu sinh viên thuộc về Model, như vậy dữ liệu về sinh viên được chọn sẽ được lưu trữ ở đâu khi cần truy xuất đến?
Vì những lí do trên, MVC sau này đã có những thay đổi và bổ sung nhất định (như khái niệm Application Model). Kiến trúc MVP chúng ta sẽ bàn dưới đây cũng dựa trên tư tưởng cơ bản của MVC nhưng với cách tiếp cận khác nhằm mục đích khắc phục các khuyết điểm đã có.
Bài viết được sự cho phép của tác giả Kien Dang Chung
Video trong bài viết
Ứng dụng Todo List đã gần thành hình với các chức năng tạo bản ghi mới, xem danh sách bản ghi và xem chi tiết từng bản ghi. Tiếp theo, trong bài học hôm nay chúng ta cùng tìm hiểu về một công việc rất quan trọng: Kiểm tra dữ liệu. Tại sao kiểm tra dữ liệu quan trọng? chúng ta cùng tìm hiểu nhé.
Người dùng không hề biết phải nhập dữ liệu như thế nào vào ứng dụng, đặc biệt khi mới lần đầu sử dụng và như vậy việc nhập liệu có thể dẫn đến lỗi ứng dụng. Hơn nữa, dữ liệu là một tài nguyên quan trọng trong ứng dụng, muốn khai thác tài nguyên này chúng ta cần có tài nguyên được sắp xếp và phân loại một cách rõ ràng. Ví dụ như một ô nhập liệu về ngày sinh, có rất nhiều các giá trị như 01/02/1983, 19830201, Feb 01 1983, Ngày 01 tháng 02 năm 1983… tuy nhiên, máy tính lại không thể hiểu tất cả các kiểu nhập liệu này, đặc biệt khi khai thác dữ liệu chúng ta rất dễ bị nhầm lẫn, vậy nên việc kiểm soát dữ liệu và bắt người dùng thực hiện các quy tắc nhập liệu ngay từ đầu là một việc rất quan trọng.
Các controller trong Laravel đều được kế thừa từ class App\Http\Controllers\Controller, mà class này sử dụng trait ValidateRequests cho phép chúng ta kiểm tra dữ liệu thông qua gọi phương thức validate().
Trở lại đoạn code lưu dữ liệu xuống database trong bài trước, chúng ta cần kiểm tra dữ liệu trước khi thực hiện lưu dữ liệu, cùng xem đoạn code thực hiện như sau:
Tham số thứ nhất là đối tượng request chứa thông tin về dữ liệu được gửi lên từ người dùng.
Tham số thứ hai là một mảng các quy tắc kiểm tra cho từng trường nhập liệu có trong request.
Trường name: bắt buộc nhập, tối thiểu 6 ký tự, tối đa 12 ký tự.
Trường description: bắt buộc nhập.
Như vậy chúng ta đã thực hiện kiểm tra dữ liệu trước khi lưu trữ xuống database. Tuy nhiên nếu chúng ta thực hiện nhập liệu sai thì không thấy ứng dụng có phản hồi gì cả, đó là do chúng ta chưa hiển thị thông báo lỗi nhập liệu ra ứng dụng.
Hiển thị thông báo lỗi kiểm tra dữ liệu
Mặc định trong Laravel, khi kiểm tra dữ liệu gặp lỗi, hệ thống tự động truyền đến trang (view) hiện tại một biến là $errors. Biến này chứa thông tin về các lỗi xảy ra khi kiểm tra dữ liệu.
Trong view hiện hành, ở đây là create.blade.php, để hiển thị các lỗi kiểm tra dữ liệu nếu có, chúng ta sử dụng một vòng lặp và hiển thị các lỗi là một thành phần của danh sách:
Bài viết được sự cho phép của blogchiasekienthuc.com
Chào các bạn, một vài hôm trước mình có đọc được một bài báo thống kê rằng năm học 2021 ngành IT nói riêng và khối ngành công nghệ kỹ thuật nói chung là một trong những ngành có tỷ lệ chọi cao nhất (khoảng 1/64).
Nói đến đây đủ để thấy rằng trong những năm trở lại đây thì ngành công nghệ thông tin đã trở nên “hot” như thế nào!
Một câu hỏi đặt ra là liệu với số lượng lớn học sinh có ý định theo học ngành IT như vậy thì trong một vài năm tới, ngành IT có còn “hot” như vậy được nữa hay không? Liệu nhân lực ngành này có bị bão hòa hay không?
Trong bài viết này mình sẽ chia sẻ một vài quan điểm của cá nhân mình dưới cái nhìn của một người đang học và làm về IT về hai câu hỏi trên.
#1. Nhiều người đang “ảo tưởng” về ngành IT
Có lẽ những câu chuyện về sinh viên IT mới ra trường làm lương 2000 – 3000$ một tháng, hay những bài báo giật tít về mức thu nhập “khủng” của dân IT đã khiến nhiều người ảo tưởng về ngành này.
Điều này cũng dễ hiểu thôi vì người dân Việt Nam mình thường có xu hướng làm theo đám đông. Nhiều người không chịu bỏ thời gian tìm hiểu gốc rễ vấn đề mà luôn tin vào hiệu ứng đám đông, ủng hộ số đông. Sợ thật ◔◡◔
Là một người học và làm IT thì mình hiểu rất rõ về vấn đề thu nhập, để đạt được mức lương ngàn đô hay mấy chục triệu một tháng khi mới ra trường (như lời đồn) là điều rất khó, thực sự khó.
Trừ khi bạn là người có năng lực thực sự, kiểu mấy ngàn người mới có một người ấy. Mà các bạn biết đấy, con số này rất ít.
Và mình tin là có rất nhiều bạn học sinh khi đăng ký học công nghệ thông tin thì ít nhiều đã bị tác động bởi những con số có chút “ảo” này, mà không chịu tìm hiểu kỹ càng.
Bạn nên nhớ là, bạn nên theo đuổi những cái mà bạn thực sự thích và muốn tìm hiểu. Giỏi thì nghề nào cũng giàu thôi. Và có như vậy mới bền lâu được !
Nhưng cũng chẳng thể trách được, vì công tác hướng nghiệp của Việt Nam chúng ta còn quá yếu kém, trong khi báo chí thì lại thường xuyên thổi phồng dẫn đến nhiều bạn học sinh bị “ảo tưởng” và hệ lụy là tỷ lệ chọi cao ngất ngưởng.
Quay lại với câu hỏi thì “ảo tưởng” như thế thì có ảnh hưởng gì đến độ “hot” của ngành này trong vài năm tới hay không?
Các bạn cứ hình dung thử xem, bạn bị lừa thì cùng lắm là chỉ bị lừa một lần thôi chớ. Ví dụ như trong nhà bạn có ông anh làm IT lương tháng cũng 9 – 10 triệu, trong khi đó phải làm sờ mờ lờ (sấp mặt luôn) suốt ngày…
Thử hỏi nếu bạn định đăng ký học IT thì ông anh bạn có nói như báo đài nói hay không? Có thể ông ý vẫn bảo bạn thích thì học, lương cũng không tệ nhưng chắc chắn là bạn sẽ phải suy nghĩ lại một cách thấu đáo hơn.
Số lượng và chất lượng là những con số thường tỷ lệ nghịch đối với lao động Việt Nam.
Mình không hề có ý chê bai chất lượng lao động của người Việt Nam thấp, nhưng thực tế cho thấy, với các ngành đòi hỏi phải làm việc trí óc nhiều như làm IT thì hiệu suất làm việc của chúng ta rất thấp, đây là một sự thật mà chúng ta cần phải nhìn nhận để cố gắng hơn.
Khi mà số lượng rất lớn người đổ xô đi học công nghệ thông tin nhưng chất lượng đào tạo lại chưa được tốt, đào tạo ra nhưng không làm được việc, vẫn nặng về lý thuyết, thiếu thực hành, thiếu tính thực tế…
Mà các bạn biết đó, bất cứ thị trường nào cũng có tính đào thải, đặc biệt là những thị trường lao động đòi hỏi trí óc. Mà với dân IT, 90% kiến thức là tự học, công nghệ thay đổi theo từng giờ..
Nhà tuyển dụng họ sẵn sàng loại đi 9 trong 10 người, chỉ để lấy một người có năng lực thực sự, phù hợp và đáp ứng được công việc mà họ cần.
Điều này đồng nghĩa với việc nhiều người nghĩ cứ học công nghệ thông tin ra trường kiểu gì cũng có việc là hoàn toàn sai lầm. Việc thì có đấy, nhưng quan trọng bạn kiếm được bao nhiêu tiền..
Bạn phải hiểu rằng, số lượng càng nhiều thì mức độ cạnh tranh càng khốc liệt, mà cạnh tranh càng khốc liệt thì mức độ đào thải càng cao.
Và đến một thời điểm, mức độ đào thải đủ để cân bằng cung và cầu về nhân lực ngành IT thì lúc đó ngành IT sẽ không còn “hot” như hiện tại nữa.
#3. Sự phát triển của nhiều ngành nghề mới
Nếu bạn để ý thì có thể thấy ngành IT bây giờ cũng giống như ngành kế toán ngày trước. Từng có thời kỳ rất nhiều người đổ xô đi học kế toán, ngân hàng… các thứ !
Ngành IT nói riêng và các khối ngành kỹ thuật nói chung chịu ảnh hưởng tích cực từ cuộc cách mạng 4.0 nên nhu cầu nhân lực chất lượng đang rất hiếm.
Nhưng rõ ràng, cuộc cách mạng 4.0 không chỉ ảnh hưởng đến lĩnh vực công nghệ không đâu, mà nó còn tác động rất nhiều đến các ngành nghề khác nữa.
Nhiều ngành nghề phát triển rất nhanh nhờ áp dụng chính thành quả của các sáng tạo công nghệ. Ví dụ như bán hàng online, Maketing online, nuôi trồng áp dụng công nghệ cao…
Bất cứ ngành nghề nào cũng có thể áp dụng các tiến bộ khoa học kỹ thuật được. Nhưng điều đó không có nghĩa là những ngành nghề đó phụ thuộc vào công nghệ.
Công nghệ mở ra một hướng đi mới để từ đó người ta phát triển ngành đó theo một hướng đi mới. Tốt hơn và hiệu quả hơn !
Và tất nhiên, như một điều tất yếu thì người lao động sẽ có thêm những lựa chọn mới, những hướng đi mới cho những gì họ vẫn đang làm.
Cá nhân mình thấy thì đây chính là nguyên nhân có tác động mạnh mẽ nhất đến mức độ “hot” của ngành IT trong vài năm tới, vì theo thống kê có một số lượng lớn người học IT sau khi học xong ra trường lại không làm IT.
Họ chuyển hướng sang làm những công việc không liên quan trực tiếp đến công nghệ, hay nói cách khác là họ chuyển hướng sang làm các công việc có ứng dụng công nghệ. Hai cái này khác nhau nhé, các bạn đừng nhầm lẫn !
#4. Lời kết
Tóm lại, theo nhận định của cá nhân mình thì trong một vài năm tới, ngành IT vẫn sẽ rất “hot” bởi vì thị trường lao động này chưa đạt đến độ bão hòa về số lượng, trong khi chất lượng chưa thay đổi nhiều.
Nhưng sau một vài năm nữa mình tin chắc mức độ “hot” sẽ giảm dần do có nhiều ngành nghề mới ra đời.
Và thực tế đã co thấy, làm việc trong ngành IT không phải “ngồi mát ăn bát vàng” như nhiều người vẫn nghĩ. Đến một lúc nào đó, nhiều người nhận ra được sự thật này thì họ sẽ tự động thay đổi quan điểm và ngành IT sẽ hết “hot” mà thôi.
Mình chỉ có một lời nhắn nhủ chân thành như thếnày: Nếu các bạn thực sự đam mê với ngành IT, một lĩnh vực nào đó trong ngành IT thì wellcome, bạn nên tham gia ngay. Còn nếu bạn chỉ học IT vì bạn đọc đâu đó, hoặc nghe đâu đó vì có lương cao thì nên cân nhắc lại.
Vâng, đó là những quan điểm của cá nhân mình, không biết các bạn nghĩ thế nào. Nếu có quan điểm gì khác thì hãy comment bên dưới nha. Xin chào và hẹn gặp lại các bạn trong các bài viết tiếp theo.
Trong các bài viết trước, chúng ta đã cùng tìm hiểu về Direct Exchange. Trong bài này, tôi sẽ giới thiệu với các bạn một loại exchange khác là Fanout Exchange.
Fanout exchange (định tuyến broadcast – amq.fanout) định tuyến message (copy message) tới tất cả queue mà nó được bind, với bất kể một routing key nào. Giả sử, nếu nó N queue được bind bởi một Fanout exchange, khi một message mới published, exchange sẽ định tuyến message đó tới tất cả N queues. Fanout exchange được sử dụng cho định tuyến message broadcast (quảng bá).
Flow của một Message trong Fanout Exchange như sau:
Một Producer sẽ tạo một Message và publish tới Exchange.
Một hoặc nhiều Queue bind tới Fanout Exchange không cần thông tin routing key.
Một Message tới Exchange sẽ được chuyển tiếp đến tất cả các Queue mà không có bất kỳ điều kiện kiểm tra nào.
Exchange Fanout hữu ích với trường hợp ta cần một dữ liệu được gửi tới nhiều ứng dụng khác nhau với cùng một message nhưng cách xử lý ở mỗi ứng dụng là khác nhau.
Ví dụ Fanout Exchange trong RabbitMQ
Trong ví dụ này, tôi tạo một Fanout Exchange có tên GPCoderFanoutExchange, tạo 3 Queue binding tới Fanout Exchange này: QDeveloper, QManager, QGeneral.
Một số class của chương trình:
ConnectionManager : hỗ trợ tạo Connection đến RabbitMQ.
FanoutExchangeChannel : class util hỗ trợ tạo Echange, Queue, binding Queue đến Exchange, publish/ subscribe message, …
Constant : định nghĩa constant chứa các thông tin về tên Exchange, Queue.
Producer: để gửi Message đến Exchange.
Consumer: để nhận Message từ Queue.
App: giả lập việc gửi nhận Message thông qua Fanout Exchange của RabbitMQ.
ConnectionManager.java
package com.gpcoder.fanoutexchange;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConnectionManager {
private ConnectionManager() {
super();
}
public static Connection createConnection() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
return factory.newConnection();
}
}
package com.gpcoder.fanoutexchange;
public final class Constant {
// Exchange
public static final String EXCHANGE_NAME = "GPCoderFanoutExchange";
// Queue
public static final String DEV_QUEUE_NAME = "QDeveloper";
public static final String MANAGER_QUEUE_NAME = "QManager";
public static final String GENERAL_QUEUE_NAME = "QGeneral";
private Constant() {
super();
}
}
package com.gpcoder.fanoutexchange;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class App {
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
// Create producer
Producer producer = new Producer();
producer.start();
// Send one message to exchange, it will be forwarded to all queues
producer.send("gpcoder message 1");
// Create consumer
Consumer consumer = new Consumer();
consumer.start();
consumer.subscribe();
TimeUnit.SECONDS.sleep(1);
// Try to send a second message
producer.send("gpcoder message 2");
}
}
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Trong OAuth 2.0, chúng ta có thể có nhiều loại Client Application khác nhau mà người dùng có thể sử dụng để access tới các resources của resource server. Ví dụ như chúng ta có native mobile application, web application bao gồm cả Single Page Application, console hay backend application, … Những Client Application này sẽ cần phải đăng ký với Authorization Server và sử dụng thông tin Client ID được cung cấp bởi Authorization Server để lấy access token. Một số grant type trong OAuth 2.0 đòi hỏi chúng ta phải cung cấp cả Client Secret, cái mà Client Application được Authorization Server cung cấp cùng với Client Id, ví dụ như grant type Client Credentials chẳng hạn.
Không phải tất cả các Client Application đều có thể lưu trữ Client Secret một cách bảo mật. Ví dụ như Native mobile application hay Single Page Application. Vì thế, OAuth 2.0 định nghĩa 2 loại Client Types khác nhau bao gồm: các confidential clients và các public clients.
Confidentials clients là những client có thể lưu trữ Client Secret bảo mật, ví dụ như chúng ta có những web application có cả backend và frontend thì Client Secret có thể lưu trữ ở backend side, không ai có thể lấy được thông tin này.
Ngược lại thì public clients là những client không thể đảm bảo việc lưu trữ Client Secret bảo mật, ví dụ như native mobile application hay Single Page Application, người dùng có thể decode hoặc view source code để xem thông tin Client Secret. Đối với những clients này, chúng ta cần sử dụng những grant type mà không cần Client Seret ví dụ như Authorization Code grant type với PKCE các bạn nhé!
Snowpack là một công cụ xây dựng để xây dựng môi trường phát triển front-end.
Snowpack cung cấp một bộ khởi động độc lập cho mỗi môi trường phát triển được gọi là Tạo ứng dụng Snowpack (CSA). Lần này, tôi sẽ giới thiệu quy trình tạo một Thành phần Web đơn giản bằng cách sử dụng app-template-lit-element là một trong Tạo ứng dụng Snowpack .
Decorators chưa có sẵn trong JavaScript gốc, nhưng chúng có thể được sử dụng với các plugin của Babel
Bên cạnh việc xác định custom element, hãy xác định mẫu Shadow DOM cho component. Hãy render()triển khai một hàm của lớp LitElement . Call the lit-element htmlfunction in a tagged template literal so that the render()function returns the result.
Khi mô tả được hoàn thành cho đến nay, các phần tử của màn hình được hiển thị ./src/app-root.jsvà thành phần đã tạo được importđọc bởi một câu lệnh. Sau đó, ./src/app-root.jscác render()chỉ định nghĩa các chức năng <toggle-button>để mô tả.
Nếu bạn thực thi mã cho đến nay trong trình duyệt, nó sẽ giống như hình chụp sau.
Property
Tôi muốn chuyển đổi kiểu nút và văn bản được kích hoạt bởi sự kiện nhấp chuột, vì vậy tôi muốn xác định thuộc tính được đặt tên cho liên kết dữ liệu trong trình trang trí @propertypressed .
Trước hết, tải trình trang trí @property từ thư viện phần tử ánh sáng và viết mã sau.
import { customElement, property, LitElement, html } from 'lit-element';
@customElement('toggle-button')
export class ToggleButton extends LitElement {
@property({
type: Boolean,
reflect: true
})
pressed = false;
// ...
}
Với LitElement, bạn có thể tùy chỉnh hành vi của các thuộc tính, v.v. và nội dung có thể được đặt dưới dạng một tùy chọn. Điểm lần này là cài đặt được gọi là phản chiếu . Điều này reflectcho phép các thay đổi thuộc tính được phản ánh dưới dạng thuộc tính trong các phần tử tùy chỉnh. Kể từ khi tài sản được thiết lập với Boolean thời gian này true, falsecác thuộc tính được thêm vào khi nào, và thuộc tính sẽ bị xóa khi. Bằng cách này, LitElement cho phép bạn tùy chỉnh hành vi của chính thuộc tính .
Tiếp theo pressed, viết một biểu thức để chuyển đổi từ ngữ của nút trong phần tử tùy chỉnh bằng cách sử dụng thuộc tính đã xác định . Ngoài ra, hãy mô tả thuộc tính @click trong mẫu và liên kết hàm pressedchuyển đổi giá trị boolean của thuộc tính toggle().
Bằng cách này, toggle()hàm sẽ cập nhật thuộc tính mỗi khi bạn nhấp vào nó và truenếu thuộc tính được nhấn có giá trị, pressedthuộc tính sẽ được thêm vào HTML .
Nếu bạn thực thi mã cho đến nay trong trình duyệt, nó sẽ giống như hình chụp sau.
Nếu bạn thực thi mã cho đến nay trong trình duyệt, nó sẽ giống như hình chụp sau. Điều này hoàn thành một thành phần đơn giản.
Build
Lệnh xây dựng như sau.
npm run build
Tại thời điểm xây dựng, Snowpack dịch các thư viện phụ thuộc vào ứng dụng của bạn để chúng có thể được tải bằng cách nhập ESM. Các thành phần được xuất ra build/_dist_/các thư mục và các gói phụ thuộc build/web_modules/được xuất ra.
Snowpack không có trình gói mô-đun theo mặc định và bằng cách giới thiệu @ snowpack / plugin-webpack và @ snowpack / plugin-parcel , được cung cấp dưới dạng plugin chính thức, nó hỗ trợ các trình duyệt cũ không hỗ trợ nhập ESM. Bạn hoàn toàn có thể làm được. Tuy nhiên, developxin lưu ý rằng ngay cả khi cài đặt Bundle, lệnh sẽ được xuất ra bởi Mô-đun ES.
Những Câu Hỏi Nên Hỏi Khi Phỏng Vấn Giúp Ứng Viên Ghi Điểm Với Nhà Tuyển Dụng
Phỏng vấn là quá trình trao đổi thông tin giữa hai bên: ứng viên và nhà tuyển dụng, để cả hai có thêm hiểu biết về nhau và đánh giá được sự phù hợp giữa hai bên. Một câu hỏi quen thuộc mà các ứng viên thường gặp trong quá trình phỏng vấn là “Bạn có câu hỏi gì muốn hỏi chúng tôi không?”, “Bạn muốn tìm hiểu thêm thông tin gì không?”. Đừng bao giờ trả lời “Tôi không có thắc mắc nào”. Hãy tìm hiểu thêm về những câu hỏi nên hỏi nhà tuyển dụng, chúng sẽ giúp bạn ghi điểm đầy ấn tượng trong mắt nhà tuyển dụng đấy.
Biết cách đặt câu hỏi sẽ giúp ứng viên “ghi điểm” với nhà tuyển dụng
Tại sao cần chuẩn bị trước những câu hỏi nên hỏi nhà tuyển dụng?
Có nhiều lý do khác nhau mà ứng viên nên để tâm đến việc chuẩn bị những câu hỏi sẽ hỏi người phỏng vấn. Cách đặt câu hỏi sẽ phản ánh rất chân thật sự quan tâm của ứng viên đến công việc và vị trí họ ứng tuyển. Người phỏng vấn, nhất là những người trực tiếp quản lý nhân sự trong phòng ban sẽ đánh giá rất cao việc ứng viên đặt những câu hỏi liên quan đến công việc chuyên môn hoặc sắp xếp tổ chức trong quá trình làm việc. Những câu hỏi này cho thấy ứng viên thật sự quan tâm và mong muốn có được công việc, vì đã dành nhiều thời gian để tìm hiểu về nó.
Thêm vào đó, nhờ đã tìm hiểu thông tin đủ nhiều và đã có một số câu hỏi liên quan, khi nhà tuyển dụng trả lời câu hỏi của mình, ứng viên có thể dựa vào các vấn đề đó để khai thác các thông tin liên quan khác. Suy cho cùng, mục đích của việc đặt câu hỏi là để ứng viên có thêm thông tin về công ty mà các tìm kiếm trên mạng không có kết quả.
Do đó, đừng bao giờ đặt ra những câu hỏi mà bạn hoàn toàn có thể tìm được câu trả lời trên internet nhé. Hãy cố gắng khai thác tối đa các thông tin từ hai phía để buổi phỏng vấn trở nên thú vị và suôn sẻ hơn thay vì ứng viên chỉ trả lời những câu hỏi của người phỏng vấn.
Những câu hỏi nên hỏi nhà tuyển dụng trong quá trình phỏng vấn
Như đã đề cập, việc đặt câu hỏi là để khai thác thông tin phục vụ cho công việc và quyền lợi ứng viên. Vậy nên không nên đặt những câu hỏi quá đơn giản, câu trả lời chỉ là có hoặc không.
Đặt những câu hỏi liên quan đến chuyên môn công việc
Việc đặt những câu hỏi về chuyên môn công việc chắc chắn là cần thiết để ứng viên có thể hiểu rõ hơn vị trí mình đang ứng tuyển, bản thân có thể đóng góp gì cho công ty từ kinh nghiệm làm việc của bản thân, và có thể học thêm được những gì mới ở công việc này. Một số mẫu câu hỏi mà bạn có thể tham khảo như:
Vị trí này có yêu cầu những kỹ năng đặc biệt gì để hỗ trợ cho công việc không?
Ngoài những gì được mô tả trong JD (Job Description), tôi phải làm thêm những việc nào khác nữa không? Nếu có, những việc đó chiếm bao nhiêu phần trăm trong khối lượng công việc tôi phải đảm nhận?
Lộ trình công việc của công ty với vị trí này như thế nào?
Từ kinh nghiệm của những người đi trước, tôi nên duy trì thói quen nào hoặc chuyên môn nào trong công việc để làm tốt hơn?
Thử thách lớn nhất ở vị trí này là gì?
Đặt những câu hỏi liên quan đến công ty
Công ty nào cũng mong muốn có thể tìm được những nhân viên tài năng và thật sự gắn bó với công ty. Đó cũng là lý do mà nhân sự luôn là phòng ban quan trọng trong việc tìm kiếm nhân tài cho công ty. Đưa ra những câu hỏi liên quan đến công ty và phòng ban làm việc sẽ giúp người phỏng vấn đánh giá được chính xác mong muốn gắn bó của ứng viên với công ty. Và đương nhiên cũng sẽ giúp ứng viên xem xét những mục tiêu của công ty với mục đích nghề nghiệp của bản thân có tương xứng.
Một số câu hỏi ứng viên có thể đặt ra với người phỏng vấn như:
Xu hướng phát triển của công ty trong 5 năm tới như thế nào? Các sản phẩm mà công ty hướng đến nằm trong lĩnh vực chính yếu nào?
Điểm mạnh của công ty là gì?
Phòng ban tôi làm việc chịu trách nhiệm với những công việc nào trong công ty?
Quy mô nhân sự của phòng ban hiện đang như thế nào?
Quản lý đánh giá như thế nào về môi trường là việc tại phòng ban cũng như chất lượng nhân sự?
Có một số câu hỏi mẫu để ứng viên tham khảo
Đặt câu hỏi về quy trình làm việc tiếp theo sau buổi phỏng vấn
Đây chắc chắn là phần quan trọng mà bất cứ ứng viên nào cũng không nên bỏ qua ở cuối mỗi buổi phỏng vấn. Hãy hỏi người phỏng vấn:
Nếu thông qua buổi phỏng vấn này thì bước tiếp theo của quy trình tuyển dụng là gì?
Sau bao lâu tôi sẽ nhận được kết quả phỏng vấn?
Tôi nên giữ liên lạc với ai để nắm được các thông tin sau buổi phỏng vấn này?
Yếu tố quan trọng của một buổi phỏng vấn là sự hòa hợp và thái độ giữa hai phía. Ứng viên có thể linh động dựa vào thái độ của người phỏng vấn để hỏi họ những câu hỏi mang tính cá nhân cũng là một lựa chọn không tồi.
Cá nhân anh/chị đánh giá như thế nào về môi trường làm việc ở công ty?
Anh/chị đã làm việc ở công ty này bao lâu rồi?
Anh/chị có nghĩ mình đã thành công và học được nhiều chuyên môn hơn ở công ty không?
Một số lưu ý khi đặt câu hỏi để tránh mất điểm trong mắt nhà tuyển dụng
Bên cạnh những câu hỏi ứng viên nên hỏi nhà tuyển dụng cũng có một số lưu ý trong quá trình đặt câu hỏi khi phỏng vấn để tránh mất điểm. Đừng đặt những câu hỏi mà câu trả lời ứng viên hoàn toàn có thể tìm kiếm trên mạng, đây chắc chắn là yếu tố rất dễ khiến bạn mất điểm trong mắt nhà tuyển dụng. Việc đặt những câu hỏi như thế này không chỉ khiến hai bên làm mất thời gian của nhau mà còn khiến người phỏng vấn đánh giá thấp sự quan tâm và mong muốn của ứng viên với công ty.
Ngoài ra, ứng viên cũng không nên đặt ra những câu hỏi quá sâu về các hoạt động riêng của công ty. Tốt hơn hết chỉ nên hỏi đến những vấn đề như văn hóa làm việc. Cũng không nên đề cập quá nhiều đến vấn đề lương thưởng nếu nhà tuyển dụng chưa nhắc đến nó. Đừng quá nôn nóng với lương thưởng sẽ giúp nhà tuyển dụng đánh giá cao tinh thần làm việc và mong muốn của bạn hơn.
Mặc dù những vấn đề nên hỏi trong khi phỏng vấn được đề cập ở trên khá nhiều, tuy nhiên bạn nên cân nhắc đặt ra những câu hỏi hợp lí và phù hợp với tình hình công ty. Không nên đặt quá nhiều câu hỏi hay hỏi quá lan man. Hãy hỏi những vấn đề mà bạn cảm thấy quan tâm nhất trong số những câu hỏi nên hỏi nhà tuyển dụng ở trên để buổi phỏng vấn diễn ra suôn sẻ nhất.
Trong các bài viết trước chúng ta đã tìm hiểu về Default Exchange, cách tạo Work Queue với RabbitMQ. Trong bài này, chúng ta sẽ cùng tìm hiểu về Direct Exchange trong RabbitMQ.
Direct Exchange (trao đổi trực tiếp – amq.direct) định tuyến message đến Queue dựa vào routing key.
Một Exchange không xác định tên (empty String), đây là loại Default Exchange, một dạng đặc biệt của là Direct Exchange. Default Exchange được liên kết ngầm định với mọi Queue với khóa định tuyến bằng với tên Queue.
Flow của một Message trong Direct Exchange như sau:
Một Producer sẽ tạo một Message và publish tới Exchange.
Một Queue sẽ binding tới Exchange sử dụng routing key. Chúng ta có thể tạo nhiều Queue và binding tới Exchange, có thể sử dụng cùng routing key, hoặc các routing key khác nhau.
Một Message tới Exchange với thông tin routing key. Dựa vào thông tin routing key, message sẽ được chuyển đến một hoặc nhiều Queue đã binding có cùng routing key với routing key của Message.
Chúng ta đã thấy cách hoạt động của Default Exchange ở các bài viết trước. Trong phần tiếp theo của bài viết này, chúng ta sẽ thấy cách hoạt động của Direct Exchange với routing key cụ thể.
Ví dụ Direct Exchange trong RabbitMQ
Trong ví dụ này, tôi tạo một Direct Exchange có tên GPCoderDirectExchange, tạo 3 Queue binding tới Direct Exchange này với 3 routing key:
QDeveloper sẽ binding với routing key devGroup.
QManager sẽ binding với routing key managerGroup.
QGeneral sẽ binding với routing key generalGroup.
Một số class của chương trình:
ConnectionManager : hỗ trợ tạo Connection đến RabbitMQ.
DirectExchangeChannel : class util hỗ trợ tạo Echange, Queue, binding Queue đến Exchange, publish/ subscribe message, …
Constant : định nghĩa constant chứa các thông tin về tên Exchange, Queue, Routing Key.
Producer: để gửi Message đến Exchange.
Consumer: để nhận Message từ Queue.
App: giả lập việc gửi nhận Message thông qua Direct Exchange của RabbitMQ.
ConnectionManager.java
package com.gpcoder.directexchange;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ConnectionManager {
private ConnectionManager() {
super();
}
public static Connection createConnection() throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
return factory.newConnection();
}
}
package com.gpcoder.directexchange;
public final class Constant {
// Exchange
public static final String EXCHANGE_NAME = "GPCoderDirectExchange";
// Routing key
public static final String DEV_ROUTING_KEY = "devGroup";
public static final String MANAGER_ROUTING_KEY = "managerGroup";
public static final String GENERAL_ROUTING_KEY = "generalGroup";
// Queue
public static final String DEV_QUEUE_NAME = "QDeveloper";
public static final String MANAGER_QUEUE_NAME = "QManager";
public static final String GENERAL_QUEUE_NAME = "QGeneral";
private Constant() {
super();
}
}
package com.gpcoder.directexchange;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import static com.gpcoder.directexchange.Constant.*;
public class App {
public static void main(String[] args) throws IOException, TimeoutException {
// Create producer
Producer producer = new Producer();
producer.start();
// Publish some message
producer.send("This message for all developers", DEV_ROUTING_KEY);
producer.send("This message for all managers", MANAGER_ROUTING_KEY);
producer.send("This message for everyone", GENERAL_ROUTING_KEY);
Consumer consumer = new Consumer();
consumer.start();
consumer.subscribe();
}
}
Output chương trình:
[Send] [devGroup]: This message for all developers
[Send] [managerGroup]: This message for all managers
[Send] [generalGroup]: This message for everyone
[Received] [QDeveloper]: amq.ctag-F_4tm402_GYRx8FBn6rLPw
[Received] [QDeveloper]: This message for all developers
[Received] [QManager]: amq.ctag-DbVV5-XhzLyFtFd5Kij8DQ
[Received] [QManager]: This message for all managers
[Received] [QGeneral]: amq.ctag-feJgzR4t-P2tjvBWEb13yA
[Received] [QGeneral]: This message for everyone
Như bạn thấy, Consumer/ Producer chỉ gửi/nhận đúng Message ở Queue mà nó binding.
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Các public client như Native mobile application or Single Page Application không thể lưu trữ Client Secret trong Authorization Code grant type một cách bảo mật được. Decode source của mobile application hay view source code của Single Page Application, chúng ta có thể xem được thông tin Client Secret này. Vì thế OAuth giới thiệu Proof Key for Code Exchange (PKCE) extension hỗ trợ cho Authorization Code grant type để giải quyết vấn đề này. Cụ thể như thế nào? Trong bài viết này, chúng ta sẽ cùng nhau tìm hiểu về Authorization Code grant type với Proof Key for Code Exchange (PKCE) trong OAuth 2.1 các bạn nhé!
Ý tưởng của PKCE là sử dụng 1 cặp secret code bao gồm Code Challenge và Code Verifier, được generate bởi ứng dụng thứ ba hay còn gọi là Client Application. Client Application sẽ gửi Code Challenge đi cùng với request để lấy authorization code. Authorization server sẽ lưu Code Challenge này lại. Trong request get access token, Client Application sẽ gửi Code Verifier, authorization server sẽ verify Code Challenge và Code Verifier để issue access token.
Workflow của Authorization Code grant type với PKCE, mình có thể diễn đạt như sau:
Như các bạn thấy, Client Secret đã không còn được sử dụng trong grant type Authorization Code với PKCE nữa!
Bài viết được sự cho phép của tác giả Kien Dang Chung
Python khác với các ngôn ngữ lập trình khác, nó đưa ra rất nhiều các cấu trúc dữ liệu dạng đa giá trị, trong bài trước chúng ta đã học về List và Tuple, bài này chúng ta tìm hiểu về hai cấu trúc dữ liệu tiếp theo của Python là Set (tập hợp).
1. Tập hợp (Set)
Set trong Python là một cấu trúc dữ liệu liên quan đến toán tập hợp hay còn gọi là lý thuyết tập hợp do nhà toán học người Đức Georg Cantor đề xuất. Set có thể chứa nhiều các phần tử và các phần tử này không có thứ tự, vị trí của nó hỗn loạn trong tập hợp. Bạn có thể duyệt qua các phần tử trong tập hợp, có thể thêm hoặc xóa đi các phần tử và thực hiện các phép toán tập hợp như phép hợp (union), phép giao (intersection), phép hiệu (difference)…
Các phần tử của tập hợp phải là các dữ liệu không thể thay đổi như một số (int), một chuỗi (string), hoặc một Tuple.
1.1 Khai báo tập hợp
Tập hợp (Set) trong Python có một số tính chất mà bạn cần nhớ:
Các phần tử trong tập hợp không có thứ tự.
Các phần tử này là duy nhất, không cho phép lặp lại.
Set có thể thay đổi (thêm bớt phần tử) nhưng các phần tử của tập hợp phải ở dạng không thể thay đổi (tức là xác định được dung lượng bộ nhớ ngay khi khai báo).
Chúng ta sử dụng các dấu ngoặc nhọn trong khai báo Set, ví dụ:
Các phần tử trong tập hợp có thể thêm hoặc loại bỏ. Python hỗ trợ rất nhiều các phương thức để thực hiện thao tác thay đổi tập hợp.
1.2.1 Phương thức .add()
Phương thức sử dụng để thêm một phần tử vào tập hợp.
Ví dụ:
friends ={"Rolf","Bob","Anne"}
friends.add("Jen")print(friends)# Kết quả là {"Bob","Jen","Anne","Rolf"}
Chú ý, kết quả có thể khác đi do Set không sắp xếp các phần tử theo một trật tự nào cả.
1.2.2 Phương thức .remove()
Loại bỏ một phần tử trong tập hợp.
Ví dụ:
friends ={"Rolf","Bob","Anne"}
friends.remove("Anne")print(friends)# Kết quả là {"Rolf","Bob"}
friends.remove("Jen")print(friends)# Kết quả là lỗi KeyError: "Jen"
Khi loại bỏ một phần tử, nếu phần tử đó không tồn tại trong tập hợp, chương trình sẽ dừng và một thông báo lỗi KeyError xuất hiện.
1.2.3 Phương thức .discard()
Giống như phương thức .remove() loại bỏ phần tử trong tập hợp, tuy nhiên nếu phần tử đó không tồn tại thì nó không báo lỗi gì cả.
friends ={"Rolf","Bob","Anne"}
friends.discard("Anne")print(friends)# Kết quả là {"Rolf","Bob"}
friends.discard("Jen")print(friends)# Kết quả là {"Rolf","Bob"}
1.2.4 Phương thức .pop()
Loại bỏ một phần tử ngẫu nhiên khỏi tập hợp.
friends ={"Rolf","Bob","Anne"}
friends.pop()print(friends)# Kết quả là {"Bob","Rolf"}
Bạn cần chú ý về thứ tự các phần tử trong tập hợp, nó không được sắp xếp theo bất kỳ quy tắc nào.
1.2.5 Phương thức .clear()
Loại bỏ tất cả các phần tử trong tập hợp, khi đó tập hợp được gọi là tập rỗng.
friends ={"Rolf","Bob","Anne"}
friends.clear()print(friends)# Kết quả là set()
1.2.6 Phương thức .update()
Phương thức .add() ở trên chỉ thêm được 1 phần tử vào tập hợp với 1 câu lệnh, để thêm nhiều phần tử, chúng ta sử dụng .update(). Chú ý, đầu vào của .update() có thể là một Set, một List hoặc một Tuple.
friends ={"Rolf","Bob","Anne"}
friends.update(["Jen","Charlie"],{"Jonhny","Sara"},("Laura","Elite"))print(friends)# Kết quả là {'Anne','Laura','Elite','Rolf','Jonhny','Charlie','Bob','Sara','Jen'}
Kết quả của bạn có thể có thứ tự khác đi, một chú ý nữa là không sử dụng chuỗi để cập nhập vào tập hợp mà các phần tử là chuỗi bởi vì chuỗi sẽ được coi là một danh sách các ký tự, ví dụ:
friends ={"Rolf","Bob","Anne"}
friends.update("Jen")print(friends)# Kết quả là {'n','e','Rolf','Bob','Anne','J'}
Không như mong đợi phải không, bạn có thể sử dụng phương thức .add() hoặc có thể chuyển chuỗi thành Set, List hoặc Tuple có 1 phần tử:
friends ={"Rolf","Bob","Anne"}
friends.update(("Jen",))# hoặc
friends.update(["Jen"])# hoặc
friends.update({"Jen"})
Có một số phương thức update khác như .difference_update(), .symmetric_difference_update() hay .intersection_update() nó có liên quan đến các phép toán trong tập hợp nên sẽ trình bày ở phần tiếp theo.
Các tập hợp có lợi thế hơn các cấu trúc dữ liệu khác ở chỗ nó thực hiện được các phép toán tập hợp như hợp, hiệu, giao… Để mô tả dễ hiểu hơn, chúng ta có hai tập hợp art_friends và science_friends là tập hợp các bạn trong lớp Mỹ thuật và tập hợp các bạn trong lớp Khoa học.
Hợp của hai tập hợp cho kết quả là tất cả các phần tử trong hai tập hợp, chú ý phần tử nào lặp lại sẽ chỉ xuất hiện 1 lần trong tập kết quả. Trong Python, để thực hiện phép hợp, chúng ta sử dụng phương thức .union(). Chú ý, sử dụng tập hợp nào trước cũng cho kết quả như nhau, art_friends.union(science_friends) cũng cho kết quả như science_friends.union(art_friends).
art_friends ={"Rolf","Anne","Jen"}
science_friends ={"Jen","Charlie"}
all_friends = art_friends.union(science_friends)print(all_friends)# Kết quả {'Rolf','Anne','Jen','Charlie'}
Chú ý, “Jen” có mặt trong cả hai lớp nhưng với tập kết quả cuối cùng thì “Jen” chỉ xuất hiện 1 lần.
1.3.2 Phép trừ (Difference)
Hiệu của một tập A trừ đi một tập B cho kết quả là tất các phần tử thuộc A nhưng không thuộc B. Sử dụng phương thức .difference() để thực hiện phép trừ hai tập hợp.
art_friends ={"Rolf","Anne","Jen"}
science_friends ={"Jen","Charlie"}
art_but_not_science = art_friends.difference(science_friends)
science_but_not_art = science_friends.difference(art_friends)print(art_but_not_science)# Kết quả {'Rolf','Anne'}print(science_but_not_art)# Kết quả {'Charlie'}
Trong ví dụ trên, tập hợp art_but_not_science chứa các bạn học lớp Mỹ thuật nhưng không học lớp Khoa học, chú ý “Jen” học cả hai lớp nên không có mặt trong tập hợp này.
1.3.3 Hiệu đối xứng của hai tập hợp (Symmetric difference)
Hiệu đối xứng của hai tập A và B được kết quả là tập hợp các phần tử thuộc cả A và B nhưng không đồng thời thuộc cả tập A và B. Phương thức .symmetric_difference() cho kết quả là hiệu đối xứng của hai tập hợp. Chú ý, do tính chất đối xứng nên art_friends.symmetric_difference(science_friends) và science_friends.symmetric_difference(art_friends) cho kết quả như nhau.
art_friends ={"Rolf","Anne","Jen"}
science_friends ={"Jen","Charlie"}
not_in_both_1 = art_friends.symmetric_difference(science_friends)print(not_in_both_1)# Kết quả {'Rolf','Charlie','Anne'}
not_in_both_2 = science_friends.symmetric_difference(art_friends)print(not_in_both_2)# Kết quả {'Rolf','Anne','Charlie'}
1.3.4 Phép giao (Intersection)
Phép giao hai tập hợp cho kết quả là các phần tử đồng thời thuộc cả hai tập hợp. Trong Python sử dụng phương thức .intersection() để thực hiện phép giao, chú ý tập hợp nào đứng trước cũng được, do đó kết quả art_friends.intersection(science_friends) và science_friends.intersection(art_friends) là như nhau.
art_friends ={"Rolf","Anne","Jen"}
science_friends ={"Jen","Charlie"}
art_and_science = art_friends.intersection(science_friends)print(art_and_science)# Kết quả là {"Jen"}
Tập hợp art_and_science chứa các bạn học đồng thời cả lớp Mỹ thuật và lớp Khoa học, do đó kết quả chỉ có “Jen” học cả hai lớp này.
Trong phần trước chúng ta đã biết đến phương thức .update() để thêm nhiều phần tử vào một tập hợp. Dựa vào các phép toán tập hợp, Python cung cấp một số các phương thức khác để thay đổi tập hợp như sau:
.difference_update()
Phương thức này là sự kết hợp của .difference() và .update(). Nó thực hiện phép trừ tập hợp trước, được kết quả như thế nào sẽ cập nhật vào tập hợp đích.
A ={1,2,3,4}
B ={3,4,5,6}
A.difference_update(B)print(A)# Kết quả {1, 2}
.symmetric_difference_update()
Phương thức này là sự kết hợp của .symmetric_difference() và .update(). Nó thực hiện phép trừ đối xứng 2 tập hợp trước, được kết quả như thế nào sẽ cập nhật vào tập hợp đích.
A ={1,2,3,4}
B ={3,4,5,6}
A.symmetric_difference_update(B)print(A)# Kết quả là {1, 2, 5, 6}
.intersection_update()
Tương tự, Python thực hiện .intersection() trước sau đó thực hiện .update():
A ={1,2,3,4}
B ={3,4,5,6}
A.intersection_update(B)print(A)# Kết quả là {3, 4}
1.3.6 Một số các phép toán khác
.isdisjoint() Trả về True nếu hai tập hợp không giao nhau, tức là hai tập hợp không có phần tử chung.
A ={1,2,3,4}
B ={3,4,5,6}print(not A.isdisjoint(B))# Kết quả là True
Ở đây, chúng ta sử dụng toán tử logic not, để thực hiện trả về True khi hai tập giao nhau, nghe nó thuận tai hơn :D.
.issubset() Trả về True nếu tập này còn tập con của tập đích (tập trong ngoặc).
A ={3,4}
B ={3,4,5,6}print(A.issubset(B))# Kết quả là True
.issuperset() Trả về True nếu tập này là tập cha của tập đích (tập trong ngoặc).
A ={3,4}
B ={3,4,5,6}print(A.issuperset(B))# Kết quả là False
Ngoài ra chúng ta có thể sử dụng các ký hiệu phép toán so sánh thông thường để kiểm tra xem là tập con, tập cha hay hai tập bằng nhau với >, >=, ==, <, <=.
A ={3,4}
B ={3,4,5,6}print(A.issubset(B))# Kết quả là True
# Tương đương với
print(A <= B)# Kết quả là True
Python cung cấp một hàm tên là frozenset(), kết quả trả về là một tập hợp (Set) không thể thay đổi. Khi đó, nếu bạn thực hiện các phương thức .add(), .remove(), .update()… sẽ báo lỗi.
“Đóng băng” tập hợp sẽ làm cho tập hợp đó giống như cấu trúc Tuple trong Python.
friends ={"Rolf","Anne","Jen"}
frozen_friends =frozenset(friends)
frozen_friends.add({"Jen","Charlie"})print(frozen_friends)# Kết quả lỗi: AttributeError: 'frozenset' object has no attribute 'add'
Đóng băng một tập hợp rất hữu ích trong trường hợp bạn muốn tập hợp đó không thể thay đổi. Ví dụ khi dùng một tập hợp làm key cho một từ điển (Dictionary), sẽ được giới thiệu trong phần tiếp theo.
A ={1,2,3}
B ={'a','b','c'}
C ={x:'foo', y:'bar'}# Kết quả lỗi: TypeError: unhashable type: 'set'
Tuy nhiên nếu bạn đóng băng các tập hợp này, sẽ không có lỗi nào xảy ra.
A =frozenset({1,2,3})
B =frozenset({'a','b','c'})
C ={x:'foo', y:'bar'}# Không có lỗi
2. Tập hợp sử dụng khi nào?
Toán tập hợp hay lý thuyết tập hợp là một trong những phần quan trọng của Toán học mà Khoa học dữ liệu (data science) và Machine Learning sử dụng kiến thức Toán rất nhiều, do vậy toán tập hợp trong Python là một phần không thể thiếu. Ngay từ đầu Python đã được phát triển cho mục đích Khoa học và Giáo dục, do vậy bạn có thể thấy các thiết kế mang hơi hướng Khoa học.
Tập hợp cũng là một nhóm các dữ liệu giống như với List và Tuple nhưng nó lại được xây dựng sẵn các phép toán tập hợp, do vậy tập hợp sẽ được sử dụng khi chương trình của bạn cần các phép toán tập hợp như .union(), .difference(), .intersection()… Để lựa chọn cấu trúc dữ liệu phù hợp, bạn cần nắm rõ những đặc điểm của từng loại, ở đây Set có những đặc điểm mà tôi đã đưa ra ở phần đầu, dưới đây chỉ nhắc lại:
Set có các phần tử là không được thay đổi, do vậy khả năng tìm dữ liệu sẽ nhanh hơn.
Set cần thiết cho các logic liên đến các cặp (key:value) trong cấu trúc Dictionary của Python.
Các phần tử là duy nhất, do đó nếu bạn có một dữ liệu tương tự thì Set là một lựa chọn.
Web components là một tập các quy chuẩn công nghệ dùng cho việc xây dựng các thành phần web được đóng gói (tách biệt với phần code còn lại của ứng dụng như View / Back For Front của server side reder) và có thể tái sử dụng cho client side (nôm na là nén thành cục javaScript for browser và tự render linh hoạt) thường sẽ áp dụng SPA.
Về cơ bản web components sử dụng 3 công nghệ cốt lõi:
Custom Elements: là tập hợp các API của Javascript để cho phép tạo ra các thành phần web tuỳ chỉnh.
Shadow DOM: là tập hợp các API của Javascript để gắn một cây DOM “shadow” (như shadow object trong javaScript) vào một thành phần của DOM, cây DOM này được quản lý riêng biệt và render riêng với cây DOM chính, do vậy nó có thể được đóng gói lại để sử dụng cho các ứng dụng khác nhau.
HTML templates: Dùng để tạo ra các template từ đó được render ra trang web. Khái niệm này được một số framework như Angular (Google) hay React (Facebook) phát triển.
Vậy là Lit đã được tạo ra để tích hợp các công nghệ Web component đúng không? Ummmm
Lit is a simple library for building fast, lightweight web components.
At Lit’s core is a boilerplate-killing component base class that provides reactive state, scoped styles, and a declarative template system that’s tiny, fast and expressive.
Như mình hiểu thì Lit là một thư viện cho việc xây dựng nhanh gọn web components tiêu chuẩn của google đề xuất và phát triển.
Với thư viện gọn nhẹ thì bạn sẽ dễ dàng tích hợp cho các framework hiện tại của bạn mà không phải tốn quá nhiều effort cho việc chuyển đổi công nghệ qua Vue, ReactJS mà vẫn có các tính năng linh hoạt cao như Vue hoặc ReactJS.
Điều khác biệt mà Lit mang lại so với Vue, ReactJS là gì??? Sau thời gian trải nghiệm các dự án sử dụng Vue, React và Lit thì thấy ở Lit nổi bật là giảm thiểu tình trạng lock-in, tối đa được tính linh hoạt và khả năng maintain tốt hơn với việc sử dụng mô hình browser’s native. Với site render lượng lớn component kết hợp server site render của React sẽ thấy khác biệt rõ rệt sau khi chuyển qua Lit… oh my goodness, oh my goodness gọi ajax rồi render page nhanh quá dậy.
Khi bạn phát triển ứng dụng bằng Lit, bạn có thể dễ dàng tích hợp các web components libraries khác. Bạn thậm chí có thể update version mới của Lit hoặc chuyển sang thư viện khác lúc phát triển mà không ảnh hưởng nhiều tới quá trình phát triển product. Còn dùng Vue hay React thì migration version thôi cũng phát ngán rồi, còn các tính năng và lifecycle mới phải học nửa…
Tuy nhiên đó chỉ là quan điểm cá nhân mình trên dự án có business phức tạp thôi còn tuỳ mức độ và business của dự án nửa mới phán đoán Lit có phù hợp hay không
Giới thiệu tới đây thôi còn muốn đào sâu hơn thì mình sẽ có bài viết khác về migration hệ thống dùng Lit.
Làm việc với MongoDB, thông thường là làm việc với dữ liệu lớn, do đó cần chuẩn bị cơ sở dữ liệu có kích thước tương đối lớn để sát với thực tế sử dụng. Tải về từ server SmartJob 2 cơ sở dữ liệu mẫu, bấm vào để download
– zips: Cơ sở dữ liệu về mã số bưu cục tại Mỹ (file download 567 KB, sau giải nén 3,03 MB, dữ liệu thật, hoàn toàn sát với thực tế).
– dataset: Cơ sở dữ liệu thông tin về quán ăn, nhà hàng (file donwload 1,5 MB, sau giải nén 11,6 MB)Sau khi download về, bạn giải nén ra.
Import collection có tên zips vào vào CSDL test (test là CSDL có sẵn sau khi cài đặt MongoDB)
Khi sử dụng tiện ích RockMongo để import dữ liệu, thời gian import rất lâu và dễ bị lỗi. Việc sử dụng câu lệnh là rất tốt, nhanh, tránh được lỗi.
Trong Hệ quản trị Cơ sở dữ liệu MongoDB sẽ có nhiều CSDL, do đó bạn cần khai báo sẽ sử dụng CSDL nào. Gõ lệnh
usetest;
Để sử dụng CSDL test
Gõ lệnh dưới đây để xem nội dung collection “zips” của Cơ sở dữ liệu “zips”. (Đây chính là câu lệnh hiển thị toàn bộ nội dung của collection zips)
db.zips.find().pretty();
Do lượng dữ liệu lớn, cửa sổ dòng lệnh không thể liệt kê hết. Để xem thêm trang sau, bạn gõ
it
rồi nhấn phím Enter.
Công tác chuẩn bị dữ liệu đã sẵn sàng để bạn tạo các truy vấn từ đơn giản đến phức tạp.
TRUY VẤN THEO ĐIỀU KIỆN
Tìm bưu cục có id = 01002, do tìm theo id, nên sẽ trả về không quá 1 document
db.zips.find({"_id":"01002"});
Để tìm document chứa dữ liệu về bưu cục vill
db.zips.find({"city":"GILBERTVILLE"});
Các bạn tham khảo mã nguồn sử dụng Spring Data Mongo để C.R.U.D. (Create – Read – Update – Delete) dữ liệu MongoDB tại: https://github.com/SmartJobVN/MongoDB_SpringDataMongo
Đỗ Như Vý – Bài viết gốc được đăng tải tại smartjob.vn
Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Chúng ta sử dụng Dockerfile để cấu hình và build các Docker Image. Để run các Docker container từ các Docker Image này, các bạn có thể sử dụng command line hoặc Docker Compose. Lợi ích của Docker Compose là giúp các bạn có thể định nghĩa và run nhiều Docker container cùng một lúc. Cụ thể như thế nào? Mình sẽ hướng dẫn các bạn cách định nghĩa và run các Docker container với Docker Compose các bạn nhé!
Để làm ví dụ cho bài viết này, mình sẽ tạo mới một Spring Boot project đơn giản, có khai báo sử dụng database nhưng sẽ không có thao tác nào đến database cả, tương tự như bài viết Deploy ứng dụng Spring Boot sử dụng Docker, như sau:
Kết quả:
SpringBootDockerComposeApplication:
package com.huongdanjava.springboot;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jdbc.metadata.HikariDataSourcePoolMetadata;
import org.springframework.web.bind.annotation.RequestMapping;
import com.zaxxer.hikari.HikariDataSource;
@SpringBootApplication
public class SpringBootDockerComposeApplication {
@Autowired
private DataSource dataSource;
@RequestMapping("/hello")
public String helloDockerCompose() {
Integer idleConnection = new HikariDataSourcePoolMetadata((HikariDataSource) dataSource).getIdle();
return "Hello Docker Compose! Idle connection to database is " + idleConnection;
}
public static void main(String[] args) {
SpringApplication.run(SpringBootDockerComposeApplication.class, args);
}
}
Để có thể sử dụng Docker Compose, chúng ta cần build Docker Image cho ứng dụng của mình. Điểm khác biệt ở đây là chúng ta không cần phải khai báo biến môi trường của ứng dụng trong Dockerfile, chúng ta sẽ sử dụng Docker Compose để làm điều này.
Mình sẽ tạo mới một tập tin Dockerfile trong project ví dụ:
Nội dung tập tin Dockerfile cho ứng dụng của mình như sau:
Sau khi đã có Docker Image cho ứng dụng của mình, các bạn có thể sử dụng Docker Compose để deploy ứng dụng của mình. Như mình đã nói, lợi ích lớn nhất của Docker Compose là giúp chúng ta có thể cấu hình và chạy nhiều Docker Image cùng 1 lúc.
Để minh hoạ điều này, mình sẽ không sử dụng PostgreSQL ở máy local của mình nữa. Mình sẽ viết một Docker Compose có thể cài đặt mới một PostgreSQL và sau đó sẽ chạy ứng dụng của mình lên.
Nhưng trước tiên, chúng ta hãy nói một ít về Docker Compose đã các bạn nhé!
Docker Compose thông thường sử dụng tập tin .yml để định nghĩa.
Mặc định, Docker sử dụng tập tin có tên là docker-compose.yml để chạy Docker Compose, nên mình sẽ tạo mới một tập tin docker-compose.yml trong project ví dụ như sau:
Đầu tiên, các bạn có thể sử dụng thuộc tính version để định nghĩa version của Docker Compose mà chúng ta sẽ sử dụng. Các bạn có thể tham khảo về version của Docker Compose tại đây.
Mình sẽ khai báo sử dụng Docker Compose version 3.8 như sau:
version: '3.8'
Mỗi Docker Container là một service trong tập tin Docker Compose và chúng ta sẽ sử dụng thuộc tính services cùng với khai báo tên của từng service cho các Docker Container của chúng ta. Mình sẽ khai báo như sau:
services:
postgresql:
spring_boot_docker_compose:
Nhiệm vụ của chúng ta là khai báo thông tin cho mỗi service. Các bạn có thể sử dụng một số thuộc tính phổ biến sau để khai báo cho mỗi service như sau:
image: Docker Image mà chúng ta sẽ sử dụng để chạy container.
container_name: tên của container.
restart: các bạn xem thêm ở đây. Thông thường chúng ta sẽ cấu hình cho thuộc tính này là on-failure và số lần restart nếu container start failed.
environment: khai báo các biến môi trường cần thiết cho mỗi container.
volumes: mount thư mục giữa máy chạy Docker và container.
ports: mapping port giữa máy chạy Docker và container.
depends_on: chỉ ra sự phụ thuộc của service này với service khác trong Docker Compose. Container với name được khai báo trong thuộc tính này bắt buộc phải available trước thì service này mới được chạy.
networks: định nghĩa một network dùng chung cho các container. Thông thường chúng ta sẽ sử dụng driver bridge cho phần network này.
Chúng ta sẽ định nghĩa service cho postgresql trước. Mình sẽ định nghĩa như sau:
Các bạn có thể tham khảo thêm bài viết Cài đặt PostgreSQL server sử dụng Docker để hiểu thêm các cấu hình cho service postgresql này.Còn ứng dụng ví dụ, mình sẽ định nghĩa như sau:
Vì phải có database thì ứng dụng ví dụ của chúng ta mới chạy được nên mình sử dụng thuộc tính depends_on trong service spring_boot_docker_compose để khai báo sự phụ thuộc này.
Cả 2 service mà mình đã định nghĩa ở trên sử dụng chung networks là huongdanjava với driver bridge. Chúng ta cần định nghĩa phần networks này như sau:
networks:
huongdanjava:
driver: bridge
Toàn bộ nội dung của tập tin docker-compose.yml như sau:
“Tôi mới làm quen với kiểm thử di động. Xin vui lòng cho tôi biết làm thế nào để bắt đầu?”. “Tôi đang làm việc với kiểm định trên web và tôi cần chuyển sang kiểm định trên các thiết bị di động, vui lòng tư vấn để tôi có thể làm tốt trong lĩnh vực này?”. Đối với các bạn mới làm quen với lĩnh vực kiểm thử di động, có một số điểm quan trọng các bạn nên biết và chúng ta hãy cùng bắt đầu từ số ZERO về kiểm thử di động.
Cho dù bạn có kinh nghiệm hay mới vào nghề, kiến thức cơ bản về kiểm thử phần mềm luôn luôn là cần thiết trong mọi loại kiểm thử mà các bạn sẽ thực hiện. Các bạn tham khảo thêm ở bài viết này nhé.
2. Cơ bản về viễn thông.
Những am hiểu cơ bản về viễn thông luôn là lợi thế. Bạn chắc chắn sẽ nhận được lợi thế nếu bạn biết được những thứ khác trong lĩnh vực này xoay quanh thử nghiệm các sản phẩm di động. 2G, 3G, CDMA, GPRS, GSM, HSCSD, SIM, tin nhắn SMS, WAP là một số điều cơ bản về viễn thông mà bạn cần phải biết.
3. Các kiến thức về hệ điều hành/nền tảng di động.
Có rất nhiều các hệ điều hành dành cho di động hiện nay trên thị trường như Android, iOS, Blackberry, J2ME, Symbian, Palm, Windows phone, Samsung Bada, Nokia Meego…Kiến thức về các hệ điều hành cho di động thực sự rất quan trọng để bạn trở thành 1 kỹ sư kiểm thử di động giỏi. Những hiểu biết về khả năng và hạn chế của từng hệ điều hành sẽ cho bạn sự tự tin để phân biệt được đâu là lỗi ứng dụng và đâu là giới hạn của hệ điều hành.
4. Làm quen với điện thoại di động của chính bạn.
Tôi có thể chắc chắn một điều là rất nhiều trong số các bạn thậm chí không biết một cách đầy đủ về chiếc điện thoại mà các bạn đang sử dụng như mẫu điện thoại (model), phiên bản phần mềm, hệ điều hành, tên mã…Nếu bạn mới bắt đầu với kiểm thử di động, hãy bắt đầu khám phá chiếc dế của mình. Hãy thử truy cập Internet bằng chiếc điện thoại thông minh của bạn, sử dụng wifi, GPRS. Kiểm tra xem làm cách nào để đưa điện thoại của mình về trạng thái ban đầu (Factory reset – nhớ cẩn thận nhé các bạn, sao lưu dữ liệu…) Thử kiểm tra số IMEI của điện thoại, thử nâng cấp phiên bản của hệ điều hành, thử những cài đặt khác (settings). Nói một cách ngắn gọn hãy làm sử dụng hết tất cả các chức năng của chiếc điện thoại. Chắc chắn là bạn sẽ nghĩ ra thêm vài tình huống trong khi các bạn thực hiện kiểm thử?
5. Tìm hiểu kiến thức chuyên ngành kiểm thử di động (mobile testing).
Kiểm thử di dộng các ứng dụng có thể tải về: một vài ứng dụng được cài sẵn khi được sản xuất, và một số khác có thể được tải về từ kho ứng dụng (Apple App store, Android Market, Gẹtar, Nokia Ovi Store, Blackberry App world…)
Kiểm thử di động các thiết bị cầm tay: Tương tự như các tổ chức phát triển ứng dụng tải về di động, có rất nhiều công ty phát triển thiết bị cầm tay di động hoàn chỉnh. Bộ phận bảo đảm chất lượng ở đây có thể cần phải kiểm tra các ứng dụng hoặc các tính năng có sẵn trong điện thoại. SMS, MMS, Voice Call, MMS, danh bạ điện thoại, Máy tính, Bluetooth và tính năng di động khác. Bao gồm đa phương tiện (máy ảnh, Video, Media player, nhạc chuông) và thử nghiệm giao thức ngăn xếp điện thoại di động.
Kiểm thử trang web trên di động (WAP Sites): không như các ứng dụng có thể tải về, web trên di động có thể được truy cập thông qua trình duyệt, không cần tải về. Kiểm thử này có những thách thức riêng của nó. Chuyển hướng đúng đắn, giao diện người dùng tốt (thiết kế), an toàn, hiệu quả và khả năng tưng thích trình duyệt di động là những lĩnh vùng quan trọng.
6. Nhận biết các loại kiểm thử ứng dụng di động.
Cũng giống như kiểm thử phần mềm, kiểm thử ứng dụng di động cũng bao gồm
Kiểm thử giao diện (màu sắc, phong cách Menu, nhất quán của giao diện người dùng trên thiết bị khác nhau)
Kiểm thử chức năng (kiểm tra chức năng chính của ứng dụng di động theo đặc điểm kỹ thuật)
Kiểm thử hiệu suất và chịu tải (Hành vi của ứng dụng di động trong các nguồn tài nguyên thấp (bộ nhớ / không gian lưu trữ), hành vi của trang web điện thoại di động khi nhiều người sử dụng điện thoại di động đồng thời truy cập vào trang web di động)
Kiểm tra khả năng sử dụng (kiểm tra các khía cạnh khả năng sử dụng các ứng dụng di động)
Thử nghiệm tương thích: Kiểm tra khả năng tương thích của ứng dụng của bạn với các tính năng thiết bị gốc (tức là để đảm bảo rằng ứng dụng của bạn không cản trở chức năng thiết bị gốc)
Kiểm tra gián đoạn (cuộc gọi thoại, tin nhắn SMS, sạc, thông báo bộ nhớ thấp) trong khi ứng dụng đang chạy.
Monkey Testing (không biết dịch sao luôn – kiểm tra khỉ haha): bấm bàn phím liên tục thông qua các công cụ để kiểm tra sự ổn định ứng dụng với sự kiện nhấn phím khác nhau.
7. Tham khảo các trường hợp thử nghiệm mẫu cho ứng dụng di động.
Đối với các bạn mới tiếp cận kiểm thử di động, sẽ là rất thông minh khi các bạn tham khảo các trường hợp thử nghiệm mẫu cho thiết bị di động. Tham khảo chúng từ những dự án đã hoàn thành trước kia hoặc hỏi các anh chị đi trước. Ngoài ra các bạn có thể tìm những thử nghiệm mẫu này từ Internet.
8. Khám phá những khả năng của trình mô phỏng.
Trình mô phỏng đóng vai trò đặc biệt quan trọng khi không có thiết bị thật cho việc kiểm thử. Mặc dù thử nghiệm trên thiết bị luôn được ưu tiên vì nó tái lập hành động của người dùng cuôi, tầm quan trọng của trình mô phỏng không thể bỏ qua. Để có thử nghiệm hiệu quả trên Simulator, tôi đề nghị khám phá tất cả các khả năng của trình mô phỏng.
9. Sử dụng các dịch vụ cho thuê thiết bị từ xa.
Vì có qúa nhiều loại thiết bị di động trên thị trường, nên chúng ta không thể mua tất cả chúng. Trong khi đó, trình mô phỏng không thể tin tưởng 100% để phát hành ứng dụng. Các dịch vụ thiết bị từ xa có thể là giải pháp tốt để đối phó với thách thức này. Là một kỹ sư kiểm thử di động giỏi, bạn nên biết các loại dịch vụ này và đề nghị với người quản lý của bạn về các dịch vụ này khi cần thiết
Device Anywhere (Paid)
Perfecto Mobile (Paid)
Nokia RDA (Free, For Symbian Phones)
*** Lợi ích của dịch vụ
Bạn không phải mua thiết bị
Người dùng có thể lựa chọn nhà mạng (Verizon, T-Mobile, AT&T)
Độ tin cậy cao hơn sử dụng trình mô phỏng bởi vì chúng là thiết bị thật
Một số dịch vụ thiết bị từ xa như Device Anywhere còn hỗ trợ kiểm thử tự động
*** Bất lợi
Mất thời gian để các sự kiện gõ phím, hành động được truyền tải tới thiết bị và phản hồi lại cho người dùng
Đôi khi những thiết bị bạn cần không có sẵn (vì người khác đã đặt trước rồi)
Chi phí khá cao.
10. Khám phá công cụ và tiện ích.
Có nhiều công cụ và tiện ích có trên thị trường, chúng có thể giúp ích cho các bạn trong việc kiểm thử ứng dụng di động hiệu quả. Một số công cụ có sẵn trong bộ SDK. Tuy nhiên bạn có thể sẽ tìm kiếm thêm trên Internet cho những nền tảng/hệ điều hành khác nhau
Công cụ kiểm tra sự tiêu thụ pin trong khi ứng dụng đang chạy Nokia Energy Profiler.
Công cụ/phần mềm chụp màn hình
Công cụ tạo ra những file giả để kiểm tra sự phản ứng của ứng dụng
Công cụ lấy logs file
11. Khám phá các công cụ kiểm thử tự động cho thiết bị di động.
TestComplete
M-Eux
TestQuest Countdown
Test Quest Pro
Robotium
VNC
Sikuli
Deviceanywhere
FoneMonkey (iPhone)
Eggplant (iPhone)
TestiPhone( For iPhone Mobile Web)
IBM® Rational® Performance Tester (RPT)
3P Mobile
Expertest
MITE
12. Khám phá các cộng đồng, diễn dàn, blogs.
Càng khám phá các bạn sẽ thấy có rất nhiều thứ để học. Hơn nữa, công nghệ luôn luôn thay đổi và ngày càng nhanh hơn. Giải pháp là tham gia các cộng đồng, diễn đàn để học từ kiến thức và kinh nghiệm của những người khác. Bắt đầu và thảo luận, bạn sẽ tìm thấy rất nhiều những chia sẻ và kinh nghiệm.
Bài viết được sự cho phép của blogchiasekienthuc.com
Chào các bạn, khi nói đến những sản phẩm phần mềm, dịch vụ phần mềm hay hạ tầng phần cứng, thiết bị công nghệ… thì không thể không nhắc tới ông trùm Microsoft được.
Với ngôn ngữ lập trình C# (C Sharp) được đánh giá thuộc TOP các ngôn ngữ lập trình nên học năm 2021 thì Microsoft cũng cho ra đời một công cụ lập trình rất mạnh đó là Visual Studio.
Visual Studio được thiết kế để phù hợp với các dự án sử dụng ngôn ngữ lập trình C# và các công nghệ .NET do Microsoft phát triển.
Trong bài viết này, mời các bạn hãy cùng mình đến với nội dung hướng dẫn cài đặt Visual Studio (phiên bản 2019 – LTS) trên hệ điều hành Windows 10. Các hệ điều hành khác cũng hoàn toàn tương tự nha các bạn !
+ Bước 2: Sau khi có file cài đặt thì các bạn kích đúp chuột để bắt đầu cài đặt. Visual Studio sẽ download một vài thông tin trên mạng nên các bạn nhớ giữ Internet ổn định.
+ Bước 3: Tiếp theo các bạn sẽ chọn các option để cài đặt, Visual Studio đã hỗ trợ khá nhiều công nghệ.
Ở đây để nhanh mình chỉ chọn mỗi ASP.NET and web deveopment. Yêu cầu về không gian lưu trữ là 9.28 GB => Sau đó các bạn bấm Install để bắt đầu cài đặt.
Quá trình cài đặt tương đối lâu (5-7 phút) do dung lượng cài đặt lớn.
+ Bước 4: Sau khi cài đặt xong thì sẽ có một popup như hình bên dưới để các bạn đăng ký tài khoản. Các bạn có thể bấm vào Not now, maybe later để đăng ký sau.
+ Bước 5: Tiếp theo các bạn sẽ chọn theme cho Visual Studio (có 4 theme cơ bản, bạn chọn theme nào cũng được). Ở đây mình chọn Blue => rồi bấm chọn Start Visual Studio.
#2. Tạo một Project mới trên Visual Studio
+ Bước 1: Đây chính là giao diện đầu tiên khi các bạn sử dụng Visual Studio. Có một vài lựa chọn như:
Clone a repository: Là bạn lấy code từ các repos trên mạng như Github về.
Open a project or solution: Mở một Project có sẵn trên máy của bạn.
Open a local folder: Mở một Folder trong máy.
Create a new project: Tạo mới một Project mới.
+ Bước 2: Ở đây mình chọn Create a new project để tạo mới một Project đơn giản nha các bạn.
Có rất nhiều loại Project khác nhau và để cho đơn giản thì mình sẽ tạo một Console Project với ngôn ngữ C# và có chức năng in ra màn hình chữ Hello World như hình bên dưới.
=> Sau đó bấm Next để tiếp tục.
+ Bước 3: Một vài thông tin các bạn phải điền đó là:
Project name: Tên Project
Location: Vị trí lưu Project
Solution name: Nó giống như tên Package vậy, nhưng trong Visual Studio gọi là Solution.
=> Sau đó bấm Next để tiếp tục.
+ Bước 4: Tiếp theo các bạn phải chọn Target Framework, ở đây mình chọn .NET Core 3.1 (LTS) => rồi bấm Create để tạo mới một Project.
Và đây chính là project cũng như đoạn code C# mặc định được Visual Studio tạo ra cho bạn.
(1) – Các bạn có thể bấm vào biểu tượng này để chạy project.
(2) – Đoạn mã C# sẽ in ra màn hình console dòng chữ “Hello World”
(3) – Logs trong quá trình chạy chương trình
Ok, và đây chính là dòng chữ được in sau khi chạy chương trình.
#3. Lời kết
Okay, như vậy là trong bài viết mình đã cùng với các bạn cài đặt thành công Visual Studio trên máy tính Windows – một công cụ lập trình mạnh mẽ của Microsoft, hỗ trợ rất tốt cho ngôn ngữ lập trình C# rồi nhé.
Phiên bản mình sử dụng để cài đặt và hướng dẫn trong bài viết là phiên bản cộng đồng, phiên bản dành cho cá nhân nên nó miễn phí và tất nhiên là nó sẽ ít chức năng hơn các phiên bản dành cho doanh nghiệp.
Hi vọng là bài viết này sẽ hữu ích với bạn. Hẹn gặp lại các bạn trong các bài hướng dẫn tiếp theo nha.
Làm việc với Stream Collector/ Collectors đã lâu, liệu rằng bạn có biết ngoài Grouping và Partitioning, Stream còn hỗ trợ cả thống kê (Statistics). Bất ngờ chưa, Collector thật sự còn ẩn chứa nhiều điều mà anh em còn chưa biết tới.
Hãy cùng tìm hiểu collector và các methods của nó qua bài viết dưới đây. Cuộc đời anh em developer chúng ta sẽ bớt khổ.
Trường hợp muốn tìm hiểu sâu hơn về stream và stream how it’s works, các bạn có thể khảo bài viết này.
Thực sự những method được cung cấp bởi collectors như Partitioning hay Grouping có sức hấp dẫn lạ kì.
1. Collectors.
A Collector represents a way to combine the elements of a Stream into one result.
Collector đại diện cho cách kết hợp tất cả các đối tượng trong Stream thành một kết quả duy nhất.
Để hoàn thành nhiệm vụ của mình, collectors sẽ chịu trách nhiệm thực thi 3 nhóm tác vụ chính:
A supplier of an initial value. Cung cấp một giá trị ban đầu.
An accumulator which adds to the initial value. – Nơi tổng hợp một loạt các giá trị ban đầu.
A combiner which combines two results into one. – Kết hợp hai kết quả thành một.
Collector được sử dụng thường xuyên khi ta sử dụng Stream API, nhưng ta ít khi để ý tới. Có hai cách để sử dụng:
// Phương thức ngắn gọn.
collect(Collector) (types left off for brevity)
// Các phương thức chi tiết để có một collection.
collect(supplier,accumulator,combiner).
Hình ảnh mô tả các bước để có một Collection thông qua Collector. Giá trị trả về sẽ là Optional.
Phương thức import để sử dụng collectors là:
import staticjava.util.stream.Collectors.*;
1.1 Collectors đơn giản.
Hai methods đơn giản và thường được sử dụng nhiều với collectors là toList() và toCollection().
// Lấy danh sách tên toàn bộ gái xinh, chuyển qua List.
List<String> listGaiXinh = Gai.stream() .map(Gai::getName)
.collect(toList());
// Lấy danh sách tên toàn bộ gái xinh, chuyển qua TreeSet.
Set<String> setGaiXinh = Gai.stream() .map(Gai::getName)
.collect(toCollection(TreeSet::new));
1.2 Joinning.
Trước đây, muốn Joining chuỗi trong Java, thường ta sử dụng Apache Common StringUtils.join. Khi sử dụng collector, ta có thể gọi phương thức joining. Khi gọi phương thức này, bản thân collectors lúc này biến thành một thùng chứa, kết nối các chuỗi String nhỏ, cho ra một String lớn.
// Tạo chuỗi gái xinh, cách nhau bởi dấu phẩy.
gaiXinhStr = gai.stream() .map(Gai::getName)
.collect(joining(","));
Xưa rồi nhé StringUtils của Apache. Stream nay hỗ trợ joining chỉ trong một nốt nhạc.
2. Statistics.
Ngoài công việc kết nối hoặc tổng hợp một loạt các giá trị. Collector còn cung thêm cả chức năng thống kê (statistics).
// Đọc file Rio, tính trung bình các dòng khác rỗng.
System.out.println(
Files.lines(Paths.get("Rio.java"))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(averagingInt(String::length))
);
2.1 Summarizing.
Summarizing là một method của collector, phương thức này trả về một lớp đặc biệt chứa thông tin thống kê (statistical information). Thông tin này thống kê dữ liệu cuối đã được trích xuất khỏi Stream.
// Lấy danh sách gái xinh có số đo vòng một cực lớn.
// Ôi, tao thích Collectos quá đi thôi. =)))
int soEmVongMotLon = gaiXinh.stream()
.collect(summarizingInt(Gai::vongMotLon));
2.2 Averaging.
Phương thức averaging trả về giá trị trung bình của các đối tượng.
// Tính tuổi trung bình danh sách gái xinh.
// Có collectors, đã không còn cực như xưa.
int tuoiTrungBinh = gaiXinh.stream()
.collect(averagingInt(Gai::getAge));
2.3 Summing.
Tương tự như tính giá trị trung bình, Summing trả về tổng các đối tượng trong Stream.
// Tính tổng số tuổi danh sách gái xinh.
// Có collectors, đã không còn cực như xưa.
int tongSoTuoi = gaiXinh.stream()
.collect(SummingInt(Gai::getAge));
Luồng thực hiện summing ở Stream. Các phép cộng được thực hiện tuần tự ở mỗi lần gọi method getCalories.
2.4 MaxBy / MinBy.
MaxBy/MinBy collectors return the biggest/the smallest element of a Stream according to a provided Comparator instance.
MaxBy/MinBy collectors trả về giá trị lớn nhất/ nhỏ nhất của Stream theo thể hiện được cung cấp bởi Comparator.
// Lấy
// Có collectors, đã không còn cực như xưa.
Optional<String> result = gaiXinh.stream()
.collect(maxBy(Comparator.getAge()));
Có một lưu ý nhỏ là giá trị trả về khi gọi phương thức MaxBy và MinBy phải được đóng gói theo kiểu Optional instance.
2.5 Grouping By.
GroupingBy collector is used for grouping objects by some property and storing results in a Map instance.
GroupingBy collector được sử dụng để gom một số đối tượng bởi thuộc tính của chúng, kết quả trả về sẽ được lưu vào một thể hiện (instance) của Map.
Map<Integer, Set<String>> result = givenList.stream()
.collect(groupingBy(String::length, toSet()));
Cơ chế groupingBy ở Stream tương tự như GROUP_BY ở SQL, các nhóm sẽ gom lại với nhau tùy theo điều kiện được thiết lập ở Stream.
2.6 Partitioning By.
PartitioningBy is a specialized case of groupingBy that accepts a Predicate instance and collects Stream elements into a Map instance that stores Boolean values as keys and collections as values.
PartitioningBy là một trường hợp đặc biệt của groupingBy, nó chấp nhận thêm Predicate Instance và Stream elements bên trong Map, các giá trị này sẽ được lưu kiểu Boolean giống như một keys.
Lý thuyết như thế này thì hơi khó hiểu. Ví dụ như sau: Nếu bạn có một nhóm bạn năm người. Trong đó, ba người ăn chay, hai người còn lại thì không. Ta sẽ sử dụng partitioning để chia nhóm người thành 2 vùng (ăn chay và không).
Chỉ nên sử dụng partitioningBy trong trường hợp phép so sánh để phân các đối tượng thành vùng là phức tạp. Ngược lại, đơn giản ta chỉ cần sử dụng Stream.filter().
Stream và Collectors kết hợp lại với nhau thật sự là một cặp đôi song sát. Hữu hiệu và mạnh mẽ. Việc ghi nhớ các method được cung cấp bởi Collector sẽ rất hữu hiệu cho anh em trong quá trình code. Sử dụng linh hoạt collector giúp code trở nên đơn giản, dễ đọc, dễ mantainance.
Ngoài ra, collectors còn trở nên mạnh mẽ hơn khi ta có thể custom một class của nó, tạo riêng cho mình một collector.
Khi cần thiết, hãy sử dụng Java Stream Collectors, cuộc đời bạn sẽ bớt khổ.
Mong rằng bài viết này sẽ giúp đỡ các bạn phần nào.
— name <container_name> là tên Docker container mà các bạn muốn đặt cho container của PostgreSQL server.
-e POSTGRES_USER=<postgre_user> khai báo biến môi trường POSTGRES_USER, là tên user mà chúng ta sẽ sử dụng để đăng nhập vào PostgreSQL service. Tham số này là optional, nếu các bạn không khai báo thì mặc định, user với username “postgres” sẽ được sử dụng.
-e POSTGRES_PASSWORD=<postgre_password> là mật khẩu để đăng nhập với username ở trên. Tham số này là bắt buộc các bạn nhé!
-v <mount_folder>:/var/lib/postgresql/data giúp chúng ta mount một thư mục trên máy cài Docker với thư mục /var/lib/postgresql/data của PostgreSQL server, giúp chúng ta có thể synchronize data của PostgreSQL server trong container lên máy cài Docker, phòng trường hợp Docker Container của chúng ta có vấn đề gì, có thể chạy lại mà không mất dữ liệu.
-d là tham số giúp chúng ta chạy câu lệnh trong background, giúp chúng ta có thể tiếp tục container khi tắt Terminal hoặc Ctrl+C.
postgres:<tag> là tag Docker Image của PostgreSQL server mà các bạn muốn chạy.
Các bạn có thể định nghĩa thêm biến môi trường POSTGRES_DB để định nghĩa tên database mặc định sẽ được tạo khi container chạy. Mặc định, tên database này sẽ có giá trị giống với tên của user đăng nhập.
Còn khi tháo Type Cover ra thì nó là một chiếc máy tính bảng sang, xịn và mịn 🙂 Cá nhân mình thì thấy thiết kế của Surface Pro không thể chê vào đâu được, với khung kim loại từ hợp kim nhôm và Magie..
À quên, hơi lan man sang phần giới thiệu sản phẩm rồi 🙂
Ngay bây giờ mình sẽ hướng dẫn cho các bạn cách truy cập vào BIOS để bạn có thể thiết lập/ tùy chỉnh theo nhu cầu sử dụng của bạn.
Hướng dẫn truy cập vào BIOS trên Surface Pro
Thực ra nếu bạn đã biết cách vào Advanced Options trên Windows rồi thì bạn sẽ làm được ngay thôi. Tuy nhiên, nhiều anh em mới sử dụng dòng máy này sẽ hơi bị lúng túng và bỡ ngỡ 🙂
Cách thực hiện như sau:
+ Bước 1: Bạn khởi động đến màn hình đăng nhập, hoặc vào trong màn hình Windows cũng được. Tùy bạn..
Sau đó click vào nút Nguồn => giữ phím SHIFT trên bàn phím => và nhấn vào nút Restart để khởi động lại máy tính.
+ Bước 2: Tiếp theo bạn vào Troubleshoot
Sau đó chọn Advanced Options
+ Bước 3: Và cuối cùng chọn UEFI Firmware Settings như hình bên dưới.
Rồi nhấn vào nút Restart để khởi động lại máy tính, lúc này máy sẽ tự động truy cập vào BIOS cho ban..
Đây là giao diện Surface UEFI (quen gọi là BIOS :D), bạn có thể thiết lập theo nhu cầu của bạn rồi đó.
P/s: Đang nghiên cứu về Windows 11 nên tiện thể viết luôn bài này. May quá Surface Pro 6 có hỗ trợ TPM 2.0 😀 Vậy là có thể nâng cấp lên Windows 11 ngon lành rồi anh em ạ ᵔᴥᵔ
Okay, như vậy là việc truy cập vào BIOS của máy Surface Pro cũng không có gì khó khăn cả đúng không các bạn 🙂 Hi vọng là bài viết này sẽ hữu ích với bạn, chúc các bạn thành công !