Home Blog Page 108

Trình duyệt ẩn danh có thực sự an toàn như bạn nghĩ?

Trình duyệt ẩn danh có thực sự an toàn như bạn nghĩ?

Bài viết được sự cho phép của blogchiasekienthuc.com

Internet và mạng xã hội đang ngày càng phát triển, kéo theo đó là nguy cơ dữ liệu cá nhân của người dùng dễ bị đánh cắp một cách bất hợp pháp.

Đồng ý là mạng xã hội nói riêng hay Internet nói chung là sự hòa nhập của cả thế giới, nhưng như thế không có nghĩa là chúng ta không có quyền giữ kín những thông tin cá nhân riêng tư !

  8 câu hỏi phỏng vấn dành cho các lập trình viên Mobile app
  Mười điều răn dành cho lập trình viên

Để đáp ứng cho nhu cầu đó thì rất nhiều trình duyệt web đã thêm tính năng lướt web ẩn danh cho người dùng, hay những phần mềm hỗ trợ ẩn danh trên Internet. Và thực tế thì chế độ ẩn danh này cũng đã xuất hiện từ rất lâu rồi.

trinh-duyet-an-danh-co-an-toan-khong (2)

#1. Trình duyệt web ẩn danh là gì?

Chế độ ẩn danh về bản chất là sẽ không lưu lại lịch sử duyệt web, cũng như dữ liệu cookie trên máy tính của bạn.

Nếu bạn nào có chút kiến thức về máy tính thì đều biết rằng, khi duyệt web ở chế độ thông thường thì những dữ liệu này sẽ nằm trên máy tính và có một thư mục nhất định để chứa nó. Mục đích là để giúp bạn lướt web nhanh hơn, thuận tiện hơn..

Việc không lưu lại dữ liệu duyệt web trên máy tính sẽ hạn chế tối đa việc các phần mềm gián điệp đang ngầm thu thập dữ liệu mà người dùng vô tình dính phải.

trinh-duyet-an-danh-co-an-toan-khong (1)

#2. Trình duyệt web ẩn danh liệu có thực sự an toàn?

Như mình đã nói ở trên, trình duyệt web ẩn danh chỉ đơn giản là không lưu lại dữ liệu trên máy tính của bạn.

Nhưng điều này không đồng nghĩa với việc nó sẽ không bị thu thập bởi các bên thứ ba: như là nhà mạng, các nhà quảng cáo hay thậm chí là chính trình duyệt web bạn đang sử dụng.

trinh-duyet-an-danh-co-an-toan-khong (1)

Về cơ bản thì khi bạn duyệt web, những đối tượng sau có thể biết được những dữ liệu duyệt web của bạn:

1. Nhà mạng: Nghe thì có vẻ hơi vô lý và có phần đổ oan cho nhà mạng nhỉ – nhưng thực tế là như vậy !

Nhà mạng hoàn toàn có thể truy được IP mà bạn đang sử dụng đã từng duyệt web như thế nào, thậm chí là làm gì trên đó. Điều này là hoàn toàn có thể !

Hãy nhớ rằng, các nhà mạng Việt Nam đã không ít lần chặn các trang web nước ngoài để người dùng không truy cập được, vậy nên việc nắm rõ mọi thông tin sử dụng của bạn trên Internet là điều hoàn toàn có thể.

Và thông qua những việc xử lý tội phạm công nghệ cao trên Internet thì bạn cũng đủ hiểu được vấn đề rồi đúng không 🙂

Tuy nhiên, mình chỉ dám khẳng định là họ nắm rõ thôi, còn họ có sử dụng nó cho mục đích gì khác hay không thì mình chịu nhé 😀

2. Plugin (tiện ích mở rộng) cài trên trình duyệt: Như đã nói, ẩn danh chỉ ngăn dữ liệu không lưu trên máy tính, còn bản thân các Plugin thì đa số đều chạy qua hệ thống online, vậy nên vẫn có thể truy cập vào dữ liệu người dùng khi duyệt web.

3. Phần mềm được cài trên máy: Chắc hẳn các bạn đã không ít lần gặp trường hợp đột nhiên máy tính chạy chậm lại, hay việc lướt web bị chậm đi đáng kể, hoặc thậm chí là xuất hiện những quảng cáo vô cùng lạ…

Hãy cẩn thận với những trường hợp này và ngay bây giờ, bạn hãy cài đặt phần mềm diệt virus đi nhé. Bởi máy tính của bạn rất có thể đã dính phần mềm quảng cáo độc hại và nó đang sử dụng đường truyền Internet của bạn đấy.

#3. Có cách nào để không bị lộ thông tin trên Internet không?

Nhiều bạn cho rằng nếu thực hiện Fake IP, hay thay đổi DSN…..là có thể thoát được. Nhưng mình xin khẳng định là bạn có làm gì đi chăng nữa thì bạn cũng không thoát được đâu.

trinh-duyet-an-danh-co-an-toan-khong (3)

Nói đơn giản thế này cho các bạn dễ hiểu nhé, đôi lúc chúng ta sẽ thấy báo đài thông tin về việc điều tra các hacker tấn công vào các web chính phủ, và kết quả như thế nào thì các bạn cũng đều đã biết rồi, họ đã truy ra được nhóm nào, thậm chí là ở khu vực nào…

Đấy! các bạn thấy không, hacker có trình độ cao như vậy, thậm chí được nuôi bởi chính phủ mà vẫn bị truy vết thì không có gì là không được với dân đen chúng ta cả, những người mà kiến thức máy tính chỉ ở mức độ rất cơ bản.

Nói chung là sẽ truy vết được, vấn đề là ở mức độ nào mà thôi, họ có thực sự muốn truy ra bạn hay không thôi. Nhưng vềcơ bản thì việc Fake IP sẽ giúp cho những người dùng phổ thông an toàn hơn trên Internet.

Để hạn chế việc bị lộ thông tin thì về mặt lý thuyết, chúng ta hãy hạn chế cài những tiện ích mở rộng không an toàn, cài những phần mềm không rõ nguồn gốc, những phần mềm/ ứng dụng c.r.a.c.k…

Nhưng tất nhiên, đó chỉ là giải pháp tạm thời để tránh những thông tin của mình bị bên nào đó lợi dụng cho mục đích xấu mà thôi.

Nếu ví Internet như một con dao thì phần đông chúng ta đang cầm phần dao sắc nhọn, còn các nhà mạng đang cầm phần chuôi. Chúng ta chỉ có thể tuân thủ theo luật chơi do họ tạo ra mà thôi !

Có chăng, điều an ủi nhất là nếu không làm việc gì trái pháp luật thì những thông tin đó vốn biết cũng chẳng để làm gì cả (ý mình là đang nói nhà mạng nhé), còn với những kẻ có chủ đích xấu thì chúng ta cũng đành chịu.

#4. Lời Kết

Vâng, trên đấy là những quan điểm của mình về việc chế độ ẩn danh trên trình duyệt liệu có an toàn như chúng ta nghĩ hay không.

Có thể kết luân lại là, một khi đã tham gia vào môi trường Internet thì không thể giấu giếm hết những thứ riêng tư được – mà thay vào đó bạn hãy hạn chế tối đa việc để những thứ riêng tư lên Internet, vậy thôi !

Điều này cũng là lý do mà một số người nổi tiếng không sử dụng bất kì một mạng xã hội nào, vì họ hiểu rõ không thể nào giấu được nếu tham gia.

Lê Đinh Hoàng Vũ – Bài viết gốc tại blogchiasekienthuc.com

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

Xem thêm tuyển dụng các it giỏi hấp dẫn trên TopDev

Một người kiểm thử có tâm

kiếm thử một người có tâm

Bài viết được sự cho phép của tác giả To Thi Van Anh

Bạn nghĩ thế nào là một người kiểm thử có tâm? Có giống như một người chụp ảnh có tâm mà bạn vẫn dành cho người nào chụp cho bạn bức ảnh mà bạn thấy bạn xinh lung linh nhất không?

  A/B testing và những tiêu chí chính để đánh giá sự thành công của ASO
  Automation skills cho tester già mà lười

Mình thấy là làm gì mà có tâm một chút là cũng được người ta yêu quý hết – mặc dù không biết trong lòng người ta nghĩ thế nào nhưng mà cứ khen là ta phải vui cái đã! hihi

Trong công việc cũng vậy, làm việc tốt không phải chỉ vì đồng lương mà còn là trách nhiệm đối với cái mình đang làm, đầu tiên cứ phải là cố gắng hết sức đã, kết quả có thể đạt được như mong đợi, có khi còn hơn, rồi cũng có khi không được như mình mong muốn ban đầu nhưng mà mình vẫn tin là dù thế nào tự chúng ta cũng sẽ rút ra được một số bài học nào đó cho bản thân, để lần sau tiếp tục cố gắng nhiều hơn nữa, và quan trọng là sẽ không mắc phải sai lầm giống như trước nữa. 😀

Blank poster in a white loft interior with sunlight, mock up, 3d render

Dưới góc nhìn của mình (có tham khảo một vài nơi mà mình đã tìm hiểu được) mình sẽ đưa ra một so sánh nho nhỏ để các bạn thấy được một người kiểm thử có tâm và chưa có tâm khác nhau ở những điểm nào nhé. Các bạn có thể để lại bình luận và nhận xét phía dưới cho mình về các ý dưới này nếu có điểm gì đó chưa đúng hoặc cần bổ sung nhé!

Yếu tố Người bình thường (Chị A) Người có tâm (Chị B)
1. Chất lượng test case Chị A nghĩ rằng chị chỉ cần viết test case với một chất lượng ở mức bình thường và có thể chấp nhận được là được.
Test case chị viết có thể là đã đủ theo các yêu cầu của hệ thống, nhưng chị lại không quan tâm đến việc tối ưu các test case mà chị đã viết, chị cũng không quan tâm lắm đến việc các bước thực hiện của chị nhiều chỗ hơi rườm rà và đôi khi thì lại chưa đầy đủ và không dễ để thực hiện lắm!
Có thể vấn đề của chị chị nhìn ra rồi, hoặc chưa nhìn ra. Cơ mà chị vẫn chẹp cho qua!
Chị B thì khác, chị ciết test case với chất lượng rất tốt, chi tiết và đầy đủ các thông tin và trường hợp cần thiết, và kết quả review của người khác dành cho các test case mà chị viết không có quá nhiều comment.
Mọi người rất ấn tượng với test case của chị B vì sự chi tiết và cẩn thận từ những chi tiết nhỏ, rồi từ chất lượng cho đến sự trình bày.
2. Chất lượng bug Chị A nghĩ rằng viết bug cũng chỉ đơn thuần là viết bug, để cho thằng dev biết là mày đã làm sai, hệ thống đã có bug, đôi khi với nhiều trường hợp có thể cung cấp thêm được thông tin nhưng chị lại không đưa vào, hoặc có khi hơi sơ sài nữa. Không chỉ là viết bug, chị B còn cung cấp thêm đầy đủ thông tin giá trị đầu vào của trường hợp này, chị cũng tìm hiểu thêm và sâu hơn những nguyên nhân liên quan khác có thể gây ra vấn đề đó, giúp dev có thể debug và giải quyết vấn đề nhanh hơn.
3. Hiệu quả log bug Chị A log bug cũng tốt nhưng đôi khi chính chị hoặc dev không tái hiện lại được bug mà chị đã log.
(Đọc cột bên cạnh để thấy là chị A có thể thiếu gì nhé :v)
Trước khi lug bug, chị B đã thực hiện kiểm tra kỹ càng nhiều lần hệ thống trên môi trường test của chị và cả ở môi trường trên máy khác nữa. Chị cũng luôn luôn cung cấp đầy đủ các tài liệu và thông tin cần thiết khi viết bug như: thông tin bản build, hệ điều hành, hình ảnh bug, các bước thực hiện để đảm bảo rằng là ai cũng có thể tái hiện được cái bug này.
(Chắc là chị B đã đọc bài về viết bug hiệu quả của mình rồi, bạn nào chưa đọc thì đọc để như chị B nhé Kaka)
4. Trong quá trình kiểm thử Chị A có phương pháp tư duy và hành động theo lối mòn, không có hoặc rất ít sự sáng tạo và cải tiến, chỉ biết đến duy nhất công việc của mình.
Qua bao nhiêu vòng test, chị vẫn chỉ làm như thế, chắc là chị chưa biết đến các nguyên tắc của kiểm thử phần mềm, hoặc là chị không quan tâm!
Chị B thì khác, không chỉ biết đến công việc của mình, mà còn luôn suy nghĩ để hướng đến những kịch bản kiểm thử tốt hơn, tìm ra những hướng tiếp cận kiểm thử mới, để việc thực thi test case ngày càng hiệu quả hơn.
5. Thái độ đối với công việc Chị A làm việc với suy nghĩ chỉ là làm cho xong công việc của mình mà thôi. Chị B bên cạnh hoàn thiện công việc của mình, bên cạnh đó luôn suy nghĩ để cải tiến chất lượng của hệ thống. Đưa ra các quy trình tốt hơn, những sáng kiến, ý tưởng tốt hơn để đơn giản hóa công việc kiểm thử, giúp nâng cao hiệu quả và nỗ lực kiểm thử của chị cũng như của đồng nghiệp.
6. Mức độ quan tâm đến hệ thống làm việc Chị A là người kiểm thử nhưng chỉ nắm được hệ thống chỉ đến một mức hạn chế nào đó.
Ví dụ, giao cho chị các phần này thì chị chỉ biết đến phần đó, còn của người khác ra sao như thế nào thì hầu như chị không quan tâm! Cũng không suy nghĩ phía dưới hệ thống làm gì, có gì!
Bên cạnh các phần được giao cho mình, chị B luôn luôn dành thời gian để khám phá để hiểu sâu hơn chi tiết hơn về hệ thống mà chị đang làm việc. Khi được bàn giao hệ thống, chị có thể chưa biết nhiều về hệ thống đó, nhưng chị là người mà nhất định sẽ đi sâu tìm hiểu những ngõ ngách, những chi tiết nhỏ nhất của hệ thống, và để hiểu về tất cả những cái phức tạp, sự phụ thuộc và liên quan lẫn nhau giữa các chức năng, những thông tin xử lý phí sau…
7. Góc nhìn của tester Chị A nghĩ rằng, mình là kiểm thử thì mình chỉ việc kiểm tra hệ thống với góc nhìn của một kiểm thử là đã ok rồi Chị B thì lại thực hiện kiểm tra hệ thống dưới góc nhìn của một khách hàng.
Chị B nghĩ rằng một người có tâm luôn đặt mình vào vị trí của khách hàng để kiểm thử hệ thống của mình.
Chị cũng nghĩ đây một yếu tố then chốt quyết định việc chúng ta có thể sử dụng hệ thống theo cái cách mà một người dùng thực sự mà họ sẽ dùng, để từ đó có thể  đưa ra được những kịch bản thực tế và giống thật nhất.

Mintpot và hành trình kiến tạo cuộc sống mới – Cơ hội mới dành cho các Techies

Mintpot là một trong những công ty sáng tạo thông minh, không ngừng phát triển và dẫn đầu xu hướng mới của công nghệ hiện đại, theo đuổi mục tiêu tạo ra cuộc sống tốt hơn với VR (Virtual Reality). Ra đời vào năm 2016 tại Hàn Quốc, đến nay, Mintpot đã có nhiều dự án với các sản phẩm thú vị, mang đến cơ hội cho các kỹ sư, lập trình viên IT nhiều thách thức giới hạn và bùng nổ đam mê.

Mintpot Vina – Xu hướng phát triển của công nghệ hiện đại

Hoạt động tại thị trường Việt Nam từ năm 2019, Mintpot Vina là công ty Outsource, chuyên nhận và phát triển các dự án từ công ty mẹ Mintpot tại Seoul, Hàn Quốc. Đây là một trong những công ty sáng tạo thông minh, mang đến các dịch vụ tiện ích, cung cấp các video VR có phụ đề sử dụng công nghệ Real-time.

VR (Virtual Reality) là công nghệ thực tế ảo hay thực tại ảo, đưa người dùng trải nghiệm các cảm giác chân thực trong môi trường giả lập (ảo hóa) được tạo ra nhờ các phần mềm chuyên dụng và điều khiển bởi thiết bị hỗ trợ thông minh. Ngoài ra, công nghệ thực tế ảo VR còn có thể tương tác thực tế với người dùng qua cử chỉ và nhiều giác quan khác nhau như thính giác, khứu giác và xúc giác.

Để mang đến trải nghiệm lý thú cho người dùng, lần đầu tiên trên thế giới, Mintpot đã triển khai chức năng phụ đề VR giúp xóa bỏ rào cản cho người dùng trên nhiều quốc gia khác nhau với 4 ngôn ngữ: Tiếng Hàn, tiếng Anh, tiếng Trung, tiếng Nhật, và sẽ tiếp tục bổ sung, cải tiến trong tương lai.

Các dự án hấp dẫn hướng đến mục tiêu tạo nên cuộc sống tốt đẹp hơn

