Bài viết được sự cho phép của tác giả Phạm Công Sơn
Đây là plugin giả lập gõ văn bản, rất phù hợp với những web cần hiển thị text dạng ngắn hay slogan hiện ra từ từ bằng hiệu ứng typing. Các bạn có thể tải plugin này tại đây
<divdata-form="typing"class="hide"><mark><a>Chào mừng các bạn đã đến với blog son20.com của mình</a></mark><br/>Hãy chờ mình một chút <del>Khoảng</del> tầm 2 giây thôi rồi thì mình giới thiệu nhé..<ins>2</ins><br/><strong>Đây là Plugin giả lập Typing rất thú vị.</strong><br/><del></del> để thực hiện giả lập xóa text *<ins>2</ins><br/><ints>{numeric}</ints> để thực hiện delay một khoảng thời gian (tính bằng giây)*<ins>2</ins><br/><kbd></kbd> để tối ưu việc gõ nhầm *<ins>2</ins><br/>Chúc <delstyle="color:red;border-bottom:1px dashed red;">mọi người</del>các bạn sử dụng plugin này vào những trường hợp hữu ích.Chờ xíu để chạy lại nhé <ints>2</ints></div>
Bài viết được sự cho phép của tác giả Trần Thị Thu Hà
Để tuyển dụng được một lập trình viên tốt, thì các nhà tuyển dụng thường đặt khá nhiều kỳ vọng vào các kỹ năng mà lập trình viên đã tự trang bị được cho mình.
Trong bài này, trong lĩnh vực PHP, các nhà tuyển dụng cần gì ở một lập trình viên? Bạn đã chuẩn bị được những kỹ năng gì để đi xin việc tuyển dụng PHP?
1. Những kỹ năng bắt buộc
Nắm chắc kiến thức cơ bản về lập trình web với HTML, CSS (và cả JS thì là tốt nhất)
PHP là để lập trình web, mà HTML+CSS(+JS) là bộ cơ sở đi với nhau, và do đó, bạn muốn làm web mà không biết HTML+CSS thì chắc chắn là không thể được. Thực tế, với HTML+CSS bạn không cần phải biết tường tận mọi ngõ ngách, không cần phải siêu đẳng, thế nhưng những thứ thường gặp bạn cần phải nắm rõ.
Về ngôn ngữ PHP
Bạn làm về PHP, rõ ràng bạn phải hiểu được cơ bản về nó. Cách bạn đặt biến như nào, đặt hàm như nào,… rồi những vấn đề cơ bản như: hiển thị một chuỗi lên HTML bằng PHP như thế nào, PHP kết nối đến DB như là MySQL ra sao,… Bạn có thể lúc nhớ lúc quên, nhưng khi đưa code có sẵn ra bạn phải đọc được và hiểu được, rồi mới tính đến chuyện tự tay code được.
Nếu bạn đã thành thạo một số kỹ năng dưới đây, ngoài việc tăng khả năng kiếm được một công việc như ý về tuyển dụng PHP, bạn còn có lợi thế nhất định khi đàm phán lương bổng.
Thành thạo nhiều các PHP framework
Với cộng đồng PHP lớn mạnh, cũng như vị trí quan trọng của bộ sậu PHP-MySQL trong thế giới web cộng với nhu cầu tuyển dụng PHP ngày càng lớn thì việc mà có vô số các sản phẩm opensource, hoặc có phí là điều dễ hiểu. Tương tự đó, rất ít các công ty phát triển web làm từ đầu sản phẩm của mình, mà thường dựa vào một nền tảng framework nào đó để tuỳ biến. Nhất là các công ty ở Việt Nam, có rất ít công ty bỏ tiền ra đầu tư làm từ đầu sản phẩm của mình. Do đó, bạn nắm được nhiều framework thì bạn lại càng có nhiều lợi thế hơn khi xin việc cũng như khi đàm phán lương bổng.
Nhu cầu tuyển dụng PHP ngày càng lớn.
Các framework đáng chú mà các bạn cần bỏ thời gian nghiên cứu, làm thử gồm:
– Về CMS: WordPress, Joomla, CakePHP, Yii, Laravel, …
– Về eCommercer: Magento, OpenCart, Shopify,…
– Ngoài ra, còn có một số khác, mặc dù ít gặp ở Việt Nam nhưng không phải là không cần: CRM như Sugar hoặc Tiger,..
Thành thạo làm Responsive
Với thời điểm bùng nổ smartphone, tablet iOS, Android như hiện tại, việc có thêm kỹ năng làm web Responsive là cực kỳ quan trọng. Các website lớn, hoặc chuyên nghiệp sẽ yêu cầu điều này. Việc học cách để làm responsive này cũng không tốn nhiều thời gian, cũng như PHP, hiện nay có rất nhiều framework giúp cho các bạn về việc này.
Thành thạo các Javascript framework, tối đặc biệt JQuery
Tương tự với các quan điểm trên, bạn cũng nên nắm được vững cách sử dụng JQuery. Tài liệu hướng dẫn rõ ràng dễ hiểu, các biện pháp giải quyết khó khăn bằng JQuery nhiều vô kể. Và cũng có vô số người sẵn sàng giúp bạn trên StackOverflow.
Ngoài những điểm đề cập trên, thật tuyệt vời nếu nhà tuyển dụng cũng biết được bạn thành thạo, hoặc đã từng làm, hoặc có hiểu biết, hoặc thậm chí là có nghe nói đến một số các thứ sau đây:
– Kỹ thuật về AJAX với JQuery.
– JSON
– Restful Webservices
– Tương tác với web API, request header, response header
– AngularJS
– Thành thạo các tool như Sublime Text, Notepad++, IntelliJ IDEA,…
– Cách deploy một web PHP lên hosting bằng FTP, CPanel,…
Với những chia sẻ trên hy vọng sẽ giúp ích cho các bạn trong quá trình đi xin việc. Chúc các bạn thành công!
Tôi đã làm việc như một nhà tư vấn về phát triển bản thân trong phần lớn cuộc đời. Tôi đã đi qua rất nhiều khái niệm và ý tưởng cũng như phát minh ra một số khái niệm cho riêng mình. Nhưng sau đây là một trong những ý tưởng quan trọng nhất mà tôi đã có:
Hành động không chỉ chịu ảnh hưởng của động lực mà nó còn là nguyên nhân gây ra động lực.
Hầu hết mọi người chỉ cam kết hành động nếu họ được thúc đẩy ở một mức độ nhất định. Và họ chỉ có động lực khi họ cảm thấy một nguồn cảm hứng cảm xúc. Một người chỉ bắt đầu có động lực để học tập cho kỳ thi khi người đó hình dung ra những hậu quả nếu họ thi rớt. Một người quyết định học một loại nhạc cụ nào đó khi họ cảm thấy được truyền cảm hứng vì có thể chơi nhạc cho bạn bè và người thân của họ nghe.
Và tất cả chúng ta đã từng buông lơi mọi thứ vì thiếu động lực ít nhất một lần trong đời. Đặc biệt là trong thời điểm mà chúng ta không nên. Chúng ta cảm thấy thờ ơ và lãnh đạm khi hướng tới một mục tiêu nhất định đã đặt ra cho chính mình bởi vì chúng ta thiếu động lực và chúng ta thiếu động lực bởi vì chúng ta không cảm thấy bất kỳ khao khát về cảm xúc nào để thực hiện điều đó.
Cảm hứng → Động lực → Hành động mong muốn
Nhưng có một vấn đề với khuôn mẫu này: Phần lớn những thay đổi và hành động mà chúng ta cần trong cuộc sống đều được truyền cảm hứng bởi những cảm xúc tiêu cực và chính những cảm xúc đó lại cản trở chúng ta thực hiện những hành động đó.
Nếu một người đang cố hàn gắn mối quan hệ của họ với người khác, những cảm xúc nội tại (những tổn thương, oán giận, sự trốn tránh) hoàn toàn đi ngược lại những hành động cần thiết để hàn gắn (đối mặt, trung thực và giao tiếp).
Cảm giác xấu hổ về cơ thể tạo nên động lực mong muốn giảm cân của một người, nhưng cũng chính cảm xúc xấu hổ đó lại cản trở họ đi đến phòng tập gym vì lo sợ bị người khác chê cười.
Những tổn thương trong quá khứ, kỳ vọng tiêu cực và cảm giác tội lỗi, xấu hổ và sợ hãi thường khiến chúng ta trốn tránh những hành động cần thiết để vượt qua những tổn thương, kỳ vọng và cảm xúc tiêu cực đó.
Động lực thực sự hoạt động như thế nào?
Chuỗi động lực không chỉ gồm 3 phần, mà nó là một vòng lặp vô hạn:
Cảm hứng → Động lực → Hành động → Cảm hứng → Động lực → Hành động → …
Hành động của bạn sẽ tạo ra các phản ứng về cảm xúc và cảm hứng tiếp theo và lặp đi lặp lại thúc đẩy những hành động trong tương lai. Lợi dụng kiến thức này, chúng ta có thể định hướng lại tư duy của chúng ta theo cách sau:
Hành động → Cảm hứng → Động lực
Kết luận là nếu bạn không có động lực để thực hiện một sự thay đổi quan trọng trong cuộc sống của bạn, thì hãy làm một cái gì đó, bất cứ điều gì, và sau đó khai thác các phản ứng với hành động đó như một cách để bắt đầu thúc đẩy bản thân.
Tôi gọi điều này là Nguyên tắc “Hãy làm gì đó đi”. Và tôi đã phát triển nó trong những năm làm việc như một nhà tư vấn giúp đỡ mọi người thoát ra khỏi nỗi sợ hãi và sự thờ ơ để hành động.
Nó bắt nguồn từ chủ nghĩa thực dụng đơn giản: Bạn trả tiền cho tôi để bạn được ở đây và làm điều gì đó. Tôi không quan tâm, hãy làm điều gì đó đi!
Những gì tôi tìm thấy là thường khi họ làm một cái gì đó, thậm chí là những hành động nhỏ nhặt nhất, nó sẽ sớm cung cấp cho họ nguồn cảm hứng và động lực để làm một điều gì đó khác. Họ đã gửi một tín hiệu cho chính mình, “OK, tôi đã làm điều đó, tôi đoán tôi có thể làm nhiều hơn.” Và cứ chậm rãi như vậy, chúng tôi bắt đầu làm cho mọi thứ tiến triển tốt hơn.
Làm thế nào để có động lực làm bất cứ điều gì?
Qua nhiều năm, tôi đã áp dụng Nguyên tắc “Làm Cái Gì Đó” trong cuộc sống của chính mình.
Ví dụ rõ nhất chính là trang web cá nhân và các hoạt động kinh doanh trực tuyến của tôi. Tôi làm việc cho bản thân mình. Tôi không có một ông chủ nói với tôi phải làm gì và không được làm gì. Tôi cũng thường gặp rủi ro về đầu tư cá nhân, cả về tài chính lẫn tình cảm. Đôi khi có những lúc căng thẳng thần kinh, và những cảm giác về sự nghi ngờ cũng như sự không chắc chắn nảy sinh. Và khi không có ai xung quanh thúc đẩy bạn, ngồi một chỗ và xem lại chương trình truyền hình mỗi ngày có thể nhanh chóng trở thành một lựa chọn hấp dẫn hơn.
Hai năm đầu tiên tôi làm việc cho bản thân mình, cả tuần trôi đi mà tôi không làm được gì nhiều bởi vì tôi cứ luôn lo lắng và căng thẳng về những gì tôi phải làm. Và quá dễ để bỏ cuộc. Tôi đã nhanh chóng học được rằng mình phải ép buộc bản thân làm một việc gì đó. Nếu tôi cần phải thiết kế trang web, tôi sẽ buộc mình ngồi xuống và nói “Được rồi, tôi sẽ thiết kế phần tiêu đề ngay bây giờ!” Nhưng ngay sau khi phần tiêu đề đã được hoàn tất, tôi thấy mình đang tiếp tục thực hiện những phần tiếp theo của trang web. Và trước khi tôi nhận ra được điều đó, tôi đã tràn đầy năng lượng và chú tâm vào dự án.
Tôi cũng thường xuyên áp dụng nó trong cuộc sống của mình. Nếu tôi sắp sửa giải quyết một dự án lớn mà tôi đang lo lắng, hoặc nếu tôi cảm thấy bản thân mình nên đi ra ngoài để gặp gỡ nhiều người hơn, tôi sẽ áp dụng nguyên tắc “Hãy làm gì đó đi”. Thay vì mong đợi một kết quả lớn, tôi sẽ chỉ quyết định “OK, bắt đầu một bản phác thảo thôi!” hoặc “OK, tôi sẽ đi ra ngoài làm một chai bia và xem những gì đang diễn ra!”
Giáo viên dạy Toán thời trung học của tôi đã từng nói: “Nếu các em không biết làm cách nào để giải một bài toán, cứ viết một cái gì đó, bộ não sẽ tự động tìm ra cách để thực hiện những bước tiếp theo”. Và cho đến ngày nay, lời khuyên đó vẫn đúng. Bản thân hành động tự nó sẽ truyền cảm hứng cho những suy nghĩ và ý tưởng mới dẫn dắt chúng ta đến những phương pháp giải quyết các vấn đề trong cuộc sống. Những cái nhìn sâu sắc sẽ không đến nếu chúng ta chỉ đơn giản ngồi im và suy nghĩ về nó.
Gần đây tôi đã nghe một câu chuyện về một tiểu thuyết gia đã viết được hơn 70 cuốn tiểu thuyết. Có người hỏi ông ấy làm cách nào mà ngài có thể viết nhất quán và duy trì được cảm hứng mỗi ngày như vậy. Ông ấy đã trả lời: “Mỗi ngày cố gắng viết 200 từ, chỉ có vậy!”. Ý tưởng ở đây là nếu chúng ta buộc mình phải viết 200 từ mỗi ngày, chính 200 từ đó sẽ truyền cảm hứng cho chúng ta tiếp tục viết, và đến khi nhận ra thì ta đã có hàng ngàn từ trên bản thảo.
Bạn có thể đã nhận ra khái niệm này ở đâu đó. Nhưng không quan trọng nó đến với bạn bằng hình thức nào, đó là một lối suy nghĩ vô cùng hữu ích và là một thói quen tốt cần được áp dụng.
Càng trải nghiệm nhiều tôi càng thấm thía rằng thành công trong bất cứ lĩnh vực nào chỉ phụ thuộc ít đến hiểu biết hay tài năng mà gắn kết chặt chẽ với hành động được bổ trợ bởi kiến thức và tài năng.
Bạn có thể thành công trong một lĩnh vực nào đó dù có thể hiện tại bạn không biết bạn đang làm gì. Bạn cũng có thể thành công dù không có tài năng đặc biệt nào trong lĩnh vực đó. Nhưng bạn sẽ không bao giờ thành công ở bất cứ lĩnh vực nào nếu không hành động. Không bao giờ.
Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh
Nhiều bạn newbie sẽ rất khó trả lời câu hỏi: Làm sao để viết code swift đúng chuẩn thế giới? Bạn viết code và người khác đọc được một cách dễ dàng, tuân theo tiêu chuẩn của cộng đồng Swift.
Khi viết ngôn ngữ lập trình nói chung, Swift nói riêng không ai có thể nói bạn viết sai hay đúng như nào. Ví dụ đoạn code sau:
class classSample {
var BienGido = ""
func TenHam() {
print(BienGido)
}
}
Khi biên dịch chương trình, nó không báo lỗi. Nhưng đoạn code trên mắc 3 lỗi code style nghiêm trọng:
Tên lớp bắt đầu bằng chữ thường. Luật bất thành văn, khi đặt tên class ở đa số tất cả các ngôn ngữ lập trình, người ta đều phải bắt đầu bằng chữ in hoa. Lý do là: tên lớp là 1 class – nó là 1 danh từ. Ở bộ môn tiếng Việt lớp 3, có quy định: danh từ chỉ tên riêng đều phải viết hoa, ví dụ: Hà Nội, Hồ Chí Minh, Lào Cai.. Cũng tương tự, ở programing language cũng có quy luật tương tự.
Đặt tên biến bắt đầu bằng chữ hoa. Tên biến ở đây là thuộc tính để lưu trữ giá trị của class. Do vậy bạn không thể đặt tên viết hoa được, vì nó đại diện cho nhiều đối tượng kế thừa từ lớp. Bạn không thể nói là tim là 1 danh từ riêng được. Vì con người nào cũng có tim cả.
Tên hàm bắt đầu bằng chữ hoa. Tương tự, tên hàm là phương thức cho class, cho nên nó cũng là chung cho các đối tượng kế thừa từ lớp. Nó bắt buộc phải viết thường.
Sau khi sửa lại, đoạn code sẽ như sau:
class ClassSample {
var bienGido = ""
func tenHam() {
print(bienGido)
}
}
Tuy nhiên, với 1 bạn mới dấn thân vào con đường lập trình, thì ai sẽ là người nhắc nhở bạn những rule này? Thật may mắn, Swift đã có 1 thư viện hỗ trợ cho bạn viết code 1 cách clean nhất, lỡ bạn có đặt tên biến viết hoa hay tên class viết thường như trên, thì nó tự động báo cho bạn biết để sửa, nhằm đảm bảo code là đẹp nhất.
Tin tôi đi, khi bạn dùng library này, bạn sẽ ngày càng chuẩn chu hơn trong việc viết code và tự tin phang vào đứa nào dám bảo bạn viết sai quy tắc của IOS programing.
Đầu tiên bạn cần phải cài đặt em nó vào project mới của bạn. Project của bạn có thể là đã có sẵn hoặc tạo mới từ đầu, bạn thoải mái chọn lựa.
Cách cài đặt có thể xem readme của nó, hoặc không thì tôi làm đơn giản như sau:
Nếu bạn thích Homebrew, thì bạn gõ dòng lệnh:
brew install swiftlint
Còn nếu đam mê CocoaPods thì gõ:
pod init
pod 'SwiftLint'
Đọc đến đây có nhiều bạn hỏi tôi là “Ơ thế Homebrew là gì mà CocoaPods là gì?” Bạn ơi, ngồi xuống đây làm điếu thuốc, uống chén nước để tôi nói bạn nghe này:
Homebrew và CocoaPods là 2 thư viện hỗ trợ bạn cài thư viện ngoài 1 cách nhanh chóng và đơn giản bằng dòng lệnh.
Mặc định máy Macbook của bạn sẽ không có cài đặt nó đâu, và nếu bạn muốn chơi với 2 em nó thì có 2 cách: 1 là bạn google từ khóa “cách cài đặt Homebrew” hay là CocoaPods, sau đó bạn tìm 1 video nào đó trên youtube chẳng hạn, xem rồi thẩm thôi. Cách 2 là đợi tôi có thời gian tôi giải thích bọn nó làm gì. Bật mí là để hiểu bản chất hơn về việc xây dựng thư viện thì bạn dùng Homebrew hay hơn CocoaPods, sau này có thời gian chúng ta sẽ xây dựng các library của các bạn và đẩy lên cho cộng đồng nhé. Bạn sẽ hiểu hơn các khái niệm static hay dynamic library. Còn bây giờ chưa phải lúc làm chuyện đó chúng ta vẫn còn non.
Quay lại với swiftLint, hiện tại khi cài đặt thư viện xong, bạn mở lên thì nó vẫn chưa hoạt động với project của bạn. Chúng ta cần giao thông với em ấy và thực hiện 1 vài bước setting nhỏ như sau:
Bạn vào setting -> Chọn vào tab Build Phases và nhấn vào nút + -> “New Run Script Phase”. Thêm đoạn script sau:
"${PODS_ROOT}/SwiftLint/swiftlint"
Đoạn code trên nhằm báo cho Xcode dùng Swiftlint để check code convention.
Bạn sửa tên Run scipt thành swiftlink. Sau đó kéo cái script này lên gần trên cùng, sau cái [CP] Check Pods Manifest.lock như hình:
Để kiểm tra lại, bạn thử sửa đoạn code tên class viết thường xem nó báo lỗi không nha!
Lỗi vì tên class viết thường
Thử với nhiều code lỗi như sau:
import Foundation
class classSample {
enum enumLoi {
case case1
case Case2
}
var BienGido = ""
func TenHam() {
var EnumLoi: enumLoi = .case1
switch EnumLoi {
case .case1:
print("case1")
case .Case2:
print("case2")
break
}
print(BienGido)
}
}
Thông báo lỗi bạn thu được:
Các lỗi code sinh ra
Các dòng đỏ báo lỗi bạn có thể dịch như sau:
Tên phải uppercase, viết hoa chữ đầu
enumLoi cũng phải viết hoa chữ đầu
Case2 phải viết chữ thường
Tên biến không được viết hoa chữ đầu
Tên hàm phải bắt đầu bằng chữ thường
Tương tự 5
Trong case đã có lệnh print nên không cần thiết phải có break
Sau khi chuẩn hóa ta có đoạn code sau:
class ClassSample {
enum EnumDung {
case case1
case case2
}
var bienGido = ""
func tenHam() {
var enumDung: EnumDung
enumDung = .case1
switch enumDung {
case .case1:
print("case1")
case .case2:
print("case2")
}
print(bienGido)
}
}
Ồ vậy là bây giờ bạn đã yên tâm mỗi khi viết code, có quên có sai ở đâu đo thì yên tâm đã có thằng check cho bạn rồi. Và đảm bảo sau 1 thời gian sử dụng swiftlint thì bạn viết code sẽ chuẩn mực hơn, sexy hơn.
Hi vọng bài viết này sẽ giúp được cho các bạn ngày càng phát triển kỹ năng coding của mình.
Hiện nay, các lập trình viên hay lẫn lộn giữa các khái niệm Dependency Inversion, Inversion of Control (IoC), Dependency Injection (DI). Ba khái niệm này tương tự nhau nhưng không hoàn toàn giống nhau.
Sự khác biệt giữa 3 khái niệm trên:
Dependency Inversion: Đây là một nguyên lý để thiết kế và viết code.
Inversion of Control: Đây là một design pattern được tạo ra để code có thể tuân thủ nguyên lý Dependency Inversion. Có nhiều cách hiện thực pattern này: ServiceLocator, Event, Delegate, … Dependency Injection là một trong các cách đó.
Dependency Injection: Đây là một cách để hiện thực Inversion of Control Pattern (Có thể coi nó là một design pattern riêng cũng được). Các module phụ thuộc (dependency) sẽ được inject vào module cấp cao.
Ghi chú: Đôi khi chúng ta so sánh giữa Dependency Injection với Abstraction Factory Design Pattern. Thế những có 1 chút khác biệt giữa hai phương pháp này, đó là DI có một Framework làm việc phía sau nó để gọi các factory và các service đã đăng ký.
Tóm lại, Dependency Injection (DI) là một mẫu thiết kế phần mềm (software design parttern). Đây là cách tuyệt vời để giảm các kết nối chặc chẽ giữa các thành phần của phần mềm (software components). Nó cho phép chúng dễ dàng quản lý các thay đổi trong tương lai cũng như quản lý những hệ thống phần mềm phức tạp dễ hơn.
Ưu điểm:
Giảm sự kết dính giữa cách thành phần của phần mềm. Hay gọi là giảm sự phụ thuộc của các thành phần với nhau.
Dễ bảo trì và dễ thay đổi khi có nhu cầu. (không làm ảnh hưởng đến các thành phần khác trong cùng 1 hệ thống)
Tăng khả năng tái sử dụng.
Dễ viết Unit Test và kiểm thử.
Nhược điểm:
Sử dụng interface nên đôi khi sẽ khó debug, do không biết chính xác module nào được gọi.
Làm tăng độ phức tạp của code.
2. Các dạng Dependency Injection
Constructor Injection: Các dependency sẽ được container truyền vào (inject vào) 1 class thông qua constructor của class đó. Đây là cách thông dụng nhất.
Setter Injection: Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter.
Interface Injection: Class cần inject sẽ implement 1 interface. Interface này chứa 1 hàm tên Inject. Container sẽ injection dependency vào 1 class thông qua việc gọi hàm Inject của interface đó. Đây là cách rườm rà và ít được sử dụng nhất.
3. Mục đích của Dependency Injection là gì?
Chúng ta cần biết mục đích của DI dùng làm gì thì mới có thể áp dụng vào dự án của mình được và sử dụng loại DI nào cho phù hợp.
Với cách code thông thường, các module/class cấp cao sẽ gọi các module cấp thấp. Module/class cấp cao sẽ phụ thuộc và module/class cấp thấp, điều đó tạo ra những phụ thuộc giữa chúng (gọi là dependency). Khi module/class cấp thấp thay đổi, module/class cấp cao phải thay đổi theo. Một thay đổi sẽ kéo theo hàng loạt thay đổi, giảm khả năng bảo trì của code. Nếu bạn đang làm trên một dự án lơn thì việc thay đổi sẽ là điều kinh khủng đối với bạn (bạn sẽ sợ sửa cái này ảnh hưởng đến cái khác vì chúng đang có 1 sự phụ thuộc lẫn nhau mà).
Vậy nếu tuân theo Dependendy Inversion principle, các module cùng phụ thuộc vào 1 interface không đổi. Ta có thể dễ dàng thay thế, sửa đổi module cấp thấp mà không ảnh hưởng gì tới module cấp cao.
Mình phải công nhận là lý thuyết về thằng DI hơi khó tiêu, bạn cần phải đọc nhiều nguồn khác nhau bao gồm tiếng anh và tiếng việt để không bị bỏ xót và nhầm lẫn thông tin.
Bây giờ, mình có project đơn giản là đọc và hiển thị thông tin từ Database. Chúng ta sẽ cùng xem và so sánh giữa cách viết thông thường và cách viết sử dụng Dependency Injection để hiểu rõ hơn nhé.
Nhìn hình trên, Tôi giả sử rằng lúc ban đầu ứng dụng của chúng ta chỉ cần lấy thông tin từ SQL database và hiện thị. vơi làm thông thường, chúng ta sẽ bắt đầu viết class GetMessageFromDatabase. hàm Main sẽ gọi class DisplayMessage và class DisplayMessage cần khởi tạo class GetMessageFromDatabase để lấy thông tin từ Database. Vài tháng sau, chúng ta nhận được yêu cầu từ khách hàng là họ muốn lấy thông tin từ Database và XML file. Vậy là chúng ta lại viết thêm class GetMessageFromXML để lấy thông tin từ XML file. Sau đó vài tháng, khách hàng lại muốn lấy thêm thông tin từ Text file và chúng ta lại ngồi viết thêm class GetMessageFromText tương ứng.
Vấn đề phát sinh là mỗi lần thêm một datasource mới (database, xml, text file) chúng ta cần phải viết một class để lấy dữ liệu tương ứng, sau đó lại phải sửa class DisplayMessage để nó khởi tạo và lấy đúng datasource mình cần. Nếu là một hệ thống lơn thì việc thay đổi này sẽ là một vấn đề lớn và mang lại nhiều phiền toái.
Mục đích của chúng ta cần là viết code theo một cách mà khi cần thêm vào một nguồn dữ liệu mới, thì chỉ cần update lại lời gọi datasource ở hàm Main thôi. Chúng ta không cần thay đổi code ở class DisplayMessage để thích ứng với các loại datasource mới được thêm vào.
Code không dùng Dependency Injection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DisplayMessage dm = new DisplayMessage();
dm.ShowMessage();
}
}
public class DisplayMessage
{
GetMessageFromDatabase Gmd;
public DisplayMessage()
{
Gmd = new GetMessageFromDatabase();
}
public void ShowMessage()
{
Console.WriteLine(Gmd.GetMessage());
Console.ReadLine();
}
}
public class GetMessageFromDatabase
{
public string GetMessage()
{
//Pretend this comes from the database
return "Hi from database";
}
}
}
Mọi thứ OK, giả sử vài tháng sau chúng ta cần lấy nguồn dữ liệu từ XML dựa vào tham số ở hàm Main. Vậy chúng ta cần phải thêm class GetMessageFromXMLvào code của mình. Đồng thời chúng ta cần phải sửa lại một chút code ở hàm Main và class DisplayMessage. Bây giờ code của chúng ta sẽ như sau:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DisplayMessage dm = new DisplayMessage(args[0].ToString());
dm.ShowMessage();
}
}
public class DisplayMessage
{
string source;
public DisplayMessage(string s)
{
source = s;
}
public void ShowMessage()
{
if (source.ToUpper() == "DATABASE")
{
GetMessageFromDatabase Gmd = new GetMessageFromDatabase();
Console.WriteLine(Gmd.GetMessage());
Console.ReadLine();
}
else if (source.ToUpper() == "XML")
{
GetMessageFromXML Gmx = new GetMessageFromXML();
Console.WriteLine(Gmx.GetMessage());
Console.ReadLine();
}
}
}
public class GetMessageFromDatabase
{
public string GetMessage()
{
//Pretend this comes from the database
return "Hi from database";
}
}
public class GetMessageFromXML
{
public string GetMessage()
{
//Pretend this comes from an XML file
return "Hi from XML";
}
}
}
Bây giờ giả sử vài tháng sau nữa chúng ta lại cần lấy dữ liệu từ file Text dựa vào tham số truyền vào ở hàm Main. Giờ mình làm gì đây? viết thêm class GetMessageFromTextFile, rồi sửa lại code của class DisplayMessage nửa hả?
Bạn có thấy sự phụ thuộc của class DisplayMessage khi thực thi thế nào chưa? Đó là nó phải thay đổi dựa vào nguồn dữ liệu được lấy.
Inversion of Control cố gắng làm cho class DisplayMessage và các class dữ liệu lấy ra hoàn toàn độc lập với nhau. Inversion of Control (IoC) thường được thực thi bằng việc áp dụng Dependency Injection (DI) như mình đã có nhắc ở phần định nghĩa.
Bây giờ chúng ta sẽ xem đoạn code trên dược áp dụng DI vào thì nó sẽ như thế nào nhé.
Code dùng Dependency Injection:
Trong đoạn code bên dưới tôi sẽ dùng 1 trong 3 loại Dependency Injection đó là Constructor Injection.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public interface IGetData
{
string GetMessage();
}
class Program
{
static void Main(string[] args)
{
IGetData IG;
string source = args[0].ToString();
if (source.ToUpper() == "DATABASE")
{
IG = new GetMessageFromDatabase();
}
else if (source.ToUpper() == "XML")
{
IG = new GetMessageFromXML();
}
else if (source.ToUpper() == "TEXT")
{
IG = new GetMessageFromTextFile();
}
else
{
IG = new GetMessageFromDatabase();//default set to database
}
DisplayMessage dm = new DisplayMessage(IG);
dm.ShowMessage();
}
}
public class DisplayMessage
{
IGetData IGLocal;
public DisplayMessage(IGetData IG)
{
IGLocal = IG;
}
public void ShowMessage()
{
Console.WriteLine(IGLocal.GetMessage());
}
}
public class GetMessageFromDatabase : IGetData
{
public string GetMessage()
{
//Pretend this comes from the database
return "Hi from database";
}
}
public class GetMessageFromXML : IGetData
{
public string GetMessage()
{
//Pretend this comes from an XML file
return "Hi from XML";
}
}
public class GetMessageFromTextFile : IGetData
{
public string GetMessage()
{
//Pretend this comes from an Text file
return "Hi from Text file";
}
}
}
Như bạn thấy ở ví dụ trên, việc tiêm (injecting) vào các phụ thuộc (dependencies) thông qua constructor (), Tôi đã tách class DisplayMessage và các class lấy dữ liệu (ex: class GetMessageFromDatabase ,…. ). Tôi có thể thêm nhiều class mới để lấy data nêu tôi muốn mà không cần phải sửa lại class DisplayMessage, miễn sao những class đó phải được kế thừa (inherit) từ interface IGetData. Nghĩa là, mọi thứ ở đây sẽ phụ thuộc vào chỉ 1 Interface. Đây đều chúng ta mong muốn (giảm được sự phụ thuộc – reduce dependencies ).
Hy vọng sẽ giúp bạn nắm được cơ bản về khái niệm và cách sử dụng Dependency Injection.
Luôn có hai dạng lập trình viên, một dạng luôn nắm vững lý thuyết, dạng còn lại thì không.
Những người nắm vững lý thuyết thì luôn có năng suất làm việc cao hơn hẳn những người không học lý thuyết, vì không phải tốn thời gian để thử sai (trial and error), cũng không cần tốn thời gian tra cứu lại kiến thức.
Một ví dụ đơn giản về CSS, chúng ta có class .gift-image có thuộc tính top = 10px, và chúng ta muốn class này có thuộc tính top = 0 trên các thiết bị có màn hình nhỏ hơn 600px:
Bài viết được sự cho phép của tác giả Tô Thị Vân Anh
Không biết viết mở đầu như thế nào, thôi thì đi thẳng vào vấn đề chính luôn cho nhanh. Bây giờ nếu muốn thực hiện tự động download file từ một trang web nào đó bằng Selenium thì chúng ta sẽ phải làm những gì và như thế nào?
Đầu tiên mình sẽ đưa ra các bước mô phỏng được thực hiện trên trình duyệt Firefox như thế này nhé:
1. Mở trình duyệt Firefox và đi tới link có chứa thông tin file cần tải xuống
2. Nếu khi mở link trang web ra mà đã có chứa file cần download ở đó luôn rồi thì sang bước tiếp theo. Hoặc chưa có thì các bạn có thể thực hiện click vào menu nào đó để đi đến trang có thông tin download được là được nhé.
3. Thực hiện click vào link hoặc button để tải file xuống.
4. Lúc này, có 1 cửa sổ của hệ thống hiển thị ra có hỏi bạn là bạn muốn mở file này hay muốn lưu file này. Rất tiếc là bạn không thể sử dụng Selenium để thực hiện lựa chọn nào đó được, vì thế sẽ phải tìm cách xử lý cái popup này.
5. Cuối cùng, chờ file tải xong và đóng trình duyệt.
Thực tế thì chúng ta vẫn làm như vậy, còn để biến các bước này vào trong code và để nó làm được các công việc kia thì sẽ cần làm gì? Cũng rất đơn giản thôi.
Không tính các bước râu ria, không liên quan lắm đến chủ đề bài viết thì các bước cơ bản sẽ như sau:
1. Khởi tạo một profile cho FirefoxProfile.
FirefoxProfile profile=new FirefoxProfile();
2. Set Preference cho profile đó – Các preference cho từng loại file mà bạn muốn tải xuống, (có thể là file .Zip, .docx, .elsx, .pdf … ) tùy từng loại file mà bạn sẽ cần có các preference tương ứng. Và bạn cũng có thể lựa chọn thêm các Preference khác để có các tùy chọn cài đặt tương ứng, như mình đã giải thích ở bài trước. Ví dụ:
//set = 2 để lưu file vào một thư mục cụ thể nào đó trong máy tính của
profile.setPreference("browser.download.folderList", 2);
//Giá trị = false, không mở cửa sổ khi download
profile.setPreference("browser.download.manager.showWhenStarting", false);
// Set đường dẫn lưu file xuống máy tính
profile.setPreference("browser.download.dir",
"D:\\AnhTo\\Draft\\DownloadFile");
// Ở đây mình truyền vào các loại file liên quan đến bộ office thì nó sẽ không hỏi, mà lưu luôn xuống máy.
profile.setPreference("browser.helperApps.neverAsk.saveToDisk",
"text/csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
3. Khởi tạo trình duyệt với profile đã tạo:
WebDriver driver=new FirefoxDriver(profile);
4. Đi đến link trang web có thông tin file cần tải xuống:
Chào các bạn, kể từ khi công nghệ ảo hóa ra đời thì nó đã giúp chúng ta rất nhiều trong việc giảm thiểu chi phí đầu tư cho các thiết bị cơ sở hạ tầng, kiểm thử phần mềm và nhiều những ưu điểm tuyệt vời khác.
Đơn cử như việc bạn có thể tạo ra một hoặc nhiều máy tính ảo chạy trên một máy tính thật, mà chức năng của các máy ảo đó tương tự như máy thật. Và tất nhiên, các máy ảo này khi chạy thì cũng sẽ chiếm tài nguyên phần cứng của máy thật.
Hiện nay có rất nhiều công cụ hỗ trợ việc ảo hóa như vậy. Tiêu biểu nhất có thể kể đến như: VirtualBox, VMware, Parallels… Trong số này có VirtualBox là miễn phí còn lại hầu như đều phải trả phí.
Để tìm hiểu kỹ hơn về các phần mềm này, và hiểu hơn về tác dụng của phần mềm ảo hóa thì bạn có thể tham khảo các bài viết sau:
Trong bài viết này mình sẽ hướng dẫn các bạn cách cài đặt VMware trên Ubuntu (một trong những phần mềm tạo máy tính ảo tốt nhất và phổ biến nhất hiện nay). Ok, giờ thì bắt đầu thôi nào !
Cài đặt VMware Workstation trên Ubuntu
+ Bước 1: Đầu tiên, các bạn hãy truy cập vào đường link bên dưới để download file cài đặt phần mềm VMware về, các bạn lưu ý chọn đúng phiên bản cho hệ điều hành Linux nha.
NOTE: Các bạn có thể đổi tên tùy ý nha. Bạn có thể đổi tên file này cho dễ gõ lệnh hơn nhé. Ví dụ abc.bundle. Còn ở đây mình giữ nguyên tên file nhé !
+ Bước 4: Tiếp theo các bạn chạy lệnh sau:
sudo bash <filename> như hình bên dưới và nhấn Enter..
Áp dụng vào ví dụ này là: sudo bash VMware-Workstation-Full-16.1.0-17198959.x86_64.bundle
Nếu sau khi chạy 100% mà hiện lên thông báo Installation was successful như hình bên dưới thì tức là bạn đã cài đặt thành công rồi nhé.
+ Bước 5: Sau đó các bạn vào kho ứng dụng đã cài đặt, tìm kiếm với từ khóa VM thì kết quả sẽ xuất hiện như hình bên dưới. Các bạn bấm vào VMware Workstation để bắt đầu một số công việc cấu hình.
Ở bước này các bạn tích vào I accept terms in the license agreement => sau đó bấm Next để tiếp tục.
NOTE: Ở đây các bạn phải cuộn hết cái License Agreement để đồng ý với điều khoản của họ thì mới bấm Next được nha. Để xác nhận là bạn đã đọc hết rồi ấy mà 🙂
+ Bước 6: Tiếp theo các bạn cứ chọn như trong hình => rồi bấm Next thôi.
Tiếp tục chọn theo như hình bên dưới rồi bấm Next.
+ Bước 7: Ở bước này, nếu có yêu cầu quyền quản trị thì bạn nhập mật khẩu máy khi các bạn Ubuntu hoặc các hệ điều hành tương ứng.
=> Sau đó bấm Enter hoặc bấm vào Authentication để bắt đầu xác nhận.
Và đây là giao diện của phần mềm VMware Workstation trên Ubuntu. Vì VMware Workstation là phiên bản trả phí nên bạn chỉ có quyền dùng thử 30 ngày, tính từ ngày cài đặt.
Sau đó, nếu bạn muốn dùng tiếp bạn phải mua bản quyền thì mới có thể tiếp tục sử dụng được.
Mình nghĩ 30 ngày là khoảng thời gian đủ để bạn trải nghiệm và đưa ra quyết định có nên mua thêm hay không. Khi mua bạn sẽ được cấp key và bạn sẽ dùng key đó để sử dụng phần mềm.
GỢI Ý: Bạn có thể sử dụng thẻ MasterCard ảo để thanh toán Quốc tế một cách dễ dàng.
Lời Kết
Vậy là trong bài viết mình đã hướng dẫn các bạn cách cài đặt VMware Workstation trên hệ điều hành Ubuntu phiên bản 20.04 rồi ha. Các phiên bản mới hơn thì các bạn cũng làm hoàn toàn tương tự vậy thôi, không khác gì cả.
Trong các bài viết tiếp theo mình sẽ hướng dẫn các bạn cách thiết lập cũng như cài đặt máy ảo bằng cách sử dụng VMware Workstation. Hẹn gặp lại các bạn trong các bài viết tiếp theo nha !
Trong ví dụ này mình sẽ có input là một tấm ảnh chụp từ màn hình mobile, kết quả output mong muốn sẽ là nội dung chữ trên bức ảnh đó và kiểm tra lại để đảm bảo trên ảnh có chứa những nội dung chữ mình mong muốn.
Optical character recognition (also optical character reader, OCR) is the mechanical or electronic conversion of images of typed, handwritten or printed text into machine-encoded text, whether from a scanned document, a photo of a document, a scene-photo (for example the text on signs and billboards in a landscape photo) or from subtitle text superimposed on an image.
OCR Input (PNG file): Screenshot_2017-03-15-14-57-02.png OCR Output (text): The text “Logs saved to sdcard/SysLog/2017-03-15_14.56.59”
Các bước thực hiện:
1. Bạn có thể tạo một project mới hoặc tải project mẫu mình đã upload tại đây.
2. Import thư viện Tess4J và các thư viên liên quan (có thể import hết thư viện trong thư mục “tesslibs” mình để trong project).
3. Đặt thư mục “tessdata” (data dùng để nhận diện ký tự) và hình ảnh cần test ra thư mục root, sau này bạn có thể thay đổi đường dẫn đến hình ảnh cũng được.
Sau khi có đủ thư viện, đặt thư mục tessdata và hình ảnh input đúng vị trí, chúng ta tạo một class mới để bắt đầu. Đây là một đoạn code ngắn để thực hiện những yêu cầu ban đầu:
1. Đọc chữ từ screenshot.
2. In tất cả các chữ có trên ảnh ra.
3. Kiểm tra những chữ đã xuất ra được có chứa các nội dung mình cần hay không.
public static void main(String[] args) {
// Set the image source path
String imagePath = “Screenshot_2017-03-15-14-57-02.png”;
File image = new File(imagePath);
// JNA Interface Mapping
ITesseract instance = new Tesseract();
try {
String Textresult = instance.doOCR(image);
// Print out the text results
System.out.println(Textresult);
// Verify to check the text is displayed
System.out.println(“**************”);
String ExpectedText = “Logs saved to sdcard/SysLog/”;
if (Textresult.contains(ExpectedText)) {
System.out.println(“Passed. The expected text is displayed!”);
} else {
System.out.println(“Failed. The text was not found!”);
}
} catch (Exception e) {
System.out.println(“Failed. Could not read the text from image file!”);
}
}
}
Nội dung chúng ta có được:
Cách này khá hữu ích khi làm automation, đôi lúc có những thành phần không thể getText do không lấy được locators, dùng cách này thì chúng ta sẽ không cần locators, ngoài ra còn ứng dụng trong các trường hợp khác như đọc nội dung PDF, tài liệu scanned. Các bạn thử nhé!
HTML Web Storage được tạo ra để lưu trữ data của user ở dưới local giống như cookie.
HTML Web Storage và Cookie khác nhau như thế nào ? Tại sao nên dùng HTML Web Storage ?
Cookie là một đoạn văn bản ghi thông tin được tạo ra và lưu trên trình duyệt của máy người dùng. Cookie thường được tạo ra khi người dùng truy cập một website. Cookie sẽ ghi nhớ những thông tin như tên đăng nhập, mật khẩu, các tuỳ chọn do người dùng lựa chọn đi kèm… Các thông tin này được lưu trong máy tính để nhận biết người dùng khi truy cập vào một trang web. Tuy vậy, cookie có một số khuyết điểm như:
Cookie luôn luôn gửi request tới web server vì vậy đối với các tệp lớn thì nó có thể tiêu tốn băng thông đáng kể.
Giới hạn của một cookie chỉ là 4 KB.
Người dùng có thể mở file chứa cookie và sửa nội dung trong đó.
Trong một số trường hợp người dùng disable cookie trên trình duyệt thì tính năng này sẽ bị vô hiệu hóa.
Có lẽ vì những khuyết điểm đó mà HTML Web Storage được sinh ra.
Ưu điểm của HTML Web Storage :
HTML Web Storage có thể lưu trữ một lượng data lớn từ 2MB tới 10MB. Giới hạn này phụ thuộc vào browser, protocol (HTTP hoặc HTTPS).
Web Storage an toàn hơn: người dúng khó mà có thể tìm ra file lưu Web Storage để sửa data. Tuy vậy thì chúng ta vẫn có thể sửa data Web Storage khi F12 trên trình duyệt.
Web Storage cũng lưu trữ ở dưới local nhưng nó không bao giờ được gửi tới web server vì vậy mà không ảnh hưởng tới băng thông.
Data được lưu trữ trên một trình duyệt nên không thể truy xuất trên trình duyệt khác.
Data được lưu trữ dưới dạng chuỗi JSON.
Web Storage là tính năng của HTML5 nhưng nó hỗ trợ đến cả những phiên bản trình duyệt cũ mà hiện tại ít ai dùng.
Ứng dụng của Web Storage
Dùng để lưu những data của user mà được sử dụng nhiều lần trên các phiên làm việc khác nhau (một phiên làm việc được tính là một lần đóng mở tab).
Dùng cho các ứng dụng SPA ( Single page application). Thông thường khi xử lí dữ liệu thao tác của user trên 1 page thì chúng ta lưu vào biến javascript. Còn nếu muốn share dữ liệu giữa các page thì có thể dùng Web Storage. Ví dụ lưu thông tin đăng nhập của user, lưu thông tin giỏ hàng, …
Không dùng Web Storage để lưu các dữ liệu quan trọng như mật khẩu người dùng, …
Làm việc với web storage
Có 2 loại storage:
localStorage – dữ liệu được lưu mãi mãi kể cả khi đóng tab hoặc đóng trình duyêt. Dữ liệu chỉ mất khi clear history.
sessionStorage – dữ liệu được lưu trong 1 phiên làm việc. Dữ liệu mất khi người dùng đóng tab.
Kiểm tra trình duyệt có hỗ trợ storage không
if (Storage) {
// Storage is supported!
} else {
// No support. Use a fallback such as browser cookies or store on the server.
}
Dữ liệu được lưu dưới dạng key:value. Tùy vào dữ liệu mà chúng ta có các cách lưu khác nhau. Với dữ liệu đơn giản thì lưu key value như một chuỗi đơn giản. Với dữ liệu phức tạp thì nên lưu value dưới dạng chuỗi JSON, khi lưu dữ liệu dùng JSON.stringify() còn khí lấy dữ liệu dùng JSON.parse(). Vì dữ liệu được lưu dưới dạng string nên khi lấy ra có thể cần phải xử lí bằng cách dùng các hàm parseInt(), parseFloat(), …
Lấy Data
localStorage.getItem(‘name’);
localStorage.name
localStorage[‘name’]
Xóa Data
localStorage.removeItem(‘name’);
localStorage.clear();
Event
window.addEventListener(“storage”, function(event) {
var key = event.key;
var newValue = event.newValue;
var oldValue = event.oldValue;
var url = event.url;
var storageArea = event.storageArea;
// handle the event
});
Các Interactive Game bên trong trợ lý ảo Google Assistant được xây dựng như thế nào và Google đã ứng dụng những công nghệ gì bên trong. Bài viết sẽ giúp bạn giải đáp thắc mắc trên đồng thời hướng dẫn cách xây dựng một Interactive Game cho trợ lý ảo Google.
Nội dung này được trình bày bởi Ms. Mandy Chan – Developer Advocate @Google. Qua bài chia sẻ, bạn sẽ hiểu thêm về:
Khái niệm Conversational Action (tạm dịch: Hành động hội thoại)
Khái niệm Interactive Canvas API
Cách để xây dựng một full-screen interactive game trên Android với JavaScript
Tại sao bạn nên xây dựng Interactive Game trong Google Assistant
Hiện tại, Google Assistant đang hỗ trợ hơn 19 ngôn ngữ và hoạt động trên 80 quốc gia. Dù người dùng mục tiêu của bạn ở bất kỳ đâu, Google Assistant đều có thể giúp đỡ họ thông qua hơn 1 tỷ thiết bị đang sử dụng ứng dụng này. Bạn có thể tiếp cận họ theo nhiều cách khác nhau thông qua Google Assistant.
Người dùng hiện tại đang sử dụng các thiết bị thông minh theo nhiều cách khác nhau. Theo nghiên cứu được thực hiện bởi Adobe, phần lớn người dùng sử dụng các thiết bị thông minh nhằm phục vụ cho nhu cầu âm nhạc và cho các hoạt động thường nhật, chẳng hạn như cập nhật thông tin thời tiết. Đồng thời, cũng có một lượng lớn người dùng sử dụng các thiết bị để giải trí, chơi game.
Trong số những người sử dụng Google Assistant, có 55% người dùng sử dụng cô trợ lý ảo này chỉ để hỏi những câu hỏi vui; có 20% thì sử dụng để chơi các trò chơi bên trong ứng dụng Google Assistant (*Google gọi đây là Interactive Game).
Giờ hãy cùng đi vào nội dung chi tiết.
Interactive Game là gì?
Smart display lần đầu ra mắt vào năm 2019. Trong suốt năm đó, số lượng người dùng tương tác với các thiết bị smart display đã tăng lên gấp 4 lần.
Từ hai năm trước, chúng ta đã thấy được sức hút của các trò chơi bằng giọng nói (voice game) bên trong trợ lý ảo Google Assistant.
Các lập trình viên đã tạo ra những ứng dụng mang tính tương tác cao như thế bằng cách tận dụng thứ mà Google Assistant làm tốt nhất. Đó là “cô ấy” có thể hiểu được giọng nói và ngôn ngữ của người dùng.
Kết quả là voice game đã rất thành công trong việc tạo ra một trải nghiệm tốt cho người dùng trong một môi trường chỉ có mỗi audio.
Ngày nay, nhờ sự phổ biến của smart display, nhiều lập trình viên cũng bắt đầu xây dựng các trò chơi có thể tương tác cả giọng nói lẫn hình ảnh, chẳng hạn như các tựa game: Guess the Drawing, Trivia Crack, Who wants to be a Millionaire,…
Với Guess the Drawing, bạn có thể chơi game với hàng trăm bức ảnh động đầy hấp dẫn ở chế độ xem chậm. Trong khi đó, nhờ Trivia Crack, bạn có thể chơi game mà vẫn có thêm kiến thức với bộ câu hỏi và câu trả lời về các chủ đề như lịch sử, mỹ thuật, giải trí và khoa học. Với Who wants to be a Millionaire, người tham gia sẽ trả lời một bộ câu hỏi để chinh phục mức giải thưởng cao nhất là 1 triệu USD, đồng thời bạn cũng có thể sử dụng các quyền trợ giúp để tham gia cuộc chơi này.
Và đây là một tựa game khác: “Are You Feeling Lucky?”
Interactive Game này sử dụng cả lợi thế của việc hiển thị trên màn hình lẫn tương tác bằng giọng nói của Google Assistant.
Nhiều người chơi sẽ cùng nhau tham gia trả lời các câu hỏi đơn giản được đưa ra và trên màn hình sẽ hiển thị các avatar khác nhau để giúp phân biệt và theo dõi xem đang đến lượt của người chơi nào.
Những hình ảnh động này có thể được tạo ra là nhờ một thứ được gọi là Interactive Canvas.
Interactive Canvas là một API cho phép các lập trình viên tạo ra fluid animation (một loại hiệu ứng chuyển động) và customize trò chơi của họ bằng cách sử dụng các công nghệ quen thuộc như HTML, CSS, JavaScript và Web Assembly.
Nhờ kết hợp giữa các khả năng hiển thị (visual capabilities) cùng với khả năng hiểu biết ngôn ngữ tự nhiên và nhận diện giọng nói của Google, các lập trình viên giờ đây có thể thỏa sức sáng tạo của bản thân thông qua việc xây dựng các Interactive Game trên Google Assistant với cả các hiệu ứng hình ảnh, chuyển động lẫn âm thanh.
Interactive Canvas hoạt động như thế nào?
Trước khi đào sâu vào Interactive Canvas, hãy cùng tìm hiểu về cách vận hành (diagram) của một Hành động (action) diễn ra với action builder/ SDK và một web service.
Lifecycle của một Conversational Action
Web service có thể được sử dụng để cung cấp dynamic prompts và làm cho API gọi vào hoặc kiểm tra bên trong database.
Web service yêu cầu thiết bị tìm nạp (fetch) web app
Khi người dùng nói chuyện với thiết bị, giả dụ: “Ok Google, talk to my conversational action”, thiết bị sẽ gửi đoạn audio những gì người dùng đã nói tới action. Action ngay sau đó tiến hành xử lý request trả về một prompt web service của bạn. Nó bao gồm các dữ liệu như canvas, web app và các metadata khác.
Khi thiết bị nhận được những thứ này, nó sẽ khởi tạo web app của bạn.
Bên trong web app, Interactive Canvas API được khởi tạo và sau đó website được render trên thiết bị.
Bởi do người dùng tương tác với action của bạn, bạn có thể update và request dữ liệu giữa server và bên client. Đây cũng là một high-level và nó có thể diễn ra.
Code: Fulfillment và Web App logic
Hiện tại, Canvas đang hỗ trợ trên các thiết bị smart display và điện thoại android. Điều này có nghĩa là trước khi bạn gửi đi một canvas response, hãy kiểm tra thiết bị của phía client xem nó có hỗ trợ canvas không. Chúng ta thực hiện nó bằng cách kiểm tra trên thiết bị (device capabilities) xem có bao gồm interactive canvas không, bằng cách tìm:
Đến phần tải lên canvas web app, bạn sẽ cần sử dụng một lớp (class) canvas mới, được cung cấp bởi node.js trong thư viện của bên phía client. Class này có 2 thuộc tính (properties) gồm: url và data.
Hãy luôn nhớ rằng lần đầu tiên mà bạn gửi lại canvas response, NÓ BUỘC PHẢI CÓ MỘT URL. Nó sẽ giúp cho thiết bị biết đâu là nơi để tìm nạp (fetch) web app.
Hãy luôn nhớ rằng lần đầu tiên mà bạn gửi lại canvas response, nó buộc phải có một URL.
Một điều cần lưu ý nữa là hãy đảm bảo URL đấy là https để chắc chắn hoạt động một cách bảo mật.
Điều gì sẽ xảy ra ở phía client sau khi nhận được canvas response?
Web app là 1 trang web được render trên thiết bị.
Nó được build chủ yếu bằng hai công nghệ web truyền thống là HTML và JavaScript.
Khi web app được tải thì cũng đồng thời khởi tạo Canvas JavaScript library. Đây là một client-side library vận hành trên thiết bị. Đừng nhầm lẫn nó với server-side node.js client library.
Canvas JavaScript xử lý response từ phía server và nó cũng tạo ra các request tới thiết bị.
Một lưu ý nhỏ đó là bạn cũng có thể build web app bằng cách sử dụng các JavaScript framework phổ biến như React hay tất cả các libraries như pixie.js.
Thêm nữa, bạn nên sử dụng Single Page Application (SPA) vì nó giúp tránh được tình trạng nhấp nháy như website và đảm bảo một UI mượt mà cho người dùng mobile.
Loading process trên thiết bị là một phần của web app. Interactive Canvas Library được nhập vào và được khởi tạo. Sau khi đã được khởi tạo, bạn có thể truy cập vào một thể hiện (instance) của interactive canvas – thứ cho phép bạn kiểm soát canvas response thông qua việc sử dụng on update callback. Gửi các request tới server bằng cách sử dụng the send text query method. Interactive canvas instance cũng cho phép bạn đăng ký callbacks thông qua ready method.
Việc gửi requests từ client đến server được thực hiện như thế nào?
Chúng ta đã trao đổi về cách để kiểm soát canvas response từ phía server của client. Vậy còn về việc gửi requests từ client đến server? Điều này có thể được thực hiện bằng cách gọi send text query method trên interactive canvas object.
SendTextQuery mang một StringValue – một cụm từ (phrase) mà người dùng sẽ nói một cách khác là để trigger chính xác intent. Đây là một method mạnh mẽ để giao tiếp với server và chúng ta sẽ cùng nhau xem qua một vài dòng code để dễ hình dung hơn.
Các nguyên tắc khi thiết kế Interactive Game (Design Principles)
Chúng ta đã làm việc với nhau về Interactive Canvas là gì, cách mà client và server tương tác với nhau và cách chúng ta duy trì trạng thái (state) giữa server và client. Giờ hãy cùng tìm hiểu về design principles ở phần xây dựng Interactive Game cho Google Assistant.
Chuyển tiếp giọng nói
Khi build một Interactive Game, hãy đảm bảo rằng nó mang tính đối thoại (conversational) thay vì ở dạng lệnh (command-based). Hãy nghĩ về những điều này từ ngay khi trò chơi được bắt đầu.
Tận dụng hiệu ứng hình ảnh
Việc tận dụng hình ảnh khi xây dựng các trò chơi cho smart display rất quan trọng. Hãy đảm bảo rằng:
Bạn mang đến người dùng những dấu hiệu trực quan (visual cue).
Làm nổi bật các item có thể tương tác trên màn hình.
Sử dụng các hình ảnh chuyển động để hiển thị cho người dùng các điểm chính cần quan tâm (point of interest).
Tối ưu hiển thị
Tối ưu hóa hiển thị và thiết kế giao diện cũng là một phần quan trọng. Sử dụng kích thước phông chữ tối thiểu là 32pt cho văn bản chính như tiêu đề và kích thước 24pt cho văn bản phụ như đoạn mô tả hay các đoạn văn bổ sung được xem là lựa chọn hợp lý.
Chế độ nhiều người chơi cục bộ
Đối với các trò chơi nhiều người chơi, tận dụng lợi thế của việc có thể hiển thị để thể hiện các lượt chơi của các người chơi bằng cách sử dụng các icon khác nhau.
Xử lý lỗi
Cũng giống như những công việc khác, hãy nhớ kiểm soát các lỗi trong trò chơi một cách khéo léo. Một mẹo để làm việc này đó là sử dụng các gợi ý ở dạng hình ảnh / văn bản hay âm thanh rõ ràng khi người dùng gặp rắc rối trong trò chơi.
Tận dụng SSML và thư viện âm thanh được cung cấp bởi Google
Để cải thiện trò chơi hơn, bạn có thể tận dụng thêm công nghệ SSML và thư viện âm thanh của Google. SSML hay còn được gọi là Speech Synthesis Markup Language. Nếu bạn là một web developer thì có thể hiểu SSML cũng tương tự CSS. Với CSS, bạn có thể thiết kế style cho văn bản thì SSML sẽ giúp bạn thiết kế style cho giọng nói (voice) bằng cách thay đổi âm lượng, cao độ giọng nói, thậm chí thêm vào các quãng ngắt nghỉ giữa các từ. Đồng thời, SSML cũng cho phép bạn thêm vào phân lớp (layering) của âm thanh vào background.
World Games được sáng tạo dưới dạng các câu hỏi đố và người chơi có thể trả lời trực tiếp bằng giọng nói.
Multiplayer Games là các loại game cho phép nhiều người chơi cùng lúc hiện cũng đang được phát triển khá phổ biến.
Persistent Games cho phép các người chơi chơi nối tiếp nhau một cách liên tục và được xây dựng dựa trên tình hình thực tế của mỗi khu vực, mỗi quốc gia.
Trên đây là giới thiệu một cách tổng quan về tất cả những gì có thể làm để phát triển game với Google Assistant. Hãy tự cởi bỏ giới hạn của bản thân và sáng tạo thêm thật nhiều những games hấp dẫn nhất.
Bài viết được trích dẫn từ phần trình bày của cô Mandy Chan – Developer Advocate @Google tại sự kiện Vietnam Web Summit 2020 LIVE do TopDev tổ chức
Bài viết được sự cho phép của tác giả Trần Anh Tuấn
Chắc hẳn nhiều bạn trong khi học hay khi đi làm ở công ty sau khi vượt qua ngưỡng newbie về HTML hay là CSS rồi. Trong quá trình code CSS sẽ thấy rằng sao có nhiều người họ code cái template đó nhanh thế nhỉ ?
Sao mình cũng dùng CSS như họ mà, hay là mình gõ chậm nhỉ, hay là tư duy phân tích yếu. Thế là mò mẫm trên mạng và thấy người ta bảo dùng SASS code lẹ lắm, chẳng biết SASS là cái gì thế là vội vàng ngồi nghiên cứu về nó.
Rồi phát hiện ra rằng CSS viết lồng nhau được luôn hay thật. Thế là cắm đầu cắm cổ tập viết lồng nhau bao nhanh luôn. Nhưng kết quả vẫn đâu vào đấy vẫn thấy chưa nhanh lắm, thế là tiếp tục hỏi cộng đồng mạng, và họ bảo dùng Mixins code cho nhanh
Và thấy dòng code trên rồi tự hỏi@mixin là cái gì thế nhỉ ? Rồi lại tiếp tục vọc tiếp và thấy rằng ah thì ra @mixin là như vậy nè nó giúp cho chúng ta có thể tái sử dụng và tận dụng code một cách triệt để, để đỡ phải gõ đi gõ lại một dòng code hoài, tiết kiệm thời gian và hoàn thành sớm nữa.
Vậy Mixins thực chất là gì ? Và làm sao để tạo một Mixin để sử dụng cho hiệu quả trong quá trình code trang web đây ?
Hiểu được nhu cầu của các bạn nên hôm nay mình viết bài này để chúng ta sẽ cùng nhau tìm hiểu về Mixins trong SASS là gì và một số hàm Mixins thông dụng trong SASS mà chúng ta nên biết để việc code được nhanh hơn nhiều nhé.
# Mixins là cái gì ?
Nếu các bạn làm lập trình thì chắc hẳn cũng biết đến function nhỉ ? Mixins cũng tương tự như vậy đấy. Nó cho phép chúng ta sử dụng đi sử dụng lại ở nơi nào mà chúng ta muốn hoặc ta có thể tùy chỉnh tham số truyền vào. Mục đích là tiết kiệm code, thời gian và đem lại hiệu quả cao.
Như đã nói Mixins cũng tương tự như function nên Mixins có 2 loại đó chính là
Loại có tham số
DÀNH CHO BẠN:
Mình có khoá học HTML CSS từ cơ bản tới nâng cao cho người mới, nếu bạn quan tâm thì bạn có thể học thử miễn phí bằng việc nhấn vào đây nha.
@mixin mixin_name(param1, param2...){
// code here
}
Loại không có tham số
@mixin mixin_name(){
// code here
}
Để gọi một Mixin ta có cú pháp như sau: @include mixin_name. Ví dụ
@mixin menulink(){
ul {
li {
display: inline-block;
a {
color: blue;
}
}
}
}
@include menulink;
Thì nó sẽ render như thế này
ul li {
display: inline-block;
}
ul li a {
color: blue;
}
# Một số hàm Mixins hay và thông dụng
Sau đây mình xin chia sẻ một số Mixins mà mình đã từng làm cũng như học hỏi được từ những pro khác trên mạng. Mình sẽ viết ra đây kèm giải thích cho các bạn nhé.
@mixin size
Cho phép chúng ta thiết lập độ rộng và chiều cao của một phần tử bất kỳ khi dùng.
Ví dụ mình muốn cho một class .box nào đó có chiều cao 100px và chiều rộng 100px mình sẽ dùng như thế này: @include size(100px), hàm ở trên mình set giá trị $height là mặc định nếu không truyền tham số thứ 2 thì nó sẽ bằng chiều rộng
Còn các bạn muốn set chiều rộng và chiều cao khác nhau thì các bạn có thể dùng như thế này: @include size(100px, 200px). Từ đó ta sẽ có kết quả
Các bạn có thấy rằng giá trị mặc định của $inset nếu không truyền vào thì sẽ là false nên câu điều kiện @if sẽ chạy đoạn code ở dưới và ngược lại nếu là true thì sẽ chạy đoạn code trên. Sử dụng if else giống trong lập trình luôn.
.box{
@include box-shadow(10px,10px,20px,0px,true);
}
// result
.box {
box-shadow: inset 10px 10px 20px 0px;
}
@mixin transform
Cho phép tạo thuộc tính transform nhanh chóng dựa vào tham số chúng ta truyền vào
Cho phép tạo border-radius cho phần tử chúng ta muốn, có thể set toàn bộ radius như nhau hoặc set từng góc có độ bo góc khác nhau nhé. Như ở dưới mình set các tham số tương ứng cho các góc.
Nếu mình chỉ điền vào một tham số đầu tiên thôi thì tất cả các tham số kia đều là tham số đầu từ đó ta có border-radius 4 góc đều như nhau. Tuy nhiên nếu các bạn muốn set riêng thì các bạn có thể dùng như thế này
Các bạn có thể tối ưu hơn dựa vào những giải pháp khác nhé. Ở đây mình chỉ code đơn giản thôi, các bạn có thể suy nghĩ và làm nó tốt hơn nà
@mixin centerAbsolute
Khi các bạn code website sẽ gặp các trường hợp muốn làm một phần tử nào đó center bằng việc sử dụng thuộc tính position: absolute kết hợp với thuộc tính transform: translate đúng không ?
Thì trong một trang web dài hay nhiều layout phức tạp chắc chắn sẽ dùng nhiều, nên để tối ưu cho việc phải code đi code lại ta sẽ tạo ra một Mixin để sử dụng nó được nhiều nơi nhé
Giả sử các bạn muốn phần tử .box đều center hàng dọc và ngang thì các bạn truyền tham số vào là both còn nếu chỉ muốn center hàng dọc thôi thì dùng top hoặc ngược lại muốn center theo chiều ngang thôi thì dùng left
Ngoài ra còn có nhiều Mixins hay khác mà các bạn có thể viết thêm như là khi viết media queries để làm responsive hay là hiển thị flexbox chẳng hạn.
@mixin min/max-width
@mixin minWidth($breakpoint) {
@media only screen and (min-width: $breakpoint) { @content; }
}
@mixin maxWidth($breakpoint) {
@media only screen and (max-width: $breakpoint) { @content; }
}
Thay vì các bạn phải viết đi viết lại dòng @media only screen dài quá thì mình viết một Mixin như trên để tiết kiệm thời gian các bạn có thể dùng nó như sau
Với các tham số truyền vào thì bạn tự do tùy chỉnh flexbox cho một phần tử mà bạn muốn một cách nhanh nhất nhé.
.box{
@include flex(row, center, center, wrap);
}
//result
.box{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
Và còn còn rất nhiều Mixins hay và tuyệt vời hơn khác nữa, trong quá trình làm các bạn sẽ tự nhận ra nên viết những Mixins gì để tiết kiệm thời gian, nâng cao năng suất, giúp cho việc code trở nên khỏe hơn và mau hoàn thành hơn.
# Tạm kết
Hi vọng với những kiến thức về Mixins sẽ giúp ích cho các bạn phần nào trong quá trình code SASS được nhanh nhất nhé. Ngoài ra mình cũng tìm kiếm thêm trên Google và tìm được khá nhiều Mixins hay khác nữa mà các bạn có thể tham khảo tại đây hoặc tại đây nhé. Chúc các bạn một ngày tốt lành.
Bài viết được sự cho phép của tác giả Trần Hữu Cương
Cấu hình compiler cho Dev C++
Dev C++ là một IDE, một phần mềm dùng để soạn thảo/ lập trình ngôn ngữ C/C++.
Trong bộ cài Dev C++ có tích hợp sẵn trình compiler C/C++ là Boost C++, tuy nhiên trình compiler này khá cũ hoặc đơn giản là máy bạn đã có sẵn trình compiler C/C++ nên bỏ qua không cài Boost C++.
Trong trường hợp này bạn cần phải cấu hình lại trình compiler trên Dev C++ để có thể thực hiện compile, run file C/C++.
Bài viết được sự cho phép của tác giả Trần Thị Thu Hà
Bài viết sẽ hướng dẫn bạn cách cài đặt Spring Boot CLI phiên bản mới nhất (1.4.0.RELEASE tại thời điểm viết bài) trên Mac OS X (El Captain 10.11.6). Bạn download file này: http://repo.spring.io/release/org/springframework/boot/spring-boot-cli/1.4.0.RELEASE/spring-boot-cli-1.4.0.RELEASE-bin.tar.gz
Hoàn thành xong bước này, Spring CLI đã hỗ trợ auto-complete.
KIỂM TRA KẾT QUẢ
spring --version
Nếu thấy kết quả trả về là:
Spring CLI v1.4.0.RELEASE
có nghĩa là quá trình cài đặt Spring Boot CLI đã thành công.
ỨNG DỤNG SPRING BOOT ĐẦU TIÊN
Kiểm tra thư mục hiện hành:
pwd
Tạo tập tin SmarjobWebController.java trong thư mục hiện hành:
touch SmartJobWebController.java
Biên soạn nội dung tập tin:
atom SmartJobWebController.java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SmartJobWebController {
@RequestMapping("/")
public String hello() {
return "<h3>Hello from SmartJob!</h3>";
}
}
Chạy ứng dụng:
spring run SmartJobWebController.java
Chúc mừng bạn, bạn vừa hoàn thành một ứng dụng Java web sử dụng Spring Framework, với sự hỗ trợ của Spring Boot (Source base này rất ổn định, là enterprise-class). Đây là cách làm rất nhanh, đặc sắc, chứng tỏ bạn am hiểu về Spring Boot khi khởi tạo cả một ứng dụng đồ sộ chỉ từ giao diện dòng lệnh (CLI: Command Line Interface).
Mẹo: Để thay đổi URL cho controller, hãy sửa giá trị mapping trong annotation @RequestMapping(“/your/prefer/url/path/foo/”)
Series bài viết chuyên sâu về Spring Framework đã được gắn tag: https://smartjob.vn/topic/spring-framework/
Bài viết gốc được đăng tải tại smartjob.vn – Đỗ Như Vý
Khi gặp tình huống một component không thể đứng độc lập, mà nó buộc phải kết hợp với một component khác và cùng chia sẻ một bộ state và phương thức. Đó là lúc chúng ta cân nhắc cách viết compound component.
Một ví dụ rất dễ thấy của compound component là element <select /> và <option />, <option/> không thể đứng độc lập, nó luôn được đặt trong <select/> có thể truy xuất và gọi các phương thức tương tự như <select/>
Nếu bạn là người viết component, người khác sử dụng component này, các dev khác sẽ cảm ơn bạn rất nhiều. Bạn đóng gói mọi thứ logic vào bên trong component cha như vậy, người sau sẽ không cần bận tâm nữa.
// parent component// xử lý event onChange, quản lý state selected value<RadioImageForm><RadioImageForm.RadioInput/><RadioImageForm.RadioInput/><RadioImageForm.RadioInput/></RadioImageForm>
Với child component của <RadioImageForm />, để cho nó rõ ràng minh bạch là chúng ta sẽ sử dụng những giá trị cung cấp từ parent, chúng ta dùng kiểu viết <RadioImageForm.RadioInput />
Một nhu cầu rất phổ biến là người khác sẽ muốn control component con <RadioInput /> bằng việc truyền thêm prop, nhưng thay vì truyền thằng vào component con, chúng ta hãy để họ truyền thông qua component cha <RadioImageForm/>, vì một lý do nào đó chúng ta cần truy cập các prop này bên trong component cha thì sao? Chúng ta làm thêm một bước pass-through các prop xuống cho component con với React.Children.map hoặc React.cloneElement
Chúng ta sẽ refactor lại <RadioImageForm/>, bỏ đi đoạn React.Children.map, thay bằng <Provider />
render():React.ReactElement{const{ children }=this.props;return(<RadioImageFormWrapper><RadioImageFormContext.Providervalue={this.state}>{children}</RadioImageFormContext.Provider></RadioImageFormWrapper>);}
Sử dụng Provider có một lưu ý sống còn là đừng bao giờ truyền value={{ some bla bla}}, như vậy nó sẽ khác nhau trên tất cả những lần render, hãy nhớ truyền một thứ gì đó cache được và chỉ bị thay đổi khi cần thiết như this.state
Trong component con <RadioInput /> chúng ta có thể truy xuất tất cả dữ liệu nội bộ thông qua consumer, bởi vì <RadioInput /> đang nằm trong <RadioImageForm /> luôn theo cách viết của chúng ta, nên có thể khai báo một static property Consumer bên trong RadioImageForm
Provider pattern là kỹ thuật kết hợp giữa React Context API và render props pattern, vẫn là để giải quyết câu chuyện chia sẻ state giữa các component trong cây.
Nếu bạn có thắc mắc, ủa vậy sao không dùng Redux, Mobx, Recoil, React Sweet State, Rematch, Unstated,… cho khỏe người ơi? Thì câu trả lời của mình là, ừ các bạn nên xài những thư viện quản lý state như vậy cho khỏe người, khỏe cho cả người maintain code bạn. Còn đây là cách làm nếu bạn muốn tham khảo, nếu không dùng gì hết, tôi dư giả thời gian để code từ đầu thì bạn có thể go-ahead với cách này
// src/components/DogDataProvider.tsxexportfunctionuseDogProviderState(){const context =React.useContext(DogDataProviderContext);if(context ===undefined){thrownewError('useDogProviderState phải được sử dụng bên trong DogDataProvider.');}return context;}
// src/index.tsxfunctionApp(){return(<Router><div className="App">{/* DataProvider phải nằm trên cùng của cây.*/}<DogDataProvider><Nav/><main className="py-5 md:py-20 max-w-screen-xl mx-auto text-center text-white w-full"><Bannertitle={'React Component Patterns:'}subtitle={'Provider Pattern'}/><Switch><Routeexactpath="/">{/* Component con sử dụng dữ liệu qua Consumer */}<Profile/></Route><Routepath="/friends">{/* Component con sử dụng dữ liệu qua Consumer */}<DogFriends/></Route></Switch></main></DogDataProvider></div></Router>);}
constProfile=()=>{// custom hook nhận "subscribes" khi có state thay đổiconst{ data, status, error }=useDogProviderState();return(<div><h1 className="//...">Profile</h1><div className="mt-10">{error ?(<ErrorerrorMessage={error.message}/>): status ===Status.loading?(<LoaderisInherit={true}/>):(<ProfileCarddata={data}/>)}</div></div>);};
Publisher confirms là một extension của RabbitMQ để thực hiện publish Message đáng tin cậy. Khi publisher confirms được bật trên một Channel, các Message mà Producer publish phải được xác nhận bởi Broker là đã nhận thành công/ thất bại. Từ đó chúng ta có thể ghi log, thông báo lỗi và / hoặc retry gửi tin nhắn. Trong bài viết này tôi sẽ hướng dẫn bạn sử dụng tính năng này.
Phương thức này phải được gọi trên mọi Channel mà ta muốn sử dụng, chỉ nên được kích hoạt một lần cho một Channel, không phải cho mọi Message được publish.
Để biết một Message đã được publisher confirm hay chưa, chúng ta đăng ký một callback để được notify về kết quả publish:
Channel channel = connection.createChannel();
channel.confirmSelect();
channel.addConfirmListener((sequenceNumber, multiple) -> {
// code when message is confirmed
}, (sequenceNumber, multiple) -> {
// code when message is nack-ed
});
Có 2 callback:
Một cho Message được xác nhậ.
Một cho tin nhắn nack-ed (tin nhắn có thể được coi là bị mất bởi boker).
Mỗi callback có 2 tham số:
sequence number (số thứ tự): một số xác định Message được xác nhận hoặc nack-ed. Nó tương ứng với số Message được publish.
multiple: đây là một giá trị boolean. Nếu false, chỉ có một Message được xác nhận / nack-ed, nếu true, tất cả các Message có số thứ tự <= được xác nhận / nack-ed.
Chúng ta có thể lấy một sequence number của một Message trước khi nó được publish thông qua phương thức sau:
Bài viết được sự cho phép của tác giả Trần Hữu Cương
Thông tin cấu hình của 1 project khá quan trọng, nó chứa nhiều thông tin nhạy cảm như username/password… nên ta cần phải bảo mật nó.
Để bảo mật thông tin cấu hình từ cloud config server có 2 cách đơn giản:
Xác thực (dùng username/password hoặc token)
Mã hóa/ giải mã (mã hóa ở cloud config server, và giải mã ở cloud config client)
Trong bài này mình sẽ thực hiện theo cách thứ nhất là xác thực các request tới cloud config server.
Trong trường hợp này bạn phải nhập username/password đã cấu hình ở bên trên để pass qua màn hình login.
Cách khác là bạn có thể truyền luôn username/password vào trong url: http://admin1234:admin1234@localhost:8888/app/dev. Tuy nhiên trình duyệt web ko hỗ trợ kiểu url này nên bạn có thể thử bằng 1 rest client như postman hoặc mở màn hình cmd và chạy lệnh curl:
Bài viết được sự cho phép của tác giả Trần Thị Thu Hà
Kể từ ngày virus đầu tiên xuất hiện, đến nay đã hơn 20 năm. Cũng có nhiều virus mới ra đời, dưới đây là một số loại virus nguy hiểm nhất, gây thiệt hại nặng nhất.
Ước tính thiệt hại 20-28 triệu USD trên toàn thế giới, không tính dữ liệu PC bị phá hủy. CIH có nguồn gốc từ Đài Loan (6/1998) được nhận dạng là một trong những virus nguy hiểm và có sức tàn phá lớn nhất. CIH còn được biết đến với tên là Chernobyl vì thời điểm kích hoạt trùng với ngày xảy ra vụ nổ nhà máy nguyên tử Chernobyl. Virus này tấn công vào các file thực thi của hệ điều hành Windows 95,98 và ME, có khả năng cư trú trên bộ nhớ máy tính để lây nhiễm và các file thực thi khác.
Chỉ sau một thời gian ngắn hoạt động CIH có thể ghi đè dữ liệu trên ổ cứng, biến dữ liệu trở nên vô dụng. Tuy nhiên ngày này CIH không còn nguy hiểm bởi các hệ điều hành mới như Windows XP, 2000 đã được cải tiến.
2. Melissa (1999)
Ngày 26/3/1999, virus Melissa đã lây nhiễm toàn cầu, ước tính thiệt hại 300-600 triệu USD. Virus dạng kịch bản macro trong Word này đã lây nhiễm vào 15/20 chiếc máy tính doanh nghiệp trên toàn cầu. Melissa phát tán nhanh đến nỗi Intel, Microsoft và một số hãng phần mềm khác sử dụng Outlook đã buộc phải đóng toàn bộ hệ thống e-mail để hạn chế thiệt hại.
Melissa sử dụng Outlook để gửi mail đính kèm bản virus tới 50 email trong danh sách liên lạc. Email này có câu: “”Here is that document you asked for…don’t show anyone else. ;-)””. Khi nhấn vào file đính kèm virus sẽ lây vào máy tính và lặp lại chu trình phát tán.
3. ILOVEYOU (2000)
ILOVEYOU còn được biết với cái tên Loveletter và The Love Bug, một dạng Visual Basic với cái tên ngọt ngào: Lời hứa tình yêu. ILOVEYOU lần đầu tiên được phát hiện vào ngày 3/5/2000 tại Hồng Kông sau đó lây lan nhanh qua email với dòng tiêu đề ILOVEYOU cùng file đính kèm: Love-Letter-For-You.txt.vbs.
Cách phát tán của ILOVEYOU cũng tương tự như Melissa. Nguy hiểm hơn nữa là virus này còn tìm tên và mật khẩu người dùng và gửi tới email tác giả. Thiệt hại ước tính là 10-15 triệu USD. Tác giả của ILOVEYOU không bị kết án do thời điểm đó Philippines không có luạt chống tội phạm máy tính.
4. Code red (2001)
Còn có tên là Bady được thiết kế với mục đích phá hủy mức lớn nhất có thể. Đây là một dạng sâu máy tính lây nhiễm trên hệ thống máy chủ, xuất hiện ngày 13/7/2001 với thiệt hại ước tính 2,6 triệu USD.
Loại virus này vô cùng độc hại bởi đích đến của chúng là các máy tính chạy phần mềm máy chủ web internet information server (IIS). Code red có khả năng khai thác một lỗ hồng trong IIS. Khi đã lây nhiễm, website lưu trữ trên máy chủ sẽ hiển thị: “Hello! Welcome to http://www.worm.com! Hack by Chinese!”.
Sau đó nó sẽ tìm kiếm các máy chủ bị lỗi và lây nhiễm. Chưa đến một tuần, Code red đã lây nhiễm khoảng 400 nghìn máy chủ trên toàn thế giới.
5. SQL Slammer (2003)
SQL Slammer được kích hoạt vào thứ 7 (thường là ngày nghỉ của dân văn phòng) nên thiệt hại về tiền không cao. Tuy nhiên virus này cũng đã lây nhiễm 500 nghìn máy chủ trên toàn thế giới và cũng là nhân tố tạo nên cơn bão dữ liệu ồ ạt, khiến toàn bộ hệ thống Internet của Hàn Quốc bị sập trong 12 giờ đồng hồ. SQL Slammer còn được gọi là Sapphire,kích hoạt vào ngay 25/2/2003 có tác động rất xấu đến toàn bộ giao vận Internet toàn cầu.
Virus này chỉ tìm kiếm các máy chủ, SQL Slammer là một gói dữ liệu đơn lẻ và tự gửi tới các địa chỉ IP. Nếu địa chỉ IP là một máy tính chạy bẳn SQL Server Desktop Engine chưa được vá lỗi thì chiếc máy chủ đó sẽ bị nhiếm virus ngày lập tức và tấn công các địa chỉ IP khác.
Với phương thức lây nhiễm này, Slammer có thể tấn công 75 nghìn máy tính chỉ trong 10 phút, khiến toàn bộ mạng internet bị tắc nghẽn, các router phải ngưng hoạt động.
Bài viết được sự cho phép của tác giả Trần Hữu Cương
Thông thường, khi lập trình android, sau khi viết code xong, bạn sẽ chạy thử ứng dụng bằng máy áo cài đặt sẵn trên IDE hoặc các máy ảo như Genymotion. Tuy nhiên chạy ứng dụng qua máy ảo khá chậm nhất là với những máy tính có cấu hình yếu
Trong bài này, mình sẽ thực hiện chạy thử các chương trình trực tiếp trên thiết bị thật.
Lập trình Android trên thiết bị thật qua USB cable
Đầu tiên bạn phải bật chế độ Developer optionstrên điện thoại
Mở điện thoại và chuyển đến mục Setting(Cài đặt). Sau đó, hãy chuyển đến “About phone” ( Giới thiệu về điện thoại)
Nếu Developer Options (Tùy chọn nhà phát triển) không được hiển thị trong thiết bị của bạn. Bạn cần nhấp 7 lần vào Build number để hiện Developer Options
Sau đó ra ngoài, vậy là ta đã có Developer options. Tiếp theo, bạn vào bật chế độ USB Debugging lên:
Nếu có được hỏi xác thực ủy quyền cho máy tính thì chọn Always allow this computervà nhấn OK.
Và giờ chúng ta chỉ cần nhấn run project rồi sẽ hiện bảng thông báo bạn muốn chọn thiết bị nào.
Nếu có tên thiết bị như trên là bạn đã cài đặt thành công máy thật connect với máy tính.
Vậy chúng ta đã cài đặt máy ảo và thiết bị thật để lập trình Android.
Bài viết được sự cho phép của tác giả Trần Thị Thu Hà
Java hiện là ngôn ngữ lập trình phổ biến hàng đầu tại Việt Nam và rất nhiều sinh viên CNTT muốn theo đuổi ngôn ngữ này để phát triển sự nghiệp của mình. Có không ít khó khăn bạn cần phải vượt qua để làm chủ ngôn ngữ đầy rắc rối ấy và việc đầu tiên là hiểu những keywords – những từ khóa trong lập trình java. Việc này sẽ làm tiền đề giúp bạn trong việc tự học, tự trải nghiệm thách thức từ java.
Hiện nay, Java có khoảng 50 keywords và Topdev sẽ giúp bạn liệt kê hết những từ khóa này ngay sau đây:
Keyword:
Abstract: Khai báo lớp, phương thức và interface trừu tượng không có thể hiện (instance) cụ thể
Assert: Kiểm tra điều kiện đúng hay sai (hay dùng trong Unit Test)
Bloolean: Khai báo biến kiểu logic với hai giá trị: True or False
Break: Lệnh switch-case hoặc dùng để thoát khỏi vòng lặp
Byte: Các giá trị nguyên chiếm 8 bit (1byte)
Case: Trường hợp được chọn theo Switch (chỉ dùng khi được đi kèm Switch)
Catch: Dùng để bắt ngoại lệ, dùng kèm với try để xử lý những ngoại lệ nảy sinh trong chương trình
Char: Là kiểu ký tự Unicode, mỗi ký tự có 16 bit (2 byte)
Class: Dùng để định nghĩa class
Const: Không thể dùng trong java bởi nó chưa được sử dụng
Continue: Được dùng để dừng chu trình (interation) lặp hiện tại và bắt đầu chu trình kế tiếp
Default: Mặc định được thực thi nếu không có case nào trả về giá trị True – được dùng trong Switch case.
Do: Dùng ở vòng lặp While
Double: Là kiểu số thực có các giá trị được biểu diển bởi dấu phẩy động 64 bit (8byte)
Else: Rẽ nhánh điều kiện ngược với If
Enum: Kiểu dữ liệu Enum – tương đối giống với kiểu dữ liệu mảng. Khác biệt ở chỗ các phần tử của kiểu này có thể bổ sung thêm các phương thức.
Extends: Dùng để định nghĩa lớp con kế thừa những thuộc tính và phương thức từ lớp cha.
Final: Dùng để chỉ ra các biến – phương thức không thay đổi sau khi đã được định nghĩa. Những phương thức final không được kế thừa và override.
Finally: Thực hiện một khối lệnh đến cùng, bỏ qua các ngoại lệ – dùng trong Try-cactch.
Float: Kiểu số thực – Các giá trị được biểu diện bởi dạng dấu phẩy động 32 bit.
For: Dùng trong vòng lặp for – Các bước lặp đã xác định từ trước.
Goto: Chưa được sử dụng
If: Là lệnh chọn theo điều kiện logic
Implements: Xây dựng 1 lớp mới cài đặt những phương thức từ interface xác định trước
Import: Dùng để yêu cầu 1 hay 1 vài lớp ở các gói chỉ định cần nhập vào để sử dụng trong ứng dụng hiện thời
Long: Là kiểu số nguyên lớn – Các giá trị chiếm 64 bit (8 byte)
Native: Sử dụng khi lập trình viên muốn dùng code bằng ngôn ngữ khác
New: Khởi tạo đối tượng
Package: Sử dụng khi xác định 1 gói sẽ chứa một số lớp trong file mã nguồn
Private: Khai báo biến dữ liệu, phương thức riêng trong từng lớp và chỉ cho phép truy cập trong lớp đó.
Protected: Dùng để khai báo biến dữ liệu – Chỉ được truy cập ở lớp cha và những lớp con của lớp đó.
Public: Dùng để khai báo biến dữ liệu, lớp – Phương thức công khai có thể tự truy cập ở mọi hệ thống.
Return: Kết thúc phương thức, trả về giá trị cho phương thức.
Short: Kiểu số nguyên ngẵn – giá trị chiếm 16 bit (2byte)
Static: Định nghĩa biến, phương thức của một lớp có thể được truy cập trực tiếp từ lớp mà không thông qua khởi tạo đối tượng của lớp.
Super: Biến chỉ tới đối tượng ở lớp cha
Switch: Sử dụng trong câu lệnh điều khiển Switch case
Synchronized: Chỉ ra là ở mõi thời điểm chỉ có 1 đối tượng hay 1 lớp có thể truy nhập đến biến dữ liệu hoặc phương thức loại đó – Thường được sử dụng trong lập trình đa luồng (multithreading).
This: Biến chỉ tới đối tượng hiện thời
Throw: Tạo một đối tượng Exception nhằm chỉ định 1 trường hợp ngoại lệ xảy ra
Throw: Chỉ định cho qua ngoại lệ nếu exception xảy ra
Transient: Chỉ định rằng nếu một đối tượng được Serialized, giá trị của biến sẽ không cần được lưu trữ
Try: Thử thực hiện cho đến khi xảy ra 1 ngoại lệ
Void: chỉ định 1 phương thức không trả về giá trị
Volatile: Báo cho chương trình dịch biết là biến khai báo volatile có thể thay đổi tùy ý trong các luồng (thread)