Bài viết được sự cho phép của tác giả Nguyễn Chí Thức
Copy một list
Giả dụ chúng ta có đoạn code sau:
>>> A = [1, 2, 3, 4, 5]
>>> B = A
thì nếu chúng ta in list B thì sẽ được các phần tử của list A, nhưng thực ra B chỉ là một biến tham chiếu đến A trong bộ nhớ, tức là thực chất trong bộ nhớ chỉ có 1 list [1, 2, 3, 4, 5] và cả A và B cùng trỏ đến list đó chứ không phải A và B có 2 list giống nhau.
Còn trong dòng code trên thì chúng ta mới thực sự tạo ra một list khác là C có các phần tử giống như list A.
Bây giờ chúng ta thử đổi một phần tử trong list A:
>>> A[0] = 8>>> A
>>> [8, 2, 3, 4, 5]
>>> B
>>> [8, 2, 3, 4, 5]
>>> C
>>> [1, 2, 3, 4, 5]
Rõ ràng khi in list A và B đều cho kết quả giống nhau vì chúng cùng tham chiếu tới một list, nhưng C thì lại khác vì các phần tử trong list C tồn tại độc lập.
Khởi tạo giá trị mặc định cho đối tượng Dictionary
Các đối tượng Dictionary được tạo ra là rỗng. Nhiều khi chúng ta làm việc với Dictionary mà không biết khóa đó có giá trị hay chưa nên truy xuất giá trị sẽ bị lỗi, do đó chúng ta có thể dùng phương thức get() rồi truyền thêm giá trị mặc định vào, tức là nếu khóa đó không có giá trị thì Python sẽ gán giá trị mặc định vào luôn.
Bạn có thể gán một lúc nhiều giá trị vào nhiều biến. Tính năng này đặc biệt hữu ích cho việc hoán đổi giá trị giữa 2 phần tử. Với Python bạn không cần phải khai báo biến tạm như temp = a; a = b; b = temp; để thực hiện công việc hoán đổi giá trị nữa.
>>> x, y = 1, 2#multiple assignment>>> x
1>>> y
2>>> x, y = y, x #swapping>>> x
2>>> y
1
Và bạn được yêu cầu viết một đoạn code Python để hiển thị kết quả như sau:
1 first
2 second
3 third
Thì lúc này bạn có thể sử dụng hàm zip:
for a, b in zip(my_numbers, my_numbers_in_english):
print a, b
Rất hữu ích phải không nào, chúng ta nhận được kết quả như ý muốn với số lượng đoạn code tối thiểu phải viết điểu này không phải lúc nào cũng dễ dàng với các ngôn ngữ script khác.
Selenium ở đây tất nhiên không phải là “Selenium là khoáng chất vi lượng quan trọng trong nhiều hoạt động như xử lý não bộ, miễn dịch và sinh sản“
Không phải là thuốc nha mấy thím. Đang nhắc tới automation test tools
Selenium được nhắc tới trong bài viết là AUTOMATIONS TEST TOOLS (kiểm thử phần mềm hoặc website tự động).
Định nghĩa nhàm chán nhưng cũng cần phải biết là:
Selenium is an umbrella project for a range of tools and libraries that enable and support the automation of web browsers.
Selenium là dự án “ô dù” với mục đích tạo ra các công cụ (tools) và thư viện (libraries) tự động hóa các trình duyệt web.
Ngoài ra, một từ khóa quan trọng đễ dễ nhớ hơn là:
It provides extensions to emulate user interaction with browsers
Selenium cung cấp các tiện ích mở rộng mô phỏng sự tương tác của người dùng với browser.
Định nghĩa loằng ngoằng là vậy, nhưng với Selenium, ta có thể mô phỏng hầu hết những thao tác người dùng với trình duyệt (nhấp – click, cuộn – scroll, đóng tab, click check box, …)
2. Ưu điểm của Selenium
Hiện tại, danh sách Top 10 Automation Testing Tools đã bao gồm nhiều cái tên (mabl, randorex). Tuy nhiên, Selenium vẫn là một cái gì đó khó thay thế, vẫn nổi bật và có nhiều giá trị.
Giới QC trong giang hồ hẳn ai cũng biết về Automation test tools này. Vang danh khắp thiên hạ.
2.1 Hỗ trợ nhiều ngôn ngữ lập trình
Bản thân mình, trong quá trình làm việc cho công ty cũng được tiếp xúc với selenium một vài lần. Cụ thể là với Webdriver Java, Javascript và Python.
Hiện tại hỗ trợ tới 6 ngôn ngữ lập trình: Java, Python, C#, Ruby, JavaScript và Kotlin. So far, so good.
Nguồn/ Source: selenium.dev
2.2 Miễn phí – free
Khỏi phải nói, ưu điểm này thật sự là đáng tiền nhất của Selenium, so với các đối thủ khác như Ranorex hoặc Mabl, Selenium hoàn toàn miễn phí. Chính vì vậy, nó thường được các doanh nghiệp IT Nhật Bản tin dùng.
Tất nhiên với Java, ta có ngay slogan quen thuộc: “Viết một lần – Chạy khắp nơi“, làm gì chả thích. “Run once time, run everywhere”.
2.3 Dễ hiểu, dễ sử dụng
2.4 Hỗ trợ đa trình duyệt với Webdriver
Selenium hỗ trợ test tự động trên nhiều browser. Hỗ trợ tốt khi khách hàng cần test trên nhiều phiên bản, nhiều loại browser khác nhau (thường thì chắc chắn sẽ yêu cầu như vậy).
Đối với môt số khách hàng từ Nhật hay cơ quan chính phủ, yêu cần website hoạt động tốt trên IE 9,10,11,. Việc viết test case một lần và chạy trên nhiều trình duyệt là vô cùng tiện lợi và nhanh chóng.
Hỗ trợ Internet Explorer, tin vui cho mấy anh em phát triển phần mềm chính phủ
2.5 Dễ dàng take evidence khi chạy
Thực tế khi làm việc, khách hàng lúc nào cũng yêu cầu evidence khi thực hiện chạy testcase.
Khi một website đã hoàn thiện để chạy automation test, nếu có lỗi xảy ra, ngoài ghi log hoặc báo file, yêu cầu cần thiết nhất luôn là chụp evidence (bằng chứng) ngay lúc đó.
Selenium hỗ trợ rất tốt cho những trường hợp muốn chụp lại màn hình. Kể cả trong trường hợp page ở website là scroll. Mình đã từng sử dụng Selenium để chụp những
3. Một số nhược điểm
Mặc dù có nhiều ưu điểm không phải automation test tools nào cũng có. Selenium vẫn tồn tại một số yếu điểm dưới đây:
3.1 Muốn chạy ổn, hãy cố handle timeout
Một nhược điểm cố hữu có các Automation test tools (không ngoại trừ Selenium) là timeout. Trường hợp sử dụng để kiểm thử cho website, tốc độ mạng có thể khác nhau giữa những lần chạy testcase. Chắc chắn là không giống nhau giữa các lần chạy.
Việc chạy automation test vào lúc mạng chậm, traffic đang stuck có thể làm fail một số testcase. Trong những trường hợp như vậy, cần xử lí tốt các trường hợp timeout.
Thực tế, trong quá trình làm việc, mình thấy các Exception Timeout thường do:
Mình đang test ở page 1 -> nhấn button A -> di chuyển tới page 2 -> tìm kiếm button B. Các hàm tìm kiếm có thể là (getElementById(), getElementByTag(), …).
Nuột nà là thế, nhưng do mạng chậm, nên lúc tới page 2 vẫn không tìm được button B -> văng Exception.
Trường hợp muốn handle exception, có thể đọc thêm bài viết này ở KieBlog.
3.2 Nếu không kiểm soát tốt, hết ram, chết đứng
Thông thường, mỗi testcase sẽ khởi chạy với một new instance của browser ta muốn chạy. Tuy nhiên, nếu có vấn đề, hoặc ta không thể handle các trường hợp cần đóng browser. Rất có thể có các trường hợp sau:
Không thể tìm đúng đối tượng trên browser do instance của browser cũ chưa tắt (close)
Quá tải ram do nhiều trình duyệt mở (nhất là chrome)
Không khó để tìm những câu hỏi rằng không thể đóng được browser đã mở.
Có rất nhiều nguyên nhân dẫn tới trường hợp này. Nếu trước đó đã có exception không được catch or throws, sẽ không thể close instance browser đã mở.
4. Tổng kết
Đọc tới đây, chắc hẳn các thím cũng có đã có cái nhìn “sơ sơ” về Selenium. Để hiểu sâu hoặc bắt đầu thực tế sử dụng, hãy chú ý xem các bài viết tutorials ở phần tham khảo.
Cảm ơn đã đọc bài của mình và hãy cố gắng sử dụng Selenium một lần cho biết nhé, nó bá đạo lắm đấy!.
Applaydu hiện đã có thể tải xuống miễn phí từ App Store hoặc từ Google Play Store.
Chỉ sau 15 tháng, Gameloft for brands và Kinder đã ra mắt ứng dụng Applaydu – một dự án đầy tham vọng – mang các nhân vật đồ chơi của Kinder vào đời sống thực tế thông qua Thực tế tăng cường (AR) với một thế giới đầy những điều thú vị đang chờ được khám phá.
Applaydu là một ứng dụng giáo dục trên điện thoại, được thiết kế cho trẻ em từ 3 đến 9 tuổi. Tại đây, các bé có thể khám phá nhiều trò chơi đầy thú vị, giúp các bé học đếm, làm quen với ngôn ngữ và mở rộng kiến thức về các quốc gia, địa lý và cả động vật.
Một đoàn làm phim chuyên nghiệp đã đến thăm Gameloft Sài Gòn Studio để có thể nắm bắt được kĩ càng nhất quá trình phát triển suốt 15 tháng của dự án Applaydu. Qua đó, “Creating Applaydu” – một phim tài liệu dài 15 phút đầy gần gũi và cảm động đã ra đời, thể hiện cận nét từng bước hành trình sáng tạo của cả nhóm. Bạn sẽ nhận ra rằng chuyên môn và niềm đam mê của từng thành viên trong team có thể giúp họ đạt được những điều to lớn như thế nào.
Đội ngũ Applaydu tại trụ sở Gameloft Sài Gòn Studio
Thế giới đã thay đổi rất nhiều kể từ khi Kinder Surprise phát hành cách đây 50 năm: trẻ em ngày nay được sinh ra với công nghệ và dành phần lớn thời gian của chúng trên điện thoại thông minh. Để bắt kịp với thời đại, Ferrero Group muốn nâng cao trải nghiệm của trẻ em bằng cách kỹ thuật số hóa những đồ chơi bình thường. Là một chuyên gia trong ngành công nghiệp game suốt 20 năm, Gameloft for brands đã giúp Ferrero đưa chiến lược của họ lên một tầm cao mới bằng cách tạo ra một ứng dụng, nơi mà trẻ em có thể vừa học vừa chơi. Đây cũng là dự án đầu tiên do Gameloft sáng tạo 100% bởi Gameloft for brands tại Sài Gòn.
Applaydu là một ứng dụng giáo dục trên điện thoại được thiết kế cho trẻ em
Một trong những thách thức lớn nhất là trò chơi được tạo ra cho các bé từ 3 đến 9 tuổi. Trong khi đó, trẻ 3 tuổi sẽ có mức độ phát triển khác với trẻ 9 tuổi, hay thậm chí 2 đứa trẻ ở cùng độ tuổi có thể có những mức độ phát triển khác nhau. Từ đó, nhóm đã đưa ra giải pháp, rằng độ khó trong trò chơi sẽ tự động thay đổi dựa trên các lần chơi trước của trẻ, vì vậy việc lựa chọn mức độ trò chơi sẽ không còn là mối bận tâm của bố mẹ nữa.
Một thách thức khác của Applaydu là các bé ở độ tuổi đang phát triển sẽ không hiểu các cơ chế trừu tượng, biểu tượng hoặc trò chơi như người lớn. Vì vậy, giao diện người dùng và trải nghiệm người dùng (UX / UI) phải thật đơn giản và dễ hiểu.
Menu chính của Applaydu được thiết kế như phòng ngủ của các bé
Nhóm còn muốn cung cấp cho các bé một vũ trụ hữu hình, một nơi mà trẻ có thể “chạm vào”, và trong đó những sáng tạo của trẻ sẽ trở thành hiện thực. Nhóm cũng đã nảy ra ý tưởng về một thế giới thủ công, được làm từ những đồ vật trong đời sống (hộp đựng giày, bưu phẩm, bìa cứng,…) giúp tạo ra những sản phẩm sáng tạo mà ngay cả những đứa trẻ cũng có thể tự làm được. “Trên hết, chúng tôi muốn truyền cảm hứng cho các bé. Giờ đây, các bé có thể xây dựng thế giới của riêng mình ngay tại nhà bằng cách sử dụng mọi thứ ở xung quanh.” – Cédric Ratajczak, Giám đốc Sáng tạo cho biết.
Với tham vọng mang đồ chơi vào cuộc sống theo đúng nghĩa đen và tạo ra một kết nối riêng giữa trẻ em và đồ chơi của chúng, đội ngũ Applaydu đã dựa trên hình ảnh ban đầu của đồ chơi và khuếch đại các đặc điểm của chúng. Có thể dễ dàng nhận ra rằng tất cả các thiết kế nhân vật đều đồng nhất với đồ chơi của Kinder cũng như thể hiện được thế giới vui nhộn của Applaydu.
Đội ngũ Applaydu trong quá trình làm việc
Là một trong những nhà phát hành game di động hàng đầu thế giới, Gameloft luôn có trách nhiệm với sản phẩm của mình, đặc biệt là với trẻ em. Chính vì thế, đội ngũ vận hành đã hợp tác với các chuyên gia giáo dục hàng đầu tại Đại học Oxford để đảm bảo những câu chuyện trong Applaydu sẽ trở thành một công cụ hỗ trợ phụ huynh trong việc dạy học cho bé. Applaydu hiện đã chính thức nhận được Chứng nhận Ứng dụng Giáo dục (EAS) và Chứng nhận kidSAFE + COPPA.
Nói về Gameloft, studio đầu tiên tại Việt Nam được mở vào năm 2004, với tham vọng đưa các game của Gameloft lên tất cả các thiết bị di động hiện có. Cho đến nay, sau 16 năm phát triển, với chuyên môn của mình, đội ngũ sáng tạo của Gameloft for brands tại Sài Gòn đã cùng nhau tề tựu tại đây để mang đến một sự bùng nổ – ứng dụng Applaydu dành cho Kinder! Đứng sau Applaydu là đội ngũ gồm 50 nhân tài đến từ Sài Gòn Studio, một trong những studio Gameloft lớn nhất thế giới. Thierry Lecat, Giám đốc điều hành, cho biết: “Các thành viên trong nhóm đều trẻ trung và tràn đầy năng lượng. Chúng tôi được coi là một ‘team quốc tế’ vì có tới 9 quốc tịch với nhiều xuất thân khác nhau, nhưng chúng tôi đều có cùng nghị lực, cùng tinh thần đồng đội, cùng tư duy và luôn mang thái độ tích cực trước bất cứ mọi khó khăn”.
Applaydu hiện đã có thể tải xuống miễn phí từ App Store hoặc từ Google Play Store.
Bài viết được sự cho phép của tác giả Kien Dang Chung
Trong lập trình quy chuẩn đầu tiên cần đưa ra là quy chuẩn cho việc đặt tên. Có hàng tỉ thứ cần đặt tên trong lập trình, nói chơi vậy thôi chứ phân loại ra khoảng hơn chục thôi à, ví dụ như tên Class, tên biến, tên phương thức, tên thuộc tính… Có 3 chuẩn để đặt tên là underscore, camelCase và PascalCase.
underscore: sử dụng dấu gạch chân giữa các từ, tất cả các từ đều viết thường, ví dụ: $this_is_my_variable.
camelCase: giống như cách viết của nó, từ đầu tiên viết thường, các từ tiếp theo viết hoa chữ cái đầu, ví dụ $thisIsMyVariable.
PascalCase: viết hoa tất cả các chữ cái đầu, ví dụ $ThisIsMyVariable.
Các quy chuẩn đặt tên thông thường
Sau đây là một số quy chuẩn đặt tên thường dùng trong dự án:
Tên lớp đặt theo PascalCase, ví dụ: UserClass, CategoryClass…
Tên hàm và phương thức sử dụng camelCase, ví dụ getUser, getCategory…
Tên biến cũng sử dụng camelCase loginUser,loginUser,categoryList…
Tên hằng số thì đặc biệt, viết hoa hết và cách nhau bởi dấu gạch dưới DISCOUNT_PERCENT, LIMIT_RATE…
Tên bảng, tên cột trong Database sử dụng underscore và sử dụng danh từ số nhiều, ví dụ bảng oauth_clients, oauth_refresh_tokens.
Tên phần tử trong HTML, ví dụ khi bạn sử dụng Vue.js, React… tạo ra thì nó sẽ có dạng KebabCase, ví dụ <my-component>.
Đặt tên là để gợi nhớ, ví dụ khi gọi đến tên của bạn là người ta biết ngay đó là bạn mà không nhầm sang người khác, đặt tên trong lập trình cũng vậy cần phải tường minh. Trước đây tôi có một người bạn trong cùng cơ quan đặt tên các biến khá thú vị: heheheeeee,heheheeeee,hihiiiiii… vãi cả nón, khi đọc code bò lăn ra cười, nói vui vậy thôi chứ như vậy là không nên, không thể hiểu được các biến này dùng làm gì, đặc biệt hơn nữa là khi xử lý qua lại đánh tên các biến này khó vãi, chắc phải copy cho chắc ăn.
Lời kết
Bạn nên tập thói quen đưa ra một quy chuẩn đặt tên trong lập trình của riêng mình, như vậy khi làm việc theo nhóm các thành viên khác có thể dễ dàng đọc được code của bạn. Hơn nữa, các thư viện mã nguồn mở hiện nay đều tuân thủ theo những quy ước đặt tên, nếu bạn không muốn mình tách rời với cộng đồng hãy tuân thủ theo “pháp luật”.
Ngược ngạo VCL, rõ ràng là phải viết code rồi mới có cái mà test chứ, viết Unit test trước thì run bằng mắt à?. Đấy, lần đầu tiên tìm hiểu kĩ thuật này tôi cũng đặt ra câu hỏi như các ông!.
Vấn đề là mình nghĩ thế nhưng nó lại không phải như thế. Viết Unit Test trước khi Implement là một trong những ý tưởng chủ chốt của TDD (Test Driven Development).
TDD Introduction – Có đọc qua mới biết nha. Nguồn/Source: Medium
Thực chất thì có nhiều cái lợi lắm nha. Để tôi kể cho nghe:
1. Hiểu rõ những gì sắp code
Leader hay Br SE nhận requirements, hoặc là tự mình nhận (nếu làm freelancer bán thời gian như tôi). Với một số requirement đơn giản, không quá bự thì theo như thông thường
Đọc hiểu requirement -> code -> gửi QC hoặc Tester test -> Có bug -> Fix bug
Tuy nhiên, chỉ đọc hiểu requirement để code lại hoàn toàn khác với hiểu requirement để test. Ở tầm test của QC cần hiểu rõ về business, về những case sử dụng thực tế của khách hàng. Trường hợp sử dụng không normal sẽ xảy ra những bug nào?.
Developers have a clear target in mind and that’s very important in agile environment.
Lập trình viên có một mục tiêu rõ ràng trong trí óc là một điều rất quan trọng trong môi trường Agile
Chính vì vậy, viết unit test trước khi code là khoảng thời gian quý báu giúp bản thân xem xét những gì sắp làm. Cần code những gì?
2. Tránh chủ quan
Tại sao dev code thường có bug?. Trời má, thế giới nào mà không có bug?. Hỏi thừa quá ông ơi!.
Ý tôi là nhiều hay ít, ít bug thì rõ ràng dev đó cẩn thận hơn, kĩ tính hơn. Một trong những nguyên nhân lớn khiến dev có nhiều bug vì không tưởng tượng ra hết các kịch bản (scenarios) để test thử trước khi đem cho Tester.
Không những vậy, chủ quan còn mang tới những con bug basic hơn. Chính vì code và có niềm tin mãnh liệt vào code của mình, nên một số bạn để lọt bug do nghĩ chắc đoạn đó code ngon rồi, không bug đâu.
Thế giới nào lại không có bug!. Nguồn/Souce: monkeyuser.com
Sự thật thì. BUG, BUG SML
3. Rèn luyện tính cẩn thận khi viết Unit test
Áp dụng phương pháp này cho mấy thanh niên code ẩu thì khỏi bàn.
Nhiều khi cắm đầu code nhưng chỉ focus vào duy nhất một case (dân trong nghề gọi là happy case). Không quan tâm những case khác -> thành ra bug tè le.
Tuy nhiên nếu viết Unit Test trước, mọi chuyện rõ ràng dễ thở hơn nhiều. Trước khi bắt tay vào code phải lường trước những trường hợp có thể xảy ra.
Unit test vẫn là một trong những yêu cầu chính phải thực hiện nha!
Trở thành Senior Software Engineer không chỉ là code nhanh và xử lí task khó. Senior còn phải code ít bug, ít thời gian maintainance.
4. Lợi ích và hại ích
The test clearly defines what constitutes “done” – Rõ ràng được khi nào thì xong
The test documents how you intend the code to be used – Code được dùng như thế nào
Coding to meet a test case (and nothing else) helps keep you focused on one task and prevents feature creep – Không có các đoạn code dư thừa, chỉ focus làm sao cho match được testcase
Như một số lập trình viên vẫn truyền tai nhau:
“If I was given the choice of losing all of my code or all of my tests, I would choose losing all of my code.”
Nếu được lựa chọn giữa mất toàn bộ code và toàn bộ test, tôi sẽ lựa chọn mất tất cả code của mình.
Tuy nhiên, phương pháp nào cũng phải một vài vấn đề. Đối với TDD (Test Driven Development), ta sẽ gặp một số vấn đề sau:
Viết Unit test không thể viết ẩu, viết ẩu sẽ để lọt case, mà lọt case là lòi BUG.
Người áp dụng phải có khả năng lường trước các vấn đề, tính cẩn thận.
Phải có thời gian (cái này quan trọng nhất).
Một số dự án bị dí SML, hoặc deadline dí tới đít thì code còn không kịp, lấy đâu ra thời gian mà ngồi viết testcase trước. Chính vì vậy, áp dụng kĩ thuật này cần có thời gian.
5. Tham khảo
Đã tìm hiểu về Unit test và kĩ thuật viết Test trước khi code thì tiện thể ngó qua luôn về Selenium Automation Test ở Kieblog. Khỏi phải giới thiệu dài dòng, những năm gần đây Automation Test đang trở nên hot vô cùng.
Không giống như chắp thêm có thể lấy một đối tượng thuộc bất kỳ loại nào làm đối số, phần mở rộng chỉ có thể lấy một đối tượng có thể lặp lại làm đối số.
Một đối tượng có thể lặp lại là một đối tượng mà bạn có thể lặp qua như chuỗi, danh sách, bộ dữ liệu, dicts hoặc bất kỳ đối tượng nào có phương thức __iter__
Những gì extend làm rất đơn giản, nó lặp đi lặp lại thông qua đối tượng lặp lại (iterable ) một mục tại một thời điểm và nối thêm từng mục vào danh sách.
Khối lượng công việc quá lớn khiến bạn trở nên mệt mỏi. Đó cũng chính là lý do bạn chưa biết cách quản lỳ thời gian hiệu quả. Do vậy, bạn tiếc nuối khi đã bỏ lỡ nhiều khoảng thời gian quý giá đó.
Bài viết sau đây, TopDev sẽ chỉ ra cho bạn những cách thức giúp quản lý thời gian hiệu quả nhất. Việc này sẽ giúp bạn giảm căng thẳng và có biểu hiện tốt hơn ở nơi làm việc.
Ủy thác lại nhiệm vụ
Việc bạn đảm đương quá nhiều việc không còn là điều quá xa lạ. Chính việc không biết cách từ chối đã dẫn bạn đến tình trạng kiệt sức. Ủy thác được xem là cách thức phù hợp nhất để giải quyết tình trạng này. Tuy nhiên, điều này không có nghĩa là bạn trốn tránh trách nhiệm của mình.
Hãy học cách ủy thác nhiệm vụ của mình xuống cấp nếu công việc quá nhiều. Việc ủy thác cũng có những điểm tích cực. Bạn sẽ tạo cho cấp dưới cơ hội làm việc phù hợp với năng lực và kỹ năng của họ.
Tính logic – Đảm bảo yếu tố ưu tiên
Mọi thứ sẽ hoàn hảo hơn nếu bạn có một kế hoạch cụ thể trước khi thực hiện. Nó có thể hiểu là một quá trình bao gồm các nhiệm vụ cần thực hiện. Chẳng hạn, nếu bạn muốn ứng tuyển các vị trí IT. Bạn cần tìm hiểu về công ty, loại hình hoạt động. Tiếp đó là chuẩn bị một CV IT tiếng anh hoặc tiếng việt. Đây là điều quan trọng. Bạn có thể sáng tạo CV riêng của mình trên các nền tảng CV online,…
Điều quan trọng, bạn cần phân loại rõ đâu là việc quan trọng – đâu là việc khẩn cấp. Hãy cân nhắc thật kỹ để đảm bảo hiệu suất công việc cũng như các giá trị mang lại cho bản thân bạn.
Một cuốn sổ có thể giúp bạn ghi chép các ý tưởng bất chợt. Bạn có thể dùng các ý tưởng đó để hoàn thiện lịch trình thực hiện các nhiệm vụ. Một điều bạn cần lưu tâm khi lên lịch các nhiệm vụ là đảm bảo tính khả thi.
Để dễ dàng kiểm soát kỹ năng quản lý thời gian, bạn nên thiếp lập mọi thứ xoay quanh các chủ đề trọng tâm: Công việc, Gia đình, Cá nhân.
Hạn chế căng thẳng
Stress thường xuất hiện khi bạn quá mệt mỏi. Nguyên nhân đến từ việc bạn chịu ức ép quá lớn từ công việc. Bạn chưa biết cách quản lý thời gian hiệu quả. Và điều này sẽ ảnh hưởng đến năng suất của bạn. Do vậy, hãy thư giãn. Đừng để bản thân phải rơi vào tình trạng căng thẳng tột độ.
Dealine có ý nghĩa rất quan trọng đối với vấn đề quản lý thời gian. Khi thực hiện Khi một nhiệm vụ nào đó, hãy lên deadline cho nó và thực hiện theo. Hãy cố gắng hoàn thành một cách tốt nhất. Đừng trì hoãn với sự lười biếng vì bạn không lường trước được rất nhiều chuyện đột xuất sẽ xảy ra. Hãy thử thách bản thân và đáp ứng thời hạn. Đừng quên thưởng cho bản thân khi hoàn thành một thử thách khó khăn nhé!
Bắt đầu sớm là cách để thành công
Dù bạn là ai, làm trong lĩnh vực gì thì việc bắt đầu sớm công việc với một tâm thế thoải mái, đó là bí quyết của sự thành công. Bạn không cần đắn đó quá nhiều thứ. Hãy bắt đầu bằng việc hít thở thật sâu. Bạn sẽ có thêm thời gian thư giãn, suy nghĩ và lên kế hoạch làm việc cho một ngày. Nguồn năng lượng làm việc rất quan trọng. Do vậy, hãy bắt đầu sớm với một tinh thần sảng khoái nhất.
Lời kết
Hãy học cách nói từ chối khi bạn cảm thấy mọi thứ quá sức. Đó là lời từ chối lịch sự. Những cân nhắc về những điều mà cần làm, phải làm và sẽ làm. Cụ thể. phân biệt rõ những công việc quan trọng – ưu tiên để đạt hiệu suất công việc một cách tốt nhất. Mọi bí quyết đều chỉ là lý thuyết nếu bạn không áp dụng chúng vào thực tế. TopDev hy vọng, bài viết đã giúp bạn có những tip bổ ích cho việc quản lý thời gian và lập kế hoạch thực hiện các công việc.
FE sẽ ko phải đợi đến khi BE làm xong API mới có thể bắt đầu integrate, nếu bạn có thể mock những API sẽ được trả về dựa trên contract đã thống nhất, thì gần như là không còn quá nhiều việc phải làm khi API làm xong.
Để mock API, kể thể dùng nhiều cách như JSON Server, mountebank, hôm nay mình hướng dẫn dùng Mirage mình mới biết, kết hợp với Vue nhé, React cũng tương tự thôi.
Cài đặt vào devDependencies
npm i miragejs -D
Mình chọn tổ chức thư mục theo kiểu này, bạn có thể để nó ở chỗ khác thì tùy ý
Nếu mọi thứ êm đẹp bạn sẽ được thông báo trên cửa sổ console
Thêm nội dung động
Bạn có thể dùng fakerjs để chèn thêm dữ liệu một cách ngẫu nhiên.
Để có dữ liệu init cho fake server, chúng ta sẽ sử dụng seeds()
exportdefaultfunction({ environment ='development'}={}){seeds(server){
server.db.loadData({
tasks:[{ id:1, text:"Feed the cat"},{ id:2, text:"Wash the dishes"},],})},routes(){this.get('/api/tasks',(schema)=>{return schema.db.tasks;}),this.post('/api/tasks',(schema, request)=>{// nhận data được gửi từ postconst task =JSON.parse(request.requestBody).data;return schema.db.tasks.insert(task);})...},});}
Thêm route động
Route động là gì, ví dụ như bạn dùng phương thức delete hay update bằng một route như thế này
// api/mock/index.js...this.delete('/api/tasks/:id',(schema, request)=>{// id từ urlconst id = request.params.id;return schema.db.tasks.remove(id);})...
Nếu bạn để ý, tất cả đều bắt đầu bằng api, namespace sinh ra là để phục vụ đối tượng lười biếng như chúng ta
routes(){// bọn dưới sẽ bắt đầu bằng /api hếtthis.namespace='/api';this.get('/tasks',()=>{...})this.delete('/tasks/:id',()=>{...})this.post('/tasks',()=>{...})}
Giả lập những route chỉ định
Nếu như bạn đã có một số API, một số BE đang implement, tất nhiên chúng ta chỉ mock những API chưa làm, còn cái nào làm rồi thì cứ xài cái thật luôn
routes(){// chỉ giả lập GET /taskthis.get('/task',()=>{...});// còn lại dùng hàng thậtthis.passthrough();}
Nhưng đa phần API thật sẽ nằm đâu đó chứ không phải localhost:3000, thêm đoạn sau
routes(){// api thực nằm ở đâythis.urlPrefix='https://devenv.ourapp.example';// chỉ giả lập GET /taskthis.get('/task',()=>{...});// còn lại dùng hàng thậtthis.passthrough();}
Lúc này tất cả API đều sẽ gọi lên https://devenv.ourapp.example, duy chỉ gặp thằng https://devenv.ourapp.example/task`, mirage sẽ intercept và đưa hàng giả vào.
Kết
Sử dụng cũng được vài cái thư viện làm mock API, MirageJS là thằng mình thấy ưng nhất, không quá phức tạp, giải quyết được những vấn đề rất căn cơ của FE.
Mirage JS còn khá nhiều chiêu trò thú vị chờ bạn khám phá trên tài liệu chính thức của nó, nếu thấy hay đừng quên nhất like và contribute cho dự án trên Github
Như cái tiêu đề sock hàng, bài viết này chủ yếu nói về việc hạn chế sử dụng if else nhiều nhất có thể.
Viết nhiều if else là phù hợp cho những người mới bắt đầu. Còn khi đã đạt tới “trình” cao hơn, hãy luôn tìm mọi cách để loại bỏ đi các đoạn if else không cần thiết trong souce.
Sử dụng if else nhiều lần gần như là vấn đề mà bất kì Junior Developer nào cũng gặp phải. Cùng xem xét ví dụ dưới đây:
Java
public void checkConditionSomething(int input) {
if (input > 10) {
// Do something in case greater than 10
} else {
// Do some something
}
}
Code như này thường là có code của Junior, suy nghĩ đơn giản. Nếu này thì làm gì, ngược lại thì làm gì. Viết kiểu này tốt cho người mới bắt đầu vì dễ hiểu, dễ áp dụng.
Tuy nhiên, nên nhớ là ta vẫn còn return, một return sẽ đổi được một else. Nhìn còn professional khi viết các function nhỏ.
Java
public void checkConditionSomething(int input) {
if (input > 10) {
return
}
// Do something like else
}
Trường hợp logic thực thi ở if và else chỉ là single (gán, so sánh, return giá trị). Cách viết chuẩn mực, gọn gàng.
Java
public boolean checkConditionSomething(int input) {
// Khỏi cần if else source vẫn đẹp như thường
return input > 10 ? true : false;
}
Cũng là một cách khác, tuy nhiên thay vì sử dụng if else với else cuối cùng, ta có thể return ngay lập tức giá trị đó.
Java
public String getStringValue(int input) {
String value = "";
// Một đoạn if else dài loằng ngoằng
if (input == 0) {
value = "Kie";
} else if (input == 1) {
value = "blog";
} else {
value = "Kieblog";
}
return value;
}
If else kiểu này thì thật sự là thảm họa. Tuy nhiên, lúc ngồi nghĩ về logic viết như thế này có thể chấp nhận được. Nhưng sau đó thì sao?.
Khi maintainance, có thể bỏ bớt else bằng cách return giá trị default.
Java
public String getStringValue(int input) {
// Không còn else, source đẹp, dễ hiểu
// Không mất công decleare variable
if (input == 0) return "Kie";
if (input == 1) return "blog";
return "Kieblog";
}
3. Bỏ if else dùng dictionary
Ngoài sử dụng if else ta còn có thể sử dụng Dictionary để thay thế cho các block if else.
Java
public String getStringValue(int input) {
String value = "";
// Một đoạn if else dài loằng ngoằng
if (input == 0) {
value = "Kie";
} else if (input == 1) {
value = "blog";
} else {
value = "Kieblog";
}
return value;
}
Có thể sử dụng Dictionary như sau:
Java
public String getStringValue(int input) {
// Dùng dictionary cũng là một cách, đẹp source ra hẳn
var operations = new Dictionary<string, Action>();
operations[0] = () => { //Do something }
operations[1] = () => { // Do something }
}
Sử dụng if else quá nhiều lần không những không làm rõ được nội dung đoạn source. Ngược lại còn làm rối tung rối mù lên. Tuy thuận tiện khi viết source logic lần đầu, nhưng nên thay đổi để bỏ bớt khi refactor source lần sau.
Viết cẩn thận chứ không em út sau đọc nó chửi sml ra.
Bài viết được sự cho phép của tác giả Nguyễn Văn Minh
Theo IIBA: Business Analyst là người kết nối giữa các bên liên quan để gợi ý, phân tích, giao tiếp và làm rõ các yêu cầu đối với các thay đổi đối với quy trình kinh doanh, chính sách và hệ thống thông tin
Nghề BA nói chung hay IT BA là một ngành nghề ngày càng phổ biến ở nước ta hiện nay. Trước đây BA chỉ thường ở các công ty làm việc tài chính, ngân hàng nhưng hiện nay thì phổ biến ở nhiều lĩnh vực. Mỗi BA thường sẽ đi sâu và làm việc chủ yếu với một domain nhất định, tuy nhiên cũng có những cách chung để tiếp cận với những domain khác nhau.
Mình xin chia sẻ những điều mà mình rút ra được trong quãng thời gian xin việc và làm IT BA trong vòng 3 năm.
Những kỹ năng cần thiết của một IT BA
1. Kỹ năng giao tiếp: BA là người phải giao tiếp trực tiếp với khách hàng để lấy yêu cầu, trao đổi dev, test để đưa ra solution tốt nhất. Vì thế người làm BA phải là một người giao tiếp tốt. Họ có thể tổ chức điều hành thành công các buổi họp, biết cách đặt vấn đề, biết lắng nghe và tiếp nhận các ý kiến trong buổi họp. Ngày nay, việc giao tiếp không phải lúc nào cũng là gặp mặt trực tiếp. Vì vậy, kỹ năng giao tiếp tốt trong các buổi họp trực tuyến cũng rất quan trọng.
2. Kỹ năng sử dụng SQL: Đây là kỹ năng quan trọng của một IT BA. Vì họ là người hiểu rõ về các bảng và cách lấy dữ liệu từ các bảng trong database.
3. Kỹ năng phân tích, phản biện: BA có trách nhiệm đánh giá, lựa chọn giải pháp trước khi làm việc với các thành viên trong nhóm. Trong quá trình xác định các vấn đề cần giải quyết của dự án, BA phải thu thập yêu cầu của khách hàng nhưng đồng thời cũng phải phân tích những yêu cầu này một cách cẩn thận và chi tiết cho đến khi BA chắc chắn hiểu được những yêu cầu, mong muốn thực sự của khách hàng. Đây là lý do tại sao kỹ năng tư duy phản biện và kỹ năng phân tích, đánh giá là rất quan trọng với một người BA mới.
5. Kỹ năng mô hình hóa vấn đề bằng biểu đồ: Phần lớn dev đều lười mở tài liệu ra đọc vì thế khi làm việc họ mong muốn có những biểu đồ rõ ràng thì sẽ đưa đến họ hơn. Một bức hình đáng giá hơn cả ngàn chữ – Các mô hình sẽ giúp người đọc dễ dàng nắm bắt ý tưởng hơn. Một vài mô hình điển hình: Use cases diagram, sequence diagram, Workflow diagrams, wireframe prototypes…. Với mỗi kĩ năng phân tích, tương ứng sẽ có một loại mô hình mà BA cần phải tạo. Đặc biệt, người làm BA nên có kĩ năng mô hình hóa lại thông tin mọi lúc, mọi nơi dù là sử dụng các mô hình chuẩn hay chỉ đơn giản là một mô hình nguệch ngoạc trên giấy.
6. Kỹ năng làm tài liệu: Khi viết tài liệu thì yêu cầu đầu tiên là viết rõ ràng và chính xác và quan trọng hơn hết là viết cho người đọc hiểu chứ không phải cho mình hiểu! Nếu bạn là một BA mới vào nghề, bạn sẽ chưa biết cách tạo ra các tài liệu đặc tả mà người làm BA phải tạo. Tuy nhiên, bạn vẫn có thể bắt đầu viết những tài liệu nếu như bạn có sẵn kĩ năng viết tốt.
Những vấn đề thường gặp khi bắt đầu đi xin việc
Đối với ngành BA thường các công ty tuyển dụng hay yêu cầu có kinh nghiệm làm việc 1 năm trở lên, tuy nhiên hiện nay cũng nhiều công ty tuyển Intern hoặc Fresher đây chính là cơ hội với người mới. Tuy nhiên, ở các công ty trong lĩnh vực IT thì mọi người hay chuyển từ dev hoặc test sang làm BA vì thế các bạn khi còn là sinh viên có thể xin thực tập dev, test ở công ty sau đó xin chuyển sang làm BA, đây cũng là một cách để tiếp cận dễ dàng hơn. Song như mình nói ở trên hiện nay thì có rất nhiều công ty tuyển Fresher hoặc Junior không yêu cầu kinh nghiệm vì thế bạn hoàn toàn có thể tự tìm hiểu và đi phỏng vấn.
Những câu hỏi thường được hỏi khi phỏng vấn
Tại sao bạn lại mong muốn chuyển sang làm BA? Trước khi chuyển sang làm BA thì mình dev vì thế lần nào đi phỏng vấn cũng nhận được câu hỏi này. Vì bản thân mình sau một thời gian làm dev thì thấy không phù hợp với nhu cầu phát triển của bản thân, khi đi học thì mình cũng thích giao tiếp với mọi người nên khi đổi ngành mình đã chọn làm BA.
Bạn hiểu BA là làm những công việc gì? Hầu hết trong trường học mọi người đều không được giới thiệu BA là gì, làm những công việc gì tuy nhiên trước khi chuyển sang công việc mới thì mọi người nên tham gia khóa học hoặc tìm hiểu thông tin trên mạng. Nội dung chi tiết BA sẽ làm những gì thì mình sẽ giới thiệu ở bài sau.
Điểm mạnh, điểm yếu của bạn khi làm BA là gì? Với mình điểm mạnh của mình là mình đã từng làm dev nên có hiểu biết cơ bản về kiến trúc của dự án công nghệ thông tin và các kỹ năng cơ bản như mô hình hóa yêu cầu, sql. Điểm yếu của mình thì nhiều khi hay đưa vấn đề của dev khi nói chuyện với khách hàng.
Một số câu hỏi liên quan đến SQL? Bạn nên nắm được một số câu lệnh SQL đơn giản như Select, Join, Group by.
Một số tình huống đơn giản và đưa ra cách giải quyết vấn đề? Ví dụ: Nếu khách hàng đưa bạn yêu cầu mới mà bạn chưa từng biết đến thì bạn phải làm thế nào?
Những công việc của một IT BA
Nhận yêu cầu từ khách hàng hoặc quản lý cấp trên, đôi khi ở các công ty làm sản phẩm thì yêu cầu sẽ đi từ đội kinh doanh hoặc từ nhu cầu thị trường
Phân tích, làm rõ yêu cầu. Đưa ra list function.
Làm các tài liệu liên quan:
Tài liệu Architecture: Tài liệu mô tả luồng thao tác người dùng, luồng hoạt động của hệ thống, cấu trúc cơ bản của hệ thống, các thành phần trong hệ thống, tương tác giữa các thành phần trong hệ thống
Tài liệu SRS hay basic design: Tài liệu mô tả chi tiết các chức năng, giao diện của từng chức năng
Tài liệu test point: Các testcase cơ bản, đặc thù liên quan đến giao diện từ phía người dùng
Thiết kế mô tả database: Database hệ thống, mô tả chức năng của các bảng các trường đặc biệt.
Transfer logic cho dev, test.
Check lại hệ thống trước khi đi đến khách hàng
Training, hướng dẫn khách hàng sử dụng hệ thống
Trên đây là khái quát các công việc của một IT BA dưới cái nhìn chủ quan của mình. Các bạn đọc có ý kiến khác vui lòng comment phía dưới. Xin cảm ơn.
Bài viết được sự cho phép của BBT Tạp chí Lập trình
Giới thiệu
Crawler là một công cụ giúp thu thập dữ liệu, thông tin từ các trang web khác nhau. Một trong những ví dụ về crawler mà chúng ta gặp hằng ngày là Google. Google là một hệ thống có nhiều máy chủ có thể crawling rất nhiều trang web trên Internet, từ đó chúng ta có thể tìm kiếm nội dung những trang web mà chúng ta cần dựa vào từ khoá cụ thể. Hoặc là những trang web so sánh giá cả từ nhiều nguồn khác nhau (websosanh.vn), trang tin báo tổng hợp (baomoi.com) và nhiều ví dụ khác mà mình không thể liệt kê hết ở đây.
Chúng ta có thể tự viết một crawler đơn giản nhằm thu gom một số dữ liệu cơ bản nào đó. Khi hướng dẫn học viên học module 2 (Advance Programming with Java) tại CodeGym, mình thường giao bài tập xây dựng công cụ crawler này. Ví dụ thu thập giá bất động sản trên các trang rao vặt hoặc giá sản phẩm trên các trang thương mại điện tử. Qua bài viết này, mình sẽ hướng dẫn lại các bạn làm bài tập này với ngôn ngữ lập trình Java.
Sử dụng được biểu thức chính quy (regular expression) — còn được gọi là regex
Một ít hiểu biết về HTTP (Giao thức được sử dụng để truy cập các trang web qua Internet)
Hiểu cơ bản phương pháp lập trình hướng đối tượng
Hiểu cơ bản về design pattern
Ghi chú: Trên thực tế, có nhiều thư viện hỗ trợ chúng ta làm crawler hiệu quả hơn cách làm trong bài này. Với mục đích học là chính, mình sẽ không sử dụng các thư viện đấy mà sẽ tự xây dựng lấy, các bạn nhé!
Thiết kế chương trình
Chúng ta sẽ xây dựng một công cụ có thể thu thập được tin tức bất động sản đang rao (bao gồm bán và cho thuê) tại các website sau:
https://batdongsan.com.vn/
https://batdongsan24h.com.vn/
https://nhadat24h.net/
https://diendanbatdongsan.vn/
Mô tả dữ liệu
Khai báo class có tên là ClassifiedAd để mô tả thông tin thu thập được từ các trang web. Bao gồm: tiêu đề, loại tin rao, diện tích, giá, mô tả chi tiết, hình ảnh (link).
Sau khi khảo sát nội dung các trang web, chúng ta thấy rằng:
Các tin có thể hiển thị giá tổng (tính trên toàn bộ diện tích) hoặc giá theo mét vuông. Vì vậy cần khai báo những class sau để mô tả loại giá được hiển thị: enum TypePrice, class Price.
Đơn vị tiền có thể là “triệu đồng” hoặc “tỷ đồng”. Vì vậy cần thuộc tính unit tương ứng trong class Price. Giá trị được liệt kê trong enum Unit để xác định đơn vị tiền tệ.
Các tin rao được phân loại thành: bán căn hộ, bán nhà đất, bán biệt thự, cho thuê,… enum TypeAd được khai báo cho mục đích này.
enum TypePrice {
PRICE_PER_M2, // loại giá dựa trên m2
TOTAL_PRICE // giá toàn bộ
}
enum Unit {
MILLION_VND,
BILLION_VND,
}
class Price {
private Float price;
private TypePrice typePrice;
private Unit unit;
}
enum TypeAd {
...,
SELL,
RENTAL,
OTHERS
}
class ClassifiedAd {
private String title; // tiêu đề
private TypeAd typeAd; // loại tin
private Price price; // giá
private Float acreage; // diện tích
private String description; // mô tả
}
Qua khảo sát các trang web mà cần thu thập tin, chúng ta có thể xác định thứ tự các bước để thu thập tin như sau:
Truy cập trang chủ, liệt kê danh sách những danh mục tin (ví dụ: chung cư, nhà đất, biệt thự,…)
Truy cập các danh mục tin để liệt kê các tin đang rao
Truy cập trang chi tiết của từng tin để lấy các thông tin chi tiết
Chúng ta sẽ áp dụng pattern Template Method để chuyển các bước trên thành một dãy các bước xử lý chung cho mỗi trang web.
public abstract class Crawler {
// bước 1
abstract Iterable<Subpage> inspectHomepage();
// bước 2
abstract Iterable<DetailPage> inspectSubpage(Subpage subpage);
// bước 3
abstract ClassifiedAd inspectDetailPage(DetailPage detailPage);
// Đây là thao tác chung cho tất cả các trang web mà chúng ta muốn thu thập tin
Iterable<ClassifiedAd> inspect() {
List<ClassifiedAd> classifiedAds = new ArrayList<>();
Iterable<Subpage> subpages = inspectHomepage();
for (Subpage subpage: subpages) {
Iterable<DetailPage> detailPages = inspectSubpage(subpage);
for (DetailPage detailPage: detailPages) {
ClassifiedAd classifiedAd = inspectDetailPage(detailPage);
classifiedAds.add(classifiedAd);
}
}
return classifiedAds;
}
}
Với mỗi trang web cụ thể, chúng ta có một cách thu thập khác nhau (vì giao diện mỗi trang khác nhau). Trong tương lai, chúng ta có thể bổ sung những trang web khác hoặc thay đổi cách thức thu thập. Vì thế chúng ta sẽ xây dựng các class phục vụ việc crawle cho từng trang web cụ thể theo thiết kế như sau:
Sơ đồ lớp (class diagram) chương trình Crawler
Ở thiết kế trên, chúng ta áp dụng kiến thức về abstract class trong lập trình hướng đối tượng nhằm đảm bảo có thể dễ dàng mở rộng các trang web muốn thu thập. Khi cần bổ sung trang mới, chúng ta có thể implement thêm Crawler mà không phải sửa đổi ở khung thiết kế và luồng thực thi của chương trình. Cuối cùng là class MySimpleCrawler chứa đoạn mã khởi động chương trình.
Bây giờ, chúng ta viết mã kiểm tra xem ý tưởng thiết kế trên có thể thực hiện được chưa nhé! Tính năng ban đầu sẽ là khởi động chương trình và lấy những tin rao ở các trang batdongsan.com.vn.
Ghi chú: Ở công cụ siêu đơn giản này, chúng ta chưa tính đến việc làm thế nào để tối ưu thời gian chạy, lấy nhiều tin ở các trang tiếp theo, lên lịch chạy để luôn cập nhật được tin mới nhất, hoặc thậm chí là cấu hình thời gian ngắt quãng giữa các lần thu thập (để tránh trường hợp một số trang không cho phép tạo request liên tục trong khoảng thời gian nhất định nào đó).
Start coding!
1. Xác định các nội dung cần thu thập
Để lấy được nội dung trang web, chúng ta có thể sử dụng một tính năng tạo HTTP request đơn giản mà Java cung cấp là class URL.
Để tạo một request đến trang web cần lấy nội dung, chúng ta sử dụng hàm dưới đây:
private static String getContentFrom(String link) throws IOException {
// Gởi HTTP request và nhận về kết quả là chuỗi các thẻ HTML
URL url = new URL(link);
Scanner scanner = new Scanner(new InputStreamReader(url.openStream()));
scanner.useDelimiter("\\\\Z");
String content = scanner.next();
scanner.close();
// xoá các ký tự ngắt dòng (xuống dòng)
content = content.replaceAll("\\\\R", "");
return content;
}
</pre
Khi request thành công, các trang web thường trả về các thẻ HTML. Nếu nơi nhận là trình duyệt thì các thẻ HTML này sẽ được dựng hình (render) thành giao diện của trang web. Còn công cụ crawler của chúng ta chỉ xem đấy là các chuỗi ký tự. Việc chúng ta cần làm là tìm những vị trí chứa thông tin cần thiết bên trong chuỗi ấy. Biểu thức chính quy (regex) có thể được áp dụng trong trường hợp này.
Như vậy, chúng ta cần làm hai bước sau để lấy được thông tin trong trang web:
Bước 1: Xác định vị trí thông tin cần lấy trong chuỗi HTML để tìm được quy tắc đánh dấu
Bước 2: Dựa vào quy tắc đánh dấu trên, chúng ta xác định biểu thức chính quy phù hợp để lọc được chuỗi thông tin cần thiết
Để đơn giản hoá Bước 1 — Tìm vị trí các thông tin cần thiết trong chuỗi HTML trả về, chúng ta có thể sử dụng chức năng Inspect (trong bộ Developer Tools) của trình duyệt Google Chrome hoặc Firefox để tra đến vị trí mã nguồn thông qua giao diện trực quan.
Dưới đây là phần minh hoạ các bước trên cho việc liệt kê danh sách những danh mục tin ở trang chủ của trang web batdongsan.com.vn (Như đã trình bày Bước 1 trong mục Thiết kế tổng quan).
1.1. Hướng dẫn bước 1
Truy cập trang web batdongsan.com.vn trên trình duyệt
Mở chức năng Inspect với phím tắt Option + CMD + I (hệ điều hành MacOS) hoặc Ctrl + Shift + P (hệ điều hành Windows)
Di chuyển chuột đến mục Nhà đất bán > Bán căn hộ chung cư trên thanh định hướng (menu) > Bấm chuột phải > Chọn Inspect.
Rê chuột đến mục Nhà đất bán > Bán căn hộ chung cư trên thanh định hướng (menu), click chuột phải, chọn Inspect.
Qua nội dung hiển thị trên tab Element, chúng ta có thể thấy mã HTML của những thẻ đánh dấu mục Bán căn hộ chung cư như bên dưới:
Qua nội dung hiển thị trên tab Element, chúng ta có thể thấy mã HTML của những thẻ đánh dấu mục Bán căn hộ chung cư như trên.
Như vậy, chúng ta xác định được mã đánh dấu các đường link của các danh mục tin trên trang web này là thẻ <a> nằm trong thẻ <li> có class là lv1.
1.2. Hướng dẫn bước 2
Qua bước 1, chúng ta xác định được rằng, để lấy được đường link của danh mục con Bán căn hộ chung cư thì phải lấy thuộc tính href của thẻ <a> nằm trong <li class="lv1">.
Đây là những đường link con, có thể kết hợp với chuỗi https://batdongsan.com.vn để tạo ra đường link dẫn tới nội dung các danh mục tin được rao.
Ở kết quả trên, chúng ta thấy có một số đường link không phù hợp. Vì đó là những đường link mà chúng ta không muốn thu thập nội dung. Ví dụ: /phong-thuy-van-phong, /tin-tuc-phong-thuy-theo-tuoi, /nha-moi-gioi,… Chúng ta sẽ tìm cách loại bỏ những kết quả không mong đợi này.
Xem xét lại mã HTML của trang web, chúng ta sẽ phát hiện ra các thẻ <li class='lv1'> chứa các thông tin cần thiết này nằm trong 2 nội dung sau:
Nhà đất bán
<li class='lv0'><a href="/nha-dat-ban" class="haslink ">Nhà đất bán</a>
...nội dung các danh mục con của mục Nhà đất bán ở đây
</li>
Nhà đất cho thuê
<li class='lv0'><a href="/nha-dat-cho-thue" class="haslink ">Nhà đất cho thuê</a>
...nội dung các danh mục con của mục Nhà đất cho thuê ở đây
</li>
Đoạn code trên cần sửa lại như dưới đây để loại ra những link không cần thiết:
public class DemoUsingURL {
private static String getContentFrom(String link) throws IOException {
...
}
private static List<String> getLinksFromMenu(String content, String menuPattern) {
// Regex
List<String> links = new ArrayList<>();
Pattern p = Pattern.compile(menuPattern);
Matcher m = p.matcher(content);
while (m.find()) {
Pattern p2 = Pattern.compile("<li class='lv1'><a href='(.*?)' class='haslink '>");
Matcher m2 = p2.matcher(m.group(1));
while (m2.find()) links.add(m2.group(1));
}
return links;
}
public static void main(String[] args) throws IOException {
String content = getContentFrom("<https://batdongsan.com.vn>");
String sellMenuPattern = "<li class='lv0'><a href='/nha-dat-ban' class='haslink '>Nhà đất bán</a><ul>(.*?)</ul>";
List<String> sellLinks = getLinksFromMenu(content, sellMenuPattern);
String rentalMenuPattern = "<li class='lv0'><a href='/nha-dat-cho-thue' class='haslink '>Nhà đất cho thuê</a><ul>(.*?)</ul>";
List<String> rentalLinks = getLinksFromMenu(content, rentalMenuPattern);
System.out.println(sellLinks);
System.out.println(rentalLinks);
}
}
Ở đoạn code trên, mình tách phần lấy nội dung từ đường dẫn trang web thành hàm getContentFrom, và một hàm tách link từ nội dung có tên là getLinksFromMenu. Hàm main sử dụng hai hàm được khai báo ở trên để lấy các đường link nằm trong mục Nhà đất bán và Nhà đất cho thuê.
1.3. Thực hành
Bây giờ, các bạn có thể tự thực hành với hướng dẫn hai bước trên để xác định những thông tin còn lại.
Nếu cần có kết quả ngay thì bạn có thể tham khảo mã nguồn mình cung cấp ở cuối bài viết này! 🙂
1.4. Tổng hợp các regex tìm được
Dưới đây các regex đã tìm được với trang batdongsan.com.vn để các bạn tham khảo:
Link các danh mục tin
Link đến nội dung chi tiết
Thông tin cụ thể (như tiêu đề, giá, diện tích,…) trong tin chi tiết
1.4.1. Link các danh mục tin
Tìm các link bên trong mục “Nhà đất bán” và “Nhà đất cho thuê”:
Pattern p1 = Pattern.compile("<li class='lv0'><a href='/nha-dat-ban' class='haslink '>Nhà đất bán</a><ul>(.*?)</ul>");
Pattern p2 = Pattern.compile("<li class='lv0'><a href='/nha-dat-cho-thue' class='haslink '>Nhà đất cho thuê</a><ul>(.*?)</ul>");
Sau đó, tìm các link danh mục thuộc “Nhà đất bán” và “Nhà đất cho thuê” để loại các link không cần thiết:
Pattern p = Pattern.compile("<div class='p-title'><h3><a href='(.*?)' title");
1.4.3. Thông tin cụ thể trong tin chi tiết
<span id="48e5" class="ir gx ap ce in b ei is it r iu" data-selectable-paragraph="">String title = "<h1 itemprop=\\"name\\">(.*?)</h1>";
String price = "<span class=\\"gia-title mar-right-15\\"><b>Giá:</b><strong>(.*?)</strong>";</span><span id="e97c" class="ir gx ap ce in b ei iv iw ix iy iz it r iu" data-selectable-paragraph="">Pattern p = Pattern.compile(title + ".*" + price);</span>
2. Viết mã crawler cho từng trang web cụ thể
Xác định được các regex pattern để lấy những thông tin cần thiết ở trên là chúng ta đã đi được 50% chặng đường. Việc còn lại là kết hợp các regex trên để viết mã crawler cụ thể cho từng trang web theo thiết kế được trình bày trong mục Thiết kế tổng quan.
Các class dành cho trang cụ thể sẽ implement những phương thức abstract đã định nghĩa trong Crawler:
inspectHomepage() sẽ sử dụng các regex như minh hoạ trong mục Hướng dẫn bước 1.
inspectSubpage trả về danh sách link các trang chi tiết.
inspectDetailPage trả về thông tin cụ thể từ trang chi tiết.
Cải tiến
Như đã trình bày ở trên, đây là một công cụ “siêu đơn giản”. Vì thế sẽ thiếu nhiều tính năng để crawler thực sự hữu ích trên thực tế như tối ưu thời gian chạy, lên lịch chạy để luôn cập nhật được tin mới nhất, lưu vào kho dữ liệu phù hợp phục vụ tra cứu hoặc tính toán/so sánh…
Mình sẽ đưa ra một số gợi ý để các bạn có thể tiếp tục tìm hiểu và cải tiến công cụ này nhé!
Sử dụng Thread để tối ưu thời gian chạy, giảm thời gian đợi giữa các lần request nội dung từng trang web. Vì mỗi trang được xử lý độc lập, việc đợi kết quả của request này sẽ không ảnh hưởng đến kết quả của các request còn lại.
Sử dụng Crob Job để lên lịch chạy hằng ngày hoặc một khung thời gian cố định (ví dụ: 10 phút 1 lần). Hiện tại, các thao tác phải được kích hoạt thủ công. Việc này sẽ không giúp hệ thống có được dữ liệu mới nhất.
Sử dụng một hệ CSDL cụ thể để gom dữ liệu thu thập được. Hệ CSDL sẽ giúp chúng ta có thể xử lý và đưa ra một số thông tin hữu ích. Ví dụ: so sánh giá thị trường với từng khu vực cụ thể, hoặc tìm giá tốt nhất được rao trên các trang theo nhu cầu của người dùng.
Chào các bạn, hôm nay mình sẽ tiếp tục series về CSS cơ bản. Bài viết lần này như tiêu đề đã ghi rõ, mình sẽ giới thiệu và phân tích về Specificity trong CSS. Đây là phần kiến thức quan trọng bậc nhất (không nhất thì nhì :D) nhưng lại không quá phức tạp, mình sẽ cố gắng trình bày những thứ đơn giản mà chúng ta hay sử dụng hàng ngày thôi. Nếu các bạn thấy có thiếu sót hay phản hồi gì thì vui lòng cho mình biết ở comment bên dưới nhé.
Trong một buổi phỏng vấn khi còn là mid-level developer, mình từng được đặt một câu hỏi cơ bản mang tính lý thuyết cao nhưng mình không trả lời được, mình xin viết lại ra đây (không chính xác hoàn toàn nhưng bản chất câu hỏi không đổi)
Câu trả lời là màu purple, các bạn có thể tự mình chứng thực kết quả. Phần giải thích cho bài toán này mình để ở cuối bài viết.
Mình đã không trả lời được câu hỏi này, nhưng thời điểm đó mình cho rằng người phỏng vấn chỉ đang đưa ra câu hỏi mang tính đánh đố thôi, chứ thực tế ai lại viết CSS như vậy. Và sau này mình mới nhận ra, đó không phải là một câu hỏi mang tính đánh đố, mà nó là một phần trong một mảng kiến thức vô cùng quan trọng của CSS, đó là CSS Specificity mà bất kì frontend developer nào cũng cần phải hiểu và nắm vững. Nếu bạn không hiểu hoặc không biết về nó, thì bạn hãy tự vấn mình rằng có phải bạn đang viết CSS theo cảm tính, hoặc theo thói quen hàng ngày hay không.
Ok vậy hãy cùng mình tìm hiểu xem CSS Specificity là gì nhé.
CSS Specificity là gì?
Hãy lấy một ví dụ đơn giản sau để mô tả cho định nghĩa bên dưới:
/* thẻ span sẽ có màu gì đây? */.parent .child{color: red;}.child{color: green;}#sample{color: blue;}
Ôi trời, một thẻ span thôi nhưng lại có đến 3 selector cố gắng “tranh nhau” thay đổi màu sắc của nó, giống như một cuộc chiến vậy. Nhưng tin vui là cuộc chiến này sẽ luôn luôn có người chiến thắng, nhờ vào trọng tài là browser. Tuy nhiên browser làm thế nào để xác định người chiến thắng? Câu trả lời là nhờ vào một tập các quy tắc, và browser cứ dựa theo tập quy tắc này để xác định ai là người chiến thắng. CSS Specificity chính là một phần chính yếu trong “tập quy tắc” đấy nhé.
Mình sẽ định nghĩa đơn giản như sau:
Specificity là một trọng số mà browser dựa vào đó để xác định xem một element sẽ có css style là gì. Trọng số chỉ đơn giản như việc 2 > 1 thì 2 chiến thắng, hay 3 > 2 thì 3 chiến thắng, vậy thôi. Một điều cũng quan trọng không kém: Specificity là trọng số của CSS selectors nhé. Nói nôm na hơn, browser sẽ cố gắng xác định xem selector nào là cụ thể nhất (most specific) và style theo selector đó.
“Tập quy tắc” này có phức tạp không? Xác định trọng số Specificity có phức tạp không? Browser dùng tới nó thì chắc hẳn là nó phức tạp lắm? Câu trả lời là nó không hề phức tạp và developer vẫn có thể học thuộc nó một cách dễ dàng. Nói cách khác, 80% các quy tắc là rất đơn giản và dễ hiểu, có thể học thuộc được, còn 20% quy tắc còn lại sẽ khá rối rắm mà ít khi chúng ta sử dụng trong thực tế, nên chúng ta không cần phải nhớ nó, cứ để browser làm việc của nó là được.
Tại sao developer lại nên học thuộc tập quy tắc này (80% các quy tắc thường sử dụng thôi)? Điều này mình không hề chém gió đâu, nếu bạn là một frontend developer chuyên xử lý layout và CSS, thì đây là một kiến thức mà bạn nên nằm lòng, chứ không phải chỉ là để đọc chơi cho biết. Tuy nhiên mình cũng không phải muốn các bạn thuộc nó một cách máy móc, mà nên hiểu nó. Và khi hiểu rồi thì sẽ tự thuộc thôi, hoặc khi quên thì chỉ cần đọc lại tí xíu là nhớ.
Cách xác định trọng số Specificity và cách so sánh
Cách xác định trọng số của CSS selectors chỉ đơn giản là chơi trò chơi đếm số và điền vào 3 ô trống bên dưới thôi.
Ở ô đầu tiên (ID), mình sẽ đếm xem selector có bao nhiêu id. Ví dụ #parent { } là 1, #parent #child { } là 2. Đếm xong rồi thì điền vào ô trống thôi.
Ở ô thứ 2, mình sẽ đếm xem có tổng cộng bao nhiêu class (ví dụ .list), psuedo-class (ví dụ :hover) và attribute (ví dụ [type=radio]).
Ở ô thứ 3, mình sẽ đếm xem có tổng cộng bao nhiêu type selector (ví dụ h1), pseudo-element (ví dụ ::before)
Chúng ta cơ bản đã xong bước xác định trọng số rồi, giờ thì so sánh chúng thôi. Cách so sánh cực kì đơn giản, như toán lớp 1 vậy:
1,1,0 lớn hơn 1,0,0 (110 > 100)
0,1,0 lớn hơn 0,0,1 (10 > 1)
1,3,0 lớn hơn 1,0,3 (130 > 103)
0,0,1 bằng với 0,0,1 (1 === 1)
Ồ, nếu bằng nhau thì thế nào? Nếu bằng nhau thì thằng nào được khai báo sau cùng sẽ thắng. Điều này mình sẽ lặp lại ở phần tiếp theo. Giờ thì cùng nhau thực hành đếm trọng số qua các ví dụ sau nhé:
#parent: 1,0,0
#parent #child: 2,0,0
[id="parent"]: 0,1,0
li: 0,0,1
ul > li: 0,0,2
ul ol + li: 0,0,3
h1 + *[rel=up]: 0,1,1
ul ol li.red: 0,1,3
li.red.level: 0,2,1
li.name::before: 0,1,2
#parent:not(ul): 1,0,1
.foo:is(.bar, #bar): 1,1,0
Một số quy tắc khác
Có một số quy tắc khác ít nhiều ảnh hưởng đến trọng số Specificity mà bạn không thể bỏ qua:
Universal selector * sẽ được bỏ qua khi xác định trọng số. Ví dụ selector * sẽ có trọng số là 0,0,0. Hay *.foo sẽ có trọng số là 0,1,0. Điều này có nghĩa là *.foo và .foo là hoàn toàn giống nhau.
Combinators như +, >, ~, || hay space cũng sẽ được bỏ qua khi xác định trọng số. Ví dụ .parent .child và .parent > .child có cùng trọng số là 0,2,0.
:not() không được xem là pseudo-class nên cũng được bỏ qua khi tính trọng số. Tuy nhiên trọng số vẫn sẽ được tính với param truyền vào nó. Ví dụ: div:not(.parent) p sẽ có trọng số là 0,1,2.
:is() cũng tương tự với :not(), tuy nhiên vì chúng ta có thể truyền vào một danh sách selector, nên trọng số sẽ được tính với matched selector nào có trọng số cao nhất. Ví dụ: div:is(.parent, #foo) sẽ có trọng số có thể vừa là 0,1,1, vừa có thể là 1,0,1, vừa có thể là 1,1,1, tùy theo việc nó match với bao nhiêu trường hợp. Cũng phức tạp ghê phải không nào.
“Inline styles” sẽ luôn luôn có trọng số cao nhất, đánh bật tất cả các đối thủ (ngoại trừ trùm cuối !important). Ví dụ bạn viết:
<span class="text" style="color: red">text</span>
thì dù bạn cố gắng viết CSS (external CSS) để thay đổi color của nó đều vô ích (tất nhiên như mình đã nói, bạn vẫn có thể nếu dùng đến !important)
.text{color: green;/* không được đâu nhé, nó thua inline style */}.text{color: blue !important;/* khi đã dùng tới trùm cuối thì đừng hỏi nữa */}
Trùm cuối của chúng ta !important có thể đánh bại mọi đối thủ, ngay cả inline style vốn đã vô cùng mạnh mẽ. Bạn xem ví dụ ngay phía bên trên là rõ. Tuy nhiên nếu 2 anh trùm cuối cùng đánh nhau thì thế nào? Câu trả lời ở quy tắc ngay bên dưới. Ví dụ:
.text{color: green !important;/* ê blue, đấu với tao không */}.text{color: blue !important;/* tao sợ mày à green, chơi luôn */}
Khi 2 hoặc nhiều selector có cùng trọng số, thì selector nào được khai báo cuối cùng sẽ thắng. Trong cuộc đối đầu ở quy tắc bên trên, blue là người chiến thắng. Tất nhiên nếu ta đổi vị trí 2 selector này cho nhau, thì green lại là người chiến thắng. Đây là một lỗi thường thấy khi chúng ta không am hiểu về Specificity (thường là các bạn junior), vô tình thay đổi vị trí hoặc chỉnh sửa CSS vô tội vạ làm thay đổi trọng số, dẫn đến lỗi style không mong muốn.
Độ gần/xa (proximity) có ảnh hưởng không?
Thật sự mình không biết nên dịch từ “proximity” thế nào cho đúng, nhưng ý nghĩa của nó có hiểu qua ví dụ ở đầu bài viết.
“Proximity” ám chỉ việc thẻ h1 gần với body hơn là html, vậy liệu selector body h1 có trọng số lớn hơn html h1 không? Câu trả lời là KHÔNG.
Trong trường hợp này, vì cả 2 đều có cùng trọng số là 0,0,2, chúng ta sẽ sử dụng quy tắc “thằng nào được khai báo cuối cùng sẽ thắng”. Vậy kết quả sẽ là html h1 chiến thắng, màu của thẻ h1 sẽ là purple.
Lưu ý & suy ngẫm
Một selector với trọng số lớn liệu có tốt không? Ví dụ:
/* Trọng số là 2,3,4 */#main article.sports table#stats tr:nth-child(even) td:last-child{
...
}
Với trọng số là 2,3,4, bạn sẽ rất khó để override nó, và sẽ làm cho code của bạn rối rắm và khó để maintain hay extend.
Bất kì khi nào bạn rơi vào tình huống không hiểu vì sao element của mình lại có style không như mong muốn, thì Specificity sẽ giúp bạn. Tuy nhiên thay vì ngồi đếm trọng số bằng tay, giờ đây với công cụ devtools mạnh mẽ của các browser thì việc xác định lỗi style là vô cùng đơn giản. Tuy nhiên các công cụ này cũng xây dựng trên nguyên lý CSS Specificity mà thôi chứ không có gì khác biệt đâu.
Specificity chỉ có ý nghĩa nếu một element có nhiều selector cùng trỏ (target) đến nó. Nói nôm na là nếu cuộc chiến mà chỉ có 1 người tham gia thì hiển nhiên người đó thắng rồi.
Trong CSS có việc kế thừa style từ các element cha. Tuy nhiên việc kế thừa này sẽ luôn xếp sau những selector trỏ (target) đích danh đến element nhé. Bạn để ý khi sử dụng devtools là thấy thôi.
Việc có nên sử dụng inline styles không vẫn là một vấn đề gây tranh cãi. Một số linter sẽ warning nếu bạn viết inline styles, nhưng bạn vẫn có thể tắt warning đó đi nếu muốn. Một trong những lý do là vì trọng số của nó quá cao sẽ dễ gây ra các lỗi không mong muốn, hoặc sẽ rất khó để override và buộc phải dùng đến !important. Một lý do khác nữa là với nhiều “chuyên gia” thì CSS nên đặt trong các file .css để dễ quản lý, chứ nếu nằm trong style (html) thì rối loạn lên hết?
Mặc dù trùm cuối !important vô cùng mạnh mẽ, việc dùng đến !important không phải là một giải pháp tốt và cần hạn chế sử dụng, giống như inline styles mà mình vừa đề cập đến. Trước khi buộc phải dùng đến !important, bạn hãy suy xét cẩn thận xem chúng ta có thể sử dụng CSS Specificity để đạt được mục đích hay không.
BEM & ITCSS
Ở đây mình không phải muốn giải thích hay giới thiệu chi tiết về 2 “phương pháp” này, mà chỉ muốn chỉ ra một vài điểm liên quan với Specificity thôi. Ngoài BEM và ITCSS ra còn có nhiều phương pháp khác nữa, nhưng cơ bản đều xây dựng trên Specificity cả.
BEM: mình mặc định bạn đã biết đến BEM, thì một vài tôn chỉ của nó có thể kể đến như:
Tránh sử dụng id (#foo): lý do thì như mình đã chia sẻ, id có trọng số lớn và khá khó để override, nên việc cố gắng override nó sẽ dễ đẩy CSS của bạn đến một tương lai không mấy sáng sủa.
Tránh nested selector, cố gắng làm phẳng selector: cũng cùng lý do, nested selector cũng làm tăng trọng số của selector. Ví dụ BEM sẽ khuyến khích:
/* BEM thích điều này, trọng số chỉ là 0,1,0
nhưng vẫn rất specific và khó bị conflict */.block{}.block__elem1{}.block__elem2{}.block__elem3{}/* Trọng số sẽ là 0,2,0, cũng không quá tệ, nhưng BEM không khuyến khích,
và nó cũng rất dễ bị conflict. */.block{}.block .elem1{}.block .elem2{}.block .elem3{}
ITCSS: cũng là một phương pháp ứng dụng triệt để các quy tắc của CSS Specificity, giúp CSS của bạn có thể dễ dàng scale, extend và maintain (SEM). ITCSS có rất nhiều thứ để nói nhưng nằm ngoài phạm vi bài viết nên mình xin dừng ở đây, nếu các bạn quan tâm thì để lại comment để mình làm một bài viết riêng về nó nhé.
CSS Specificity calculator
Chỉ cần search google là bạn sẽ thấy một vài tool sẽ giúp bạn xác định trọng số của selector:
Tuy nhiên các bạn cũng không nên hoàn toàn tin tưởng vì các tool này chỉ đếm trọng số trong những trường hợp đơn giản, còn những trường hợp phức tạp hơn thì vẫn có thể sai nhé.
Mình chốt lại bài viết bằng một tấm hình vui nhưng khá nổi tiếng nhé.
https://specifishity.com/
Lời kết
CSS cơ bản thật ra cũng không nhiều, bạn chỉ cần biết vừa đủ là có thể tung hoành giang hồ được rồi. Vì nó không nhiều và cũng không khó, nên các bạn hãy dành thời gian học và nắm vững nó nhé. Trước giờ mình đi phỏng vấn với vị trí frontend, mình thấy khá hiếm công ty nào phỏng vấn về CSS, có lẽ họ mặc nhiên rằng frontend developer thì phải biết CSS, hoặc bản thân họ không thích CSS nên không muốn đặt câu hỏi. Nhưng nếu vô tình được hỏi, thì hãy “chém tơi bời” interviewer nhé 😀
Như mọi lần, nếu các bạn thấy bài viết có gì thiếu sót hay sai chỗ nào thì vui lòng để lại comment cho mình biết để sửa đổi. Nếu các bạn thấy bài viết hay và hữu ích thì upvote hoặc comment để mình có động lực viết tiếp các bài tiếp theo nhé.
Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng
Chatbot là gì?
Trước khi thò tay vào hì hục code, ta cần hiểu chatbot là gì đã?
Chatbot là một chương trình thực hiện cuộc hội thoại qua phương pháp gửi nhận văn bản hoặc các object như hình ảnh, file, … Chú ý Chatbot không nhất thiết là phải thông minh, là phải dùng trí tuệ nhân tạo, etc …
Có bao giờ sắp đến giao thừa hay một dịp mà bạn muốn nhắn tin cho nhiều người vào 12h đêm mà bạn không thể dậy được, hoặc bạn quá lười để làm một việc lặp đi lặp lại? Câu trả lời là viết một chatbot và hẹn giờ cho nó.
Trong bài viết này mình sử dụng 2 thư viện có sẵn trên mạng là fbchat, schedule do đó bạn cần tạo virtualenv trước tiên, sau đó dùng pip để cài 2 lib trên rồi tạo một file code python tùy ý, ở đây mình dùng chatbot.py.
Tạo 1 function trong class Bot để thực hiện gửi tin nhắn, dưới đây là code của mình:
classBot(Client):defdo_something(self):#Đổi tên function cho phù hợplogging.basicConfig(level=logging.INFO)lst_id=[...]# List chứa fb id của những người bạn muốn gửiforuser_idinlst_id:self.send(Message(text="Chúc mừng năm mới"),thread_id=user_id,thread_type=ThreadType.USER)self.sendLocalImage('/home/dosontung007/Pictures/wallpaper.png',message=Message(text='Chúc mừng năm mới'),thread_id=user_id,thread_type=ThreadType.USER)logging.info('Sent success to %s'%str(user_id))
Và để nhận được tin nhắn từ những người gửi cho mình cho mình , ta viết function onMessage trong class Bot và xử lí các tin nhắn đó:
defonMessage(self,message_object,author_id,thread_id,thread_type,**kwargs):lst_msg=list('Chúc mừng năm mới')ifauthor_id!=self.uidandmessage_object.textinlst_msg:self.send(Message(text='Năm mới chúc .....'),thread_id=author_id,thread_type=thread_type)
Class Bot kế thừa Client, khi tạo một Bot object, ta cần truyền 2 tham số là username và password của Facebook của bạn. Do đó bạn cần set value cho 2 var USERNAME_ và PASSWORD bằng câu lệnh export var=value trong bash trước khi chạy chương trình (vì ta không muốn ghi trực tiếp password vào file code – lộ mật khẩu nếu up lên GitHub). Lưu ý USERNAME_ chứ không phải USERNAME.
Bây giờ còn một công việc duy nhất là hẹn giờ cho job làm việc thôi!
Thay đổi 00:00 bằng thời gian mà bạn muốn hẹn giờ.
Để nhận được message, ta sử dụng function listen từ Client , về cơ bản listen khi chạy sẽ truyền các arguments vào onMessage mỗi lần Facebook bạn có event mới (VD: có người nhắn cho bạn, bạn nhắn cho người khác hoặc tin nhắn trong nhóm, …):
Cuối cùng cũng xong .Sau tất cả, đây là một con chatbot hoàn chỉnh :
importloggingimportosimporttimefromthreadingimportThreadfromfbchatimportClientfromfbchat.modelsimportMessage,ThreadTypeimportscheduleclassBot(Client):defonMessage(self,message_object,author_id,thread_id,thread_type,**kwargs):lst_msg=list('Chúc mừng năm mới')ifauthor_id!=self.uidandmessage_object.textinlst_msg:self.send(Message(text='Năm mới chúc .....'),thread_id=author_id,thread_type=ThreadType.USER)defdo_something(self):logging.basicConfig(level=logging.INFO)user_ids=['100012610305665']foruser_idinuser_ids:self.send(Message(text="Chúc mừng năm mới"),thread_id=user_id,thread_type=ThreadType.USER)self.sendLocalImage('/home/dosontung007/Pictures/wallpaper.png',message=Message(text='Chúc mừng năm mới'),thread_id=user_id,thread_type=ThreadType.USER)logging.info('Sent success to %s'%"100012610305665")defjob_that_executes_once():Bot(os.environ['USERNAME_'],os.environ['PASSWORD']).something()returnschedule.CancelJobdefreply_msg():Bot(os.environ['USERNAME_'],os.environ['PASSWORD']).listen()defsend_msg():schedule.every().day.at('00:00').do(job_that_executes_once))whileTrue:schedule.run_pending()time.sleep(1)defmain():thread1=Thread(target=send_msg)thread2=Thread(target=reply_msg)thread1.start()thread2.start()thread1.join()thread2.join()if__name__=='__main__':main()
Bây giờ export username, password rồi chạy thôi. Và đây là thành quả:
Nếu bạn muốn chạy luôn mà không cần hẹn giờ thì chỉ cần xoá function job_that_executes_once và thay function send_msg bằng:
Khi đang cố gắng để cải thiện kỹ năng Front-end và JavaScript của mình, tôi đã nảy ra ý tưởng học thêm về các API. Dưới đây tôi sẽ chia sẻ với mọi người một số API thú vị mà tôi hay sử dụng.
API là gì?
API – Application Programming Interface là phương thức trung gian kết nối các ứng dụng và thư viện khác nhau. Nó cung cấp khả năng truy xuất đến một tập hợp các hàm hay dùng, từ đó có thể trao đổi dữ liệu giữa các ứng dụng. Bên cạnh đó, các phương thức này sử dụng mã nguồn mở, dùng được với mọi client hỗ trợ XML, JSON và được đánh giá là một trong những kiểu kiến trúc hỗ trợ tốt nhất với các thiết bị có lượng băng thông bị giới hạn như smartphone, tablet…
REST Countries là nguồn tài nguyên hữu ích để tạo các dự án mới. Nó lưu trữ tài liệu của nhiều lĩnh vực khác nhau từ đơn vị tiền tệ, thủ đô quốc gia đến các ngôn ngữ trên khắp thế giới. Cá nhân tôi từng tạo API calls trong Vue.js với Axios.
2. The PokéAPI
Tôi rất thích nền tảng này, The PokéAPI cũng là phương thức đầu tiên tôi sử dụng và đã thực hiện một số dự án bằng API này. PokéAPI chứa nguồn dữ liệu lớn đặc biệt phù hợp với những người mới bắt đầu, không giới hạn về tỉ lệ và có mọi thứ bạn cần để tạo một PokéDex của riêng mình.
Có rất nhiều API để dịch văn bản sang các ngôn ngữ khác nhau bao gồm cả Yandex Translator và Google translate. Đặc biệt, với những nhân vật trong các tác phẩm kinh điển như Elvish – Chúa tể của những chiếc nhẫn, Yoda – Chiến tranh giữa các vì sao hay Groot – Vệ binh dải ngân hà họ đều không nói ngôn ngữ của loài người, các translation APIs còn cho phép chúng ta dịch được cả tiếng của họ trong phim nữa.
4. Affirmations API
Affirmations API được Tilde Ann Thurium tạo trên Github cho phép bạn truy cập thư viện những affirmation dễ nhìn nhất. Truy cập https://www.affirmations.dev/ và bạn sẽ được recommend những ý tưởng affirmation sáng tạo nhất và áp dụng cho dự án của mình.
Nếu vẫn không có API nào thật sự thu hút bạn thì hãy thử cân nhắc đến khía cạnh âm nhạc xem. Spotify có một nền tảng với các nguồn dữ liệu mở về thông tin ca sĩ, nhạc sĩ, bài hát, album, tạo và hiển thị danh sách phát và kể cả tạo một giao diện Spotify cho riêng cá nhân bạn luôn.
Kết luận
Hy vọng rằng một số API trên đây sẽ có thể cho bạn thêm thông tin cần thiết và hữu ích với các dự án tiếp theo của bạn.
Mười mấy năm về trước, ngày còn đang học đại học, mỗi lần đến ngày đăng ký môn học là mình được nghe điệp khúc hát mãi “server quá tải, số lượng sinh viên tranh nhau vào các lớp có nhiều gái xinh quá đông, quá nguy hiểm, mấy em vui lòng canh 12 giờ đêm, khi ko còn ai lên đăng ký môn học, chúng tôi mới đáp ứng kịp”
Ngày đó Server của trường nằm ở Nguyễn Văn Tráng, phòng server nhỏ như hang thỏ, mà chỉ xài đúng mấy ngày đầu học kỳ, nên thầy trưởng khoa ko thể nào xin ngân sách được để mà nâng cấp 10 mấy con server cho các em sinh viên xài thỏa thích.
Bài toán Server đó giờ được giải quyết ra sao? Serverless
Trước tiên cần khẳng định Serverless không phải là bạn không cần server. Một shop thú nuôi đơn giản, vài ngàn người mua hoa một tháng, làm bằng wordpress bạn sẽ không thấy được lợi ích từ việc sử dụng kiến trúc mới này, không những vậy còn là việc ném một cục tiền cho mấy thằng bán dịch vụ như Amazon
Trang bán thú nuôi, kiến trúc cũ sẽ là thế này
Tất cả những logic sẽ nằm ở ứng dụng phía server: từ authentication, page navigation, searching, transaction (code backend đó)
Yêu cầu cần có ngân sách, kế hoạch cụ thể, lắp đặt các hệ thống máy chủ, tìm một chỗ để máy, đảm bảo luôn có điện, luôn mát lạnh, đi dây, chọn nhà cung cấp mạng không bị cá mập cắn…
Nói chung bạn tự làm mọi thứ, hoặc bỏ tiền ra thuê một thằng làm mọi thứ, mà nó còn hay đòi hỏi thêm thắt này kia nọ, vô cùng tốn thời gian, nhân lực, tiền bạc, cơ sở hạ tầng.
Infrastructure as a service – IaaS, các dịch vụ cho thuê mặt bằng ra đời. Đáp ứng nhu cầu tiết kiệm chi phí ở thời điểm đầu, nhưng vẫn có thể bành trướng khi cần.
Bạn hình dung nó như việc mở một quán ăn, phải tìm mặt bằng, tìm người giữ xe, chỗ để xe cho khách, thu hút khách vào ăn, thanh toán, sửa chữa điện, nước… Những thằng IaaS là các trung tâm thương mại, nó lo hết mọi thứ khác, bạn chỉ việc bỏ tiền ra và thuê lại mặt bằng và kinh doanh.
Serverless là gì
Nó như một khái niệm kinh tế học, không có một cách định nghĩa chính xác Serverless là gì! Có thể hiểu theo 2 cách sau
Serverless được dùng để ám chỉ những ứng dụng sử dụng phần lớn (hoặc toàn bộ) dịch vụ “nhà hàng xóm” (third-party), được host trên cloud, cho các vấn đề ở phía server là logic và state (ví dụ trạng thái đăng nhập, một dạng của dịch vụ chăm sóc khách hàng thân thiết). Những ứng dụng để sử dụng (không phải những trang profile công ty, show hiệu ứng bay lượn portfolio, ví dụ như Facebook, ứng dụng đăng ký môn học, hoặc ứng dụng điện thoại bị chửi bới quá trời FaceApp, tức là mô hình này không chỉ áp dụng riêng cho web). Những dịch vụ thường được outsource cho nhà hàng xóm là gì: database có Parse, Firebase, authentication có Auth0, AWS Cognito. Mấy nhà này nằm trong khu “Backend as a Service” – BaaS, khi gắn vào hậu tố as a Service bạn có thể biết là nó nằm ở nhà hàng xóm.
Serverless cũng có nghĩa là ứng dụng đó logic server vẫn có, developer vẫn phải viết logic này, tuy nhiên, không giống kiến trúc truyền thống, nó chạy theo cơ chế “tiền trao-cháo múc” (event-trigger), không quan tâm anh bạn có ở chung nhà mình không (stateless compute container). Khái niệm này được @marak trên Twitter gọi là Function as a Service – FaaS, bạn có nhu cầu cắt tóc, gội đầu, uống cafe, đánh giày thì bạn ra tiệm hết, không dùng đồ nhà có sẵn nữa. Hiện tại, AWS Lambda là một trong những platform nổi tiếng nhất khi nói đến FaaS
Giờ nói tới FaaS, nó đang là trend, nó thay đổi cách chúng ta trước đây vẫn nghĩ về kiến trúc dưới server.
Phần authen trước đây được gửi nhà hàng xóm làm (cơ quan nhà nước chuyên cung cấp CMND)
Dữ liệu được đưa một về nhà kho quản lý, kiểu như Tiki bây giờ quá mệt quản lý kho hàng, các cửa hàng nhỏ lẻ tự quản lý kho, Tiki bán được thì chạy tới kho của bên thứ 3 lấy.
Với 2 thay đổi ở trên, điều này có nghĩa là một vài logic đã được nằm ở phía client, thí dụ, user session, bạn sẽ thấy rõ nhất ở các Single Page App chúng ta build, phần logic giao diện cho user đã và chưa đăng nhập nằm ở client – nhà user, những route nào user có thể vào nằm ở code client
Một vài hiển thị, ràng buộc tất nhiên vẫn được server nắm. Thí dụ “search”. Chúng ta có thêm một nhà gọi là “API Gateway”, dịch vụ giao nhận, tất cả các yêu cầu từ client đưa về đây, các anh em HTTP sẽ đi lấy dữ liệu từ kho về cho chúng ta.
Với tính năng đặt hàng, nó do một nhà** khác cung cấp. Những logic khác nhau, được tách và deploy thành những cục* khác nhau như vậy cách tiếp cận của FaaS cũng là cách tiếp cận rất phổ biến trong “Microservices”
Nó sẽ có những lợi ích i chang như Microservices, tất nhiên là có trả giá, có nhiều thứ để kiểm soát và theo dõi hơn, vấn đề bảo mật cũng không phải đơn giản như xưa, nằm ở nhiều nơi quá mà, bài toán đi đi lại tránh kẹt xe giữa các hệ thống khác nhau, biết đâu đi lạc vào chổ nào đó mất CMND luôn !!
Function as a Service
Nãy giờ nói FaaS nhiều quá rồi, giờ “đào sâu” nghiên cứu nó chút. Trích dẫn từ trang Amazon Lambda
AWS Lambda lets you run code without provisioning or managing servers. (1) … With Lambda, you can run code for virtually any type of application or backend service (2) – all with zero administration. Just upload your code and Lambda takes care of everything required to run (3) and scale (4) your code with high availability. You can set up your code to automatically trigger from other AWS services (5) or call it directly from any web or mobile app (6).
Diễn giải đoạn dài ngoằn kia
(1) FaaS là chạy backend code mà không cần quan tâm việc quản lý và bảo trì hệ thống server.
(2) FaaS không yêu cầu một framework hay thư viện cụ thể nào. Các function trên Lambda có thể được viết bằng Javascript, Python, Go, Java, Clojure, Scala, .NET.
(3) Deploy sẽ rất khác với hệ thống truyền thống. Tới *nhà** của FaaS chúng ta đưa đoạn code cho chủ nhà, còn lại chủ nhà làm gì thì làm.
(4) Scale sẽ tự động được chủ nhà làm. Nếu hệ thống cần đáp ứng 1000 request đồng thời, chủ nhà sẽ lo, bạn chỉ cần bơm tiền. Quan trọng nhất, bên cung cấp dịch vụ sẽ quản lý hết toàn bộ resource, xin giấy phép, nói chung là toàn bộ – bạn không cần làm gì với cluster, VM cả.
(5) Cung cấp cơ chế trigger ứng với các event bạn muốn.
(6) Mấy bên cung cấp dịch vụ, cho phép các function này trigger theo những sự kiện HTTP request, như ví dụ là search, và purchase, hoặc gọi trực tiếp lên các API được cung cấp bởi bên cung cấp
Case Study
PhotoVogue trang Vogue của Ý, chạy từ năm 2011, sau một năm chạy, photographer bu vô như kiến, server ở nhà riêng quá tải không chịu nổi.
Giám đốc kỹ thuật quyết định chuyển đổi toàn bộ hệ thống server ở nhà riêng sang AWS trong 3 tháng.
Chạy theo trend này, còn có những cái tên rất phổ biến là Uber, Pokemon Go, Airbnb, Clash of Clans và rất nhiều ứng dụng khác khi số lượng user và real-time data lớn
Những vấn đề mà team PhotoVogue đã gặp
Có hơn 130,000 photographer trên khắp thế giới sử dụng hệ thống để đưa ảnh lên, ước tính có khoảng 400,000 ảnh, với dung lượng tối đa mỗi hình là 50MB (bọn này chơi sang nhỉ)
Số lượng truy cập ngày càng tăng
Trải nghiệm sử dụng của user không tốt, thao tác xử lý quá chậm, up ảnh quá rùa
Với AWS, nó đã giải quyết các vấn đề sau cho PhotoVogue
Khả năng scale, dễ maintenance, quản lý chi phí rõ ràng
Lưu trữ hình trên Amazon S3
Khi up lên Amazon S3, bật trigger sử dụng AWS Lambda function, convert các file này qua gif, jpeg, png, tiff
Amazon API Gateway được sử dụng để làm tầng caching của REST API, Amazon CloudFront cho CDN
Còn vấn đề nào nữa không, mình hy vọng bạn nào chuyên gia vào chỉ giáo
Tài liệu tham khảo
📜 What is Serverless Architecture? What are its Pros and Cons?
Bài viết được sự cho phép của tác giả Đoàn Văn Tuyển
Lâu rồi mình mới quay lại viết, chủ đề mình đã muốn viết từ rất lâu rồi: UI/UX. Mình tự nhận không phải là chuyên gia về UX, nhưng mình có thời gian đọc, tìm hiểu thử nghiệm nên cũng có một số kiến thức để chia sẻ với các bạn. Những gì mình viết ở đây chủ yếu là kiến thức liên quan phần visualization (UX thực tế là một khía cạnh rộng lớn hơn). Như mình suy nghĩ thì UX/UI có một số nguyên tắc cần ghi nhớ: First thing first (ưu tiên cho điều quan trọng nhất), Don’t make me think và Consistent (2 cái đầu trùng với tên 2 quyển sách mình khá thích).
1. First thing first
FTF nghĩa là mình luôn luôn ưu tiên cho những thứ quan trọng nhất. Nghĩa là mình sẽ ưu tiên nhóm khách hàng quan trọng, nhóm tính năng quan trọng, thông tin quan trọng với khách hàng…. Cụ thể những thứ mình nghĩ thì như sau:
1.1 Mobile First: Hiện tại đa số các website vẫn sử dụng thiết kế cho mobile dạng Responsive (nghĩa là Desktop First — Mobile là ưu tiên sau). Giờ là thời buổi mobile, 80% khách hàng sử dụng mobile. Vậy việc thiết kế riêng cho Mobile là điều cực kỳ quan trọng. Cụ thể phần mobile thì phần cuối mình sẽ có một số ví dụ cụ thể hơn, còn ở đây mình cũng nêu một số ví thứ cần để ý:
Màn hình mobile khá nhỏ nên không thể hiển thị full thông tin như desktop => thế nên cần lựa chọn thông tin nào sẽ hiển thị trên mobile
Màn hình Mobile dạng dọc, chiều ngang khá hạn chế, thế nên các bảng biểu cần đều chỉnh thông tin lọt vào màn hình 320–400 pixel (so với 1366 đến 1920 của PC) hoặc tối thiểu cũng có thể scroll để nhìn được.
1.2 Để ý đến khung nhìn đầu tiên:
Ví dụ về việc khung nhìn đầu tiên không tốt, những thứ ít quan trọng được show lên ở khung nhìn đầu tiên. Ngoài ra phần khoảng trắng cũng không hợp lý.
Khung nhìn đầu tiên là khung nhìn của người dùng mà người dùng không cần Scroll ngang hoặc scroll xuống. Mình nên đặt những thông tin quan trọng nhất vào khung nhìn này. Thay vì việc đặt một banner quá to (và có thể ít thay đổi) thì nên thu nhỏ lại và đưa thông tin quan trọng lên. Việc này đôi khi cũng không được để ý trên mobile, một số màn hình khi vào chỉ nhìn được giao diện của tab hoặc nhứng thông số filter, trên mobile có thể ẩn bớt một số thành phần ít quan trọng để vùng nhìn đầu tiên có thể thể hiện được nhiều thông tin quan trọng. Vùng nhìn đầu tiên còn đặt biệt quan trọng với màn hình chính / màn hình dashboard.
1.3 Chức năng quan trọng:
Những menu quan trọng được đưa ra trang chủ, link quan trọng hiện ra luôn thay vì ẩn trong menu.
Một trong những vấn đề cần để ý nữa là chức năng quan trọng cần được dễ dàng điều hướng tới. Ngoài việc menu sắp xếp để sao người dùng dễ dàng tìm được những menu quan trọng nhất. Menu nếu cần có thể để hiển thị thay cho việc giấu đi, chức năng muốn người dùng click nhất thì hiển thị rõ lên. “Call to action” cần làm nổi bật và hiển thị ở vùng nhìn đầu tiên. Menu trên mobile có thể thể hiện luôn thay vì giấu đi trên mobile như đa số các website. Một trong những sai lầm kinh điển phần này là người dùng sử dụng quá nhiều icon mà quên đi text. Đôi khi bản thân icon không thể hiện chính xác thông tin (cùng 1 icon mỗi người có thể có hình dung khác nhau), thế nên khi dùng icon thì mình nên thể hiện cả text để người dùng có thể hiểu được chứ năng.
1.4 Thông tin quan trọng:
Thông tin quan trọng được đưa lên trên và nhấn mạnh, căn phải số để dễ dàng so sánh
Thông tin quan trọng trên màn hình cần làm nổi bật. Một số những chỗ mình thường là như sau:
Trong bảng biểu: Cột tổng xếp lên đầu thay cho cuối, sắp xếp dữ liệu theo thứ tự giảm dần (số to lên trước)
Các thông tin muốn nhấn mạnh như giảm giá, giá tiền, status, cảnh báo, CTA… cần highlight để thể hiện rõ (nếu nhiều thứ cần chú ý thì sử dụng nhiều level như in đậm, in hoa, tăng font-size, màu sắc…)
Chia nhỏ đoạn văn thành những đoạn ngắn hơn, highlight những thông tin quan trọng.
Đưa chữ vào ảnh cũng là một thủ thuật tạo sự chú ý.
Đây là một trong những quyển sách gối đầu giường cho những người muốn biết về UX. Như tiêu đề bạn đã hình dung ra thứ mình muốn nói trong nguyên tắc này. Phần này có một số ý mình muốn nói:
2.1 Hướng dẫn cho khách hàng mới:
Khách hàng mới thường là nhóm khách hàng bơ vơ nhất, vào một hệ thống hoàn toán mới thường không biết làm gì tiếp theo. Thông thường bạn nên có làm những thứ như sau:
Gửi email chào mừng và chia sẻ những nguồn lực hỗ trợ cho họ: Hotline, support mail, link đến Q&A (nếu có), tài liệu liên quan nên đọc….
Nên có Tour hướng dẫn trên giao diện hoặc hướng dẫn hiển thị ngay trang dashboard.
Các chức năng phức tạp nên sử dụng thiết kế kiểu Wizard để dẫn dắt người dùng.
Cá nhân mình nghĩ không nên có tài liệu hướng dẫn đồ sộ, không ai có thời gian đọc chỗ đó. Có chăng chỉ là tài liệu để khi gặp vấn đề thì tra cứu (chứ ko phải để đọc hết).
2.2 Hướng dẫn khi gặp lỗi:
Mỗi khi khách hàng làm gì đó sai (ví dụ nhập thông tin không đúng định dạng) luôn hiển thị thông tin cảnh báo với 2 nội dung: lỗi gặp phải là gì & cách khắc phục thế nào. Đây là một trong những lỗi rất hay gặp khi làm giao diện. Khách hàng rơi vào tình trạng này thường rất hoang mang và không biết làm gì tiếp theo. Một trong những thứ cần để ý nữa là khi khách hàng submit form và bị lỗi, bạn phải khôi phục lại form y hệt thông tin trước khi khách hàng submit. Đặc biệt với form nhiều thông tin thì điều này khiến khách hàng rất ức chế.
Một trong những chú ý nhỏ là mình nên sử dụng hiệu ứng để thể hiện có điều gì đó đã diễn ra. Thay vì âm thầm hiển thị lỗi thì hãy để một số hiệu ứng như: loading, slide down…. để gây chú ý cho người dùng.
Trong khi 2 nguyên tắc trên liên quan nhiều đến UX, thì nguyên tắc cuối lại liên quan đến UI nhiều hơn. Một trong những nguyên tắc theo mình là quan trọng nhất của UI là sự đồng nhất về thiết kế. Font chữ, khoảng cách, kích thước, màu sắc, vị trí đặt các button… tất cả đều cần sự đồng nhất. Nếu thiết kế dạng Mobile First bạn nên sử dụng thiết kế đã được chuẩn hoá của google (Material design system) hoặc Apple’s Flat Design. Hai Design System này có đầy đủ hướng dẫn cực kỳ chi tiết đến mức bạn chỉ cần đọc và áp dụng là đáp ứng được 90% nhu cầu trang mobile web của bạn. Dù Design System đề cập đến rất nhiều yếu tố nhưng mình xin nói về một số thành phần mình cho rằng quan trọng.
3.1 Typography:
Từ này dịch ra tiếng việt mình không rõ là gì nên để tiếng anh. Typography là nói đến các yếu tố liên quan đến chữ bao gồm: font chữ, in đậm in nghiêng gạch chân, font-size, màu chữ, cách dòng, chia cột chữ, khoảng cách giữa các paragraph….. Thực tế mình đôi khi mình không để ý nhưng tất cả những yếu tố trên khi đặt vào trang web muốn đẹp đều có những tỷ lệ nhất định và quan trọng nhất phải đồng nhất trên các trang. Những content cùng ý nghĩa phải có typography đồng nhất. Các button, status, form input, select đều cần có sử sự tương đồng này. Điều này ảnh hưởng rất lớn đến sự “đẹp” của website.
3.2 Khoảng cách và sự alignment:
Ví dụ về khoảng cách giữa các khối
Việc chia cột, khoảng cách các dòng, khoảng cách giữa các khối…. tất cả những thiết kế này cần có sự tương đồng giữa các trang. Khoảng cách trong form, khoảng cách tớ hai lề… tất cả những yếu tố này cũng cần có sự tương đồng. Một gợi ý nhỏ mình hay thực hiện ở phần này như sau:
Với màn hình điện thoại thì nên để khoảng cách giữa khối chính và hai lề nhỏ (để tăng không gian hiển thị)
Hạn chế dùng bo viền, sử dụng hai khối màu khác nhau để phân chia.
Khoảng cách giữa khối dạng cột thì nhỏ hơn khoảng cách giữa hai dòng.
Khoảng cách giữa hai yếu tố liên quan gần hơn so với khoảng cách giữa hai yếu tố ít liên quan.
3.3 Khoảng trắng (đặc biệt trên mobile).
Ví dụ về việc tận dụng không gian trên Mobile.
Khi thiết kế thì một trong những yếu tố quan trọng là khoảng trắng, đặc biệt quan trọng trên Mobile. Vì màn hình Mobile nhỏ, thế nên bạn chắc không muốn scroll chục màn hình để xem thông tin, do vậy thiết kế trên mobile thường tìm cách làm đầu màn hình. Khoảng trắng trên giao diện nên hạn chế chỉ cần đủ để đáp ứng tính thẩm mỹ.
3.4 Nguyên tắc trình bày các loại dữ liệu khác nhau
Một trong những nguyên tắc có thể có nhiều bạn ít để ý là nguyên tắc trình bày văn bản, đặt biệt là những văn bản trong bảng biểu, mình luôn cố gắng tuân thủ các nguyên tắc này, điều này giúp cho thông tin được hiển thị mạch lạc hơn rất nhiều.
Số luôn căng lề phải, sử dụng dấu phẩy/chấm để phân chia số phần ngàn. Nếu có thêm số sau số thập phân thì số lượng chữ số sau số thập phân hiển thị phải luôn bằng nhau ở tất cả các dòng trong cùng 1 cột
Sử dụng ký tự (-) thay cho những dòng trắng hoặc số giá trị 0
Đặt khoảng trắng chính xác khi bỏ các dấu câu như: (.,:;’)
Viết hoa đầu dòng, tiêu đề.
… Ngoài ra còn có rất nhiều nguyên tắc để đảm bảo sự đồng nhất, để nhìn, dễ đọc nữa, mỗi team nên có một danh sách cho việc này.
Tóm lại UI/UX là chủ đề dài tập, những gì mình nói ở đây mới chỉ là một phần nhỏ của vấn đề. Mình hy vọng ai đó đọc được bài viết này nếu thấy hay hãy chia sẻ lại cho bạn bè và những người bạn cho rằng cần thiết.
Bài viết của mình sử dụng khá nhiều kiến thức mình học được từ buổi trao đổi với Tùng Jacob bên TGDD và những slide của bạn ấy. Mọi người có thể xem thêm thông tin tại những link sau:
Bài viết được sự cho phép của tác giả Trần Anh Tuấn
Chắc hẳn không ít các bạn khi code web thường hay cân nhắc việc sử dụng đơn vị như thế nào cho hợp lý mà lại hiệu quả. Nào là code trên desktop rồi khi responsive xuống mobile thì bị vỡ layout, cỡ chữ do đơn vị cố định rồi phải chỉnh css từng thành phần…
Ngoài những đơn vị như px, %, vw, vh, pt… thì trong số đó có 2 đơn vị em và rem luôn làm nhiều bạn nhầm lẫn, chưa nắm rõ nên sử dụng trong việc code khá là khó khăn, trắc trở.
Để giải quyết vấn đề đó nên hôm nay mình xin chia sẻ bài đầu tiên về 2 đơn vị em và rem này nhằm giúp các bạn có thể hiểu rõ và áp dụng chúng vào việc code giao diện ra sao nhé. Trước khi vào demo thì mình xin nhắc lại chút về khái niệm của 2 đơn vị em và rem này nha.
# Khái niệm về đơn vị em và rem
rem: là đơn vị tham chiếu tỷ lệ so với phần tử gốc của website ở đây là thẻ <html> dựa vào giá trị của thuộc tính font-size
em: là đơn vị tham chiếu tỷ lệ so với phần tử cha trực tiếp chứa nó hoặc chính nó dựa vào giá trị của thuộc tính là font-size
Sơ đồ minh họa sự khác nhau giữa đơn vị em và rem
# Áp dụng thực tế
Mình chắn hẳn nhiều bạn đọc xong và thậm chí coi sơ đồ mà vẫn chưa hiểu lắm. Trước đây mình cũng thế. Và cách tốt nhất để hiểu và nắm rõ chúng đó là bắt tay vào code. Nên ở đây mình có làm 1 demo nho nhỏ để cho các bạn dễ hình dung hơn nè.
Đầu tiên là html như thế này:
<html><head><title>Em vs Rem</title></head><body><div class="box"><div class="em">EM</div><div class="rem">REM</div></div></body></html>
Tiếp đến là css:
html {font-size:15px;}.box {color:white;display:flex;}.em {width:10em;height:10em;background-color:red;}.rem {width:10rem;height:10rem;background-color:blue;}
Ta được kết quả như sau. Bạn vẫn chưa hiểu ? Mình có giải thích chi tiết ở bên dưới cho các bạn
# Giải thích chi tiết
Đầu tiên mình tạo html layout gồm có 1 div có class box bọc ngoài và có 2 div bên trong tương ứng với class em rem sau đó mình set cho thẻ <html> có thuộc tính font-size là 15px và lần lượt 2 ô là màu đỏ xanh cho các bạn dễ phân biệt.
Cho nên lúc này 1em = 1rem = 15px. Như các bạn nhìn vào demo ở trên thì 2 ô đều bằng nhau là 10(em-rem) x 15px = 150px của mỗi ô.
À có chỗ này sẽ có bạn hỏi là đơn vị em phụ thuộc vào phần tử cha chứa nó chứ có phải thẻ <html> đâu sao mà 1em = 15px ?
Mình xin giải thích là vì do lúc này chính nó(class em) và phần tử cha chứa nó là thẻ div có class box mình chưa set thuộc tính font-size nên nó sẽ phụ thuộc phần tử lớn hơn ở ngoài đó là thẻ <body> nhưng thẻ <body> cũng chưa set thuộc tính font-size nên nó cứ thế lấy ra ngoài cùng cho tới thẻ <html>. Nên ở trên 1em = 1rem = 15px là theo thẻ <html> đấy.
Tuy nhiên bây giờ mình sẽ set cái thuộc tính font-size của thẻ div có class box là 20px thì chắn chắn sẽ có thay đổi. Các bạn nhìn dưới đây nha.
.box {font-size:20px;}
Ô màu đỏ có đơn vị em sẽ to hơn ban đầu vì như mình đã nói ở trên là đơn vị em phụ thuộc vào giá trị thuộc tính font-size của chính nó hoặc phần tử cha trực tiếp chứa nó. Cho nên lúc này ô màu đỏ sẽ có kích thước là 10em x 20px = 200px.
html {font-size:25px;}
Còn ô màu xanh(rem) do phụ thuộc vào thẻ <html> nên khi mình thay đổi giá trị font-size của thẻ <html> sang 25px thì ô màu xanh cũng sẽ thay đổi kích thước. Và lúc này giá trị của nó sẽ là 10rem x 25px = 250px. Nhìn vào demo bạn sẽ thấy nó to hơn ban đầu và to hơn ô màu đỏ luôn.
# Lời kết
Có 1 chi tiết nhỏ mình quên nói đó là nếu mình không set giá trị của thuộc tính font-size cho thẻ <html> thì font-size mặc định của thẻ <html> là 16px nha.
Hi vọng với giải thích và ví dụ demo của mình sẽ giúp các bạn dễ dàng hiểu hơn về 2 đơn vị em và rem này. Ở bài sau mình sẽ chia sẻ về cách sử dụng 2 đơn vị này vào dự án nhé. Nếu các bạn có ý kiến gì hay hoặc góp ý thì bình luận để giúp mình cải thiện hơn nha. Cám ơn các bạn đã đọc và chúc các bạn một ngày làm việc tốt lành.
Dù có là 1 lập trình viên web hay không, chắc hẳn bạn cũng đã bắt gặp HTTP status code (mã trạng thái HTTP) ít nhất 1 hay nhiều lần rồi đúng không nào?
200, 404, 500… đều là những HTTP status code phổ biến. Thậm chí các truyện vui hay ảnh chế meme về 404 cũng khá nổi tiếng và đầy rẫy trên mạng Internet mà hầu hết bất kỳ ai cũng có thể hiểu được.
Vậy thì có bao giờ bạn thắc mắc HTTP status code là gì và ý nghĩa các con số của chúng hay chưa? Hôm nay chúng ta sẽ nói tổng quát 1 chút về HTTP status code và ý nghĩa nằm ẩn sau các con số đó nhé!
HTTP Status Code – Mã trạng thái HTTP là gì?
Khi được nhận và phiên dịch 1 yêu cầu HTTP từ phía client, HTTP status code sẽ được máy chủ cung cấp để đáp ứng yêu cầu đó của họ. Nó bao gồm code từ IETF Request for Comments (RFC), các thông số kỹ thuật khác và 1 số code bổ sung được sử dụng trong 1 số ứng dụng phổ biến của giao thức HTTP.
Chữ số đầu tiên của HTTP status code chỉ định 1 trong 5 loại phản hồi quy chuẩn. Các cụm tin nhắn được hiển thị chỉ mang tính tượng trưng, nhưng cũng có thể cung cấp bất kỳ thông tin bổ sung nào để chúng ta có thể đọc được. Trừ khi có những chỉ định khác, HTTP status code được xem như 1 phần của quy chuẩn HTTP/1.1 (RFC 7231).
Cơ Quan Cấp Số Được Ấn Định Trên Internet (tức IANA hay The Internet Assigned Numbers Authority) chính là nơi duy trì sổ đăng ký chính thức của các HTTP status code.
Tất cả các HTTP status code phản hồi được chia ra thành 5 hạng mục riêng biệt và là các số nguyên có 3 chữ số. Chữ số đầu được dùng để xác định loại phản hồi, trong khi 2 chữ số cuối thì không có bất kỳ vai trò phân loại nào. HTTP status code sẽ cho ta biết liệu 1 yêu cầu HTTP cụ thể đã được hoàn thành thành công hay chưa.
Các ứng dụng hiểu HTTP status code không cần phải biết hết tất cả code, tức là dù code không xác định cũng có cụm từ để chỉ lý do không xác định. Cụm từ này không cho phía client nhiều thông tin nhưng các ứng dụng HTTP đó phải hiểu được nó thuộc 1 trong 5 hạng mục riêng biệt. 5 hạng mục đó bao gồm:
– 1xx (100 – 199): Information responses / Phản hồi thông tin – Yêu cầu đã được chấp nhận và quá trình xử lý yêu cầu của bạn đang được tiếp tục.
– 2xx (200 – 299): Successful responses / Phản hồi thành công – Yêu cầu của bạn đã được máy chủ tiếp nhận, hiểu và xử lý thành công.
– 3xx (300 – 399): Redirects / Điều hướng – Phía client cần thực hiện hành động bổ sung để hoàn tất yêu cầu.
– 4xx (400 – 499): Client errors / Lỗi phía client – Yêu cầu không thể hoàn tất hoặc yêu cầu chứa cú pháp không chính xác. 4xx sẽ hiện ra khi có lỗi từ phía client do không đưa ra yêu cầu hợp lệ.
– 5xx (500 – 599): Server errors / Lỗi phía máy chủ – Máy chủ không thể hoàn thành yêu cầu được cho là hợp lệ. Khi 5xx xảy ra, bạn chỉ có thể đợi để bên hệ thống máy chủ xử lý xong.
Danh sách đầy đủ các HTTP status code (code + cụm từ chỉ lý do):
1. Information responses / Phản hồi thông tin:
– 100 Continue: Phản hồi tạm thời này cho biết rằng mọi thứ tới hiện tại vẫn ổn và phía client nên tiếp tục yêu cầu hay bỏ qua phản hồi nếu yêu cầu đã hoàn tất.
– 101 Switching Protocol: Code này được gửi để phản hồi header yêu cầu Upgrade từ phía client và cho biết giao thức máy chủ đang chuyển sang.
– 102 Processing (WebDAV): Code này cho biết rằng máy chủ đã nhận và đang xử lý yêu cầu, nhưng phản hồi vẫn chưa có hiệu lực.
– 103 Early Hints: Được sử dụng để trả về một số tiêu đề phản hồi trước message HTTP cuối cùng.
2. Successful responses / Phản hồi thành công:
– 200 OK: Yêu cầu đã thành công. Ý nghĩa của thành công còn phụ thuộc vào phương thức HTTP là gì:
GET: Tài nguyên đã được tìm nạp và được truyền trong nội dung thông điệp. HEAD: Các header thực thể nằm trong nội dung thông điệp. PUT hoặc POST: Tài nguyên mô tả kết quả của hành động được truyền trong nội dung thông điệp. TRACE: Nội dung thông điệp chứa thông báo yêu cầu khi máy chủ nhận được.
– 201 Created: Yêu cầu đã thành công và kết quả là một tài nguyên mới đã được tạo. Đây thường là phản hồi được gửi sau các yêu cầu POST hoặc một số yêu cầu PUT.
– 202 Accepted: Yêu cầu đã được nhận nhưng chưa được thực hiện. Yêu cầu này là non-committal, vì không có cách nào trong HTTP để gửi sau đó một phản hồi không đồng bộ cho biết kết quả của yêu cầu. Nó dành cho các trường hợp trong đó 1 quá trình / máy chủ khác xử lý yêu cầu hoặc để xử lý hàng loạt.
– 203 Non-Authoritative Information: Code phản hồi này có nghĩa là siêu thông tin được trả về không hoàn toàn giống với thông tin có sẵn từ máy chủ gốc, nhưng được thu thập từ phần copy local hay của bên phía thứ 3. Code này chủ yếu được sử dụng để phản chiếu hoặc sao lưu tài nguyên khác. Ngoại trừ trường hợp cụ thể đó, thông thường phản hồi “200 OK” được ưu tiên cho trạng thái này.
– 204 No Content: Không có nội dung để gửi cho yêu cầu này, nhưng các header có thể hữu dụng. User-agent có thể cập nhật các header đã lưu trong bộ nhớ cache cho tài nguyên này bằng các header mới.
– 205 Reset Content: Cho user-agent biết để reset document đã gửi yêu cầu này.
– 206 Partial Content: Code phản hồi này được dùng khi Range header được gửi từ client để yêu cầu chỉ 1 phần của nguồn tài nguyên.
– 207 Multi-Status (WebDAV): Truyền tải thông tin về nhiều nguồn tài nguyên, đối với các trường hợp mà nhiều status code có thể đều thích hợp.
– 208 Already Reported (WebDAV): Được sử dụng trong 1 phần tử phản hồi <dav:propstat> để tránh liệt kê nhiều lần các thành viên nội tại của nhiều liên kết vào cùng 1 tập hợp.
– 226 IM Used (HTTP Delta encoding): Máy chủ đã hoàn thành yêu cầu GET cho nguồn tài nguyên và phản hồi là sự trình bày kết quả của 1 hoặc nhiều thao tác instance được áp dụng cho instance hiện tại.
– 300 Multiple Choice: Yêu cầu có thể có nhiều hơn 1 phản hồi khả dụng. User-agent hay user nên chọn 1 trong số đó. (Không có cách chuẩn hóa nào để chọn 1 trong các phản hồi, nhưng HTML liên kết đến các khả năng được khuyến nghị để user có thể chọn.)
– 301 Moved Permanently: URL của tài nguyên được yêu cầu đã được thay đổi vĩnh viễn. URL mới được đưa ra trong phần phản hồi.
– 302 Found: Code phản hồi này có nghĩa là URI của tài nguyên được yêu cầu đã được thay đổi tạm thời. Những thay đổi khác trong URI có thể được thực hiện trong tương lai. Do đó, chính URI này sẽ được client sử dụng trong các yêu cầu trong tương lai.
– 303 See Other: Máy chủ gửi phản hồi này để điều hướng client lấy nguồn tài nguyên tại 1 URI khác với 1 yêu cầu GET.
– 304 Not Modified: Code này được sử dụng cho mục đích caching. Nó cho client biết rằng phản hồi chưa được điều chỉnh, nên client có thể tiếp tục sử dụng cùng phiên bản phản hồi trong bộ nhớ cache.
– 305 Use Proxy: Được xác định trong phiên bản trước của HTTP specification để chỉ ra rằng phản hồi được yêu cầu phải được truy cập bằng proxy. Nó được yêu cầu do quan ngại về phần bảo mật liên quan đến cấu hình trong băng tần của proxy.
– 306 unused: Mã phản hồi này không còn được sử dụng nữa, nó được bảo lưu và chỉ được sử dụng trong phiên bản trước của HTTP/1.1 specification.
– 307 Temporary Redirect: Máy chủ gửi phản hồi này để điều hướng client tới lấy tài nguyên được yêu cầu tại 1 URI khác với cùng 1 phương thức đã được sử dụng trong yêu cầu trước đó. Code này có cùng ý nghĩa như code phản hồi HTTP 302 Found, ngoại trừ việc user-agent không được thay đổi phương thức HTTP sử dụng: nếu POST được dùng trong yêu cầu đầu tiên, POST phải được sử dụng trong yêu cầu thứ hai.
– 308 Permanent Redirect: Điều này có nghĩa là tài nguyên hiện được đặt cố định tại 1 URI khác, được chỉ định bởi header Location: HTTP Response. Code này có cùng ý nghĩa như code phản hồi HTTP 301 Moved Permanently, ngoại trừ việc user-agent không được thay đổi phương thức HTTP sử dụng: nếu POST được dùng trong yêu cầu đầu tiên, POST phải được sử dụng trong yêu cầu thứ hai.
4. Client errors / Lỗi phía client:
– 400 Bad Request: Máy chủ không thể hiểu yêu cầu do cú pháp không hợp lệ.
– 401 Unauthorized: Cho dù quy chuẩn HTTP chỉ định “unauthorized” (không có thẩm quyền), nhưng nó có nghĩa phản hồi này là “unauthenticated” (chưa được xác thực). Có nghĩa là, client phải các tự xác thực chính mình để nhận được phản hồi đã yêu cầu.
– 402 Payment Required: Code phản hồi này được dành cho những lần sử dụng trong tương lai. Mục đích ban đầu của việc tạo mã này là sử dụng nó cho các hệ thống thanh toán kỹ thuật số, tuy nhiên status code này rất hiếm khi được sử dụng và không tồn tại quy ước tiêu chuẩn nào.
– 403 Forbidden: Client không có quyền truy cập vào phần nội dung, nghĩa là nó không được phép, vì vậy máy chủ từ chối cung cấp tài nguyên được yêu cầu. Không giống như 401, danh tính của client đã được máy chủ nhận biết.
– 404 Not Found:
– 405 Method Not Allowed: Phương thức yêu cầu được máy chủ nhận biết nhưng đã bị vô hiệu hóa và không thể sử dụng được. Ví dụ: 1 API có thể cấm XÓA 1 nguồn tài nguyên. 2 phương thức bắt buộc, GET và HEAD, không bao giờ được vô hiệu hóa và không được trả về code lỗi này.
– 406 Not Acceptable: Phản hồi này được gửi khi máy chủ web, sau khi thực hiện server-driven content negotiation, không tìm thấy bất kỳ nội dung nào phù hợp với các tiêu chí do user-agent đưa ra.
– 407 Proxy Authentication Required: Code này tương tự như 401 nhưng việc xác thực là cần thiết để được thực hiện bởi proxy.
– 408 Request Timeout: Phản hồi này được gửi trên 1 kết nối idle bởi 1 số máy chủ, ngay cả khi không có bất kỳ yêu cầu nào trước đó của client. Có nghĩa là máy chủ muốn tắt kết nối không sử dụng này. Phản hồi này được sử dụng nhiều hơn vì 1 số trình duyệt như Chrome, Firefox 27+ hoặc IE9, sử dụng cơ chế tiền kết nối HTTP để tăng tốc độ lướt web. Cũng lưu ý rằng 1 số máy chủ chỉ tắt kết nối luôn mà không hề gửi thông báo này.
– 409 Conflict: Phản hồi này được gửi khi 1 yêu cầu xung đột với trạng thái hiện tại của máy chủ.
– 410 Gone: Phản hồi này được gửi khi nội dung được yêu cầu đã bị xóa vĩnh viễn khỏi máy chủ, không có địa chỉ chuyển tiếp. Client phải xóa bộ nhớ cache và liên kết của mình tới nguồn tài nguyên. HTTP spectication dự định status code này được sử dụng cho “các dịch vụ khuyến mại, có thời hạn”. Các API không nên bắt buộc phải chỉ ra các tài nguyên đã bị xóa bằng status code này.
– 411 Length Required: Máy chủ đã từ chối yêu cầu vì trường header Content-Lenghth không được xác định và máy chủ thì yêu cầu chuyện đó.
– 412 Precondition Failed: Client đã chỉ ra các điều kiện tiên quyết trong các header của nó mà máy chủ không đáp ứng được.
– 413 Payload Too Large: Thực thể yêu cầu lớn hơn giới hạn do máy chủ xác định, máy chủ có thể đóng kết nối hoặc trả về trường header Retry-After.
– 414 URI Too Long: URI được yêu cầu bởi client dài hơn mức máy chủ muốn thông dịch.
– 415 Unsupported Media Type: Định dạng phương tiện của dữ liệu được yêu cầu không được máy chủ hỗ trợ, do đó máy chủ đang từ chối yêu cầu.
– 416 Range Not Satisfiable: Client yêu cầu một phần của tập tin nhưng máy chủ không thể cung cấp nó. Trước đây được gọi là “Requested Range Not Satisfiable”.
– 417 Expectation Failed: Máy chủ không thể đáp ứng các yêu cầu của trường Expect trong header.
5. Server errors / Lỗi phía máy chủ:
– 500 Internal Server Error: Một thông báo chung, được đưa ra khi máy chủ gặp phải một trường hợp bất ngờ, message cụ thể không phù hợp.
– 501 Not Implemented: Máy chủ không công nhận các phương thức yêu cầu hoặc không có khả năng xử lý nó.
– 502 Bad Gateway: Máy chủ đã hoạt động như một gateway hoặc proxy và nhận được một phản hồi không hợp lệ từ máy chủ nguồn.
– 503 Service Unavailable: Máy chủ hiện tại không có sẵn (hiện đang quá tải hoặc bị down để bảo trì). Đây chỉ là trạng thái tạm thời.
– 504 Gateway Timeout: Máy chủ đã hoạt động như một gateway hoặc proxy và không nhận được một phản hồi từ máy chủ nguồn.
– 505 HTTP Version Not Supported: Máy chủ không hỗ trợ phiên bản “giao thức HTTP”.