Mintpot Vina đã và đang phát triển nhiều ứng dụng, phần mềm phục vụ cộng đồng với các sản phẩm nổi bật:

  • Live Broadcast Apps in real time: Dịch vụ truyền hình trực tiếp của Busking Land cho phép người dùng chuyển tiếp video streaming thông qua ứng dụng Busking Land dành cho các nghệ sĩ hát nhạc đường phố.
  • Self-storage Brokerage Platform: Dịch vụ hỗ trợ cho lĩnh vực thương mại cho phép doanh nghiệp vận hành không gian lưu trữ một cách hiệu quả.
  • Dementia Answer Health App For Seniors: Ứng dụng dịch vụ kiểm tra, quản lý sức khỏe và nhận thức cho người cao tuổi gặp các vấn đề về sa sút trí tuệ.
  • Traveler Companion Matching App: Dịch vụ kết hợp dành cho những người dùng muốn tìm bạn cùng đồng hành trong các chuyến du lịch của mình.

Đầu tư phát triển nguồn nhân lực – Mintpot Vina mở cơ hội hấp dẫn cho tài năng Việt

Chinh phục mục tiêu kiến tạo cuộc sống mới, Mintpot Vina đang tìm kiếm những “mảnh ghép” phù hợp, sẵn sàng cùng công ty đương đầu với những thử thách phí trước. Xứng đáng với những nỗ lực đó, Mintpot Vina trao cho các lập trình viên Việt mức offer lên đến 60Mil VND kèm theo những đặc quyền:

  • Thu nhập hấp dẫn với nhiều khoản bonus: phụ cấp ăn trưa, phụ cấp vị trí, lương tháng 13, trà và cà phê miễn phí, quà Tết…
  • Cơ hội tiếp xúc và học hỏi những công nghệ tiên tiến nhất trong lĩnh vực CNTT;
  • Các hoạt động thể thao ngoài giờ cùng tiệc công ty thường xuyên xả stress hiệu quả cùng “anh-em”.

Cơ hội hấp dẫn mở ra cho các tài năng công nghệ với loạt vị trí hấp dẫn:

Bạn đã sẵn sàng nắm bắt cơ hội?

Apply CV ngay chờ chi!

Developers xây dựng thương hiệu blog của mình như thế nào?

viết blog

Tác giả: Tapas Adhikary

Các Software Developers làm việc rất nhiều với các thiết kế, viết code, testing và cung cấp ra những phần mềm mà chúng ta đang sử dụng hàng ngày. Dù chuyên môn là gì thì họ vẫn là người biết rất nhiều thứ và có thể chia sẻ nó với người đọc cũng như những devs chưa có nhiều chuyên môn, kinh nghiệm.

Bài viết này sẽ đề cập đến những nguyên tắc cơ bản mà một blog cần có và một blogger cần biết.

1. Xác định rõ mục đích viết blog

Tất cả các bloggers đều cần xác định rõ mục đích khi bắt đầu một việc gì đó và động lực để tiếp tục nó. Bạn cần tìm ý định hoặc mục đích giải thích tại sao bạn muốn bắt đầu viết blog hoặc chia sẻ nội dung của mình.

Câu trả lời đơn giản nhất có lẽ là bạn viết blog vì bạn thích, vì bạn có đam mê với việc này. Đôi khi đó cũng có thể là một chiến lược kinh doanh, hoặc có thể bạn muốn dạy người khác. Có thể bạn muốn tiếp tục học hỏi – thực tế là bất cứ thứ gì bạn bắt đầu đều có hiệu quả.

viết blog

Là một developer, bạn luôn cần học được những điều mới mẻ. Gần như không thể ghi nhớ từng phần của những gì chúng ta đã học. Khi ghi lại những bài học và những mẩu thông tin đó, devs cũng có thể làm cho kiến ​​thức đó có thể tái sử dụng được.

Đây là lý do tại sao viết một bài báo về điều gì đó bạn đã học gần đây là một ý tưởng tuyệt vời và cung cấp cho bạn ý định rất rõ ràng cho tài liệu tiến bộ của bạn.

2. Tìm động lực cho bản thân

Động lực có thể làm nên điều kỳ diệu khi bạn có nó, và đương nhiên, sẽ thật khó để tiếp tục công việc nếu không có động lực. Là một người sáng tạo nội dung, động lực lớn nhất của bạn có thể là nghe phản hồi từ người đọc. Phản hồi tích cực và phê bình mang tính xây dựng luôn giúp bạn cải thiện nội dung bạn tạo.

Nhưng có một vấn đề. Ban đầu, bạn có thể không có nhiều độc giả để cung cấp phản hồi cho bạn. Khả năng thất vọng cao hơn nếu bạn là một blogger cá nhân. Vì vậy, nó giúp có rất nhiều động lực để duy trì và tiếp tục công việc của bạn. Hãy nhớ đừng bỏ cuộc, hãy luôn động viên. Là một dev, bạn có nhiều điều để học hỏi, chia sẻ và viết.

3. Nghiên cứu là chìa khóa cho việc viết blog thành công

Với blog, nội dung chính là yếu tố mấu chốt quyết định tất cả mọi vấn đề liên quan. Là một developer, bạn có thể có nhiều ý tưởng, các bước giải quyết vấn đề và các kiến ​​thức mới muốn đạt được. Nhưng phần quan trọng nhất là có thể biến nó thành nội dung chất lượng. Thông thường cần dành thời gian cần thiết để nghiên cứu chủ đề một cách kỹ lưỡng và lên ý tưởng cho bài viết của mình.

  25 blogger IT nổi tiếng mà dân lập trình ai cũng phải biết
  Câu chuyện về cái comment tại một blog nọ

4. Lập dàn ý bài viết

Khi bạn đã nghiên cứu nội dung của mình xong, việc tiếp theo là lập kế hoạch cấu trúc của bài viết. Nội dung bài viết dù xuất sắc vẫn có thể bị người đọc bỏ qua nếu cấu trúc nội dung không đầy đủ và lộn xộn.

Dưới đây là một số mẹo để xây dựng dàn ý bài viết:

  • Tiêu đề: Một tiêu đề hấp dẫn có thể giúp tác động đến nhiều người đọc truy cập vào bài viết. Không có vấn đề gì, mọi người hầu như không bỏ lỡ đọc tiêu đề của bài báo. Giữ cho nó hấp dẫn sẽ tăng lưu lượng truy cập vào nội dung của bạn.
  • Ảnh bìa: Ảnh bìa phù hợp sẽ làm cho bài viết của bạn trở nên rất hấp dẫn. Khi bạn chia sẻ bài viết của mình trên các phương tiện truyền thông xã hội như Twitter, Linkedin hoặc Reddit, một ảnh bìa sáng tạo có thể thu hút người đọc của bạn.
  • Phần mở đầu: phần này mô tả nội dung ở mức độ cao. Nó có thể là một đoạn giới thiệu về những gì bạn định đề cập trong bài viết.
  • Tiêu đề và Tiêu đề phụ: Bạn nên chia nhỏ nội dung thành các chủ đề phụ hợp lý. Để làm điều đó, hãy tạo các phần và cung cấp các tiêu đề và tiêu đề phụ có liên quan.
  • Hình ảnh: Tìm những hình ảnh rõ ràng và có thể minh họa cho nội dung mà bạn đang viết để thu hút người đọc.
  • Tóm tắt: Phần tóm tắt ở cuối giúp người đọc tóm tắt lại những gì họ đã biết được. Nó cũng hữu ích cho một người đọc quay lại để nhớ lại nội dung bằng cách xem qua phần tóm tắt.
    Backlinks: Bạn có thể muốn kết thúc bài viết của mình bằng một danh sách các liên kết liên quan để đọc thêm. Bạn cũng có thể sử dụng phần này để liệt kê các liên kết với những bài blogs mà mình đã thực hiện.

5. Công cụ viết blog

Để tạo nội dung chất lượng cần có thời gian. Bạn có thể biến mình thành người sáng tạo nội dung năng suất và hiệu quả bằng cách sử dụng một số công cụ có sẵn miễn phí.

Bạn có thể check lỗi ngữ pháp bằng website Grammaly, hoặc sử dụng website Hemingway Editor để viết bài bằng tiếng Anh nếu không thật sự viết tốt bằng ngôn ngữ này. Bạn có thể thực hiện việc chỉnh sửa ảnh bằng nguồn hình ảnh tại Canva, Pixteller, ShareX

6. Hiệu đính lại bài viết lần cuối trước khi đăng bài

Quá trình kiểm tra và đảm bảo rằng nội dung của bạn đã sẵn sàng để xuất bản được gọi là hiệu đính. Bạn nên kiểm tra các lỗi chính tả, lỗi ngữ pháp, các vấn đề về định dạng code, dấu câu, sự chính xác và ngôn ngữ nhất quán.

7. Xuất bản (Publish) bài viết

viết blog

Nếu bạn hài lòng với bài blog sau khi hiệu đính, bước tiếp theo chính là xuất bản nó. Bạn có thể muốn lên lịch để nó xuất bản vào một ngày cụ thể trong tuần, hoặc bạn có thể muốn xuất bản ngay lúc đó – điều đó tùy thuộc vào bạn.

Theo nguyên tắc chung, tốt hơn là nên xuất bản khi một bài báo đã sẵn sàng từ phía bạn. Tương tự như vậy, bạn đừng bao giờ vội vàng xuất bản một bài báo để kịp thời hạn.

8. Chia sẻ blog lên các nền tảng mạng xã hội

Phương tiện truyền thông xã hội là một công cụ cực kỳ mạnh mẽ và bạn nên tận dụng nó với tư cách là một blogger.

Việc xuất bản bài viết của bạn có thể là không đủ nếu bạn muốn nó tiếp cận nhiều độc giả tiềm năng nhất có thể. Do đó, bạn nên chia sẻ bài viết của mình trên các nền tảng mạng xã hội khác nhau.

TÌM VIỆC CHO LẬP TRÌNH SOFTWARE

Phỏng dịch theo bài viết gốc đăng tải tại freecodecamp.org

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

Lab – Cài đặt(cloud)

Lab – Cài đặt(cloud)

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

Các hướng dẫn dưới đây là giành cho cloud. Tuy nhiên bạn có thể tìm thấy hướng dẫn cho máy ảo VM với bài 4.

Click vào đây để tải về hướng dẫn thiết lập môi trường cho bạn.

Nào chúng ta cùng xem cài đặt như nào nhé

  CLOUD ACE: Không mang mọi người lên "mây" mà mang "mây" đến gần mọi người hơn

  Bí kíp tạo website nhờ vào GitHub và Cloudflare

1.  Tạo 1 tài khoản

Để sử dụng hệ thống IBM Analytics Demo Cloud tại địa chỉ:

https://my.imdemocloud.com/

Các bạn chọn vào sigup nếu chưa có tài khoản. Đăng ký 1 account với mật khẩu vừa chữ hoa, chữ thường, số và ký tự đặc biệt nhé. Sau đó hệ thống sẽ gửi mail cho các bạn xác thực. Mở mail ra và xác nhận đã đăng ký thành công.

rm.png

Nhấp vào chữ Confirm my account. Lúc nào thấy dòng chữ sau là đã thành công:

Welcome to Demo Cloud!

Thank you for validating your email. You are one step away from being able to use resources on the IBM Analytics Demo Cloud.

Tiếp theo là mô tả về hệ thống demo này:

  • Account – là phần thông tin tài khoản người dùng. Thông tin sử dụng dịch vụ, bao gồm điều khoản người dùng cuối.
  • Account Administrator – tài khoản của người dùng,được giao quản lý truy cập và giám sát việc sử dụng Dịch vụ của người dùng cuối.
  • Cloud Web Portal – website IDM cho phép người dùng sử dụng dịch vụ và xem thông tin tài khoản.
  • Content  – tất cả dữ liệu, thông tin, phần mềm, without limitation, any hypertext markup language files, scripts, programs, recordings, sound, music, graphics, images, applets, or servlets that are created, installed, uploaded, or transferred được chấp nhận bởi người dùng..

Nhiều quá tôi không viết hết. Bạn kéo xuống và nhấn chọn chấp nhận điều khoản để tiếp tục.

2. Truy cập ambari

Sau đó bạn chọn vào Ambari Console để chạy dịch vụ. Bạn nhập tên người dùng của bạn được cho ở phía dưới phần connect details, mật khẩu là lúc bạn thiết lập. Sau đó bạn sẽ thấy dịch vụ như hình ảnh:

ynh.png

Vậy là bạn đã cài đặt xong phần service của IBM.

3. SSH và PuTTY

SSH dùng để đảm bảo kết nối an toàn tới server của IDM. Bạn cần tải PuTTY ở trang này để làm việc với server:

http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html

Sau khi tải về bạn cài đặt nó.

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

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

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

ASP.NET MVC5 #3: Thêm mới View

ASP.NET MVC5 #3: Thêm mới View

Bài viết được sự cho phép của Tạp chí Lập trình

Trong phần này, bạn sẽ sửa đổi file “HelloWorldController.cs”, sử dụng view để đóng gói quá trình sinh ra HTML trả về cho client.

Bạn sẽ tạo một view sử dụng “Razor view engine”. “Razor view” có phần mở rộng là “.cshtml” và cung cấp cách thức để tạo ra HTML sử dụng C#. Razor sẽ giúp tinh gọn mã lệnh khi bạn viết một view.

  ASP.NET Core là gì?
  .NET core vs ASP.NET core: Phân biệt .NET Framework, .NET Core và Mono

Hiện tại, phương thức “Index” trả về một chuỗi là một thông báo đã được khai báo trong Controller. Chúng ta sẽ thay đổi phương thức “Index” để trả về một đối tượng view:

[sourcecode language=”csharp”] public ActionResult Index()
{
return View();
}
[/sourcecode]

Phương thức “Index” ở trên sử dụng một view để sinh ra HTML trả về cho trình duyệt. Các phương thức trong Controller (gọi là action methods) như phương thức “Index” ở trên thường trả về ActionResult (hoặc một lớp dẫn xuất từ ActionResult), không phải các kiểu nguyên thủy như string.

Chuột phải vào thư mục “Views\HelloWorld” và nhấn “Add”. Sau đó chọn “MVC 5 View Page with Layout (Razor)”:

Trong hộp thoại “Specify Name for Item”, nhập vào “Index” sau đó nhấn “OK”:

Trong hộp thoại “Select a Layout Page”, chọn “_Layout.cshtml” và nhấn “OK”:

Trong hộp thoại ở trên, thư mục “Views\Shared” được chọn ở danh mục bên trái. Và như vây, file “MvcMovie\Views\HelloWorld\Index.cshtml” đã được tạo:

Trong file “Index.cshtml” bạn thêm vào như sau:

[sourcecode language=”html”] @{
Layout = "~/Views/Shared/_Layout.cshtml";
}

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>
[/sourcecode]

Chuột phải vào file “Index.cshtml” và chọn “View in Browser”:

Hoặc bạn cũng có thể chạy ứng dụng và duyệt đến “http://localhost:xxxx/HelloWorld”. Phương thức “Index” trong Controller của bạn sẽ chạy câu lệnh “return View()”. Bởi vì bạn không xác định chính xác tên view được sử dụng. ASP.NET MVC mặc định sử dụng file “Index.cshtml” trong thư mục “\Views\HelloWorld”. Kết quả khi chạy như sau:

Thay đổi các views và các trang layouts

Trước tiên, chúng ta sẽ thay đổi liên kết “Application name” ở đầu trang. Đây là thành phần chung của tất cả các trang. Nó được viết tại một chỗ trong dự án nhưng sẽ xuất hiện trên mọi trang trong ứng dụng. Bạn mở file _Layout.cshtml trong thư mục “/Views/Shared”. File này được gọi là trang bố cục và nó nằm trong thư mục “Shared” để tất cả các trang khác có thể sử dụng.

Layout cho phép bạn xây dựng mã HTML ở một nơi và sau đó áp dụng nó ở nhiều nơi khác trong trang WEB của bạn. Trong trang layout, “@RenderBody()” sẽ là nơi giữ chỗ, là vị trí mà bạn sẽ gắn trang con vào trang layout. Ví dụ: nếu bạn chọn trang “About”, trang “Views\Home\About.cshtml” sẽ được thi hành bên trong phương thức “RenderBody”.

Thay đổi nội dung của phần tử “Title”. Thay đổi “ActionLink” trong file layout từ “Application name” thành “MVC Movie” và controller từ “Home” thành “Movies”. File layout sau khi thay đổi sẽ như sau:

[sourcecode language=”html”] <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title – Movie App</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")

</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("MVC Movie", "Index", "Movies", null, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>&copy; @DateTime.Now.Year – My ASP.NET Application</p>
</footer>
</div>

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
[/sourcecode]

Chạy ứng dụng, và duyệt đến “http://localhost:xxxx/HelloWorld” .“Application name” đã chuyển thành “MVC Movie”:

Nhấn vào “About”, “Contact” bạn cũng sẽ thấy sự thay đổi tương tự. Điều này là bởi vì, trang “Index”, “About”, “Contact” sử dụng chung một layout.

Trong file “Views\HelloWorld\Index.cshtml” có chứa đoạn mã sau:

[sourcecode language=”html”] @{
Layout = "~/Views/Shared/_Layout.cshtml";
}
[/sourcecode]

Đoạn mã này sử dụng để thiết lập layout “_Layout.cshtml” cho một trang. Nó cũng được khai báo trong “Views\_ViewStart.cshtml”. File “Views\_ViewStart.cshtml” định nghĩa layout chung mà tất cả các trang sẽ sử dụng. Do đó bạn không cần khai báo đoạn mã trên trong file “Views\HelloWorld\Index.cshtml” nữa. Bạn có thể sửa lại file  “Views\HelloWorld\Index.cshtml” như sau:

[sourcecode language=”html”] @*@{
Layout = "~/Views/Shared/_Layout.cshtml";
}*@

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>
[/sourcecode]

Bạn cũng có thể sử dụng thuộc tính “Layout” để thiết lập layout khác, hoặc thiết lập giá trị “null” nếu không có layout nào được sử dụng.

Bây giờ, chúng ta hãy thay đổi tiêu đề của trang “Index”. Bạn mở file “Views\HelloWorld\Index.cshtml”. Chúng ta sẽ thay đổi ở hai vị trí. Đầu tiên là văn bản xuất hiện trong tiêu đề của trình duyệt và sau đó là trong phần tử “h2”.

[sourcecode language=”html”] @{
ViewBag.Title = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>
[/sourcecode]

Chúng ta sử dụng thuộc tính “Title” của đối tượng “ViewBag” để thiết lập giá trị cho tiêu đề. File “Views\Shared\_Layout.cshtml” sẽ sử dụng giá trị này trong phần tử “title”.

[sourcecode language=”html”] <!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title – Movie App</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
[/sourcecode]

Sử dụng “ViewBag”, bạn cũng có thể dễ dàng truyền các thông số khác giữa view và layout. Chạy ứng dụng và bạn sẽ nhận thấy sự thay đổi. Tiêu đề trình duyệt được tạo với ViewBag.Title chúng ta đặt trong file “Index.cshtml” và thêm “- Movie App” trong file “_Layout.cshtml”.

Chú ý rằng nội dung trong file “Index.cshtml” đã được sáp nhập với nội dung trong file “_Layout.cshtml” và trả về một HTML duy nhất để gửi tới trình duyệt. Layout giúp bạn có thể dễ dàng thực hiện những thay đổi áp dụng trên tất cả các trang của ứng dụng.

Xem ngay tin việc làm .NET tại các doanh nghiệp hàng đầu trên TopDev

Truyền dữ liệu từ Controller tới View

Controller là nơi tiếp nhận và xử lý các yêu cầu từ trình duyệt. Controller lấy dữ liệu từ cơ sở dữ liệu và quyết định loại dữ liệu nào sẽ được trả về cho trình duyệt. Sau đó View được sử dụng để tạo ra HTML trả dữ liệu về cho trình duyệt.

Controller có trách nhiệm cung cấp bất cứ dữ liệu hoặc đối tượng nào được yêu cầu để View hiển thị ra trình duyệt. View không bao giờ thi hành các nghiệp vụ logic hoặc tương tác trực tiếp với cơ sở dữ liệu. Thay vào đó, View chỉ làm việc với dữ liệu được cung cấp bởi Controller. Điều này sẽ khiến cho mã của bạn sạch sẽ, dễ kiểm chứng và bảo trì.

Hiện tại, phương thức Welcome trong lớp HelloWorldController lấy tham số “name” và tham số “numTimes”  truyền vào sau đó xuất các giá trị trực tiếp tới trình duyệt. Thay vì trả về một chuỗi như trên, chúng ta sẽ để Controller trả về một View. Bạn có thể sử dụng đối tượng ViewBag để lưu dữ liệu, và View sẽ truy cập đối tượng ViewBag để lấy dữ liệu trả về cho trình duyệt.

Trong file “HelloWorldController.cs”. Chúng ta sẽ đi thay đổi phương thức “Welcome”. Bạn thêm giá trị Message và NumTimes vào đối tượng ViewBag. ViewBag là một đối tượng động. Có nghĩa là bạn có thể gán bất cứ thứ gì cho nó. Đối tượng ViewBag không có thuộc tính được xác định cho đến khi bạn gán cái gì đó cho nó. ASP.NET MVC sẽ tự động ánh xạ các tham số (name và numTimes) từ chuỗi truy vấn trong thanh địa chỉ đến các tham số trong phương thức “Welcome”. File “HelloWorldController.cs” sau khi sửa đổi sẽ như sau:

[sourcecode language=”csharp”] using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcMovie.Controllers
{
public class HelloWorldController : Controller
{
public ActionResult Index()
{
return View();
}

public ActionResult Welcome(string name, int numTimes = 1)
{
ViewBag.Message = "Hello " + name;
ViewBag.NumTimes = numTimes;

return View();
}
}
}
[/sourcecode]

Bây giờ đối tượng ViewBag chứa dữ liệu sẽ tự động truyền tới View. Tiếp theo bạn cần tạo View “Welcome”.

Chuột phải vào thư mục “Views\HelloWorld” và nhấn “Add”, sau đó chọn “MVC 5 View Page with Layout (Razor)” :

Trong hộp thoại “Specify Name for Item” nhập Welcome và nhấn OK:

Trong hộp thoại “Select a Layout Page”, chọn “Shared”, chọn “_Layout.cshtml” và nhấn OK:

File “MvcMovie\Views\HelloWorld\Welcome.cshtml” đã được tạo.

Trong file “Welcome.cshtml”, bạn tạo vòng lặp để hiển thị “name” với “numTimes” lần:

[sourcecode language=”html”] @{
Layout = "~/Views/Shared/_Layout.cshtml";
}

@{
ViewBag.Title = "Welcome";
}

<h2>Welcome</h2>

<ul>
@for (int i = 0; i < ViewBag.NumTimes; i++)
{
<li>@ViewBag.Message</li>
}
</ul>
[/sourcecode]

Chạy ứng dụng và duyệt tới URL sau:

“http://localhost:xxxx/HelloWorld/Welcome?name=Scott&numtimes=4

Bây giờ, dữ liệu sẽ được lấy từ URL và truyền vào Controller sử dụng model binder. Controller sẽ đóng gói dữ liệu vào đối tượng ViewBag và truyền ViewBag tới view. Sau đó view sẽ hiển thị dữ liệu dưới dạng HTML.

Trong ví dụ trên, chúng ta đã sử dụng đối tượng ViewBag để truyền dữ liệu từ controller tới view. Trong bài học tiếp theo, chúng ta sẽ sử dụng view model để truyền dữ liệu từ controller tới view.

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

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

 

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

Kiểm tra tính hợp lệ của dữ liệu đầu vào form Spring Web MVC bởi Hibernate Validator

Kiểm tra tính hợp lệ của dữ liệu đầu vào form Spring Web MVC bởi Hibernate Validator

Bài viết được sự cho phép của smartjob.vn

Trong bài viết này chúng tôi giới thiệu đến các bạn sử dụng tổ hợp nhiều kỹ thuật khác nhau:

  • Spring Web MVC 4
  • Hibernate Validator
  • Maven build tool

Chúng ta sẽ xây dựng ứng dụng gồm 2 màn hình: màn hình nhập thông tin và màn hình thông báo kết quả thành công như sau:

Kết quả trả về sau khi đã validate (kiểm tra dữ liệu đầu vào)

18 Web Developer Jobs lương cao tại TopDev

Các bước thực hiện

Tạo mới project sử dụng Maven archetype mavenarchetypewebapp . Nếu bạn chưa rõ về cách tạo project từ archetype, bạn có thể xem phần đầu bài viết Kỹ thuật Autowiring sử dụng annotation trong Spring Framework . Một project khuôn được tạo ra, bạn cần bổ sung thêm các thư mục ( src , main , java ), khai báo thêm thư viện để project có được cấu trúc như sau:

File pom.xml đầy đủ như bên dưới, Bạn cần khai báo các thư viện. Mỗi thư viện đều được khai báo 3 thông số GAV (Group – ArtifactId – Version). Chúng tôi sử dụng phiên bản mới nhất tại thời điểm viết bài.

  • spring-core
  • spring-beans
  • spring-context
  • spring-web
  • spring-webmvc
  • hibernate-validator (để validate dữ liệu từ back-end)

Tương ứng với mô hình tham chiếu như hình vẽ trên, cụ thể hóa trong ứng dụng mà chúng ta đang làm:

  • Front controllerorg.springframework.web.servlet.DispatcherServlet
  • Controllervn.smartjob.demospring.domain.JobController
  • View template: Các file index.jspaddJob.jspresultJob.jsp
  • Model: Class vn.smartjob.demospring.domain.Job  là một thành phần của model.
  • Servlet engine: Chính là Apache Tomcat mà bạn sử dụng để deploy ứng dụng.

Là ứng dụng web, nên deployement descriptor rất quan trọng, file web.xml . Phần filter có tác dụng đảm bảo dữ liệu tiếng Việt Unicode được xử lý đúng. Phần xử lý luồng đi của Spring Web MVC được xử lý bởi class org.springframework.web.servlet.DispatcherServlet

Là một ứng dụng sử dụng Spring Framework, nên không thể thiếu beans configuration, file springmvc-servlet.xml

Mỗi công việc (job) được mô tả bởi entity Job. Việc sử dụng các annotation nhằm mục đích để Hibernate Validator biết được rule validate.

Trong controller xử lý luồng đi của ứng dụng, có 2 method để xử lý 2 màn hình: Màn hình thêm công việc và màn hình hiển thị thông báo thành công. Mỗi method đều được gắn annotation @RequestMapping  của Spring Framework.

Trang addJob.jsp là giao diện để thêm công việc mới. Trong file JSP có phần CSS, phần này chỉ có tác dụng giúp giao diện nhập dữ liệu công việc và hiển thị thông báo thành công, kết quả được đẹp và dễ nhìn hơn. Không tác động vào nghiệp vụ cũng như luồng xử lý nghiệp vụ. Mỗi công việc có có các thuộc tính như sau (được tô màu highlight trong mã nguồn):

  • title: Tiêu đề công việc
  • company: Công ty cần tuyển người
  • companyAddress: Địa chỉ công ty, cũng thường là địa điểm làm việc
  • content: Nội dung chi tiết: yêu cầu công việc, kỹ năng, các chế độ đãi ngộ
  • startDate: ngày bắt đầu đăng tin
  • endDate: ngày gỡ bỏ tin tuyển dụng

Trang resultJob.jsp là giao diện để thông báo thành công và trả về kết quả

File index.jsp để trỏ trang chủ website về trang thêm công việc mới (addJob.jsp)

Để đa ngôn ngữ (sau này), các item resources bundle được khai báo trong file messages.propertiess nằm trong thư mục resources (đây là thư mục quy ước theo cấu trúc project Maven):

Bạn đã hoàn thành ứng dụng, và có thể deploy trên server Apache Tomcat, truy cập link http://localhost:8080  để xem kết quả (trên máy của bạn, có thể port Tomcat sẽ khác số 8080).

Liên kết tải về mã nguồn từ server SmartJob: beanvalidation hoặc clone/fork từ GitHub: https://github.com/SmartJobVN/beanvalidation

Đỗ Như Vý – Bài viết gốc được đăng tải tại smartjob.vn

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

Xem thêm IT Jobs Developer hấp dẫn trên TopDev

Singleton design pattern – tất cả những điều cần biết

Singleton design pattern – tất cả những điều cần biết

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

Quay lại với chuỗi bài design pattern ở Kieblog, hôm nay là Singleton Pattern. Singleton là một pattern khá quen thuộc, như là pattern vỡ lòng khi bước vào thế giới của Design Pattern.

Tuy nhiên, để nắm rõ và hiểu sâu Pattern này không dễ. Đơn cử như các câu hỏi:

  • Singleton Pattern có cung cấp Global Access cho instance không?
  • Trường hợp Multi Thread hay Concurrency, implement Singleton Pattern thế nào?

Tất cả sẽ có trong bài viết này. Viết dài vãi nồi!

1. Định nghĩa về Singleton Pattern

Định nghĩa thì nhàm chán, nhưng thử nhìn qua thì thấy từ Single. Đang FA mà nghe từ này thì thốn, nhưng pattern đọc vẫn phải đọc.

Singleton is a creational design pattern that lets you ensure that a class has only one instance, while providing a global access point to this instance

Singleton là pattern khởi tạo cho phép bạn đảm bảo rằng class chỉ có duy nhất một instance, trong khi vẫn cung cấp truy xuất toàn cục cho instance này.

Single này không phải độc thân, mà mỗi thằng sẽ có một instance duy nhất.

Nhưng nói Singleton Pattern chỉ giải quyết vấn đề only one instance là còn thiếu, nó còn cho phép cái instance đó được phép global access nữa

2. Solve two problems

Singleton pattern giải quyết 2 vấn đề. Mà thực chất hai vấn đề này vi phạm Single Responsibility Principle. Vi phạm như thế nào sẽ đề cập sau ở phần advantages và disadvantages.

2.1 Ensure that a class has just a single instance

Đầu tiên cũng là quan trọng nhất, rõ ràng Singleton Pattern đảm bảo rằng class chỉ có một instance.

imagine that you created an object, but after a while decided to create a new one. Instead of receiving a fresh object, you’ll get the one you already created.

Tưởng tượng rằng bạn tạo một object, nhưng sau khi tạo lại muốn tạo thêm cái mới. Thay vì nhận được một object mới, bạn nhật được một object đã được tạo từ trước đó.

Singleton pattern designKhách hàng thậm chí không biết rằng mình làm việc với cùng một object trong toàn bộ thời gian. Nguồn ảnh / Source: refactoring.guru

Chính vì có thể tái sử dụng, không cần lúc nào cũng phải new instance mới, ta có thể dùng Singleton Pattern để đảm bảo rằng chỉ một instance duy nhất được tạo ra.

2.2 Provide a global access point to that instance

Singleton pattern design

Giống như biến toàn cục (Global variable). Singleton pattern cung cấp Global Access cho instance mà nó tạo ra. Ở đâu cần instance đều có thể truy cập được, một hình thức như tái sử dụng.

Đấy, toàn bộ nội dung về thằng Singleton Pattern thì chỉ có vậy. Còn hiện thực ra sao mời anh em tới bước tiếp theo. Source tạm thời viết java ha.

  Design pattern là gì? Tại sao nên sử dụng Design pattern?
  Giới thiệu Abstract Factory Pattern

3. Hiện thực thế nào?

// Singleton pattern
public final class Singleton {
private static Singleton instance;
public String value;

private Singleton(String value) {
// Following code emulates slow initialization.
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
this.value = value;
}

public static Singleton getInstance(String value) {
// Nếu chưa có instance thì new, có rồi thì return cái cũ
if (instance == null) {
instance = new Singleton(value);
}
return instance;
}
}

Tuy nhiên cũng cần chú ý là trường hợp Multi Thread hoặc Concurrency, tránh Deadlock

// Singleton pattern for thread safe implement
public final class Singleton {
private static volatile Singleton instance;
public String value;

private Singleton(String value) {
this.value = value;
}

public static Singleton getInstance(String value) {
if (instance == null) {
// Sử dụng synchronized để đảm bảo class Singleton chưa bị block bởi thread khác
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(value);
}
}
}
return instance;
}
}

4. Advantages and disadvantages

  • Ưu: You can be sure that a class has only a single instance. Chắc chắn là class chỉ có một instance duy nhất.
  • Ưu: You gain a global access point to that instance. Gán được global acess cho instance đó.
  • Ưu: The singleton object is initialized only when it’s requested for the firsttime. Singleton object chỉ khởi tạo một lần duy nhất khi được request tới.

Đấy, ưu điểm có nhiều, tuy nhiên nhược điểm cũng có.

Đầu tiên là cái vi phạm Single Responsibility Principle. Cái thằng SRP này.

The Single Responsibility Principle (SRP) states that a class should have one and only one responsibility. A Singleton, by it’s very nature, has at least two responsibilities.

Trạng thía SRP hiểu rằng class nên chỉ nên có duy nhất một nhiệm vụ duy nhất. Class do only one thing. Đối với singleton pattern, một object phải kiêm nhiệm nhiều nhiệm vụ, ông nào gọi cũng phải chạy tới.

Ngoài ra, nếu lập trình đa luồng (Multi Thread) hoặc Concurrency, một singleton có thể bị giữ bởi một thread, các thread khác không thể access. Dẫn tới deadlock.

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

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

Xem thêm Việc làm tuyển ux ui hấp dẫn trên TopDev

Ngoại truyện: Export file tự động với Selenium webdriver

Ngoại truyện: Export file tự động với Selenium webdriver

Bài viết được sự cho phép của tác giả To Thi Van Anh

Tình cờ thì hôm vừa rồi mình có được một chị cùng công ty nhờ xem giúp chị ấy xem đoạn công việc của chị như thế này thì có thể automate được không. Mô tả bài toán đấy thì đại khái như thế này.

Bên mình có một số các tài liệu liên quan dự án, chúng được tạo và lưu trữ online trên một hệ thống website nội bộ. Vì tình hình dự án chưa ổn định, nên nội dung trong các tài liệu có thể bị thay đổi thường xuyên. Do đó, để thuận tiện hơn cho việc theo dõi tiến độ và quản lý của mình thì chị ấy sẽ cần phải export, lưu trữ file đó trên máy tính khá nhiều lần và định kỳ, vấn đề ở đây là trên hệ thống đó có đến hàng trăm tài liệu cần được tải xuống mỗi lần. Kể cả trường hợp dù sau này có ổn định thì việc thực hiện cả đến trăm lần những thao tác tẻ nhạt và mất thời gian đó cũng làm mất khá nhiều thời gian. Nên cần một cách nào đó để giải quyết vấn đề này.

automated-decision-making

Từ lời “nhờ vả” đó thì mình cũng bắt tay tìm hiểu kỹ hơn bài toán và vấn đề ở trên. Đầu tiên, kiểm tra tổng quát các bước được thực hiện trên thực tế như thế nào. Sau đó kiểm tra sơ bộ các element của các phần tử sẽ được tương tác. Tiếp đó lựa chọn ngôn ngữ, công cụ để code (ở đây tại vì mình mới làm quen với Python nên cũng muốn thử với nó xem sao, còn nếu không thì mình vẫn dùng Java thôi :v).

Mình chọn Python, kaka vì thấy các bước cũng không nhiều và khó quá, được cái cú pháp các thứ nó ngắn gọn hơn so với Java :v. Mình bắt đầu khá suôn sẻ với các bước auto mở trình duyệt FireFox, nhập username, password sau đó đăng nhập thành công. Mấy bước đơn giản có khác, nhanh lắm. Cứ ngỡ là mọi việc trở đi sẽ suôn sẻ như bước đăng nhập, thế nhưng không phải vậy, từ sau đấy thì sóng gió mới bắt đầu =)), mình đã mất khá nhiều thời gian để chạy được bước tiếp theo.

Rắc rối ở chỗ mình đã lựa chọn element chưa đúng, và cũng không hiểu tại sao với element đó thì nó lại không được, mặc dù đã check rất kỹ trên console của các trình duyệt, từ FireFox, Opera, rồi cả IE nữa. Cứ nghĩ do Python với cả trình duyệt nên lúc này mình mất kiên nhẫn nên lại chuyển sang Eclipse làm Java cho thêm phần tự tin. Haha thế nhưng rồi cũng xong :v

Chuyện vẫn chưa dừng lại ở đó, khi mình thực hiện click thì hệ thống hiển thị lên một form mới, và mình sẽ phải thực hiện các thao tác tiếp theo trong form đấy. Lướt qua các phần tử cần tương tác thì thấy element lấy được rất dễ dàng, vì toàn thông qua ID với name của phần tử thôi, thế nhưng khi thực hiện các thao tác click thì nó lại không được. Mình lại chủ quan ở chỗ, không lần từ gốc của phần tử HTML đó, khi mà chỉ thấy đến tag form là nó đã bao hết cái cửa sổ này rồi nên không kiểm tra tiếp nữa, chạy thử vài lần vẫn không được, cuối cùng mới nghĩ ra nó nằm trong một cái frame, keke, trong HTML của trang thì tag frame này nó ở mãi trên thảo nào mà không nhìn ra ngay từ đầu, làm phí mất mấy phút cuộc đời :v

single-frame-source-selenium-webdriver

Vậy nên kinh nghiệm rút ra ở đoạn này đó là khi làm việc mà có sự xuất hiện của form chồng lên cái màn hình trang web hiện tại, hay nếu nó là một popup gì đó thì nhất định phải tìm cho kỹ càng cái thẻ frame, tránh mất thời gian đi soi lỗi tại sao, với cả chỉnh sửa tè le vẫn không biết. Hehe

Và một bài học nữa đó là không nên chủ quan bất cứ cái gì, ngay từ đầu khi mà soi các element, mình đã khá tự tin vì các emlement này lấy rất dễ, làm rất nhanh nhưng đến khi thực tế thì lại không như mình nghĩ lắm :v. Tự tin là tốt nhưng tự tin và tự phụ thì nó cũng rất gần nhau, mình thì chưa đến mức tự phụ, chỉ nhắc ở đây cho ai đấy tự soi lại bản thân thôi nhá! Kaka

Đến đây, cơ bản thì sóng gió đã qua gần hết :v vì từ lúc này đi mình đã thực hiện được hầu hết các bước. Ối dồi nhưng khi chạy click vào nút download, thì nó không tự động lưu file xuống máy mới đau, vì file mình export ra nó là file excel, nên nó còn hỏi là mày muốn mở file hay muốn lưu file. (Cũng sẽ tương tự trường hợp file tải xuống là file .doc, .pttx… đại khái là các loại file office, hay file định dạng .pdf nữa) Cái này thì Selenium không thể thực hiện send thao tác như tương tác các phần tử web được. Nhưng với mình cái này không phải là vấn đề, chỉ là đưa ra để cho các bạn biết trường hợp có thể sẽ gặp phải thôi. Mình nhanh chóng search google và tìm được ra ngay hướng xử lý dễ dàng nhé. Kaka. Mình chưa có kinh nghiệm chỗ này vì trước đây toàn làm download với file .zip nên không có vấn đề gì.

ExportingToExcel

Cách làm thì đại khái là sử dụng FireFox profile, và set một vài thứ liên quan đến profile thôi. Bài sau mình sẽ nói về cái này. Hihi.

Thế là cuối cùng cũng download được file xuống máy. Đơn giản quá đi. :v

Tưởng vậy là xong, nhưng quay lại yêu cầu của bài toán này, đó là cần phải download được nhiều tài liệu cơ. Mình biết rằng mỗi tài liệu cần tải xuống đều có 1 id duy nhất, ý tưởng đơn giản là cho danh sách các id này vào trong 1 file và khi nào tải xong sẽ đóng trình duyệt và thực hiện mở trình duyệt với id của file cần tải khác ra rồi lại tải file xuống, và cứ như thế cho đến khi hết danh sách thì thôi (mặc dù biết cách này đang hơi cùi, nhưng vì áp lực thời gian hoàn thành nên mình làm tạm cách này, và hứa sẽ update khi mà tranh thủ được thời gian)

Vấn đề mình gặp phải ở đây mới hay nè, sau khi thực hiện click vào nút để file download file xuống thì mình không thể thực hiện được bất kì thao tác gì phía sau đấy, thế nên không thể thực hiện được nhiều lần download như ý tưởng ban đầu. Debug vài lần mình phát hiện code chạy đến dòng btnExport.click() vừa kịp click tải file xuống xong thì treo luôn, bới tung google, soi lại các profile đã set phía trên, thay đổi các cách, nói chung là đều đã làm hết cả, mất mấy ngày liền vẫn chưa tìm được lý do tại sao.

Nhưng cuối cùng thì chính ở chỗ mình không ngờ đến nhất thì vấn đề nó lại nằm ở đấy 😀 chính là btnExport.click(), rõ ràng button này mình lấy theo ID của phần tử, click thực hiện được thì có chuyện gì với nó? Tình cờ phát hiện ra khi mà mình quyết định thử thay đổi từ khóa tìm kiếm khác 😀 kaka, đó là thay bằng cách dùng JavascriptExecutor:

JavascriptExecutor executor = (JavascriptExecutor) browser; 
executor.executeScript("var elem=arguments[0]; setTimeout(function() {elem.click();}, 100)", btbExport);

Thay xong, code chạy vù vù như thanh niên nam trong quảng cáo Sting dâu luôn! =))

14514511375134800125

Vui mừng khôn xiết, và rồi như vậy sau hơn 1 tuần tranh thủ đến sớm và ở lại sau giờ làm việc một tí thì cũng đã gọi là tạm ổn. Chạy được ngon lành, đáp ứng được mục đích sử dụng. (Mình vẫn biết là bên trong code vẫn hơi lởm khởm chút, nhưng quan trọng là nó đã chạy được ngon lành đã =)) )

Bài này chia sẻ vui câu chuyện của mình thế thôi, còn cụ thể về cái FireFox profile và cách download file bằng Selenium webdriver như thế nào mình sẽ chia sẻ trong bài biết sau nhé! Cảm ơn các bạn đã theo dõi và đọc đến tận dòng cuối cùng này! 😀

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

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

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

Python call by gì?

Python call by gì?

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

Một câu hỏi nhạt toẹt của nhà phỏng vấn có thể đưa ra (với người phỏng vấn thường có kiến thức từ ngôn ngữ khác như Java, PHP hay C++, hoặc một chuyên gia Python thực sự và hỏi để check xem bạn có mắc bẫy không – loại này thì hiếm, và không rảnh ).

Python dùng call-by-value hay call-by-reference?

Hai khái niệm này thực ra không tồn tại trong Python, bạn có thể đào tung cả trang document của Python cũng sẽ không thấy nói gì về khái niệm này. Tức là: nó không có thật! Nó không cần thiết! bạn chỉ cần hiểu function hoạt động thế nào, cách Python sử dụng “name binding”. Còn không nên ngồi cãi nhau về “call-by-reference”, “call-by-value” làm gì cho tốn thời gian, vô tác dụng.

Call by XYZ là cái gì?

Mọi khái niệm viết sau đây không tồn tại trong Python, các thuật ngữ được viết với “từ vựng” của ngôn ngữ lập trình khác.

Trong một số ngôn ngữ như C, C++, khi gọi function ta có truyền vào các “tham số” (pass argument), nếu function đó nhận vào một array (trong Python hiểu nôm na là list), thì trong function, ta sẽ xử lý chính array đó hay một bản copy của nó?

Kiểu 1

update(danh_sach)

Kiểu 2

update(&danh_sach)

Với câu gọi function (call function) thứ nhất ta gọi function với giá trị (value) của biến danh_sach. Mọi thay đổi trong function thực hiện trên argument được gọi là thực hiện trên bản copy của danh_sach.

Câu gọi function thứ hai ta gọi function với con trỏ (pointer) đến biến danh_sach hay còn gọi là reference. Mọi thay đổi sẽ thay đổi trực tiếp trên danh_sach.

Những ngôn ngữ lập trình bị ảnh hưởng bởi C thường cắt giảm khái niệm “pointer” để tránh gây phức tạp, vì vậy khi gọi function sẽ mặc định dùng 1 trong 2 kiểu trên. Hoặc dùng một cơ chế khác hoàn toàn.

Ví dụ:

Tuyển python nhiều vị trí lương cao

Call by và pass by

  • Khi nói function call by , người ta đang lấy function làm trọng tâm của câu chuyện.
  • Khi nói argument pass by, người ta đang lấy argument làm trọng tâm của câu chuyện.

Chỉ là hai cách tập trung khác nhau vào một việc: call function với các argument.

  Viết ứng dụng tra số điện thoại thuộc Quốc gia nào bằng Python

Call function trong Python hoạt động thế nào?

Nếu bắt phải đưa ra một từ khoá, thì đó là các argument sẽ được “pass by assignment”. Để thực sự hiểu Python assignment làm gì, bạn cần hiểu về khái niệm name và binding trong Python.

Cách hoạt động của name và binding

x = 4
y = x
x = x + 1
print(x, y)

x là mấy và y là mấy?

Code này đọc theo thuật ngữ của Python như sau:

  • bind name x vào object 4
  • bind name y vào object mà x HIỆN TẠI đang bind vào (tức 4)
  • bind name x vào object tạo ra bởi x+1 (tức 5) do x là 4, khi +1, nó sinh ra một object mới là 5.

Vậy rõ ràng kết quả ở đây: x là 5, y là 4. Chú ý rằng y không đi theo x, cũng không bind vào x, nó bind vào object mà x bind tại thời điểm đó.

Xem ví dụ sau tương tự, nhưng khác hẳn:

L = [1,2,3]
K = L
L[0] = 9
print(L, K)

L là mấy? và K là mấy?

Đây nhẽ ra, phải là câu hỏi phỏng vấn mặc định cho lập trình viên Python chứ không phải mấy câu vớ vẩn như tiêu đề bài này. Vì sao? vì nếu lập trình viên trả lời đúng, tức là anh ta hiểu cách Python hoạt động, và sẽ không tạo ra những bug rất cơ bản trong chương trình.

Hãy đọc đoạn code này theo thuật ngữ Python:

  • bind name L vào list object chứa 1,2,3
  • bind name K vào object mà L hiện tại đang bind vào (tức list 1,2,3)
  • Thay đổi phần tử đầu tiên của list, gán cho giá trị bằng 9

Hãy nhớ L và K chỉ là 2 cái tên cùng bind vào một object, khi object này bị thay đổi, dù dùng qua tên L hay tên K, thì thay đổi đó là thực hiện trên object đó. Tức kết quả sẽ cho L và K giống nhau (hay chính xác hơn, chúng là một). Dùng function id sẽ giúp hiểu rõ hơn khi nói về object và name:

>>> L = [1,2,3]
>>> K = L
>>> L[0] = 9
>>> print(L, K)
[9, 2, 3] [9, 2, 3]
>>> id(L)
4326049992
>>> id(K)
4326049992
>>> L is K
True

id sẽ trả về một số ID (đảm bảo là duy nhất) gắn liền với object mà cái name đó đang bind.

  Khởi Đầu Dự Án Python Như Thế Nào Để Thuận Tiện Phát Triển Lên

Cơ chế hoạt động của function

>>> def change(numb, ns):
...     numb = numb + 1
...     ns[0] = 0
...     return None
...
>>> N = 9
>>> L = [1,2,3]
>>> change(N, L)
>>> print(N, L)
9 [0, 2, 3]

Cơ chế gọi function của Python hoạt động như sau:

  • bind name numb vào argument thứ nhất, tức numb = N
  • bind name ns vào argument thứ hai, tức ns = L
  • bind numb vào object tạo ra bởi numb + 1, tức 10
  • thay đổi object mà name ns đang bind tới, tức list [1,2,3], thay đổi giá trị ứng với index 0, tức sẽ có [0,2,3]
  • nên nhớ rằng ns và L cùng bind đến 1 object. Vì vậy giờ L cũng đã bị thay đổi

Vậy làm sao để không thay đổi list L và thu về một list mới sau khi gọi function? Hãy tạo một bản copy của list rồi dùng bản copy đó.

>>> def change(L):
...     L = L[:] # slicing là một cách đơn giản để tạo một bản shallow copy
...     L[0] = 0
...     return L
...
>>> newL = change(L)
>>> print(L)
[1, 2, 3]
>>> print(newL)
[0, 2, 3]

CHÚ Ý: Nếu list L chứa các mutable object (xem ở dưới), cần sử dụng function copy.deepcopy trong standard library copy.

Một số kiểu dữ liệu trong Python không cho phép thay đổi giá trị của nó sau khi tạo ra (immutable) như int, float, str, NoneType, bool, tuple. Vì vậy mỗi lần “thay đổi”, ta sẽ tạo ra một object mới chứa giá trị mới:

>>> N = 9
>>> id(N)
4297624192
>>> N = N + 2
>>> id(N)
4297624256
>>> N
11

>>> T1 = (1,2,3)
>>> id(T1)
4326100280
>>> T1 = T1 + (3,4,5)
>>> id(T1)
4325883048
>>> print(T1)
(1, 2, 3, 3, 4, 5)

Các kiểu dữ liệu khác cho phép thay đổi sau khi tạo ra (mutable): list, dict, set.

>>> L = [1,2,3]
>>> id(L)
4326050504
>>> L.extend([3,4,5])
>>> id(L)
4326050504
>>> print(L)
[1, 2, 3, 3, 4, 5]

Với kiểu mutable, cần đặc biệt chú ý phép toán nào trả về object mới, phép toán nào thay đổi object hiện tại:

>>> L = [1,2,3]
>>> id(L)
4326050568
>>> L = L + [3,4,5]
>>> id(L)
4326095240
>>> L
[1, 2, 3, 3, 4, 5]

appendextend của list đều thay đổi object gọi method. Phép + list với list, sinh ra một list mới.

Python dùng pass by assignment, call by object reference

Pass by assignment là khái niệm lấy từ Python FAQ, khi mà người ta bắt buộc phải giải thích khái niệm này cho những người đã biết ngôn ngữ lập trình khác. Các name trong function sẽ bind tới các object mà argument đang bind tới.

Trong tutorial Python, có viết “các argument được pass sử dụng call by value, với các value luôn luôn là các object reference chứ không phải value của object.” – yup, I lied

Định nghĩa name trong Python:

Names refer to objects.

Liệu bạn có thể bịa ra một thuật ngữ nữa là “call by name” ??!!!

Chốt, thông

Để khỏi đau đầu về những điều này, chỉ cần nắm chắc các khái niệm namebindingmutableimmutable là đủ biết chương trình chạy thế nào. Bạn không cần biết gọi tên Python là call-by-gì? Nếu cần thể hiện thì hãy nói “call-by-object-reference” và gửi kèm link doc.

Trên internet có nhiều nơi hỏi đáp, cố đưa ra một cái tên, nhưng những cái tên đó không có trong tài liệu chính thống của Python.

Tham khảo

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

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

Xem thêm việc làm it online hấp dẫn trên TopDev

AspectMock là gì? Tại sao dùng AspectMock với Codeception

AspectMock là gì? Tại sao dùng AspectMock với Codeception

Bài viết được sự cho phép của tác giả Lê Chí Dũng

1. AspectMock là gì?

AspectMock là PHP mocking framework đã được tối ưu và dễ sử dụng so với Mock trong PHP Unit và Mockery. Nó được tạo ra như một phần mở rông trong việc sử dụng Codeception hoặc PHP Unit để test. Vì quá thuận tiện và ngắn gọn nên trong lúc viết test code, mình vẫn thấy khó khăn trong việc custom lại. Cái này thì tùy mỗi người dùng sẽ có cảm nhận riêng, mình vẫn đánh giá cao framework này.

2. Tại sao dùng AspectMock với Codeception?

Để biết câu trả lời hãy xem ưu điểm khi sử dụng AspectMock so với Mock/Stub trong PHP Unit:

  • Nhân bản được các static methods
  • Nhân bản các class methods called anywhere
  • Cách viết dễ dàng, dễ nhớ và ngắn gọn vô cùng so với PHP Unit.
  • Do kế thừa từ PHP Unit nên bạn có thể dùng PHP Unit tùy ý trong AspectMock nếu cần.

3. Cài đặt

Tham khảo tại https://github.com/Codeception/AspectMock

php composer.phar update

composer require codeception/aspect-mock --dev

4. Sử dụng

4.1. Mock / Stub (Object / Function)

4.1.1. Object and some function in it

Mock Class and fake some method in it using aspectMock

aspectMock::double function
$mock = aspectMock::double('\Name\Space\MockClassName', array(
    'methodNeedMock' => 'fake return value',
    'methodNeedMock2' => array('different fake return value'),
));

Stub Class and fake some method in it using aspectMock (replace double for Stub)

aspectMock::spec function 
$mock = aspectMock::spec('\Name\Space\MockClassName', array(
    'methodNeedMock' => 'fake return value',
    'methodNeedMock2' => array('different fake return value'),
));

Another way, using PhpUnit (not recommended in this document)

PhpUnit getMockBuilder 
$resultSet = $this->getMockBuilder('ResultSet')
    ->setMethods(['current', 'as_array'])        // Add list function for use
    ->getMock();
$resultSet->method('as_array')->willReturn(array('Fake return array'));

Get Class instance with call / not call constructor

PhpUnit getMockBuilder 
//  Simple
$obj = $mock->construct();
 
//  With construct params
$obj = $mock->construct($param1,$param2);
 
//  Without calling constructor
$obj = $mock->make();

4.1.2. Built-in PHP function

public static func($namespace, $functionName, $body)
aspectMock::func('\Name\Space', 'date', function($format) {
   if ($format == 'Y') {
     return 2004;
   } else {
     return \date($format);
   }
}

4.1.3. Test private / protect function

$reflection        = new \ReflectionClass('MyClassName');
$reflection_method = $reflection->getMethod('MyMethodName');
$reflection_method->setAccessible(true);

4.2. Verify Invoked Function

// Verify invoked at least once
$obj->verifyInvoked('methodName');
 
 
// Invoked exactly with $param1 and $param2 values
$obj->verifyInvoked('methodName',[$param1,$param2]);
 
 
// Inovked that method was called exactly $times times.
 $obj->verifyInvokedMultipleTimes('methodName', $times, $params = array());
 
 
// Method never invoked
$obj->verifyNeverInvoked('methodName', $params = array());
 
 
// Get list of call method with all of params for each call
$user = aspectMock::double('UserModel');
$user->someMethod('arg1', 'arg2');
$user->someMethod('arg3', 'arg42');
$user->getCallsForMethod('someMethod') // Will return [ ['arg1', 'arg2'], ['arg3', 'arg4']]

4.3. Annotations

4.3.1. @dataProvider

Test function with params in data set

Examplie 
/**
 * @dataProvider additionProvider
 */
public function testAdd($a, $b, $expected)
{
    $this->assertEquals($expected, $a + $b);
}
 
public function additionProvider()
{
    return [
        [0, 0, 0],
        [0, 1, 1],
        [1, 0, 1],
        [1, 1, 3]
    ];
}

4.3.2. @require

Possible @requires usages

Type
Possible Values
Examples
Another example
PHP Any PHP version identifier @requires PHP 5.3.3 @requires PHP 7.1-dev
PHPUnit Any PHPUnit version identifier @requires PHPUnit 3.6.3 @requires PHPUnit 4.6
OS A regexp matching PHP_OS @requires OS Linux @requires OS WIN32|WINNT
function Any valid parameter to function_exists @requires function imap_open @requires function ReflectionMethod::setAccessible
extension Any extension name along with an optional version identifier @requires extension mysqli @requires extension redis 2.2.0

4.3.3. @codeCoverageIgnore

exclude lines of code from the coverage analysis

4.4. Assert

Show more here

  • assertTrue()
  • assertFasle()
  • assertEquals($expect,$actual)
  • assertEmpty()
  • assertNull()
  • assertCount()
  • assertContain()

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

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

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

Tổng quan về Mobile Testing

Tổng quan về Mobile Testing

Bài viết được sự cho phép của vntesters.com

Mình có nhiều thời gian tham gia vào các dự án Mobile khác nhau, học tập từ các PM, developer để đúc rút ra các kinh nghiệm này. Mình nghĩ là những cái mình viết ra ở dưới đây sẽ có ích cho các bạn mới vào nghề Tester, còn chưa có kinh nghiệm gì với mảng này. Tất nhiên là nội dung của bài viết còn nhiều hạn chế, có thể nó không đúng với nhiều anh/ chị tester có kinh nghiệm, rất mong mọi người cho thêm các phản hồi.

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

  7 Tip tăng tương tác hiệu quả trên mobile
  Flutter là gì? Ưu điểm vượt trội và cơ hội việc làm hấp dẫn

Cấu trúc các phần của 1 dự án Mobile (không tính đến các app game offline kiểu Plappy Bird) gồm có 2 phần: Client và Server.

Nhưng dự án chia thành những đầu việc khác nhau:
– Phân tích business để đưa ra cấu trúc hệ thống tổng thể, bao gồm luồng logic + cấu trúc DB + chọn ngôn ngữ lập trình + ứng dụng bên thứ 3 (cổng thanh toán, tổng đài điện thoại…)
– Viết Back-end và API
– Viết giao diện Mobile (Android và iOS) + ghép API + config cơ chế Notification và connection
– Viết trang Admin quản trị.

Tương ứng với phần trên, mình sẽ phải test những thành phần sau:
– Hiển thị của Mobile
– Logic của App
– Trang quản trị Admin
– Performance của Mobile và performance của Server

Mình quan sát thấy nhiều bạn nghĩ đơn giản công việc hàng ngày là cầm điện thoại để bấm bấm xem nó hoạt động có đúng không? Thì đúng rồi, công việc test mobile chính xác là như vậy. =)))) Mình có thể chỉ cần dùng điện thoại để test tất cả hệ thống, nhưng mình sẽ chả biết lỗi của Client hay Server, cũng không biết là mình sẽ phải học cái gì để nâng cao trình độ cho Mobile Testing. Xin được nhắc lại, 1 dự án Mobile KHÔNG nằm chỉ trên Mobile. Nó còn là API testing, Web testing…

Sau khi xác định đối tượng test là cái gì, mình để có thể dùng các công cụ khác nhau làm giảm thời gian tạo data –> giảm thời gian test mà vẫn chính xác.

Ví dụ: Khi bạn muốn tạo ra đăng ký 1 chuyến đi (kiểu uber). Nếu như bạn test trên điện thoại thì phải điền điểm đến, điểm đi và 1 vài trường dữ liệu nữa. Như thế tốn khoảng 30s để tạo được 1 chuyến đi trên điện thoại, trong khi đó, nếu ta dùng 1 công cụ để call API thì mất tầm 1-2s là xong. Tất nhiên, ta phải mất thời gian cho việc lưu thông số API lần đầu tiên.

Những bài viết sắp tới, mình sẽ nói rõ hơn, test từng cái mục ở trên thì làm như thế nào và cần trang bị kiến thức Tech gì. 😀

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

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

Các loại layout trong Android (RelativeLayout, LinearLayout)

Các loại layout trong Android (RelativeLayout, LinearLayout)

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

Các loại layout trong Android (RelativeLayout, LinearLayout)

1. Layout là gì?

Layout là thành phần định nghĩa cấu trúc giao diện người dùng hay nói cách khác là thành phần quyết định đến giao diện của một màn hình trong ứng dụng Android. Layout hỗ trợ việc căn chỉnh các widget (Ví dụ: TextView, Button, hay EditText…) như chúng ta thấy trong các ứng dụng Android.

2. Các loại Layout trong Android.

Android đang hỗ trợ chúng ta 6 loại layout:

  • RelativeLayout
  • LinearLayout
  • GridLayout
  • TableLayout
  • Framelayout
  • ConstraintLayout.

Hôm nay mình sẽ hướng dẫn các bạn làm việc với RelativeLayout và LinearLayout

Tuyển dụng lập trình android làm việc online

3. RelativeLayout

RelativeLayout là một ViewGroup có hiển thị các View con ở các vị trí tương đối. Vị trí của mỗi View có thể được quy định liên quan đến các View anh em (như bên trái của hoặc bên dưới một View khác) hoặc ở các vị trí tương đối với khu vực cha RelativeLayout(chẳng hạn như sắp xếp ngay phía dưới, bên trái hoặc trung tâm).

a. Thuộc tính Gravity

Các View con khi đã định vị xong trong RelativeLayout, giả sử coi như tất cả các View con nằm vừa trong một đường biên chữ nhật, thì cả khối các View con này có thể dịch chuyển tới những vị trí nhất định trong RelativeLayout bằng thuộc tính: android:gravity, nó nhận các giá trị (có thể tổ hợp lại với ký hiệu | )

Giá trị Ý nghĩa
center Căn ở giữa
top Ở phần trên
bottom Phần dưới
center_horizontal Ở giữa theo chiều ngang
center_vertical Ở giữa theo chiều đứng
left Theo cạnh trái
right Theo cạnh phải
bottom Cạnh dưới

b. Định vị view con bằng view cha

Vị trí của View con trong RelativeLayout có thể thiết lập bằng cách chỉ ra mối liên hệ vị trí với view cha, như căn thẳng cạnh trái View cha với View con, căn thẳng cạnh phải View cha với View con… Các thuộc tính thực hiện chức năng này như sau:

Thuộc tính Ý nghĩa
android:layout_alignParentBottom true căn thẳng cạnh dưới view con với cạnh dưới View cha
android:layout_alignParentLeft true căn thẳng cạnh trái view con với cạnh trái View cha
android:layout_alignParentRight true căn thẳng cạnh phải view con với cạnh phải View cha
android:layout_alignParentTop true căn thẳng cạnh trên view con với cạnh trên View cha
android:layout_centerInParent true căn view con vào giữa View cha
android:layout_centerHorizontal true căn view con vào giữa View cha theo chiều ngang
android:layout_centerVertical true căn view con vào giữa View cha theo chiều đứng
  Hướng dẫn sử dụng Framelayout trong android
  Làm layout masonry bằng flexbox

c .Định vị các view con với nhau bằng thuộc tính liên hệ với nhau

Tất cả các thuộc tính dưới đây cần phải truyền vào một ID @+id/

  • android:layout_alignTop – Chỉ định đỉnh của thành phần này sẽ được canh theo đỉnh của thành phần gọi đến bằng ID.
  • android:layout_alignBottom – Chỉ định đáy của thành phần này sẽ được canh theo đáy của thành phần gọi đến bằng ID.
  • android:layout_alignStart – Chỉ định cạnh start của thành phần này sẽ được canh theo cạnh start của thành phần gọi đến bằng ID.
  • android:layout_alignEnd – Chỉ định cạnh end của thành phần này sẽ được canh theo cạnh end của thành phần gọi đến bằng ID.
  • android:layout_alignBaseline – Chỉ định baseline của thành phần này sẽ được canh theo baseline của thành phần gọi đến bằng ID. Baseline này bạn không nhìn thấy được, dùng để canh chỉnh cho text hiển thị bên trong widget, do đó sẽ hữu dụng khi canh chỉnh các TextView với nhau).
  • android:layout_above – Chỉ định thành phần này sẽ nằm ở trên so với thành phần gọi đến bằng ID.
  • android:layout_below – Chỉ định thành phần này sẽ nằm dưới so với thành phần gọi đến bằng ID.
  • android:layout_toStartOf – Chỉ định thành phần này sẽ nằm bên phía start so với thành phần gọi đến bằng ID.
  • android:layout_toEndOf – Chỉ định thành phần này sẽ nằm bên phía end so với thành phần gọi đến bằng ID.
  • android:layout_toLeftOf – Chỉ định thành phần này sẽ nằm bên phía trái so với thành phần gọi đến bằng ID.
  • android:layout_toRightOf – Chỉ định thành phần này sẽ nằm bên phía phải so với thành phần gọi đến bằng ID.

Ví dụ: Hôm nay mình sẽ hướng dẫn các bạn thiết kế giao diện như này mà code xml sử dụng relativeLayout.

Các loại layout trong Android (RelativeLayout, LinearLayout)

mình có 4 cái hộp với màu sắc khác nhau được sắp xếp cạnh nhau và mỗi hộp đều được gán id từ hop1->hop4 như bạn thấy hộp 2 ở bên phải hộp 1 nên tôi dùng thuộc tính:

android:layout_toRightOf="@+id/hop1” để đưa hộp 2 về bên phải hộp 1. Hộp 4 nằm bên phải hộp 3 và dưới hộp 2 nên tôi sử dụng hai thuộc tính
android:layout_below="@+id/hop2" android:layout_toRightOf="@+id/hop3" để đưa hộp 4 về bên trái hộp 3 và dưới hộp hai. Bạn thấy trong thuộc tính android:layout_toRightOf có giá trị là 1 id của một view vì Relative Layout sử dụng ID để xác định các vị trí của view với nhau mà.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:text=" Hop 1"
android:textColor="@android:color/black"
android:id="@+id/hop1"
android:textSize="10pt"
android:textAlignment="center"
android:background="#D32F2F"
/>

<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:text=" Hop 2"
android:textColor="@android:color/black"
android:id="@+id/hop2"
android:textSize="10pt"
android:textAlignment="center"
android:layout_toRightOf="@+id/hop1"
android:background="#FFEB3B"
/>

<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:text=" Hop 3"
android:textColor="@android:color/black"
android:id="@+id/hop3"
android:background="#FFAB40"
android:textSize="10pt"
android:textAlignment="center"
android:layout_below="@+id/hop1"
/>

<TextView
android:layout_width="150dp"
android:layout_height="50dp"
android:text="Hop 4"
android:textColor="@android:color/black"
android:id="@+id/hop4"
android:textSize="10pt"
android:textAlignment="center"
android:background="#E040FB"
android:layout_below="@+id/hop2"
android:layout_toRightOf="@+id/hop3"
/>
</RelativeLayout>

4. LinearLayout

LinearLayout là loại layout sẽ sắp xếp các view theo chiều dọc hoặc ngang theo thứ tự của các view.

Đây là ViewGroup sẽ giúp các bạn sắp xếp các view con chứa bên trong theo dạng hàng ngay hoặc hàng dọc với nhau. Nhìn vào các hình ảnh dưới đây bạn sẽ hình dung được ngay công dụng của LinearLayout là gì liền.

Đây là ví dụ sắp xếp theo chiều ngang

Các loại layout trong Android (RelativeLayout, LinearLayout)

a. Thuộc Tính Lực Hấp Dẫn (Gravity)

Mặc định thì các thành phần con bên trong LinearLayout sẽ được “hút” về start-top theo “lực hấp dẫn” mặc định

Thuộc tính android:gravity để căn chỉnh các View nằm ở vị trí nào trong LinearLayout, nó nhận các giá trị (có thể tổ hợp lại với ký hiệu |)

center Căn ở giữa
top Ở phần trên
bottom Phần dưới
center_horizontal Ở giữa theo chiều ngang
center_vertical Ở giữa theo chiều đứng
left Theo cạnh trái
right Theo cạnh phải
bottom Cạnh dưới

Ví dụ android:gravity=”right|center”

b. Thuộc Tính Trọng Số (Weight)

Các View con trong LinearLayout có thể gán cho nó một giá trị trọng số bằng thuộc tính android:layout_weight ví dụ như: android:layout_weight="2"; android:layout_weight="1.5" ... . Nếu View không gán giá trị này coi như nó có trọng số bằng không.

Trường hợp LinearLayout không sử dụng đến thuộc tính android:weightSum.

Khi chúng ta muốn các view tự động full màn hình thì sử dụng android:weightSum.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:background="#a6dfdfdf"

android:weightSum="4"

android:divider="@drawable/butterfly"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:background="#dc9e1a"
android:text="B1"
android:layout_width="match_parent"
android:layout_height="30dp" />
<Button
android:layout_weight="1"
android:background="#00c853"
android:text="B1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Butto
android:layout_weight="1"
android:background="#141ba9"
android:text="B1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_weight="1"
android:background="#dc1a8b"
android:text="B1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

Các loại layout trong Android (RelativeLayout, LinearLayout)

References: https://developer.android.com/guide/topics/ui/declaring-layout

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

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

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

Hiểu hơn về CAP Theorem trong System Design

Hiểu hơn về CAP Theorem trong System Design

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

Một số bạn mới bắt đầu làm quen với System Design khi thấy CAP Theorem không khỏi bỡ ngỡ. Theorem – Định lý, nghe thôi là đã thấy nhức đầu. Tuy nhiên trong System Design thì CAP không quá phức tạp.

  11 mẹo đơn giản để tăng hiệu suất Java cấp tốc
  Capacity Planning - Dự toán công suất cho ứng dụng (Tập 1 )

Biết về CAP Theorem giúp ta có cái nhìn tổng quan hơn, tốt hơn khi thiết kế hệ thống. Không những vậy còn tránh những sai sót không đáng có khi thiết kế.

Bắt đầu ngay thôi nào!

1. CAP Theorem là gì?

CAP bao gồm 3 từ consistencyavailability, và partition tolerance. (Tính nhất quán, tính khả dụng và dung sai phân vùng).

The CAP theorem applies a similar type of logic to distributed systems—namely, that a distributed system can deliver only two of three desired characteristics: consistencyavailabilityand partition tolerance (the ‘C,’ ‘A’ and ‘P’ in CAP).

Định lý CAP áp dụng một loại logic tương tự cho các hệ thống phân tán (Distributed Systems) — cụ thể là hệ thống phân tán chỉ có thể cung cấp hai trong ba đặc tính mong muốn: tính nhất quán, tính khả dụng và dung sai phân vùng (chữ ‘C,’ ‘A’ và ‘P’ trong CAP ).

2. Cap Theorem và Cloud Applications

Đọc qua định nghĩa phía trên chắc một số bạn sẽ thắc mắc về Hệ thống phân tán. (Distributed System)

A distributed system is a network that stores data on more than one node (physical or virtual machines) at the same time. Because all cloud applications are distributed systems, it’s essential to understand the CAP theorem when designing a cloud app so that you can choose a data management system that delivers the characteristics your application needs most.

Hệ thống phân tán và mạng lưới lưu trữ dữ liệu trên nhiều hơn một node (vật lý hoặc máy ảo) trong cùng một thời điểm. Bởi vì tất cả các cloud applications là hệ thống phân tán, điều cần thiết là phải hiểu định lý CAP khi thiết kế ứng dụng đám mây. Để sau này có gì còn có thể chọn hệ thống quản lý dữ liệu phù hợp nhất với ứng dụng đang phát triển.

Đấy, hiểu biết về CAP Theorem cũng là một điểm cộng lớn, cần thiết để nâng cao skills khi làm việc với cloud applications. Phân tích sâu hơn vào từng chữ cái ha.

2.1 Consistency – tính nhất quán

Giả sử bạn đang thiết kế hệ thống bán vé máy bay. Sau khi thiết kế xong xuôi, hệ thống đưa vào vận hành.

Giá vé từ HCM- Thailand có thay đổi, cập nhật từ $300 lên $350. Client A load website trước khi giá cập nhât, thấy giá vé chỉ $300. Client B vào ngay sau đó, lại thấy giá $350.

Hiểu hơn về CAP Theorem trong System Design

Chính sự khác biệt này được gọi là không nhất quán, dữ liệu hiển thị cho client tốt nhất nên giống nhau về tất cả nội dung.

Consistency means that all clients see the same data at the same time, no matter which node they connect to. For this to happen, whenever data is written to one node, it must be instantly forwarded or replicated to all the other nodes in the system before the write is deemed ‘successful.’

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

Hiểu hơn về CAP Theorem trong System Design

Thiết kế sao cho dữ liệu trong toàn bộ hệ thống được nhất quán, giống nhau ở tất cả các client, giống nhau ở cùng hoặc một thời điểm client load máy. Đó là đảm bảo cho chữ C – Consistency – Tính nhất quán trong CAP Theorem

2.2 Availability – tính sẵn sàng

Phần thứ hai trong CAP Theorem là Availability – tính sẵn sàng. Ngoài chuyện dữ liệu phải đảm bảo tính nhất quán. Dữ liệu cũng phải sẵn sàng cho người dùng.

Availability means that that any client making a request for data gets a response, even if one or more nodes are down.

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

Tính sẵn sàng cũng là một phần đáng nhớ. Thực tế ứng dụng rất nhiều trong micro service. Khi một node hoặc một service con down, các service khác vẫn có thể hoạt động độc lập.

Hiểu hơn về CAP Theorem trong System Design

2.3 Partition tolerance – dung sai phân vùng

Chỗ này dịch dung sai phân vùng thì không biết có đúng không nữa. Thôi thì điểm xuyết qua cái lý thuyết bên tiếng Anh xem sao.

Partition tolerance means that the cluster must continue to work despite any number of communication breakdowns between nodes in the system.

Dung sai phân vùng ở đây được hiểu rằng cụm máy tính vẫn nên tiếp tục hoạt động, cho dù một số kết nối giữa các nối bị hư hại.

À, vậy là từ Partition tolerance dung sai phân vùng ở đây phải được hiểu như bên kỹ thuật. Khi thực hiện hàn, cắt, ghép với độ chính xác cao, sẽ có một con số có thể chấp nhận là dung sai

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

Hiểu hơn về CAP Theorem trong System Design

3. Tổng kết

The CAP theorem is also called Brewer’s Theorem, because it was first advanced by Professor Eric A. Brewer during a talk he gave on distributed computing in 2000

CAP Theorem cũng có tên khác là Brewer’s Theorem, bởi vì nó xuất hiện lần đầu khi giá sư Brewer nói chuyện về distributed computing năm 2000

4. Tham khảo

Bài viết về CAP

Một số bài viết hay khác về Design System.

Có gì thắc mắc cứ comment đây nha! – Please feel free to comment here!
Bài viết gốc được đăng tải tại kieblog.vn
Có thể bạn quan tâm:
Xem thêm Việc làm Developer hấp dẫn trên TopDev

Kết nối ứng dụng Spring Framework với Cơ sở dữ liệu SQL

Kết nối ứng dụng Spring Framework với Cơ sở dữ liệu SQL

Bài viết được sự cho phép của tác giả Trần Thị Thu Hà

Hầu hết các ứng dụng Java doanh nghiệp (Java enterprise system) đều cần kết nối đến Hệ quản trị cơ sở dữ liệu SQL. Spring Framework hỗ trợ thao tác với Hệ quản trị CSDL thuộc 3 dạng thường gặp là:

– JPA (Java Persistence API)

– JDBC (Java database Connectivity)

– Hibernate

Trong bài viết này, SmartJob sẽ hướng dẫn bạn cấu hình kết nối ứng dụng Spring Framework với CSDL MySQL. Trong tình huống này, có 3 cách để cấu hình kết nối:

– Sử dụng file XML

– Sử dụng code Java (*)

– Sử dụng Annotation

  Bảo mật ứng dụng Java web bởi Spring Security
  10 Frameworks tốt nhất hiện nay cho PHP

Bài viết này sử dụng cách (*) để khai báo thông số kết nối.

Khởi tạo project Spring sử dụng Gradle buid system
(Nếu bạn chưa rõ cách khởi tạo project theo cách này, hãy xem lại bài viết Kỹ thuật Autowiring sử dụng annotation trong Spring Framework và Gọi các object của Autowired Collections theo thứ tự trong Spring Framework)

File build.gradle

Cấu hình kết nối đến CSDL bởi một class Java:

Khi kết nối đến CSDL, cần các thao tác như tạo kết nối, mở kết nối, đóng kết nối:

Download source code: configuring-datasource . Hoặc clone/fork từ GitHub: https://github.com/SmartJobVN/configuring-datasource

Đỗ Như Vý – Bài viết gốc được đăng tải tại smartjob.vn

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

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

Một vài thay đổi đáng chú ý của Chrome 90

Một vài thay đổi đáng chú ý của Chrome 90

Bài viết được sự cho phép của tác giả Lưu Bình An

Công cụ debug CSS Flexbox xịn xò hơn

Một vài thay đổi đáng chú ý của Chrome 90

Giờ nếu có một HTML element có dạng display: flex hoặc display: inline-flex, bạn sẽ thấy một cái nút bé bé flex trên cái Element panel

Bên dưới Style panel, sẽ có thêm một icon nhỏ kế bên display: flex, click vào đó sẽ mở ra một menu để lựa chọn như trên hình.

Trong Layout Panel sẽ có thêm một khu vực cho Flexbox liệt kê tất cả các element đang có dạng hiển thị flex

  30 tiện ích Chrome (extensions) cho Designer và Developer
  30 tiện ích Chrome cho designer và dev

Đo performance bằng Core Web Vitals

Core web vitals là một bộ hướng dẫn do google khởi xướng để đánh giá thế nào là một trang web xịn xò.

Ctrl + Shift + P để mở Command menu trong DevTools, tìm mục Show Rendering, click vào checkbox Core Web Vitals

Một ô màu đen nho nhỏ sẽ xuất hiện chứa các thông tin quan trọng sau:

Một vài thay đổi đáng chú ý của Chrome 90

Tab Issue

Một vài thay đổi đáng chú ý của Chrome 90

Số issue có trên trang được move lên trên cùng của Console Panel để nhắc nhở chúng ta ngày này quá tháng nọ.

Bổ sung Trusted Web Activity, lại nhắc nhẹ chúng ta về chất lượng của ứng dụng

Một vài thay đổi đáng chú ý của Chrome 90

Xem thêm video này của Andre để hiểu thêm

Định dạng lại chuỗi trong console

Chuỗi trong console sẽ được định dạng theo chuẩn JS string literal, nó sẽ escape ký tự "

Một vài thay đổi đáng chú ý của Chrome 90

Trust token panel trong Application

Bên trong tab Application, có thêm mục mới Trust Tokens

Trust Token là một API mới giúp chống gian lận, phân biệt người thật với bot, tìm hiểu thêm

Một vài thay đổi đáng chú ý của Chrome 90

Ngưng support fn.displayName

Một vài thay đổi đáng chú ý của Chrome 90

Trước đây Chrome vẫn cho phép sử dụng fn.displayName để có dễ trace lỗi lúc debug. Giờ sẽ được thay thế bằng fn.name

Xem toàn bộ các thay đổi khác

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

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

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

Viết React Code sạch hơn như thế nào? (Phần 2)

clean react code
Viết React Code sạch hơn như thế nào? (Phần 2)

Tác giả: Reed Barger

Tiếp tục chuỗi bài chia sẻ về cách viết React code như thế nào để gọn gàng và dễ đọc nhất, các React developers có thể tham khảo thêm phần tiếp theo với bài viết này.

clean react code
Clean React code cùng một số tips dưới đây

5. Xóa càng nhiều JavaScript khỏi JSX càng tốt

Một cách khác rất hữu ích nhưng thường bị các devs bỏ qua khi dọn dẹp các thành phần không cần thiết trong code của mình đó là xóa càng nhiều JavaScript khỏi JSX càng tốt.

Hãy xem qua ví dụ dưới đây:

// src/components/FeaturedPosts.js

import useFetchPosts from '../hooks/useFetchPosts.js';

export default function FeaturedPosts() {
  const posts = useFetchPosts()

  return (
    <ul>
      {posts.map((post) => (
        <li onClick={event => {
          console.log(event.target, 'clicked!');
        }} key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

Với đoạn code trên chúng ta có thể dễ dàng thấy rằng JSX đã trở nên khó đọc hơn nhiều. Cho rằng hàm được bao gồm như một hàm nội tuyến, vì thế đã khiến mục đích của thành phần này cũng như các chức năng liên quan của nó bị che khuất.

Vậy chúng ta có thể làm gì để khắc phục các vấn đề này? Các devs có thể trích xuất hàm nội tuyến, được kết nối với hàm onClick thành một trình xử lý riêng biệt. Khi làm như vậy, JSX có thể đọc được code một lần nữa:

// src/components/FeaturedPosts.js

import useFetchPosts from '../hooks/useFetchPosts.js';

export default function FeaturedPosts() {
  const posts = useFetchPosts()
  
  function handlePostClick(event) {
    console.log(event.target, 'clicked!');   
  }

  return (
    <ul>
      {posts.map((post) => (
        <li onClick={handlePostClick} key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

6. Định dạng kiểu nội tuyến để code đơn giản hơn

Mô hình chung cho các React dev là viết các kiểu nội tuyến – inline styles trong JSX của mình. Nhưng điều này có thể làm cho code trở nên khó đọc hơn và khó viết thêm JSX:

// src/App.js

export default function App() {
  return (
    <main style={{ textAlign: 'center' }}>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  return (
    <div style={{ marginTop: '20px' }}>
      <h1 style={{ fontWeight: 'bold' }}>{title}</h1>
    </div>
  )
}

Ở đây sẽ áp dụng khái niệm tách biệt mối quan tâm này cho các kiểu JSX bằng cách chuyển các kiểu nội tuyến vào một CSS stylesheet, ở đó cho phép bạn nhập vào bất kỳ thành phần nào.

Một cách thay thế để viết lại các kiểu nội tuyến là sắp xếp chúng thành các đối tượng như bên dưới

// src/App.js

export default function App() {
  const styles = {
    main: { textAlign: "center" }
  };

  return (
    <main style={styles.main}>
      <Navbar title="My Special App" />
    </main>
  );
}

function Navbar({ title }) {
  const styles = {
    div: { marginTop: "20px" },
    h1: { fontWeight: "bold" }
  };

  return (
    <div style={styles.div}>
      <h1 style={styles.h1}>{title}</h1>
    </div>
  );
}

7. Giảm prop drilling với React context

Một pattern thiết yếu khác để sử dụng cho các dự án React là sử dụng React Context.

Chẳng hạn nếu bạn muốn chia sẻ dữ liệu người dùng trên nhiều thành phần, thay vì nhiều props lặp lại (một pattern được gọi là props drilling), có thể sử dụng context feature được tích hợp trong thư viện React.

Trong trường hợp này, nếu muốn sử dụng lại dữ liệu người dùng trên các Navbar và FeaturesPosts components, tất cả những gì cần làm là wrap toàn bộ ứng dụng trong một thành phần của provider.

Tiếp theo, có thể chuyển dữ liệu người dùng xuống value prop và sử dụng context đó trong các individual components với sự trợ giúp của useContexthook

// src/App.js

import React from "react";

const UserContext = React.createContext();

export default function App() {
  const user = { name: "Reed" };

  return (
    <UserContext.Provider value={user}>
      <main>
        <Navbar title="My Special App" />
        <FeaturedPosts />
      </main>
    </UserContext.Provider>
  );
}

// src/components/Navbar.js

function Navbar({ title }) {
  const user = React.useContext(UserContext);

  return (
    <div>
      <h1>{title}</h1>
      {user && <a href="/logout">Logout</a>}
    </div>
  );
}

// src/components/FeaturedPosts.js

function FeaturedPosts() {
  const posts = useFetchPosts();
  const user = React.useContext(UserContext);

  if (user) return null;

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

Trên đây là tổng hợp những cách các React developers có thể áp dụng để cải thiện code của mình. Việc áp dụng chúng một cách hiệu quả sẽ giúp cho code dễ đọc hơn, gọn gàng hơn và tăng thêm hiệu quả cho các dự án làm việc liên quan đến React.

Bài viết phỏng dịch theo bài viết gốc tại freecodecamp.org

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

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

Cây nhị phân trong C++

Cây nhị phân trong C++
Bài viết được sự cho phép của tác giả Khiêm Lê

 

Cây nhị phân là một cấu trúc dữ liệu quan trọng mà trong môn Cấu trúc dữ liệu và giải thuật các bạn sẽ được học, nó được sử dụng rất rộng rãi trong lập trình vì các ứng dụng của nó. Trong bài viết này, mình sẽ giới thiệu đến các bạn về cây nhị phân và một phiên bản đặc biệt của nó là cây nhị phân tìm kiếm. Trước tiên, ta cần biết được cây là gì?

  1001 Tips: Con trỏ và hàm (Pointer & Function) trong C++
  Bảng băm trong C++

Cấu trúc cây

Cấu trúc cây (Tree) là một tập hợp các phần tử gọi là nút (node), mỗi cây có một nút gốc (root) chứa nhiều nút con, mỗi nút con lại là một tập hợp các nút khác gọi là cây con (subtree).

Các khái niệm cơ bản về cây:

  • Bậc của nút: là số nút con của nút đó. Ví dụ bậc của nút A là 3, bậc của nút C là 1, bậc của nút G là 0…
  • Bậc của cây: là bậc lớn nhất của nút trong cây đó, cây bậc n sẽ được gọi là cây n – phân. Ví dụ cây trong hình trên có bậc 3, gọi là cây tam phân, cây có bậc 2 gọi là cây nhị phân…
  • Nút lá: nút lá là nút có bậc bằng 0. Ví dụ các nút lá: B, G, H, K, L, F
  • Nút nhánh: là nút có bậc khác 0 mà không phải nút gốc (hay còn gọi là nút trung gian). Ví dụ các nút C, D, E
  • Mức của nút: là số nguyên đếm từ 0, các nút ngang hàng nhau thì có cùng mức. Nút gốc A có mức là 0, mức 1 gồm các nút B, C, D, nút 3 gồm H, K, L.
  • Chiều cao (chiều sâu): là mức lớn nhất của các nút lá. Ví dụ cây trên có nút lá bậc lớn nhất là H, K, L mức 3, vậy chiều cao của cây là 3.
  • Độ dài đường đi đến nút x: là số nhánh (cạnh nối hai nút) cần đi qua tính từ nút gốc đến nút x. Hay độ dài đường đi đến nút mức i chính là i. Ví dụ nút E có độ dài đường đi là 2.

Khi bạn đã nắm được các khái niệm cơ bản này, chúng ta hãy đến luôn với cây nhị phân.

Cây nhị phân

Cây nhị phân là một trường hợp đặc biệt của cấu trúc cây và nó cũng phổ biến nhất. Đúng như tên gọi của nó, cây nhị phân có bậc là 2 và mỗi nút trong cây nhị phân đều có bậc không quá 2.

Các khái niệm

Có một số khái niệm khác về cây nhị phân các bạn cần nắm như sau:

  • Cây nhị phân đúng: là cây nhị phân mà mỗi nút của nó đều có bậc 2. Ví dụ như hình trên, hoặc hình trên bỏ đi nút H và I cũng là cây nhị phân đúng.
  • Cây nhị phân đầy đủ là cây nhị phân có mức của các nút lá đều bằng nhau. Ví dụ hình trên, tất cả các nút lá đều có mức 3.
  • Cây nhị phân tìm kiếm (sẽ tìm hiểu bên dưới)
  • Cây nhị phân cân bằng: số phần tử của cây con bên trái chênh lệch không quá 1 so với cây con bên phải.

Định nghĩa cấu trúc nút

Nhìn vào hình, ta có thể dễ dàng phân tích được rằng, mỗi nút trong cây nhị phân sẽ gồm 3 thành phần như sau:

  • Thành phần dữ liệu: có thể là bất kỳ kiểu dữ liệu nào.
  • Thành phần liên kết trái: lưu trữ địa chỉ của nút gốc của cây con bên trái. Kiểu dữ liệu là con trỏ trỏ vào node.
  • Thành phân liên kết phải: lưu trữ địa chỉ của nút gốc của cây con bên phải. Kiểu dữ liệu là con trỏ trỏ vào node.

Chúng ta sẽ có struct lưu trữ một node như sau – ở đây để đơn giản mình sử dụng kiểu dữ liệu int cho thành phần dữ liệu của node:

struct Node
{
    int data;
    Node *left;
    Node *right;
};

Khi tạo một nút node mới, chúng ta cần phải gán lại các thành phần của node để nó không nhận giá trị rác, tránh lỗi không mong muốn. Chúng ta sẽ tạo một biến động cho node và trả về địa chỉ của node đó, mình sẽ có đoạn code tạo node như sau:

Node *CreateNode(int init)
{
    Node *p = new Node;
    p->data = init;
    p->left = NULL;
    p->right = NULL;
    return p;
}

Định nghĩa cấu trúc cây

Để quản lý một cái cây, bạn chỉ cần quản lý được nút gốc, bạn có thể đi được đến các nhánh và lá của nó từ đó. Trên thực tế bạn không cần phải định nghĩa một kiểu dữ liệu nào để quản lý cả, tuy nhiên, để cho code rõ ràng hơn, bạn nên định nghĩa một kiểu dữ liệu cây nữa.

typedef Node* Tree;

Lúc này, khi tạo một cây, bản chất là nó sẽ tạo cho bạn một con trỏ có thể trỏ vào một node.

Tree myTree;

Vì nó là con trỏ nên các bạn gán nó bằng NULL để tránh lỗi, nhưng để mọi thứ rõ ràng hơn, mình sẽ dùng hàm tạo cây đơn giản gán nó bằng NULL.

void CreateTree(Tree &root)
{
    root = NULL;
}

// Khi tạo cây
CreateTree(myTree);

Duyệt cây nhị phân

Có 3 cách duyệt cây nhị phân:

  • Duyệt tiền tự (NLR): duyệt nút gốc, duyệt tiền tự cây con trái, duyệt tiền tự cây con phải.
  • Duyệt trung tự (LNR): duyệt trung tự cây con trái, duyệt nút gốc, duyệt trung tự cây con phải.
  • Duyệt hậu tự (LRN): duyệt hậu tự cây con trái, duyệt hậu tự cây con phải, duyệt nút gốc.

Để bạn hiểu rõ hơn ba cách duyệt này, chúng ta sẽ sử dụng lại hình ảnh cây nhị phân trên:

  • Duyệt tiền tự: A B D H I E K L C F M N G O P
  • Duyệt trung tự: H D I B K E L A M F N C O G P
  • Duyệt hậu tự: H I D K L E B M N F O P G C A

Ứng với từng cách duyệt đó, chúng ta sẽ có các hàm duyệt cây như sau:

Duyệt tiền tự

void NLR(Tree root)
{
    if (root)
    {
        // Xử lý nút gốc (root)
        NLR(root->left);
        NLR(root->right);
    }
}

Duyệt trung tự

void LNR(Tree root)
{
    if (root)
    {
        LNR(root->left);
        // Xử lý nút gốc (root)
        LNR(root->right);
    }
}

Duyệt hậu tự

void LRN(Tree root)
{
    if (root)
    {
        LRN(root->left);
        LRN(root->right);
        // Xử lý nút gốc (root)
    }
}

Hủy cây nhị phân

Để hủy đi cây nhị phân, các bạn cũng thực hiện duyệt và xóa đi các nút của cây, tuy nhiên, các bạn dễ thấy rằng, nếu ta duyệt tiền tự và trung tự, khi xóa nút nhánh thì sẽ bị mất luôn địa chỉ của các nút con. Do đó, việc hủy cây nhị phân bắt buộc phải duyệt hậu tự. Hay nói cách khác, bạn phải xóa các phần tử là nút lá xóa dần lên đến nút gốc.

Chúng ta sẽ có hàm hủy như sau:

void DestroyTree(Tree &root)
{
    if (root)
    {
        DestroyTree(root->left);
        DestroyTree(root->right);
        delete root;
    }
}

Như vậy là chúng ta đã tìm hiểu về cách tạo một nút, kết nối chúng lại thành một cây nhị phân, duyệt cây và hủy cây. Tiếp theo chúng ta sẽ tìm hiểu về cây nhị phân đặc biệt khác là cây nhị phân tìm kiếm.

Tham khảo thêm các vị trí tuyển lập trình viên C++ mới nhất.

Cây nhị phân tìm kiếm

Cây nhị phân tìm kiếm là cây nhị phân mà trong đó, các phần tử của cây con bên trái đều nhỏ hơn phần tử hiện hành và các phần tử của cây con bên phải đều lớn hơn phần tử hiện hành. Do tính chất này, cây nhị phân tìm kiếm không được có phần tử cùng giá trị.

Nhờ vào tính chất đặc biệt này, cây nhị phân tìm kiếm được sử dụng để tìm kiếm phần tử nhanh hơn (tương tự với tìm kiếm nhị phân). Khi duyệt cây nhị phân theo cách duyệt trung tự, bạn sẽ thu được một mảng có thứ tự. Chúng ta sẽ lần lượt tìm hiểu qua chúng.

Thêm phần tử vào cây nhị phân tìm kiếm

Để thêm phần tử vào cây nhị phân tìm kiếm, ta phải thêm vào cây nhưng vẫn đảm bảo được cây đó vẫn là cây nhị phân tìm kiếm. Ví dụ thêm phần tử 12 vào cây trong hình trên, mình sẽ cần chèn vào vị trí bên trái 13. Hàm duyệt tìm vị trí thích hợp và chèn của mình như sau:

void AddNode(Tree &root, Node *node)
{
    if (root)
    {
        if (root->data == node->data) // Nếu bị trùng giá trị thì không thêm
            return;
        if (node->data < root->data) // Thêm vào cây con bên trái (nhỏ hơn nút hiện tại)
            AddNode(root->left, node);
        else
            AddNode(root->right, node); // Thêm vào cây con bên phải (lớn hơn nút hiện tại)
    }
    else
    {
        root = node; // Đã tìm thấy vị trí thích hợp, thêm node vào
    }
}

Tìm một phần tử trong cây nhị phân tìm kiếm

Như đã giới thiệu ở trên, để tìm một phần tử trong cây nhị phân tìm kiếm, chúng ta sẽ thực hiện tương tự việc tìm kiếm nhị phân. Nếu như nút cần tìm nhỏ hơn nút đang xét, chúng ta sẽ tìm cây con bên trái, ngược lại chúng ta sẽ tìm trong cây con bên phải, nếu đúng nút cần tìm thì mình sẽ trả về địa chỉ của nút đó. Mình sẽ có thuật toán sau:

Node *FindNode(Tree root, int x)
{
    if (root)
    {
        if (root->data == x) // Tìm thấy
            return root;
        if (x < root->data)
            return FindNode(root->left, x); // Tìm cây con bên trái
        return FindNode(root->right, x); // Tìm cây con bên phải
    }
    return NULL; // Không tìm thấy
}

Hủy nút trên cây nhị phân tìm kiếm

Để hủy một nút có khóa X trong cây nhị phân tìm kiếm, chúng ta cần giải quyết ba trường hợp sau:

  1. Nút X là nút lá, ta xóa đi mà không làm ảnh hưởng đến các nút khác. Ví dụ xóa nút 15 đi không ảnh hưởng gì đến các nút khác.
  2. Nút X có 1 cây con, chúng ta chỉ cần nối nút cha của X với nút con của X. Ví dụ xóa nút 13 đi, ta chỉ cần nối nút 18 và 15 lại, sau đó xóa nút 13 đi.
  3. Nút X có đầy đủ 2 cây con: vì X có đầy đủ 2 nút nên nếu ta xóa đi, ta sẽ bị mất toàn bộ cây con. Do đó chúng ta cần tìm phần tử thế mạng cho X mà vẫn đảm bảo được cây nhị phân tìm kiếm, sau đó mới xóa X đi.

Đối với hai trường hợp đầu thì dễ, tuy nhiên, với trường hợp thứ 3, chúng ta cần phải giải quyết vấn đề tìm phần tử thế mạng cho x, chúng ta sẽ có hai cách thực hiện như sau:

  1. Nút thế mạng là nút có khóa nhỏ nhất (trái nhất) của cây con bên phải x.
  2. Nút thế mạng là nút có khóa lớn nhất (phải nhất) của cây con bên trái x.

Lấy ví dụ cho các bạn dễ hiểu hơn, hình phía trên, xóa đi phần tử 18 theo cách 1, phần tử lớn nhất của cây con bên trái là 15, vậy thì thay 18 bằng 15 rồi xóa đi nút 15 cuối. Cách 2, phần tử nhỏ nhất của cây con bên phải là 23, vậy 18 sẽ thay bằng 23 và xóa nút 23 đó đi.

Đối với hai trường hợp đầu tiên khá đơn giản, nên mình sẽ lồng nó vào code luôn ở phần dưới, mình sẽ giải quyết cách tìm phần tử thế mạng ở trường hợp 3 trước và theo cả hai cách. Theo cách 1, mình sẽ làm như sau:

Trường hợp 1

// nút p là nút cần thay thế, tree là cây đang xét (cây bên phải)
void FindAndReplace1(Tree &p, Tree &tree)
{
    if (tree->left) // chưa phải nhỏ nhất (trái nhất)
        FindAndReplace1(p, tree->left); // tiếp tục tìm
    else // tree là nút trái nhất
    {
        p->data = tree->data; // copy data
        p = tree; // trỏ nút p vào nút tree sẽ làm thế mạng bị xóa
        tree = tree->right; // nút trái không còn tuy nhiên nút phải có thể còn nên ta phải nối chúng lại
    }
}

Đối với trường hợp này, các bạn phải gọi hàm FindAndReplace1(p, root->right) trong hàm DeleteNode ở phía trên. Trường hợp thứ 2 thì ngược lại.

Trường hợp 2

// nút p là nút cần thay thế, tree là cây đang xét (cây bên trái)
void FindAndReplace2(Tree &p, Tree &tree)
{
    if (tree->right) // chưa phải lớn nhất (phải nhất)
        FindAndReplace2(p, tree->right); // tiếp tục tìm
    else // tree là nút trái nhất
    {
        p->data = tree->data; // copy data
        p = tree; // trỏ nút p vào nút tree sẽ làm thế mạng bị xóa
        tree = tree->left; // nút phải không còn tuy nhiên nút trái có thể còn nên ta phải nối chúng lại
    }
}

Và trong hàm DeleteNode, các bạn sẽ gọi hàm FindAndReplace(p, root->left). Bây giờ, tổng hợp lại, chúng ta đã có thể dể dàng xóa một nút khỏi cây nhị phân tìm kiếm, mình sẽ code như sau:

void DeleteNode(Tree &root, int x)
{
    if (root)
    {
        if (x > root->data)
            DeleteNode(root->right, x);
        else if (x < root->data)
            DeleteNode(root->left, x);
        else // nút hiện tại (root) là nút cần xóa
        {
            Node *p = root; // lưu lại nút cần xóa tránh bị ghi đè
            if (!root->left)
                root = root->right; // trường hợp 1
            else if (!root->right)
                root = root->left; // trường hợp 2
            else
                FindAndReplace1(p, root->right); // cách 1
                // FindAndReplace2(p, root->left); // cách 2
            delete p; // xóa nút
        }
    }
    else
    {
        cout << "Not found!\n"; // Không tìm thấy phần tử cần xóa
    }
}

Tổng kết

Vậy là qua bài viết này, mình đã giới thiệu đến các bạn về cấu trúc cây, cây nhị phân và cây nhị phân tìm kiếm. Đương nhiên, mình không phải “master” và mình cũng không thể nào mà nắm được hết tất cả các lý thuyết đồ thị hay thuật toán, do đó sai sót là không thể tránh khỏi, hy vọng các bạn góp ý thêm.

Cảm ơn các bạn đã theo dõi bài viết, nếu thấy bài viết này hay, đừng quên chia sẻ cho mọi người cùng biết nhé! Cảm ơn các bạn!

Source code

struct Node
{
    int data;
    Node *left;
    Node *right;
};

typedef Node *Tree;

Node *CreateNode(int init)
{
    Node *p = new Node;
    p->data = init;
    p->left = NULL;
    p->right = NULL;
    return p;
}

void CreateTree(Tree &root)
{
    root = NULL;
}

void DestroyTree(Tree &root)
{
    if (root)
    {
        DestroyTree(root->left);
        DestroyTree(root->right);
        delete root;
    }
}

void AddNode(Tree &root, Node *node)
{
    if (root)
    {
        if (root->data == node->data)
            return;
        if (node->data < root->data)
            AddNode(root->left, node);
        else
            AddNode(root->right, node);
    }
    else
    {
        root = node;
    }
}

Node *FindNode(Tree root, int x)
{
    if (root)
    {
        if (root->data == x)
            return root;
        if (x < root->data)
            return FindNode(root->left, x);
        return FindNode(root->right, x);
    }
    return NULL;
}

void PrintTree(Tree root)// print tree using LNR
{
    if (root)
    {
        PrintTree(root->left);
        cout << root->data << ' ';
        PrintTree(root->right);
    }
}

void NLR(Tree root)
{
    if (root)
    {
        // Xử lý nút gốc (root)
        NLR(root->left);
        NLR(root->right);
    }
}

void LNR(Tree root)
{
    if (root)
    {
        LNR(root->left);
        // Xử lý nút gốc (root)
        LNR(root->right);
    }
}

void LRN(Tree root)
{
    if (root)
    {
        LRN(root->left);
        LRN(root->right);
        // Xử lý nút gốc (root)
    }
}

void FindAndReplace1(Tree &p, Tree &tree)
{
    if (tree->left)
        FindAndReplace1(p, tree->left);
    else
    {
        p->data = tree->data;
        p = tree;
        tree = tree->right;
    }
}

void FindAndReplace2(Tree &p, Tree &tree)
{
    if (tree->right)
        FindAndReplace2(p, tree->right);
    else
    {
        p->data = tree->data;
        p = tree;
        tree = tree->left;
    }
}

void DeleteNode(Tree &root, int x)
{
    if (root)
    {
        if (x > root->data)
            DeleteNode(root->right, x);
        else if (x < root->data)
            DeleteNode(root->left, x);
        else
        {
            Node *p = root;
            if (!root->left)
                root = root->right;
            else if (!root->right)
                root = root->left;
            else
                FindAndReplace1(p, root->right);
            // FindAndReplace2(p, root->left);
            delete p;
        }
    }
    else
    {
        cout << "Not found!\n";
    }
}
Bài viết gốc được đăng tải tại khiemle.dev
Có thể bạn quan tâm:

SNTP – Simple Network Time Protocol là gì?

SNTP – Simple Network Time Protocol là gì?

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

Hôm nay nhận được task đi fix bug, lò mò điều tra mới biết nó liên quan tới SNTP (Simple Network Time Protocol). Vậy SNTP là gì?. Nốt công tìm hiểu nên viết ra luôn cho anh em xem.

  Cách thiết lập và duy trì mối quan hệ (networking) hiệu quả
  Làm thế nào để xây dựng social network bằng Ruby on Rails

Đầu tiên thì nói sơ qua về cái bug. Fix bug này cho một application trên MacOS. Ứng dụng khi start sẽ kiểm tra thời gian ở phía client (Mac Mini) và phía Server (Apple time) có chính xác hay không. Hiện tại thì app crash -> banh chành.

SNTP – Simple Network Time Protocol là gì?
SNTP có response trả về nhưng app vẫn bị crash

1. Simple Network Time Protocol là gì?

Bắt đầu với định nghĩa:

The simple network time protocol (SNTP) is a time synchronization protocol of the TCP/IP protocol family. It is based on the connectionless user datagram protocol (UDP) and can be used on all supporting devices to synchronize system time in IP networks (IPv4 and IPv6).

Simple Network Time Protocol (SNTP) là phương thức đồng bộ hóa thời gian, thành viên của TCP/IP protocol. Dựa trên kết nối của user datagram protocol (UDP) và có thể sử dụng để đồng bộ hóa tất cả thời gian trên thiết bị. Cả trên IPv4 và IPv6

Đó, theo như cái lý thuyết, đầu tiên SNTP là phương thức đồng bộ thời gian. Trong mạng máy tính, có thể vì các lý do khách quan dẫn tới thời gian ở client và server khác nhau.

SNTP – Simple Network Time Protocol là gì?
Kết nối vàng cho biết là kết nối trực tiếp. Đỏ là giao tiếp giữa các máy client với nhau. Nguồn ảnh source: Wikipedia.com

Nếu client không sử dụng dữ liệu về thời gian, rõ ràng là không có vấn đề gì. Trường hợp cần tính toán về thời gian, độ sai lệch chắc chắn phải ở trong range được cho phép.

Lúc này ta cần tới SNTP. Cụ thể thì SNTP hoạt động như thế nào?

2. Hoạt động như thế nào?

Nguyên tắc hoạt động của SNTP – Simple Network Time Protocol cũng khá đơn giản. Luôn có một server time chuẩn được đặt ở đâu đó, lưu trữ thời gian chuẩn cho từng múi giờ.

Đồng hồ ở trên máy này có thể là động hồ nguyên tử, lượng tử hoặc bất cứ thứ gì đó luôn cho thời gian chính xác. Khi client yêu cầu kiểm tra thời gian tại máy có chính xác hay không?. Đầu tiên gửi một packages chứa các thông tin sau:

SNTP – Simple Network Time Protocol là gì?
Client hỏi, server trả lời. Đó là cách mà SNTP hoạt động. Nguồn ảnh / Source: wikipedia.com
  • Thời gian ở máy hiện tại (Client time, System time).
  • Server name muốn thực hiện kiểm tra thời gian. Bug của mình thì đang xài “time.asia.apple.com”

Khi server nhận được package, nó sẽ thực hiện kiểm tra và tính toán thời gian sai lệch giữa client và server time chuẩn. Trả về response như sau:

SNTP – Simple Network Time Protocol là gì?
Response trả về sau khi gửi request tới SNTP asia của apple

3. Nội dung response

Đã có response nhưng nội dung response là gì thì lại cần phải phân tích thêm. Như ví dụ phía trên. Theo như document của SNTP thì:

  • +0.141219 cho biết rằng thời gian ở phía client trễ hơn (behinds) so với thời gian ở server là 0.141219s.
  • +/- 0.000168 cho biết thời gian request gửi đi và nhận response, có thể tính là thời gian sai lệch
  • time.asia.apple.com là server name, nơi muốn check thời gian
  • 17.253.68.251 là địa chỉ IP của server

Chi tiết hơn anh em có thể tham khảo ở Sntp User’s Manual. Có ví dụ cụ thể một response và các thành phần trong đó.

4. Fix bug

Điều tra một hồi thì thấy bug là do hiện tại ở các bản MacOS version 10.15 Catalina trở xuống, response của SNTP khác biệt so với bản mới BigSur

Vì vậy index của field muốn lấy cũng phải thay đổi. Thay vì trước lấy ở 3 thì giờ lấy ở 2. Nếu vấn lấy ở index cũ thì lấy ra “time.asia.apple.com”, nhưng lại parse qua float, dẫn tới Null Pointer Exception.

Xong!, fix bug 2 phút, đi đọc tìm hiểu về SNTP mất khoảng 1 tiếng. Đáng, đáng bỏ công để học , để biết thêm!

5. Tham khảo

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

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

Xem thêm Tuyển dụng it network hấp dẫn trên TopDev

Dự án anh hóa – ngôn ngữ C#

Dự án anh hóa – ngôn ngữ C#

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

Cuộc đời này thật trớ trêu, bốn năm dùi mài kinh sử “java đại pháp” ở giảng đường, cứ ngỡ khi đi làm sẽ được ứng dụng những cái đã học, thế nhưng cái số của tôi nó không được may mắn lắm, khi đi làm toàn làm về những cái không phải là chuyên môn của tôi. Và dự án tiếp theo tôi tham gia đó chính là ngôn ngữ C#.

  Dependency Injection – Web API ( C# )
  Kiểm thử đơn vị trong C# với Nunit và .Net Core

Dự án đầu tiên được viết bằng Delphi và đã có sẵn source code, dự án tiếp theo tôi tham gia cũng giống như vậy, đã được phát triển ở một công ty khác, source code cũng đã có sẵn. Đây là một trang web về bảo hiểm được xây dựng bằng ASP.NET MVC3, ngôn ngữ C#, trang web này hiển thị nội dung là chữ tiếng Nhật, công ty khách hàng họ yêu cầu chúng tôi chuyển toàn bộ ngôn ngữ tiếng nhật sang ngôn ngữ tiếng anh cho trang web hiện tại của họ và làm thêm một số chức năng mới. Lại một lần nữa tôi phải tìm hiểu về cái mới. Dự án kiểu này người ta gọi là những dự án maintenance, nghĩa là những dự án nâng cấp, bảo trì, thêm tính năng mới…

Quay trở lại với dự án như thường lệ để bắt đầu một dự án thì chúng tôi tiến hành kick off dự án. Tôi đã giải thích từ kick off ở phần 4 các bạn có thể quay lại xem để biết nhé. Dự án này tôi sẽ không làm chung với chị quản lý cũ nữa mà lần này quản lý trực tiếp của tôi là anh leader, người mà đã training cho tôi trong thời gian thử việc, anh này cực kỳ khó tính, tôi sẽ nói về anh ấy trong bài viết này luôn. Trong buổi kick off thì anh leader phổ biến về công việc của dự án. Dự án sẽ làm hai công việc chính, thứ nhất đó là anh hóa, chuyển toàn bộ ngôn ngữ hiển thị của trang web từ tiếng nhật sang tiếng anh, thứ hai là khách hàng muốn làm thêm khoảng năm cái màn hình mới. Về nghiệp vụ của hệ thống thì không có tài liệu nào mô tả, họ chỉ cung cấp những từ tiếng nhật và nội dung tiếng anh tương ứng để chúng tôi thay đổi, còn những màn hình làm thêm thì sẽ cung cấp cho chúng tôi thiết kế chi tiết mô tả các chức năng của các màn hình đó.

Dự án này khá lớn và gấp nên team chúng tôi có khoảng mười người, chia ra làm hai team nhỏ, một team làm về anh hóa, một team làm những màn hình mới. Tôi và anh B (anh B tôi đã nhắc tới ở phần 1) vẫn làm chung dự án này và cùng vào team làm những màn hình mới, team chúng tôi có bốn người và điều đặc biệt là không ai biết về ASP.NET MVC3. Tới đây nghe là thấy vui rồi và dự án của chúng tôi bắt đầu.

Anh leader gửi mail cho mọi người về thông tin của dự án, bao gồm tài liệu thiết kế, source code và thông tin database. Về source code thì chúng tôi chạy trên Visual Studio 2010, database là SQL server. Phần tài liệu thiết kế chi tiết các màn hình thì toàn bộ bằng tiếng nhật, tuy nhiên hên cái là trong công ty có phiên dịch, họ sẽ dịch toàn bộ tài liệu sang tiếng việt. Vì bản chất họ là phiên dịch thì họ không hiểu nhiều về nghiệp vụ của lập trình nên chỉ có những phiên dịch có kinh nghiệm lâu năm thì sẽ dịch đúng, còn những phiên dịch mới thì dịch nhiều khi đọc không hiểu gì. Trở lại với dự án, chúng tôi bắt đầu setting source code và database để chạy trang web lên xem mặt mũi nó như thế nào, tiến hành tìm hiểu kiến trúc của nó được xây dựng ra sao đó là ngồi đọc code. Tôi mở code ra và đọc, ôi thôi một rừng code không là code, tôi không nhớ chính xác là có bao nhiêu file class, nhưng số lượng ước chừng là vài trăm, chưa tính cả các folder javascript, image… Tôi mở một file lên khoảng vài ngàn dòng code. Tôi bị ngộp trong đống code này và không biết bắt đầu từ đâu, thứ nhất là tôi không hiểu cái luồng xử lý của ASP.NET MVC, thứ hai là tôi sợ vì nó quá nhiều code. Từ lúc làm dự án đầu tiên thì tôi đã bắt đầu sợ, nỗi sợ kéo dài sang dự án tiếp theo.

Sau khi tôi và anh B đọc source code thì hai anh em nhìn nhau cười, anh leader đi lại và hỏi tình hình như thế nào rồi, có tìm hiểu được luồng xử lý của nó chạy như thế nào chưa. Hai chúng tôi nói rằng chưa nắm được gì, thế là anh leader bay vào điều tra. Công nhận kỹ năng của một leader có khác, không biết là anh có biết cái này trước chưa, nhưng sau khi xem một lúc thì anh đã giải thích được cho mọi người về luồng xử lý của một màn hình trong ASP.NET MVC. Việc nắm được luồng đi là một chuyện, còn việc apply được hay không lại là một chuyện khác. Nếu như lúc đó tôi có trình độ như bây giờ thì mọi chuyện sẽ dễ dàng hơn nhưng không thể nói được chữ nếu ở đây. Tôi và anh B cùng nhau apply trước một màn hình để sau đó hướng dẫn cho mọi người cách làm, thực sự mà nói thì cách tổ chức source code của project này không giống như một project ASP.NET MVC bình thường, trong visual studio khi chúng ta tạo ra một project ASP.NET MVC thì mặc định sẽ tạo ra cho chúng ta một cấu trúc thư mục với Model, View, Controller mà khi nhìn vào khá là dễ dàng để hiểu đối với những ai đã từng học mô hình MVC. Tuy nhiên cái dự án của tôi thì nó đã chỉnh sửa lại một cách phức tạp, kể cả anh B có kinh nghiệm khoảng một năm rưỡi cũng khó có thể hiểu được nó.

Sau một buổi ngồi làm thì chúng tôi cũng đã chạy lên được một màn hình với nội dung trang web không có gì. Layout của trang web thì đã có sẵn trong thiết kế chi tiết, ban đầu tôi chỉ chạy lên màn hình trắng, như vậy là thành công được 30% rồi. Việc code layout và các xử lý logic chỉ là chuyện sớm muộn mà thôi. Mỗi người được leader lên schedule cho một màn hình trước để làm, mỗi ngày đều phải điền tiến độ để leader theo dõi, anh leader này rất là kỹ tính trong công việc, luôn bám sát theo member và nếu gặp vấn đề gì khó không giải quyết được thì leader sẽ bay vào support. Trở lại với schedule, tôi được giao cho một màn hình hiển thị danh sách thông tin từ một table dưới database, và có một số button di chuyển qua lại giữa các màn hình khác. Về nghiệp vụ thì màn hình này không có gì khó, tuy nhiên khi code thì bạn không thể code theo ý riêng của bạn mà phải code sao cho nó đồng nhất giữa source code có sẵn. Có nghĩa là cách đặt tên hàm, biến, class thì phải đặt tương tự như source code có sẵn. Ban đầu tôi cũng không biết về việc này, sau khi code xong và được anh leader review code thì bắt tôi sửa lại và thống nhất một cái rule để làm cho tất cả màn hình. Cứ mỗi lần leader review là y như rằng là phải sửa, có một lần tôi code bên file javascript dư một dấu chấm phẩy, mặc dù không ảnh hưởng gì nhưng tôi vẫn phải sửa lại. Như tôi đã nói anh leader này khó và kỹ, khi review code thì gọi tôi lại hỏi “Tại sao em lại code như vầy, chỗ này là sao?, giờ anh không thích em code kiểu này, em phải code lại theo ý của anh” nhiều khi hỏi những câu bắt bí tôi vậy. Tôi biết lúc này kinh nghiêm tôi chưa có nhiều nhưng thái độ của một leader như vậy làm tôi và mọi người rất bức xúc. Leader thường xuyên la mắng nhân viên, lúc nào gần tới giờ ăn cơm cũng gọi lại hỏi để rồi thời gian ăn cơm cũng hết, cơm cũng hết sạch luôn. Đôi lời gửi đến anh leader, nếu anh đọc được bài viết này thì em xin lỗi đã nói xấu anh nha :))

Sau khi chỉnh sửa các nội dung theo đúng ý sếp thì cũng đã hoàn thành việc coding cho màn hình của tôi, tiếp theo là sẽ đến giai đoạn viết testcase để thực hiện test. Việc viết testcase thì ở đây mỗi người đều phải làm cho màn hình của mình, dựa vào thiết kế chi tiết để viết ra tất cả các trường hợp test. Tôi cũng tiến hành viết cho màn hình của mình, sau khi viết xong, lại tới giai đoạn leader review lại. Chuyện gì tới cũng sẽ tới, tôi biết rằng chắc chắn phải sửa lại. Những không ngờ tôi phải sửa một lần, hai lần, ba lần. Những người khác cũng phải sửa số lần giống như tôi. Tôi chắc chắn rằng không một ai có thể làm mà cho ãnh hài lòng mà không cần phải chỉnh sửa gì cả. Việc chỉnh sửa liên lục và họp hành để thống nhất câu chữ để viết cho mọi màn hình thì mất quá nhiều thời gian, nên chúng tôi làm không kịp và mọi người trong team đều phải OT để cover lại tiến độ và những màn hình tiếp theo chúng tôi làm đều diễn biến như vậy chúng tôi OT sấp mặt, team bên anh hóa cũng không khá hơn gì chúng tôi.

Việc thống nhất về cách viết testcase, cách viết code thì đúng là cần thiết cho một dự án, tuy nhiên anh quá khắt khe về những cái nhỏ nhặt làm tốn thời gian của mọi người. Sau một thời gian OT thì dự án cũng đã kết thúc, bài viết này không phải tôi muốn nói xấu về sếp cũ của tôi, có lẽ anh ấy có cách nghĩ riêng của một người leader có nhiều năm kinh nghiêm, về mặt khách hàng thì rất khó tính nên leader phải cẩn thận trong từng cái nhỏ nhặt. Như thường lệ tôi vẫn sẽ rút ra những cái mà tôi học được trong dự án.

1. Khi coding việc có một người review code là rất cần thiết, người này sẽ chỉ ra những chỗ bạn code chưa ổn, code không dư thừa, code đúng thiết kế.
2. Khi làm những dự án kiểu maintenance thì cần chú ý đến cách source sẵn có họ code như thế nào, rồi bắt chước code lại cho đồng nhất về cách code.
3. Việc đặt tên biến, hàm thì hãy đặt sao cho có ý nghĩa. Việc này giúp đảm bảo code của bạn rõ ràng, người đọc code nhìn vào sẽ hiểu ngay.
4. Việc có một anh leader tốt cũng là một điều hết sức cần thiết. haha

Đến đây cũng đã kết thúc bài viết, các bạn nhớ follow fanpage của mình nhé.

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

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

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