Home Blog Page 69

Tìm hiểu hệ thống lương 3P

lương 3p

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

Một khái niệm nữa mà những bạn đang tìm hiểu Công việc C&B không thể bỏ qua đó là xây dựng, tính và chi trả lương theo 3P.

Tìm hiểu hệ thống lương 3P

Chào mừng các bạn đang đến với series các bài học trong Khoá học C&B cơ bản cho người mới (newbie) hoàn toàn miễn phí. Tôi là Thành HR sẽ đồng hành cùng bạn trong khoá học này. Và chủ đề mà chúng ta cùng nhau tìm hiểu ngày hôm nay là Tìm hiểu hệ thống lương 3P.

Chúng ta đã cùng nhau tìm hiểu về Cách xây dựng thang bảng lương, rồi cũng đã tìm hiểu qua hệ thống lương thưởng trong công ty quy mô nhỏ. Và có một khái niệm nữa mà những bạn đang tìm hiểu Công việc C&B không thể bỏ qua đó là xây dựng, tính và chi trả lương theo 3P.

Xem thêm tuyển dụng Designer lương cao trên TopDev

Lương 3P là gì?

Bất kỳ doanh nghiệp nào, khi phát triển đến một giai đoạn nào đó thì Ban Lãnh Đạo luôn muốn cải thiện năng suất người lao động, nâng cao hiệu quả làm việc để từ đó gia tăng lợi nhuận cho công ty. Và việc xây dựng được một phương pháp trả lương phù hợp cũng giúp góp phần vào điều này.

Trả lương theo 3P là một mô hình trả lương hiệu quả của Mercer được khá nhiều doanh nghiệp tại Việt Nam áp dụng trong thời gian qua nhờ tính ưu việt của nó. Tuy nhiên, lương 3P có khá nhiều phiên bản và cách áp dụng khác nhau để phù hợp với các mô hình đa dạng của các Doanh nghiệp nhỏ.

3P (3P Compensation) là hình thức trả lương được xây dựng để trả lương theo vị trí, năng lực và hiệu quả công việc của nhân viên nhằm tạo sự công bằng, khuyến khích và tạo động lực giúp mỗi nhân viên phát huy tối đa khả năng của mình trong công việc, đóng góp cho sự phát triển của công ty.

3P là từ viết tắt của 3 từ: Position, Person, Performance. Đây là 3 hạng mục cấu thành nên thu nhập của một Người lao động được nhận. Có thể hiểu nôm na là:

Thu nhập = P1 + P2 + P3. 

– P1 (Position) – Pay or position: Trả lương theo vị trí công việc. Doanh nghiệp trả lương hàng tháng cho chức danh đó, bất kể người đảm nhận là ai và có năng lực thế nào. Thông thường các Công ty sẽ căn cứ trên thang bảng lương để trả P1 này.

– P2 (Person) – Pay for Person: Trả lương theo năng lực. Dùng kết quả đánh giá năng lực nhân sự để định ra số tiền tương xứng với năng lực đó. Với các doanh nghiệp đang hoạt động thì phần P2 này có thể được thể hiện trong Quy chế lương thưởng.

– P3 (Performance) – Pay for Performance: Trả lương theo kết quả đạt được. Phần lương này nhân viên có thể được nhận hàng tháng hoặc hàng quý tùy chính sách công ty.

Tính lương chuẩn xác với công cụ tính lương gross to net của TopDev ngay!

Cách xây dựng Hệ thống lương 3P

Trong phần này, chúng ta sẽ cùng tìm hiểu các bước chuẩn để có thể xây dựng một hệ thống lương 3P. Còn thực tế triển khai thì một số công ty chấp nhận thay đổi một chút cho phù hợp với thực tế doanh nghiệp của mình.

Vì không phải Công ty nào cũng đủ điều kiện để thực hiện và áp dụng theo mô hình chuẩn. Chằng hạn như Xây dựng được khung năng lực chuẩn, áp dụng công nghệ để đánh giá hoàn thành công việc…Và mô hình chuẩn ấy chưa chắc đã hoàn toàn phù hợp ngay với văn hóa doanh nghiệp hiện tại.

Nên ở đây, mình sẽ cùng nhau tìm hiểu cách thực hiện cho một doanh nghiệp quy mô nhỏ. Vẫn giữ lại phần lõi, nhưng vẫn đảm bảo phát huy được các điểm mạnh của hệ thống lương 3P này:

Bước 1: Xây dựng P1 (Position) – Pay or position

Phần P1 – Trả lương theo vị trí công việc: Bạn có thể hình dung nó chính là phần lương mà bạn đã xây dựng trong thang bảng lương. Cho nên, nếu Công ty bạn đã xây dựng được thang bảng lương chuẩn thì có thể lấy để áp vào P1. Mình cùng tham khảo lại các bước chuẩn để xây dựng P1 như sau:

– Bắt đầu từ chiến lược kinh doanh của Công ty thể hiện qua Sứ mệnh / Tầm nhìn / Giá trị cốt lõi. Và dựa vào đó để xây dựng cơ cấu tổ chức trên cơ sở chuỗi giá trị của doanh nghiệp.

– Chuẩn hóa hệ thống chức danh, giá trị công việc (Job Evaluation) và mô tả công việc (Job Description) trên cơ sở phân bổ các phòng ban chức năng của doanh nghiệp. Từ đó xác định được cấp bậc lương và dải lương của các vị trí chức danh đảm bảo hài hòa với quỹ lương của Doanh nghiệp và cạnh tranh với thị trường.

Bước 2: Xây dựng P2 (Person) – Pay for Person

Để hiểu rõ phần P2 – Trả lương theo năng lực thì đầu tiên mình cùng nhau tìm hiểu khái niệm năng lực là gì? Các công cụ nào có thể đo lường và dùng để đánh giá năng lực nhân viên?

Năng lực (Competency): được hiểu là kiến thức, kỹ năng, khả năng và hành vi mà người lao động cần phải có để đáp ứng yêu cầu công việc, và là yếu tố giúp một cá nhân làm việc hiệu quả hơn so với những người khác. Tùy vào mỗi doanh nghiệp sẽ xây dựng hệ thống đánh giá năng lực với các tiêu chí phù hợp.

Xây dựng khung năng lực chuẩn: Để làm được việc này thì đầu tiên công ty cần xây dựng được từ điển năng lực, sau đó mới xây dựng khung năng lực cho các vị trí. Cần lưu ý phần năng lực mong đợi và thực tế mà các nhân viên đang có. Khung năng lực này cũng là cơ sở để tuyển dụng nhân sự mới đúng yêu cầu.

Bạn có thể tham khảo Mô hình ASK để xây dựng và đánh giá năng lực nhân viên theo chuẩn quốc tế. ASK là viết tắt của Attitude (Phẩm chất / Thái độ) – Skill (Kỹ năng) – Knowledge (Kiến thức), mỗi một nhóm là những yêu cầu mà doanh nghiệp đặt ra cho cá nhân để hoàn thành xuất sắc vị trí công việc cụ thể.

Những năng lực này được chấm theo 5 mức độ:

  • Mức độ 5 – Mức độ xuất sắc
  • Mức độ 4 – Mức độ tốt
  • Mức độ 3 – Mức độ khá
  • Mức độ 2 – Mức độ cơ bản
  • Mức độ 1 – Mức độ kém

Từ những căn cứ trên, Công ty sẽ tiến hành đánh giá năng lực cá nhân theo khung năng lực của từng vị trí, từ đó xác dựng level lương P2 này. Nếu công ty có số lượng nhân sự ít có thể thực hiện việc đánh giá bằng excel, nhưng nếu số lượng nhiều thì phải nghĩ đến việc sử dụng phần mềm.

Bước 3: Xây dựng P3 (Performance) – Pay for Performance

Về phần P3 – Trả lương theo kết quả đạt được này có thể hiểu nôm na như một phần thưởng thêm cho Người lao động khi họ hoàn thành tốt công việc, mang lại giá trị cộng thêm cho doanh nghiệp. Vậy thì rõ ràng, P3 là phần tạo động lực và thúc đẩy nhân viên nâng cao hiệu suất lao động, được đo đếm bằng con số rõ ràng.

Cần xác định rõ ràng ngay từ đầu phần lương P3 này sẽ chi trả hàng tháng hay hàng quý. Nếu trả hàng tháng thì P3 có thể nằm trong khoảng từ bao nhiêu đến bao nhiêu, thậm chí là bằng 0, cần cân nhắc khi cho P3 là một số âm như một số công ty đang áp dụng. Còn nếu trả theo quý thì cũng cần quy định rõ ràng và trả đúng thời hạn.

Để xây dựng được P3 thì phải bắt đầu từ Mục tiêu chiến lược của Công ty, rồi đến mục tiêu phòng ban, mục tiêu cá nhân. Mục tiêu cá nhân này được cụ thể hóa bằng tiêu chí KPI, đánh giá hàng tháng hay hàng quý thì tùy công ty quy định.

Lưu ý khi xây dựng KPI cho cá nhân cần đảm bảo yếu tố đơn giản dễ hiểu, từ 3 – 5 tiêu chí chứ đừng quá nhiều, có thể đo lường kết quả bằng các con số thì mới giúp tạo động lực cho nhân viên cố gắng hoành thành vượt chỉ tiêu. Nếu không nó chỉ mang tính hình thức và Người lao động xem phần lương P3 là phần không thể đạt được và không quan tâm thì mất ý nghĩa của lương 3P.

Một số công ty lấy mức P1 + P2 cũng sẽ là mức đóng các khoản Bảo hiểm bắt buộc cho người lao động (BHXH, BHYT, BHTN…). Vì P3 là phần biến thiên hàng tháng hoặc hàng quý mới được nhận nhân nên có thể không nằm trong khoản bắt buộc đóng. Một số khác thì chỉ đóng cho Người lao động trên mức P1, còn phần P2 họ sẽ chia thành các khoản phụ cấp không nằm trong danh mục đóng.

  4 mẹo deal lương như ý với vị trí Product Manager
  5 tips cải tiến chất lượng phát triển Mobile App

Một số sai lầm khi áp dụng lương 3P

Một số công ty đang hoạt động khi chuyển đổi sang trả lương theo 3P cần đảm bảo việc xếp lại level lương của nhân viên ở P1 + P2 không nên thấp hơn thu nhập họ đang nhận. Nên lưu ý phần năng lực kỳ vọng và năng lực thực tế khi đánh giá của nhân viên hiện tại. Có thể xử lý bằng cách bổ sung các khóa đào tạo để nâng cao năng lực cho phù hợp.

Nên xem phần lương P3 là phần mà nếu Người lao động đạt hoặc vượt chỉ tiêu mong đợi thì sẽ được nhận. Chứ đừng cắt xén ra từ thu nhập đang có của họ để hình thành phần P3 này, vì như vậy nó chẳng khác gì lấy mỡ nó rán nó. Họ sẽ xem là công ty đang không công bằng và không minh bạch.

Phần lương P3 cần quy định rõ ràng thời gian chi trả, một số công ty trả theo quý thường không trả đúng hạn dẫn đến sự bất mãn và mất động lực làm việc của nhân viên dẫn đến nghỉ việc hàng loạt. Nếu có suy nghĩ này thì công ty không nên áp dụng hệ thống lương 3P làm gì cả.

Và đặc biệt, để áp dụng hệ thống lương 3P chuẩn thì công ty nên đầu tư và hướng đến việc số hóa dữ liệu, áp dụng phần mềm trong việc phân phối chỉ tiêu, tổng hợp kết quả đánh giá tự động và có cảnh báo đánh giá theo thời gian thực sẽ phát huy được tối đa hiệu quả của hệ thống lương 3P này.

Trên đây mình đã cùng nhau tìm hiểu hệ thống lương 3P ở bước hiểu và nắm được phần cơ bản nhất của nó. Nếu bạn có bất kỳ thắc mắc nào vui lòng để lại comment bên dưới, mình sẽ trả lời cho các bạn trong thời gian sớm nhất. Trân trọng.

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


Tuyển Dụng Nhân Tài IT Cùng TopDev
Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products

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

Xem thêm các việc làm lĩnh vực IT hấp dẫn trên TopDev

Thói quen viết code an toàn trong khi xây dựng ứng dụng PHP

viết code trên php
Thói quen viết code an toàn trong khi xây dụng ứng dụng PHP

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

Bất cứ khi nào bạn xây dựng một hệ thống xong xui và hệ thống đang chạy ngon lành đều bị phá hoại vào ngày đẹp trời nào đó.!? Vì lý do bla, bla,… gì đó họ sẵn sàng dùng mọi cách phá hoại dự án kỳ công của bạn chính vì thế xây dựng code an toàn từ lúc xuất xưởng là cần thiết, hãy áp dụng thói quen này để đảm bảo rằng các ứng dụng của bạn là an toàn mức cao nhất có thể nhé.

  • Kiểm tra hợp lệ đầu vào (validate ngoài form)
  • Bảo vệ post form (validate trong file xử lý)
  • Bảo vệ hệ thống file (ghi logs khi phát sinh tải file mà mình giới hạn)
  • Bảo vệ cơ sở dữ liệu (Chống lại sự tấn công SQL INJECTION)
  • Bảo vệ dữ liệu phiên làm việc (đảm bảo hệ thống luôn chạy tốt)
  • Bảo vệ chống lại các sơ hở của ứng dụng lệnh xuyên các trang (Cross-Site Scripting – XSS)
  • Bảo vệ chống lại các giả mạo yêu cầu xuyên các trang (Cross-Site Request Forgeries – CSRF)
  10 Frameworks tốt nhất hiện nay cho PHP

Kiểm tra hợp lệ đầu vào (validate ngoài form)

Đây là quy tắc cơ bản trong lập trình và nó cũng có 4 bước cơ bản, bạn làm theo thì chắc chắn sẽ K.O.

  1. Lập ra danh sách hợp lệ(while list) vs bất hợp lệ (black list)
  2. Luôn luôn kiểm tra hợp lệ trong black list.
  3. Kiểm tra kiểu dữ liệu đúng. ví dụ như là các số, chuỗi,…
  4. Trong quá trình xử lý danh sách bất hợp lệ cần dùng hàm thoát để giảm tải quá trình xử lý.

Tuy nhiên hiện nay các jquery validate ngày càng thông dụng nên bạn có thể tham khảo cách viết trong các jquery đó. Còn dùng framework JS thì nó cũng đảm bảo nhiều thứ hơn.

Bảo vệ post form (validate trong file xử lý)

– Attacker có thể dễ dàng fake 1 post form của bạn ở đâu đó rồi gửi vào file PHP xử lý của bạn vì mục đích nào đó. Do các ứng dụng web là phi trạng thái (stateless), nên không có cách nào để chắc chắn tuyệt đối là dữ liệu đã được gửi lên từ nơi mà bạn muốn nó đến từ đó. Mọi thứ từ các địa chỉ IP cho đến tên máy chủ, cuối cùng rồi đều có thể bị fake.

Ví dụ:

<html>
<head>
<title>Collecting your data</title>
</head>
<body>
<form action="http://path.example.com/processStuff.php" 
    method="post"><input type="text" name="answer"
    value="There is no way this is a valid response to a yes/no answer..." />
<input type="submit" value="Save" name="submit" />
</form>
</body>
</html>

– Tuy nhiên một kỹ thuật mà bạn có thể sử dụng là thẻ bài sử dụng một lần (single-use token), nó không làm cho việc fake post form của bạn bất khả thi nhưng nó trở thành một điều rắc rối kinh khủng cho người fake.!? Vì token thay đổi mỗi khi mẫu được đưa xuống client, attacker cần phải lấy một form đang gửi, lấy token, và đặt nó vào phiên bản post fake đó. Kỹ thuật này rất hại não vì khó có khả năng một ai đó lập ra một fake post form lâu dài để gửi các yêu cầu không mong muốn đến ứng dụng của bạn.

Ví dụ một thí dụ về một thẻ bài biểu mẫu dùng một lần.

<?php
session_start();
?>
<html>
<head>
<title>SQL Injection Test</title>
</head>
<body>
<?php

echo 'Session token=' . $_SESSION['token'];
echo '<br />';
echo 'Token from form=' . $_POST['token'];
echo '<br />';

if ($_SESSION['token'] == $_POST['token']) {
    /* cool, it's all good... create another one */

} else {
    echo '<h1>Go away!</h1>';
}
$token = md5(uniqid(rand(), true)); 
$_SESSION['token'] = $token; 
?>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>"
    method="post">
" /> " />
</form> 
</body> 
</html>

Trên nguyên tắc là token này dc tạo ra để dc dùng 1 lần hoặc trong khoảng thời gian nhất định (5s, 5 min,…). Có nhiều cách tạo token an toàn

  5 tính năng mới trong PHP 7 cần phải biết

Bảo vệ hệ thống file (ghi logs khi phát sinh tải file mà mình giới hạn)

– Vấn đề đặt ra là có những file quan trọng mà bạn không muốn bất kỳ ai cũng có quyền lấy xuống mà giới hạn lấy xuống. Chính vì vậy tốt nhất là thiết kế ứng dụng sử dụng một cơ sở dữ liệu và các tên file được tạo ra và giấu kín. Tuy nhiên, không phải lúc nào cũng có thể làm thế.

Ví dụ về một thủ tục kiểm tra hợp lệ tên tệp tin. Nó sử dụng các biểu thức chính quy để đảm bảo rằng chỉ các ký tự hợp lệ là được sử dụng trong tên tệp tin và đặc biệt kiểm tra các ký tự chấm chấm: ...

function isValidFileName($file) {
    /* don't allow .. and allow any "word" character  / */
    return preg_match('/^(((?:.)(?!.))|w)+$/', $file);
}

Bảo vệ cơ sở dữ liệu (Chống lại sự tấn công SQL INJECTION)

– Vấn đề đặt ra là attacker có thể vượt qua rào validate trong front end hoặc fake post form thành công và truyền dc những giá trị không mong muốn vào file PHP để xử lý nếu ta không chặn dc những giá trị này thì 0.O sẽ có những câu lệnh SQL ko chính quy thâm nhập vào những câu SQL chính quy của bạn phá hỏng database của bạn tồi tệ hơn là tạo ra những người dùng siêu quyền hạn để đánh cắp thông tin, bla bla….

Ví dụ về form lỏng lẻo có thể bị attack

<html>
<head>
<title>SQL Injection Example</title>
</head>
<body>
<form id="myFrom" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Account <input name="account" type="text"/>
Number <input name="number" type="text"/>
Name <input name="name" type="text"/>
Address <input name="address" type="text"/>
</form> 
<?php if ($_POST['submit'] == 'Save') {
/* do the form processing */ 
$link = mysql_connect('hostname', 'user', 'password') or die ('Could not connect' . mysql_error()); 
mysql_select_db('test', $link); 
$col = $_POST['col']; 
$select = "SELECT " . $col . " FROM account_data WHERE account_number = " . $_POST['account_number'] . ";" ; 
echo '<p>' . $select . '</p>'; 
$result = mysql_query($select) or die('<p>' . mysql_error() . '</p>'); 
echo '<table>'; 
while ($row = mysql_fetch_assoc($result)) { 
echo '<tr>'; 
echo '<td>' . $row[$col] . '</td>'; 
echo '</tr>'; 
} 
echo '</table>'; 
mysql_close($link); 
} ?> 
</body> 
</html>

– Chúng ta có thể khắc phục dc việc này bằng nhiều cách đơn giản như

  • dùng hàm mysql_real_escape_string(). Hàm này làm sạch đầu vào của bạn, sao cho nó không còn bao gồm các ký tự không hợp lệ.
  • Kiểm tra xem định dạng chuỗi: email, username, password… đều có một định dạng nhất định, do đó có thể viết các biểu thức chính qui (Regular Expression) cho mỗi định dạng này.

Xem ngay tin tuyển dụng PHP lương cao trên TopDev

Bảo vệ dữ liệu phiên làm việc.

– Vấn đề đặt ra là chúng ta 1 hệ thống có nhiều server khác nhau để duy trì 1 hệ thống site vậy làm sao để đảm bảo được các session trong giao dịch dùng để xử lý, có thể hoạt động trên các server khác trong cùng hệ thống.!?

Để làm được điều này chúng ta cần xử lý sao cho tất cả các máy chủ đều sử dụng chung một hệ thống quản lý session .

Hoặc đơn giản là sử dụng chung một session storage .

Mặc định trong php sẽ sử dụng file session handle các file chứa session sẽ nằm trong /tmp của mỗi server .

Điều này có thể gợi ý cho chúng ta việc share chung 1 vùng lưu trữ (ví dụ dùng NFS để share chung /tmp giữa các máy chủ).

Tuy nhiên cách này lại ảnh hưởng đến tốc độ truy xuất (vì phải qua mạng – sau đó là đến việc máy host session sẽ quá tải diskio).

Một hướng khác là sử dụng một db mysql chung để lưu session , thực tế thì cách này tạm được .

Để làm như vậy chúng ta cần override lại các hàm xử lý session của php

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

Sử dụng hàm session_set_save_handler để trỏ các call back function cần thiết , như vậy chúng ta cần viết lại 6 hàm open, close , read ,write ,destroy , gc .

tạm thời chúng ta viết tạm các hàm như sau :

<?php
function open($save_path, $session_name)
{
echo "open";
}

function close()
{
echo "close";
}

function read($id)
{
echo "read";
}

function write($id, $sess_data)
{
echo "write";

}

function destroy($id)
{
echo "destroy";
}

function gc($maxlifetime)
{
echo "gc";
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
// test thử phát
session_start();

?>

Chạy thử . kết quả : openread writeclose …

Như vậy chúng ta thấy thứ tự của một quá trình đọc session .

Việc tiếp theo là implement mấy hàm trên vào mysql , memcached , file , hay bất kỳ một storage nào có thể dùng chung được là xong .

với file (cái này chỉ là làm lại những gì php đã làm  )

<?php
$sess_save_path=".";
function open($save_path, $session_name)
{
global $sess_save_path;

$sess_save_path = $save_path;
return(true);
}

function close()
{
return(true);
}

function read($id)
{
global $sess_save_path;

$sess_file = "$sess_save_path/sess_$id";
return (string) @file_get_contents($sess_file);
}

function write($id, $sess_data)
{
global $sess_save_path;

$sess_file = "$sess_save_path/sess_$id";
if ($fp = @fopen($sess_file, "w")) {
$return = fwrite($fp, $sess_data);
fclose($fp);
return $return;
} else {
return(false);
}

}

function destroy($id)
{
global $sess_save_path;

$sess_file = "$sess_save_path/sess_$id";
return(@unlink($sess_file));
}

function gc($maxlifetime)
{
global $sess_save_path;

foreach (glob("$sess_save_path/sess_*") as $filename) {
if (filemtime($filename) + $maxlifetime < time()) {
@unlink($filename);
}
}
return true;
}

session_set_save_handler("open", "close", "read", "write", "destroy", "gc");

//test
session_start();

?>

Hay với mysql đại khái thế này :

function read($id)
{
$sql = "select * from `tb_session` where `session_id`=$id";
mysql_query($sql);
//....
}

function write($id, $sess_data)
{
$sql = "INSERT INTO `tb_session` (`session_id`, `updated_on`) VALUES ('{$this->session_id}', NOW())";
mysql_query($sql);

}

function destroy($id)
{
$sql = "Delete from `tb_session` where `session_id`=$id";
mysql_query($sql);
}

Hay với memcached :

function read($id)
{
return memcached::get("sessions/{$id}");
}

function write($id, $data)
{
return memcached::set("sessions/{$id}", $data, 3600);
}

function destroy($id)
{
return memcached::delete("sessions/{$id}");
}

Dùng memcache hay mysql cũng khá nhanh , mysql thì chạy bàng memory storage engine , bật query cache tướng đối lớn cho nhanh , có thể replication ra nhiều server để đẩy performed lên cao nữa nếu tải lớn .

Bảo vệ chống lại các sơ hở của ứng dụng lệnh xuyên các trang (Cross-Site Scripting – XSS)

– Vấn đề đặt ra là người dùng sẽ nhập nội dung và hệ thống của bạn sẽ hiển thị nội dung đó lên. Nếu nội dung người dùng nhập là script có chứa mã độc phát tán virus,… thì sao.!?

<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo($_POST['myText']);//Mã script độc lấy từ database sẽ hiển thị ở đây
echo("</p>");
?>
</body>
</html>

– Để tự bảo vệ bạn chống lại các tấn công XSS, hãy lọc đầu vào của bạn thông qua hàm htmlentities() bất cứ khi nào giá trị của một biến được in đến đầu ra. Hãy nhớ làm theo thói quen đầu tiên về kiểm tra hợp lệ dữ liệu đầu vào bằng các giá trị trong danh sách trắng trong ứng dụng web của bạn đối với tên, địa chỉ email, số điện thoại, và thông tin về hoá đơn thanh toán.

<html>
<head>
<title>Results demonstrating XSS</title>
</head>
<body>
<?php
echo("<p>You typed this:</p>");
echo("<p>");
echo(htmlentities($_POST['myText']));
//htmlentities(): đã chặn việc thực thi đoạn script độc mà chỉ hiển thị chúng lên như thml
echo("</p>"); ?> 
</body> 
</html>

Bảo vệ chống lại các giả mạo yêu cầu xuyên các trang (Cross-Site Request Forgeries – CSRF)

– Một vấn đề là chúng ta phải thật cẩn trọng với người dùng đã là member chính thức vì lúc đó họ đã có dc quyền hạng trong site và họ có thể upload, post,… thoải mái nếu họ lợi dụng quyền này để tấn công bằng cách upload file image nhưng đó thực sự không phải là file image thì sao.!?

Các cuộc tấn công CSRF thường được thực hiện dưới dạng các thẻ <img> vì trình duyệt gọi URL một cách không ý thức để lấy hình ảnh. Tuy nhiên, nguồn hình ảnh dễ dàng có thể chỉ là URL của một trang web trên cùng một site, thực hiện các việc xử lý nào đó dựa trên các tham số chuyển cho nó. Khi thẻ <img> này được đặt trong một cuộc tấn công XSS — cũng là các tấn công phổ biến nhất được ghi chép lại — người sử dụng dễ dàng có thể làm một việc gì đó với quyền ưu tiên được cấp mà không biết mình đã làm — như vậy, có thể giả mạo.

<img src="http://www.example.com/processSomething?id=hacking" />

– Lúc đó ngoài việc áp dụng các cách bảo vệ bên trên trước XSS thì chúng ta cần xác minh các form gửi lên chặc hợn. Ngoài ra, sử dụng biến hiển $_POST thay vì $_REQUEST và kiểm tra kỹ lưỡng các file được up lên nếu là hình ảnh ngoài kiểm tra file_upload,… thì cần kiểm tra size ảnh để chắc chắn đó là một hình ảnh thông qua hàm getimagesize() trong php.

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

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

Xem thêm các việc làm PHP lương cao trên TopDev

Kiểm thử theo hướng Data-Driven với Selenium IDE

data driven
Kiểm thử theo hướng Data-Driven với Selenium IDE

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

Ở phần trước, mình đã giới thiệu với các bạn một phần mở rộng của Selenium IDE cho phép chúng ta điều hướng luồng thực thi của mã Selenium IDE – Selenium IDE Flow Control. Phần này, mình sẽ giới thiệu với các bạn một công cụ khác của Selenium IDE hỗ trợ chúng ta chạy kiểm thử theo hướng Data-Driven – SelBlocks.

  Download, Export file tự động với Selenium Webdriver
  Giới thiệu công cụ kiểm thử tự động Selenium

Xem thêm tuyển dụng C# lương cao trên TopDev

Cài đặt SelBlocks

Các bạn có thể download phần SelBlocks ở đây. Vì cách cài đặt cũng giống như Selenium IDE Flow Control hay những add-on khác của Selenium, nên mình sẽ không nói chi tiết, các bạn có thể xem lại cách cài đặt của Selenium IDE Flow Control trong clip dưới đây

SelBlocks, bên cạnh việc hỗ trợ chúng ta thực thi kiểm thử theo hướng data-driven, nó có cung cấp một số câu lệnh đặc biệt như:

  • if/elseIf/else
  • try/catch/finally/throw
  • for/foreach/while
  • continue/break
  • call/function/return
  • loadXmlVars/loadJsonVars
  • forXml/forJson
  • exitTest

Nhưng trong bài này, mình chỉ tập trung vào phần Data-Driven thôi 🙂

Sử dụng SelBlocks

Ví dụ như chúng ta có một kịch bản như sau

  1. Truy cập trang web Google
  2. Tìm kiếm với từ khóa Selenium/SeleniumHq
  3. Nhấp vào đường dẫn đến trang chủ của Selenium

Kiểm tra trang chủ của Selenium được hiển thị thành công.

SelBlocks sử dụng 1 tập tin XML để chứa các thông tin dữ liệu cho việc thực thi kiểm thử theo hướng data-driven. Vậy nên, trước hết chúng ta cần một file xml, chứa các thông tin mà chúng ta muốn sử dụng để lặp lại phần mã kiểm thử. Chúng ta sẽ có một tập tin xml cho hai trang từ khóa cần tìm: Selenium và SeleniumHq

<testdata>
    <vars searchterm=”Selenium”/>
    <vars searchterm=”SeleniumHq”/>
</testdata>

Sau đó, chúng ta tiến hành record các bước kiểm thử từ khóa đầu tiên. Và, thêm các câu lệnh dành cho việc data-driven. Các bước được mô tả ở video dưới đây.
[adToAppearHere]

Mã Selenium IDE, các bạn có thể download ở đây.

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

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

Xem thêm các việc làm lĩnh vực IT hấp dẫn trên TopDev

Chuyện gõ tiếng Việt trên Linux

gõ tiếng việt trên linux
Chuyện gõ tiếng Việt trên Linux

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

Hẳn là các bạn xài Linux (dù là distro nào) thì cũng đều gặp phải một vấn đề giống nhau, đó là gõ tiếng Việt.

Đã từng gõ tiếng Việt trên Windows với Unikey hay Vietkey ngày xưa thì hẳn ai cũng cảm thấy khá là khó chịu với cái dấu gạch đít quái đản khi chuyển qua xài macOS hoặc Linux. Đối với các bạn chưa biết, thì dấu này gọi là preedit và là một phương pháp “chính thống” theo lời tác giả Trung Ngo (thành viên team phát triển BogoEngine) trong bài viết Ước mơ bộ gõ kiểu Unikey.

  10 điều bạn có thể làm với Linux mà bạn không thể làm với Windows
  6 câu lệnh linux hay dùng trong phân tích log

Xem thêm các việc làm Linux lương cao trên TopDev

1. Hai cách gõ tiếng Việt

Đại ý của bài viết trên thì: tựu chung, các bộ gõ tiếng Việt hiện nay có 2 cách để xử lý tiếng Việt khi gõ, đó là Backspace và Preedit.

  • Preedit: là cách gõ xuất hiện dấu gạch đít, đây thực chất là một vùng buffer lưu tạm các kí tự đang gõ, thay thế nó, ví dụ aa đưọc thay thành â, khi ngưòi dùng nhấn space để kết thúc từ đang gõ thì nó sẽ commit từ đó về cho UI của ứng dụng. Các bộ gõ tiếng Việt sử dụng kĩ thuật này thì có: ibus-unikey, bộ gõ tiếng Việt mặc định của macOS,…
  • Backspace giả: là cách gõ không xuất hiện dấu gạch đít, cơ chế hoạt động của giải pháp này là khi gõ các kí tự tiếng việt như aa, bộ gõ sẽ tự động gửi 2 dấu backspace vào ứng dụng, và gửi tiếp một kí tự â thay thế. Các bộ gõ sử dụng kĩ thuật này có ibus-bogo, fcitx-bogo, GoTiengViet trên macOS,…

2. Kĩ thuật Backspace

Lại nói về Backspace giả, trong bài viết của mình, tác giả Trung Ngo có nói:

Gần như tất cả các bộ gõ trên Windows (tôi không dám chắc nhưng không thể kiểm chứng được vì phần lớn là phần mềm nguồn đóng) giải quyết vấn đề này bằng cách sử dụng dấu backspace giả.

Mình nghĩ là đúng, ít ra là với một vài bộ gõ như GoTiengViet trên Windows (không biết phiên bản trên macOS và Linux anh Trần Kỳ Nam có cải tiến hay sử dụng kĩ thuật khác không, mình không kiểm chứng đưọc), vì từng có một thời gian lúc mình còn tham gia diễn đàn Câu lạc bộ VB, mọi ngưòi cũng thảo luận về vấn đề phát triển bộ gõ, kĩ thuật hồi đó mọi ngưòi áp dụng là:

- Hook keyboard để bắt lại các kí tự đang gõ
- Đưa kí tự vừa đưọc hook vào buffer và kiểm tra theo luật gõ (Telex, VNI,...)
- Gửi backspace để xóa các kí tự đã gõ, ví dụ `aa`
- Đưa kí tự cần thay thế, ví dụ `â`, vào clipboard và gửi phím `Shift + Insert` 
  hoặc `Ctrl + V` để "dán" kí tự này vào ứng dụng đang chạy.
- Hoặc gửi trực tiếp kí tự cần thay thế vào thông qua API của Windows

Và thêm một lý do nữa đó là lần cuối cùng mình check thì không nhớ trên Windows có API nào để hỗ trợ các kĩ thuật khác ngoài chuyện send key.

Hiện giờ nội dung các bài thảo luận đó vẫn còn, các bạn có thể tìm đọc để hiểu thêm:

3. Cấu trúc một bộ gõ thông thường trên Linux

Phải nói là trên X Window System mới đúng. Các bộ gõ khác nhau có nhiều cách xử lý khác nhau, đoạn này mình chỉ nói đến các bộ gõ dùng kiến trúc X Input Method (XIM) như ibusSCIM,…

Nếu để ý, các bạn sẽ thấy các bộ gõ như ibus-bogo hay scim-unikey thưòng hay tự gọi mình là một frontend cho một cái engine gì đó để dùng với ibus hoặc scim:

IBus frontend for the BoGo engine.

scim-unikey là một bộ xử lý nhập liệu tiếng Việt cho scim, sử dụng engine xử lý tiếng Việt của unikey

Đọc phần này sẽ giúp các bạn hiểu thêm về cái vụ “engine gì đó” đó.

Hình sau mô tả toàn cảnh việc xử lý nhập liệu trong một hệ thống X Window System:

  • Khi user nhấn một phím trên bàn phím, keycode của phím này sẽ đưọc gửi về cho X Server.
  • X Server gửi một sự kiện nhấn phím (KeyPress Event) tới cho các X client đang đăng ký chờ event (application sẽ làm nhiệm vụ báo cho client biết nó có nên đăng kí nhận event hay ko)
  • Event loop trên X client sẽ đọc KeyPress Event đó bằng một lệnh gọi tới hàm XNextEvent()
  • Thông tin của Event này sẽ được gửi sang Input Method (ibus, scim,…) và tại đây, tùy theo mỗi bộ gõ khác nhau, mà sẽ thực hiện việc kiểm tra các tổ hợp phím đưọc nhấn, rồi thay thế kí tự cho phù hợp với tập luật của bộ gõ, các nhà phát triển thưòng viết riêng phần xử lý này thành một engine để có thể sử dụng lại với nhiều loại bộ gõ khác nhau.
  • Trong quá trình xử lý (compose), Input Method cũng sẽ báo lại cho application biết để nó update phần preedit cho phù hợp.
  • Sau khi xử lý xong, Input Method sẽ gửi lại nội dung đã đưọc xử lý (một từ tiếng Việt hoàn chỉnh – composed text) về cho X client để in ra màn hình (bưóc này là bước commit). Commit xong thì application cũng thôi không in cái preedit ra nữa.

Engine xử lý việc bỏ dấu (thay thế kí tự phù hợp với tập luật của bộ gõ) có rất nhiều loại khác nhau, đây là tài liệu mô tả logic cho engine mà ibus-bogo sử dụng.

Việc trao đổi giữa X client và Input Method được thực hiện thông qua một phương thức gọi là XIM Protocol.

Và như các bạn thấy thì mô hình này phụ thuộc lớn vào preedit, chính vì vậy mới nói preedit là phưong pháp chuẩn cho việc soạn thảo với các ngôn ngữ ngoài tiếng Anh.

4. Thử nghiệm các bộ gõ trên Linux

Vì phần lớn thời gian làm việc của mình là trên terminal, nên chuyện chấp nhận thưong đau mà dùng Preedit khi gõ lệnh hay xài trong VIM thì mình chịu, không làm đưọc, nên dù không hoàn thiện, mình vẫn chấp nhận được các bộ gõ dùng phưong pháp dùng Backspace, vậy nên bài viết này mình chỉ nhắm tới việc tìm ra bộ gõ xài Backspace hoạt động hiệu quả nhất trên Linux.

4.1. xvnkb

Bộ gõ đầu tiên mình tìm hiểu thử là xvnkb, vì khá ấn tưọng với cái dòng release notes trên trang chủ:

WoW! After 6 years, we have a new official release! L0LzZzzZZzz… Some bugs with Firefox and other apps have been fixed in this release. Still having fun! Hahaha!

LOL.

Quá trình download và cài đặt diễn ra rất trơn tru, không có lỗi gì xảy ra.

Nhưng sau khi cài đặt xong và restart lại máy tính thì xvnkb làm crash luôn X server và máy tính không thể khởi động vào môi trưòng đồ họa đưọc nữa, đáng lý ra thì tới đây mình phải tìm hiểu thêm lý do crash là gì nhưng vì vừa tốn công cài đặt lại máy xong, khá là lưòi, không thấy chạy nữa thì cứ remove thẳng tay thôi :)) thành thật xin lỗi tác giả.

Thế là ứng viên đầu tiên đã bị loại.

4.2. ibus-bogo

Thật sự là sau khi đọc bài viết của tác giả Trung Ngo và xem homepage của project trên Github xong thì không muốn xài ibus-bogo tí nào, nhưng vì đã hết option rồi nên thôi cài vào xài luôn. Quá trình cài đặt thì khá là đơn giản:

$ sudo pacman -S ibus
$ yaourt -S ibus-bogo

Để ibus tự động khởi động thì chúng ta có thể thêm dòng sau vào ~/.xinitrc:

ibus-daemon -drx

Kết quả gõ thử nghiệm cho thấy ibus-bogo hoạt động rất tốt trên terminal, trên các trình duyệt như surffirefox,… không hiện thanh preedit phiền toái.

Tuy nhiên với chế độ gõ TELEX, một vài từ có các nguyên âm ươ như trước, bước, nước, ta bắt buộc phải gõ uwow hoặc uow nếu không muốn bị sót mất chữ ơ, ví dụ nưóc, trưóc. Các bộ gõ như GoTiengViet hay Unikey trên Mac và Windows không bị trường hợp này.

Một nhược điểm khác của ibus-bogo là không hỗ trợ các trình duyệt ChromiumGoogle Chrome, lý do thì tác giả Trung Ngo đã giải thích trong Issue #216 – ibus-bogo.

Lý do lớn nhất khiến nhiều người ngại dùng ibus-bogo có lẽ là vì project này đã không còn được maintain nữa. Ở thời điểm viết bài này, có 63 open issues trên trang Github của project. Thành viên của team phát triển là Trung Ngo đã ngừng maintain dự án vì bất đồng quan điểm với tác giả Ha-Duong Nguyen và fork ra một project khác tên là ibus-ringo (project này add thêm vài chức năng khác trong đó có preedit, nên mình ko xài :D)

4.3. fcitx-bogo

Một phiên bản khác cũng dùng BogoEngine đó là fcitx-bogo, xây dựng cho fcitx. Cách cài đặt thì cũng đơn giản:

$ pacman -S fcitx
$ yaourt -S fcitx-bogo

Khởi động với lệnh sau trong ~/.xinitrc:

fcitx -d

Kết quả thử nghiệm cho thấy bộ gõ này hoạt động tạm gọi là tốt trên mọi phần mềm, trong đó đặc biệt là có thể gõ đưọc tiếng Việt trên Chromium và Google Chrome luôn.

Tuy nhiên khi sử dụng trên terminal thì khá là lag, thời gian từ lúc gõ phím cho tới lúc hiện ra kí tự tiếng Việt rất chậm, không như ibus-bogo, và thêm một điểm trừ nữa là rất không ổn định, hay bung lụa kiểu:

Và khi gõ trên Firefox thì vẫn gặp hiện tượng không gõ đầy đủ dduwocj tiêngs Viêjt =.= (đó, bị như vậy đó).

5. Kết luận

Hy vọng bài viết này giúp các bạn có thêm cái nhìn sâu hơn về các loại bộ gõ tiếng Việt hiện có và những thử thách về mặt kĩ thuật mà chúng ta đang phải đối mặt để có thể phát triển đưọc một bộ gõ tiếng Việt hoàn chỉnh cho môi trưòng Linux.

Bài viết chỉ dựa trên quan điểm chủ quan của tác giả khi tìm hiểu về các bộ gõ không dùng preedit, nên còn nhiều thiếu sót và có nhiều nội dung liên quan đến phưong pháp chuẩn (preedit) và các kĩ thuật khác như surrounding text,… đã bị bỏ qua.

Hy vọng các bạn quan tâm có thể nhiệt tình góp ý, bổ sung và giúp mình hoàn thiện bài viết. Xin cảm ơn 😀

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

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

Xem thêm các việc làm lĩnh vực IT hấp dẫn trên TopDev

Code ví dụ Spring Cloud Config Client

spring cloud config client
Code ví dụ Spring Cloud Config Client

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

Code ví dụ Spring Cloud Config Client

Trong ví dụ này chúng ta sẽ thực hiện load cấu hình để sử dụng cho project từ 1 server khác (Spring Cloud Config)

Việc load cấu hình từ 1 server khác thường áp dụng cho các project có nhiều instance trên nhiều server, mỗi lần đổi cấu hình ta chỉ cần đổi cấu hình trên server config là được chứ không cần phải sửa cho từng server một.

(Xem lại: Code ví dụ Spring Cloud Config Server)

  Xác thực trong Spring Cloud Config (Spring Cloud Config Authenticate)
  Authentication trong Spring Security

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

Code ví dụ Spring Cloud Config Client

Tạo project Spring Boot: File > New > Module

Code ví dụ Spring Cloud Config Client Code ví dụ Spring Cloud Config Client Code ví dụ Spring Cloud Config Client

Cấu trúc project sau khi hoàn thành:

Code ví dụ Spring Cloud Config Client

File Application: (giống hệt các project spring boot thông thường)

package stackjava.com.scconfigclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringCloudConfigClientApplication {
public static void main(String[] args) {
 SpringApplication.run(SpringCloudConfigClientApplication.class, args);
}

}

File bootstrap.yml:

spring:
 application:
 name: app
 profiles:
 active: dev
 cloud:
 config:
 uri: http://localhost:8888

Đây là một project spring cloud nên các thông tin cấu hình về server config, name ta sẽ đặt trong file bootstrap.yml

Trong ví dụ này mình sẽ load cấu hình từ server có địa chỉ http://localhost:8888, cấu hình được load sẽ có tên là app với profiles là dev. (Đây là server mình đã dựng trong bài trước)

File application.yml

server:
 port: 7777

Server sẽ chạy trên port 7777

File controller:

package stackjava.com.scconfigclient.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope
public class HomeController {
@Value("${database.host}")
private String host;
@Value("${database.database}")
private String database;
@Value("${database.username}")
private String username;
@Value("${database.password}")
private String password;

@GetMapping("/config")
public String config() {
return "host: " + host + "<br/>username: " + username + "<br/>password: " + password + "<br/>database: " + database;
}
}

Annotation @RefreshScope là 1 annotation của spring cloud. Các Bean được đánh dấu với annotation này sẽ được làm mới tại thời gian chạy (runtime). Mỗi khi gọi tới thì nó sẽ tạo 1 bean mới.

Start project:

 . ____ _ __ _ _

 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/ ___)| |_)| | | | | || (_| | ) ) ) )

 ' |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot :: (v2.3.3.RELEASE)




2020-08-20 14:20:12.155 INFO 12476 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8888

2020-08-20 14:20:12.984 INFO 12476 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=app, profiles=[dev], label=null, version=31254e088069d8f5c2651156237f2973613a9781, state=null

2020-08-20 14:20:12.985 INFO 12476 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-C:/Users/stackjava/Desktop/spring-cloud-config-server-repo/app-dev.properties'}, BootstrapPropertySource {name='bootstrapProperties-C:/Users/stackjava/Desktop/spring-cloud-config-server-repo/app.properties'}]

...

2020-08-20 14:20:14.616 INFO 12476 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 7777 (http) with context path ''

2020-08-20 14:20:15.227 INFO 12476 --- [ main] s.c.s.SpringCloudConfigClientApplication : Started SpringCloudConfigClientApplication in 5.492 seconds (JVM running for 6.63)

2020-08-20 14:20:19.989 INFO 12476 --- [nio-7777-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'

2020-08-20 14:20:19.989 INFO 12476 --- [nio-7777-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'

2020-08-20 14:20:19.992 INFO 12476 --- [nio-7777-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms

Mở trình duyệt web và truy cập vào địa chỉ: http://localhost:7777/config

Code ví dụ Spring Cloud Config Client

Mặc dù các biến database.host, database.name... không có trong file cấu hình là application.yml nhưng nó vẫn có giá trị là do chúng đã được load từ server config.

Trong bài tiếp theo chúng ta sẽ tìm hiểu việc authen khi giao tiếp giữa spring cloud config server với spring cloud config client. Refresh lại cấu hình cho client khi cấu hình trên server, repository được thay đổi.

Download code ví dụ trên tại đây hoặc tại: https://github.com/stackjava/spring-cloud-config-client

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

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

Xem thêm các việc làm lĩnh vực IT hấp dẫn trên TopDev

REST Web service: Tạo ứng dụng Java RESTful Client với Jersey Client 2.x

java restful client
REST Web service: Tạo ứng dụng Java RESTful Client với Jersey Client 2.x

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

Trong bài trước chúng ta đã cùng tìm hiểu cách xây dựng ứng dụng Java Restful web service với Jersey 1.x. Trong bài này, chúng ta sẽ cùng tìm hiểu cách tạo ra ứng dụng Java Restful web service với Jersey 2.x và ứng dụng Java RESTful Client sử dụng Jersey Client API để gọi tới RESTful web service.

  4 tips học Java cơ bản nhanh nhất dành cho Beginner Developer
  5 cách chia một mảng lớn thành nhiều mảng nhỏ trong Javascript

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

1. Tạo Jersey project

Trong bài trước chúng ta đã tạo Restful web service sử dụng Jersey version 1.x. Trong bài này, chúng ta sẽ tạo Jersey project với version 2.x.

  • Jersey 1.x : các thư viện nằm trong package com.sun.
  • Jersey 2.x : các thư viện nằm trong package org.glassfish.

Vào Menu File -> New -> Dynamic Web Project -> Finish.

new dynamic web project

Nhấn chuột phải lên project vừa tạo -> Configure -> Convert to Maven Project:

Convert to Maven Project

Nhập thông tin Maven project như sau:

Maven project

Chúng ta có project như sau:

Mở file pom.xml và cập nhật lại như sau:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>     <groupId>RestfulWebServiceWithJersey2Example</groupId>     <artifactId>RestfulWebServiceWithJersey2Example</artifactId>     <version>0.0.1-SNAPSHOT</version>     <packaging>war</packaging>     <properties>         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>         <maven.compiler.source>1.8</maven.compiler.source>         <maven.compiler.target>1.8</maven.compiler.target>         <jersey.version>2.28</jersey.version>         <lombok.version>1.16.20</lombok.version>     </properties>     <dependencies>         <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->         <dependency>             <groupId>org.glassfish.jersey.core</groupId>             <artifactId>jersey-server</artifactId>             <version>${jersey.version}</version>         </dependency>         <dependency>             <groupId>org.glassfish.jersey.containers</groupId>             <artifactId>jersey-container-servlet</artifactId>             <version>${jersey.version}</version>         </dependency>         <dependency>             <groupId>org.glassfish.jersey.inject</groupId>             <artifactId>jersey-hk2</artifactId>             <version>${jersey.version}</version>         </dependency>         <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client -->         <dependency>             <groupId>org.glassfish.jersey.core</groupId>             <artifactId>jersey-client</artifactId>             <version>${jersey.version}</version>         </dependency>         <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-common -->         <dependency>             <groupId>org.glassfish.jersey.core</groupId>             <artifactId>jersey-common</artifactId>             <version>${jersey.version}</version>         </dependency>         <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->         <dependency>             <groupId>org.glassfish.jersey.media</groupId>             <artifactId>jersey-media-json-jackson</artifactId>             <version>${jersey.version}</version>         </dependency>         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->         <dependency>             <groupId>org.projectlombok</groupId>             <artifactId>lombok</artifactId>             <version>${lombok.version}</version>             <scope>provided</scope>         </dependency>     </dependencies>     <build>         <sourceDirectory>src</sourceDirectory>         <plugins>             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-compiler-plugin</artifactId>                 <version>3.8.0</version>                 <configuration>                     <source>1.8</source>                     <target>1.8</target>                 </configuration>             </plugin>             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-war-plugin</artifactId>                 <version>3.2.1</version>                 <configuration>                     <warSourceDirectory>WebContent</warSourceDirectory>                 </configuration>             </plugin>         </plugins>     </build> </project>

Lưu ý: đối với project chỉ bao gồm Client (không bao gồm Server), chúng ta chỉ cần 2 thư viện jersey-client và jersey-media-json-jackson.

Sau khi đã cập nhật file pom.xml, chúng ta cần update lại mavent project: Nhấn chuột phải lên project -> Maven -> Update Project… -> OK.

Tạo file jersey config: file này bao gồm config package chứa api và logging.

JerseyServletContainerConfig.java

package com.gpcoder.config;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.jersey.logging.LoggingFeature;
//Deployment of a JAX-RS application using @ApplicationPath with Servlet 3.0
//Descriptor-less deployment
import org.glassfish.jersey.server.ResourceConfig;

public class JerseyServletContainerConfig extends ResourceConfig {
public JerseyServletContainerConfig() {
// if there are more than two packages then separate them with semicolon
packages("com.gpcoder.api");
register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.INFO,
LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
}
}

Tạo file WebContent/WEB-INF/web.xml với nội dung như sau:

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">     <display-name>RESTful CRUD Example by gpcoder</display-name>     <servlet>         <servlet-name>jersey2-serlvet</servlet-name>         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>         <init-param>             <param-name>javax.ws.rs.Application</param-name>             <param-value>com.gpcoder.config.JerseyServletContainerConfig</param-value>         </init-param>         <init-param>             <param-name>jersey.config.server.provider.classnames</param-name>             <param-value>org.glassfish.jersey.jackson.JacksonFeature</param-value>         </init-param>         <load-on-startup>1</load-on-startup>     </servlet>     <servlet-mapping>         <servlet-name>jersey2-serlvet</servlet-name>         <url-pattern>/rest/*</url-pattern>     </servlet-mapping> </web-app>

2. Jersey chuyển đổi XML và JSON sang Model Class như thế nào?

Theo mặc định Jersey API sử dụng JAXB là XML-Binding mặc định để chuyển đổi các đối tượng Java thành XML và ngược lại. Chúng ta cần gắn các Annotation của JAXB lên các class model để chú thích cách chuyển đổi cho JAXB. Chi tiết về JAXB Annotation và cách sử dụng các bạn xem lại bài viết: Hướng dẫn chuyển đổi Java Object sang XML và XML sang Java Object sử dụng Java JAXB.

Jersey chuyển đổi XML và JSON sang Model Class như thế nào

Jersey sử dụng MOXy là JSON-Binding mặc định để Jersey chuyển đổi các đối tượng JSON thành Java và ngược lại. Chúng ta không gần gắn các Annotation lên các class model.

3. Tạo Java REST Web service với Jersey2

Tạo data model:

User.java

package com.gpcoder.model;

import javax.xml.bind.annotation.XmlRootElement;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement(name = "user")
public class User {

private Integer id;
private String username;
}

Tạo Restful CRUD:

UserService.java

package com.gpcoder.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import com.gpcoder.model.User;

// URI:
// http(s)://:(port)/// // http://localhost:8080/RestfulWebServiceExample/rest/users
@Path("/users")
public class UserCrudService {

private static final Map<Integer, User> USERS = new HashMap<>();
static {
// Create dummy data
for (int i = 1; i <= 10; i++) { USERS.put(i, new User(i, "dummy " + i)); } } private int generateUniqueId() { return USERS.keySet().stream().max((x1, x2) -> x1 - x2).orElse(0) + 1;
}

@GET
@Path("/{id}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public User get(@PathParam("id") int id) {
return USERS.getOrDefault(id, new User());
}

@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public List getAll() {
return new ArrayList<>(USERS.values());
}

@POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public int insert(User user) {
Integer id = generateUniqueId();
user.setId(id);
USERS.put(id, user);
return id;
}

@PUT
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public boolean update(User user) {
return USERS.put(user.getId(), user) != null;
}

@DELETE
@Path("/{id}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public boolean delete(@PathParam("id") int id) {
return USERS.remove(id) != null;
}
}

4. Tạo Java REST Client với Jersey2 Client

Tạo Java REST Client với Jersey2 Client

JsonJerseyRestClientExample.java

package com.gpcoder.client;

import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.logging.LoggingFeature;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gpcoder.model.User;

public class UserCrudJerseyRestClientExample {

public static final String API_URL = "http://localhost:8080/RestfulWebServiceExample/rest/users";

public static void main(String[] args) {
System.out.println("Get User: " + getUser(1));

System.out.println("Get Users: " + getUsers());

Integer insertedId = createUser();
System.out.println("Created User: " + insertedId);

System.out.println("Updated User: " + updateUser(insertedId));
System.out.println("After Updated User: " + getUser(insertedId));

System.out.println("Updated User: " + deleteUser(insertedId));
}

private static Client createJerseyRestClient() {
ClientConfig clientConfig = new ClientConfig();

// Config logging for client side
clientConfig.register( //
new LoggingFeature( //
Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), //
Level.INFO, //
LoggingFeature.Verbosity.PAYLOAD_ANY, //
10000));

return ClientBuilder.newClient(clientConfig);
}

/**
* @GET /{id}
*
* Get one user with the given id
*/
private static User getUser(Integer id) {
Client client = createJerseyRestClient();
WebTarget target = client.target(API_URL).path("" + id);
return target.request(MediaType.APPLICATION_JSON_TYPE).get(User.class);
}

/**
* @GET
*
* Get all users
*/
private static List getUsers() {
Client client = createJerseyRestClient();
WebTarget target = client.target(API_URL);
GenericType<List> entity = new GenericType<List>() {
};
return target.request(MediaType.APPLICATION_JSON_TYPE).get(entity);
}

/**
* @POST
*
* create user
*/
private static Integer createUser() {
User user = new User();
user.setUsername("gpcoder client");
String jsonUser = convertToJson(user);

Client client = createJerseyRestClient();
WebTarget target = client.target(API_URL);
Response response = target.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(jsonUser, MediaType.APPLICATION_JSON));
return response.readEntity(Integer.class);
}

/**
* @PUT
*
* Update user
*/
private static Boolean updateUser(Integer id) {
User user = getUser(id);
user.setUsername(user.getUsername() + " edited");
String jsonUser = convertToJson(user);

Client client = createJerseyRestClient();
WebTarget target = client.target(API_URL);
Response response = target.request(MediaType.APPLICATION_JSON_TYPE)
.put(Entity.entity(jsonUser, MediaType.APPLICATION_JSON));
return response.readEntity(Boolean.class);
}

/**
* @DELETE
*
* Delete user
*/
private static Boolean deleteUser(Integer id) {
Client client = createJerseyRestClient();
WebTarget target = client.target(API_URL).path("" + id);
Response response = target.request(MediaType.APPLICATION_JSON_TYPE).delete();
return response.readEntity(Boolean.class);
}

private static String convertToJson(User user) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(user);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

Ứng dụng Client ở trên gửi và nhận dữ liệu kiểu json. Để gửi dữ liệu và nhận kiểu dữ liệu xml, các bạn đơn giản thay thế MediaType.APPLICATION_JSON sang MediaType.APPLICATION_XML.

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

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

Cách Viết Thư Cảm Ơn Chinh Phục NTD Từ 3 Giây Đầu Tiên!

thư cảm ơn phỏng vấn
Cách Viết Thư Cảm Ơn Phỏng Vấn Chinh Phục Nhà Tuyển Dụng Từ 3 Giây Đầu Tiên!

Việc gửi thư cảm ơn nhà tuyển dụng sau buổi phỏng vấn là một văn hóa phổ biến ở các quốc gia. Tuy nhiên, ở Việt Nam, nhiều ứng viên vẫn chưa thật sự chú trọng đến vấn đề này. Một bức thư cảm ơn sau buổi phỏng vấn sẽ giúp bạn gây ấn tượng tốt hơn trong mắt nhà tuyển dụng. Vậy làm thế nào để viết thư cảm ơn phỏng vấn đạt chuẩn? Tìm hiểu thêm với bài viết này nhé!

thư cảm ơn phỏng vấn

Tại sao nên gửi thư cảm ơn phỏng vấn?

Thực tế thì những ứng viên có sự chủ động ngay từ vòng phỏng vấn vẫn luôn gây được ấn tượng tốt với nhà tuyển dụng hơn so với các ứng viên khác. Vậy nên thay vì ngồi chờ đợi thư báo kết quả phỏng vấn từ nhà tuyển dụng, bạn hãy chủ động soạn một bức thư cảm ơn với nội dung ngắn gọn trong vòng 24 giờ sau khi phỏng vấn xong. Một cách hay để vừa cảm ơn, vừa cho thấy sự nhiệt tình và mong muốn của bạn với công việc này.

Nội dung bức thư như đã đề cập, sẽ cảm ơn nhà tuyển dụng vì đã dành thời gian để phỏng vấn bạn cũng như cảm ơn vì đã cho ứng viên cơ hội để trao đổi thêm về suy nghĩ và định hướng công việc giữa hai bên. Ngắn gọn, đơn giản nhưng đủ tôn trọng nhà tuyển dụng, đó chính là cách viết thư cảm ơn phỏng vấn hay nhất.

Xem thêm Viết Đơn Xin Việc Như Thế Nào Để Gây Ấn Tượng Với Nhà Tuyển Dụng?

Cách viết thư cảm ơn sau phỏng vấn đúng chuẩn

1. Tiêu đề

Khi đã làm việc với email, việc viết mail với một tiêu đề chuyên nghiệp thật sự rất quan trọng. Tiêu đề của mail cần được đặt một cách rõ ràng, mạch lạc và đề cập đến nội dung chính của vấn đề bạn muốn nhắc đến trong thư. Khi viết rõ ràng như thế sẽ khiến người nhận thư xem thư của bạn ngay thay vì bỏ qua hay thêm vào danh sách xem sau do nội dung không rõ ràng.

2. Mở đầu thư

Sau tiêu đề thư sẽ bắt đầu với nội dung chính của bức thư. Trong phần mở đầu, người viết thư nên gửi lời chào cũng như nêu rõ họ tên và vị trí mình ứng tuyển, ngày phỏng vấn. Đó là cách để nhắc nhớ nhà tuyển dụng về bạn giữa rất nhiều các ứng viên đã phỏng vấn. Các thông tin cơ bản như trên là đủ để nhà tuyển dụng biết được bạn là ai.

nội dung thư
Bức thư cần đảm bảo các tiêu chuẩn về mặt hình thức

3. Nội dung chính của thư cảm ơn phỏng vấn

Có một ưu điểm khác của thư cảm ơn phỏng vấn mà có thể bạn chưa biết đó là giúp bạn khắc phục những khuyết điểm của mình trong buổi phỏng vấn. Trong lúc phỏng vấn, có thể vì những lý do cá nhân hay quá căng thẳng mà có thể bạn không đủ tự tin thể hiện hết năng lực của mình. Thư cảm ơn giúp ứng viên giải quyết được vấn đề này.

Nếu gặp phải trường hợp này, hãy trình bày thêm về những điều bạn ấn tượng hay cảm thấy thú vị trong buổi phỏng vấn. Có thể đề cập thêm một số điểm để cho thấy bạn là ứng viên phù hợp với công ty và cho thấy mong muốn thật sự muốn tham gia vào hoạt động công ty của bạn.

Ứng tuyển ngay các vị trí đang tuyển dụng Flutter đãi ngộ cực tốt

Hoặc ngược lại, ngay cả khi bạn cảm thấy mình không phù hợp với văn hóa công ty sau buổi phỏng vấn thì việc viết thư cảm ơn vẫn cần thiết. Bạn có thể nêu rõ trong email những lý do bản thân không hợp với công việc. Việc này không chỉ giúp tiết kiệm thời gian của hai bên mà nhà tuyển dụng cũng đánh giá rất cao sự trung thực của ứng viên.

4. Lời cảm ơn cuối thư

Để kết thúc email, ứng viên hãy gửi lời cảm ơn chân thành đến nhà tuyển dụng vì đã dành thời gian phỏng vấn cũng như xem qua thư. Và đừng quên thể hiện mong muốn được đồng hành với công ty trong thời gian tới cũng như bạn đang chờ đợi kết quả phỏng vấn.

thư cảm ơn

Một số lưu ý khi viết thư cảm ơn phỏng vấn

Bên cạnh một nội dung hợp lí thì có một số lỗi thường gặp khi viết mail mà ứng viên nên chú ý để tránh mắc sai lầm.

  • Độ dài của thư: độ dài một email cảm ơn hợp lý nằm trong khoảng nửa trang A4 trở lại. Bạn không nên kể lể quá dài dòng nhưng cũng không nên viết quá ngắn vì sẽ không cho thấy được sự chân thành của người viết.
  • Lỗi chính tả: đây là một lỗi nhỏ nhưng rất dễ khiến người đọc mất cảm tình. Vậy nên sau khi viết thư xong bạn hãy đọc lại một lần nữa toàn bộ nội dung để đảm bảo không có lỗi chính tả trong thư.
  • Thời gian gửi thư: khoảng thời gian hợp lý nhất để gửi thư cảm ơn là trong vòng 24 giờ sau khi kết thúc buổi phỏng vấn. Nếu bạn phỏng vấn vào thứ 6, hãy gửi thư cảm ơn vào thứ 2 tuần sau thay vì gửi vào cuối tuần là thời gian không làm việc.

Một quy trình phỏng vấn thành công luôn ẩn chứa nhiều khó khăn, thậm chí là thử thách. Để đảm bảo có được công việc mình mong ước, hãy dành thời gian nhiều hơn cho vị trí đó. Sự chân thành và tận tâm với công việc sẽ giúp bạn có được công việc mình mong muốn. Đón đọc thêm nhiều bài viết hấp dẫn khác trong lĩnh vực nhân sư và IT tại topdev.vn/blog

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

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

Code ví dụ Spring Cloud Config Server

Spring Cloud Config Server
Code ví dụ Spring Cloud Config Server

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

Code ví dụ Spring Cloud Config Server

Trong bài này mình sẽ làm ví dụ về Spring Cloud Config Server load data cấu hình từ github hoặc từ các folder ở local.

  Authentication trong Spring Security
  Bean, ApplicationContext, Spring Bean Life Cycle và Component scan

Xem thêm các việc làm Spring lương cao trên TopDev

Code ví dụ Spring Cloud Config Server

Tạo project Spring Boot: File > New > Module

Code ví dụ Spring Cloud Config Server Code ví dụ Spring Cloud Config Server Code ví dụ Spring Cloud Config Server

Đây là cấu trúc project sau khi hoàn thành.

Code ví dụ Spring Cloud Config Server

File Application: chúng ta thêm annotation @EnableConfigServer để nó hiểu đây là một Config Server

package stackjava.com.scconfigserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@SpringBootApplication
public class SpringCloudConfigServerApplication {

public static void main(String[] args) {
 SpringApplication.run(SpringCloudConfigServerApplication.class, args);
}

}

File cấu hình:

server:
 port: 8888

spring:
 cloud:
 config:
 server:
 git:
 uri: https://github.com/stackjava/spring-cloud-config-server-repo.git
 search-paths: demo
# username:
# password:

# uri: C:/Users/stackjava/Desktop/spring-cloud-config-server-repo

Trong ví dụ này chạy server trên port 8888 và lưu cấu hình ở github với uri như trên.

  • Mặc định thì các file cấu hình lưu ở root folder, tuy nhiên nếu muốn load các file cấu hình ở folder con ta có thể dùng thêm search-paths
  • Trường hợp git repository của bạn là private thì bạn có thể dùng thêm thuộc tính usernamepassword
  • Nếu bạn không muốn dùng github mà dùng một folder trên local để chứa các file cấu hình thì bạn thay uri bằng địa chỉ folder đó là được. (lưu ý, folder đó cũng phải là 1 repository, và chỉ những data đã được commit mới được sử dụng)

Đây là git repository của mình:

Gồm các file chứa cấu hình cho ứng dụng spring có name là app với các profiles khác nhau:

Code ví dụ Spring Cloud Config Server

Tương tự mình có một sub folder để chứa cấu hình cho ứng dụng spring có name là demo với các profiles tương ứng:

Code ví dụ Spring Cloud Config Server

Start ứng dụng spring boot này:

 . ____ _ __ _ _

 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/ ___)| |_)| | | | | || (_| | ) ) ) )

 ' |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot :: (v2.3.3.RELEASE)




2020-08-20 09:54:57.120 INFO 7956 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://localhost:8888

2020-08-20 09:54:58.878 INFO 7956 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Located environment: name=app, profiles=[dev], label=null, version=34f63fea1576b0c5e5bb67d9a32420d10cb48f3f, state=null

2020-08-20 09:54:58.879 INFO 7956 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-configClient'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/stackjava/spring-cloud-config-server-repo.git/app-dev.properties'}, BootstrapPropertySource {name='bootstrapProperties-https://github.com/stackjava/spring-cloud-config-server-repo.git/app.properties'}]

2020-08-20 09:54:58.884 INFO 7956 --- [ main] s.c.s.SpringCloudConfigClientApplication : The following profiles are active: dev

2020-08-20 09:54:59.256 INFO 7956 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=ab77c954-7bc9-3c62-b748-55ed0878c2e0

2020-08-20 09:54:59.407 INFO 7956 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 7777 (http)

2020-08-20 09:54:59.413 INFO 7956 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]

2020-08-20 09:54:59.413 INFO 7956 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.37]

2020-08-20 09:54:59.415 INFO 7956 --- [ main] o.a.catalina.core.AprLifecycleListener : An older version [1.2.21] of the Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of [1.2.23]

2020-08-20 09:54:59.415 INFO 7956 --- [ main] o.a.catalina.core.AprLifecycleListener : Loaded Apache Tomcat Native library [1.2.21] using APR version [1.6.5].

2020-08-20 09:54:59.415 INFO 7956 --- [ main] o.a.catalina.core.AprLifecycleListener : APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true].

2020-08-20 09:54:59.415 INFO 7956 --- [ main] o.a.catalina.core.AprLifecycleListener : APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]

2020-08-20 09:54:59.418 INFO 7956 --- [ main] o.a.catalina.core.AprLifecycleListener : OpenSSL successfully initialized [OpenSSL 1.1.1a 20 Nov 2018]

2020-08-20 09:54:59.499 INFO 7956 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext

2020-08-20 09:54:59.499 INFO 7956 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 603 ms

2020-08-20 09:54:59.643 INFO 7956 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'

2020-08-20 09:55:00.429 INFO 7956 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 7777 (http) with context path ''

2020-08-20 09:55:01.028 INFO 7956 --- [ main] s.c.s.SpringCloudConfigClientApplication : Started SpringCloudConfigClientApplication in 6.098 seconds (JVM running for 7.174)

2020-08-20 09:55:37.804 INFO 7956 --- [nio-7777-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'

2020-08-20 09:55:37.804 INFO 7956 --- [nio-7777-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'

2020-08-20 09:55:37.809 INFO 7956 --- [nio-7777-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms

Bạn có thể xem thông tin các file cấu hình theo path như sau:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

Ví dụ: http://localhost:8888/app/dev để xem thông tin cấu hình của ứng dụng app với profiles là dev

Code ví dụ Spring Cloud Config Server

Hoặc: http://localhost:8888/app-dev.properties

Code ví dụ Spring Cloud Config Server

Tương tự xem các cấu hình khác:

Code ví dụ Spring Cloud Config Server Code ví dụ Spring Cloud Config Server Code ví dụ Spring Cloud Config Server

Okay, Done!

Download code ví dụ tại đây hoặc tại https://github.com/stackjava/spring-cloud-config-server

References: https://cloud.spring.io/spring-cloud-config/reference/html/#_spring_cloud_config_server

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

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

Xem thêm các việc làm công nghệ hấp dẫn trên TopDev

Tản mạn về nghề đi code thuê

code thuê
Tản mạn về nghề đi code thuê

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

Cũng lâu rồi mình chưa viết bài mới, dạo này toàn draft mấy bài kĩ thuật dài dòng lê thê thành ra viết nửa chừng toàn tụt hết cảm xúc, thôi thì hôm nay tranh thủ ngồi viết tí random vậy.


Bài này nói về những chuyện thường gặp khi làm nghề gõ code thuê. Trong đây có một vài từ ngữ không hợp với thuần phong mỹ tục, cân nhắc kĩ trước khi đọc.

Gõ code thuê tức là code bạn viết ra không thuộc về bạn, mà thuộc về công ty, khách hàng, chủ dự án, người trả tiền cho bạn để bạn code.

Gõ code thuê xuất hiện ở mọi nơi, mọi lúc và đối với mọi người. Nói như vậy để các bạn không có cãi, vì dù bạn là nhân viên của một công ty outsourcing, offshore hay công ty làm product, thì chừng nào người ta vẫn trả tiền cho bạn để bạn code, thì đó là bạn đi code thuê.

Và đây là khúc mà vấn đề xuất hiện. Suy nghĩ của số đông những người đi code thuê là: Vì đi code thuê, nên không việc gì chúng ta phải dồn hết tâm huyết, trách nhiệm vào cho nó hết.

  24 code ES6 tân tiến để khắc phục các lỗi thực hành JavaScript
  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết

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

Nó xuất hiện dưới 1001 hình dạng khác nhau:

  • Viết code kiểu hack đại cho xong, tạm bợ, overwrite lại code của người khác,…: Code kiểu này thường là fix được bug rất nhanh, qua mặt được QA và không màn tới ngày mai, vì kiểu gì ngày mai nó cũng sẽ phòi ra bug, hoặc fix xong bug của mình rồi đó, nhưng tự nhiên hôm sau sẽ có thằng nào đó trong team ngồi chửi thề, đơn giản vì cái chỗ fix này làm hỏng phần khác của nó. Kệmẹnóđi, việc của nó mà, đ’ phải việc của mình là được rồi. Ví dụ: xài !important =)))
  • Hard code: Code kiểu này cũng rất nhanh, giải quyết vấn đề một cách cực kì chính xác, khỏe quá mà, nhưng nếu ngày mai business logic có thay đổi thì việc update là gần như không thể. Kiểu code 1 giây cho thằng khác maintain mất 1 tháng.
  • Không review code: Đây là việc mà hầu như team nào cũng có trong quy trình làm việc của mình, nhưng số người làm tốt việc này là rất ít, nếu bạn thường review code một cách nghiêm túc thì xin chúc mừng bạn, và cũng chúc bạn may mắn luôn khi review code của đồng nghiệp, bảo trọng! Nếu bạn có một thằng khó tính chuyên bắt lỗi mình ở khâu review trong team, xin chúc mừng bạn, đó là người bạn tốt, đừng gây sự với người ta. Nếu bạn thường xuyên review code theo kiểu scroll 1 phát từ đầu trang tới cuối trang rồi bấm nút Approve, merge code, thì xin phép được chửi vào mặt bạn 1 phát, hai cái tính xấu nêu ở trên đều dễ dàng lọt qua được vòng review vì những thằng cẩu thả như bạn. Mình thề là 10 năm đi review code bạn sẽ chẳng học thêm được cái gì từ đồng nghiệp, đừng nói đến chuyện truyền thụ lại được gì cho đàn em.
  • Đổ thừa, không fix những thứ không phải của mình: Việc bạn thường làm khi bị giao một con bug đó là bật git blame để truy xem thằng nào viết cái đoạn code bị lỗi đó, và nếu không phải là bạn thì bạn nhất quyết không fix, cố cãi cho bằng được để cái thằng sinh ra bug dù đang bận cắm đầu ra cũng phải quay lại fix con bug đó. Tưởng tượng bạn đánh DotA và bạn đi top, thằng kia đi bot, và dưới bot đang bị 1vs4, bạn từ chối xuống cứu bot chỉ vì top lane đang không có hero địch nào, farm xả láng và def bot là nhiệm vụ của thằng kia, hay lắm $!& #^ #@&…
  • Chỉ làm đúng requirement, không hơn không kém: Bạn vào một dự án outsource, anh PM dặn trước với bạn là chỉ làm những gì trong scope, không chiều lòng khách hàng mà làm những thứ ngoài phạm vi những gì mà họ đã thỏa thuận với công ty. Và bạn được giao làm một user story về thanh toán online, trong đó bạn PO có ghi là: user nhập thông tin thẻ tín dụng vào form -> frontend gửi thông tin đó về cho backend để tiến hành thanh toán, không có đề cập tới chuyện có mã hóa hay không, nên bạn không làm dù bạn thừa biết là phải mã hóa thì mới đảm bảo về mặt security, và cũng vì nó ngoài scope, bạn cũng không việc gì phải raise vấn đề này lên trong team hoặc với PO để họ sửa sai, đơn giản vì việc đó nằm ngoài scope, hay lắm $!& #^ #@&…
  • … còn nhiều lắm …

Và khi tất cả những việc trên xảy ra, thì khách hàng sẽ phàn nàn, thậm chí là mắng chửi, rồi sẽ bắt bạn và cả team đi làm OT vào cuối tuần, rồi các bạn sẽ vừa làm vừa chửi: “Đ!& #^ bọn tây, bóc lột vcl”, hoặc chửi bạn PM không biết cách quản lý dự án để cả team phải đi nhận tiền OT như thế này =)))

OK, giờ nhìn lại vấn đề theo một hướng khác:

Tèo là nhân viên của một tiệm bán bánh mì nổi tiếng trong thành phố, vì vậy Tèo cũng là thằng làm bánh thuê, vì đi làm thuê nên Tèo không việc gì phải dồn hết tâm huyết vào mỗi ổ bánh mì mà mình làm ra, Tèo có thể cầm điện thoại vào nhà vệ sinh để ngồi làm chuyện đại sự trong 30 phút sau đó không cần rửa tay và đi ra quầy bánh bốc từng mảng patê trét vào ổ bánh mì thịt chả mà bạn đang chờ mua trên đường đi làm mỗi sáng. Bạn nhận lấy ổ bánh mì được gói trong tờ giấy báo Tèo mua lại từ mấy bà bán ve chai, và nhai ngấu nghiến một cách đầy biết ơn, mì hơi dở, nhưng được cái nó rẻ, kệ. Đến trưa thì bạn bị đau bụng (hiển nhiên rồi =))) bạn bực mình chạy tới tiệm và chửi, đơn giản vì bạn bỏ tiền ra mua bánh mì. Tèo bị chửi thì bực tức suốt từ trưa đến tối. Sau vài tháng thì tiệm bánh mì phải đóng cửa vì quá dở và không đảm bảo vệ sinh, Tèo cũng vì thế mà thất nghiệp vì dính phốt “đi ra” từ cái tiệm mất vệ sinh nhất thành phố, không ai dám nhận Tèo vào làm nữa. ¯\_(ツ)_/¯

Trích một đoạn trong cuốn The Pragmatic Programmer:

When you do accept the responsibility for an outcome, you should expect to be held accountable for it. When you make a mistake (as we all do) or an error in judgment, admit it honestly and try to offer options.

Don’t blame someone or something else, or make up an execuse. Don’t blame all the problems on a vendor, a programming language, management, or your coworkers. Any and all of these may play a role, but it is up to you to provide solutions, not execuses.

Kêt bài: vì là random nên chả có kết bài gì đâu :)) các bạn đọc cho vui thôi nha.

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

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

Xem thêm các công việc ngành IT hấp dẫn trên TopDev

Webp là gì? Tăng tốc độ tải của website bằng webp

tốc độ tải trang
Tăng tốc độ tải trang của website bằng webp

Bài viết được sự cho phép của tác giả Võ Xuân Phong

Webp là gì?

Webp là một định dạng hình ảnh hiện đại, nó cung cấp cơ chế nén lossless (nén không mất mát) và lossy (nén mất mát), hiểu nôm na cơ chế nén lossless giúp file được nén giữ nguyên chất lượng ban đầu, còn cơ chế nén lossy làm cho hình ảnh có độ phân giải và chất lượng bị thay đổi.

Những hình ảnh được nén theo cơ chế nén lossless dung lượng giảm đi 26% khi nén từ định dạng PNG và giảm từ 25% đến 34% khi nén từ định dạng JPEG mà vẫn giữ nguyên chất lượng hình ảnh.

Cơ chế nén lossless và lossy đều hỗ trợ transparency (hình ảnh trong suốt). Hình ảnh có thể giảm dung lượng đi 3 lần so với dung lượng hình ảnh ban đầu khi nén ở cơ chế lossy ở định dạng PNG.

Ưu điểm của Webp

  1. Tăng tốc độ tải trang: Do webp làm giảm dung lượng của file ảnh vì thế tốc độ tải trang khi sử dụng định dạng webp sẽ nhanh hơn các định dạng như PNG và JPEG.
  2. Tiết kiệm băng thông hơn: Cũng do dung lượng file ảnh nhỏ mà chi phí băng thông sẽ giảm đi đáng kể.
  3. Tốt cho SEO: Trang web tăng tốc độ tải đồng nghĩa trải nghiệm người dùng trên trang sẽ tốt và google sẽ đánh giá cao trang web của anh em.
  4. Hiển thị hình ảnh đủ chất lượng: Như đã trình bày với anh em ở trên thì cơ chế nén lossless sẽ giúp cho hình ảnh giảm đi dung lượng nhưng chất lượng hình vẫn không thay đổi là bao.
  5. Hỗ trợ nhiều loại hình ảnh khác nhau như ảnh động và ảnh trong suốt.

Nhược điểm của Webp

  1. Định dạng webp còn khá mới nên chưa được hỗ trợ rộng rãi ở một số phần mềm xem ảnh và các trình duyệt.

Xem chi tiết tại link

  1. Ngoài file gốc như có định dạng như .png hoặc .jpg thì lại phải sinh ra thêm file .webp trên server lưu trữ.

Cài đặt webp trên linux server sử dụng lệnh apt

Anh em có thể cài đặt webp bằng câu lệnh apt của máy Ubuntu

sudo apt install webp

Cài đặt webp trên linux server theo version cụ thể

Trên những server linux khác anh em có thể tải trực tiếp package về và cài đặt

Version mới nhất của   libwebp tính tới thời điểm hiện tại là 1.2.1 anh em có thể tham khảo tại link https://chromium.googlesource.com/webm/libwebp/

Đây là download list của libwebp https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html

wget -c https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.2.1-linux-x86-64.tar.gz

Giải nén package vừa tải về

tar -xvf libwebp-1.2.1-linux-x86-64.tar.gz

cd libwebp-1.2.1-linux-x86-64
cd bin/
ls

Trong thư mục bin này anh em sẽ thấy libwebp có rất nhiều công cụ như cwebp, dwebp, gif2webp v..v. Trong bài viết này mình chỉ quan tâm đến công cụ cwebp thôi, những công cụ khác anh em có thể tự tìm hiểu thêm.

     ⦿ anim_diff → công cụ cho chỉ ra sự khác biệt giữa các hình ảnh động.

     ⦿ anim_dump → công cụ dành cho việc xuất ra sự khác biệt giữa các hình ảnh động.

     ⦿ cwebp → công cụ để mã hóa webp.

     ⦿ dwebp → công cụ dành cho giải mã webp.

     ⦿ gif2webp → công cụ cho chuyển đổi ảnh GIF sang webp.

     ⦿ img2webp → công cụ cho chuyển đổi chuỗi hình ảnh thành tệp web động.

     ⦿ vwebp → đây là một trình xem tệp tin webp.

     ⦿ webpinfo → công cụ xem thông tin về một tập tin webp.

     ⦿ webpmux → công cụ tạo ra những hình ảnh webp động từ những hình ảnh tĩnh.

Với cách cài đặt thủ công như thế này thì anh em cần phải cài đặt thêm biến môi trường nữa.

nano ~/.bashrc

Dán dòng này ở cuối file nhé anh em.

export PATH=$PATH:/home/vxphong/libwebp-1.2.1-linux-x86-64/bin

Anh em nhớ đổi đường dẫn tới libwebp cho đúng nha, bây giờ thì mình đã sử dụng được công cụ cwebp rồi hãy thử xem nào.

Cách sử dụng Webp để chuyển đổi định dạng ảnh

Sau khi đã cài đặt được webp, anh em hãy thử dùng lệnh cwebp để chuyển đổi hình ảnh nào đó sang định dạng webp ví dụ:

cwebp -q 80 old_image.png -o new_image.webp

Trong đó -q 80 tương ứng với chất lượng hình ảnh là 80%, anh em có thể chỉnh lại thông số tùy theo nhu cầu về chất lượng hình ảnh sau khi hình ảnh mới được tạo ra.

  "Ngành IT này học rất dễ, tài liệu ko bao giờ thiếu. Quan trọng là phải có đam mê và chịu cày"
  "Thiếu hiểu biết về Công nghệ ở thế kỷ 21 coi như là mù chữ" - Nhân Nguyễn, CEO tại KALAPA

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

Tạo Webp service tự động convert ảnh

Tạo 1 file có tên monitor-file-creation.sh ở /home/vxphong/scripts đường dẫn này anh em tùy chỉnh lại nha, file này có nội dung như sau:

nano  /home/vxphong/scripts/monitor-file-creation.sh
#!/bin/sh
MONITORDIR="/home/vxphong/test-webp"
inotifywait -m -r -e move -e create --format '%w%f' "${MONITORDIR}" | while read NEWFILE;do
  echo  "File has ${NEWFILE} been created"
  if [ ! -f "${NEWFILE%.*}.webp" ]; then
    sleep 10
    cwebp -q 80 "${NEWFILE}" -o "${NEWFILE%.*}.webp"
  fi
done

File này mục đích để giám sát những hình ảnh trong thử mục /home/vxphong/test-webp được tạo ra hoặc được di chuyển vào thì nó sẽ tự động tạo ra 1 file webp.

Trong file này anh em nhớ thay đổi đường dẫn MONITORDIR đến đúng đường dẫn anh em lưu các file hình ảnh nha.

Ở đây mình tạo ra thư mục test-webp và sẽ lưu hình ảnh ở thư mục này

mkdir /home/vxphong/test-webp

Thiết lập quyền excute cho file.

chmod 755 monitor-file-creation.sh

Tới bước này anh em nhớ cài thêm inotify-tools nữa nhé tool này dùng để giám sát sự thay đổi các file trong thư mục nào đó.

sudo apt update
sudo apt install inotify-tools

Sau khi đã cài đặt xong thì tạo 1 service để chắc chắn cái script chuyển đổi file webp của anh em luôn hoạt động.

nano /etc/systemd/system/webp.service

Anh em tạo một service webp ở đường dẫn  /etc/systemd/system/webp.service với nội dung sau:

[Unit]

Description=Webp Converter

[Service]

ExecStart=/home/vxphong/scripts/monitor-file-creation.sh

[Install]

WantedBy=multi-user.target

Ở file service này anh em nhớ thay đổi đường dẫn của ExecStart thành đường dẫn mà anh em đã lưu file  monitor-file-creation.sh nha.

Khởi chạy service

systemctl start webp

Khởi chạy khi khởi động service

systemctl enable webp

Kiểm tra status của webp service

systemctl status webp

Kiểm tra kết quả:

Mình sẽ copy một hình ảnh jpg từ ngoài Desktop vào hoặc anh em có thể sử dụng ứng dụng web của anh em để upload hình ảnh lên thư mục này và chờ xem kết quả.

Sau khi thực hiện việc copy hình ảnh vào thư mục này thì anh em đã thấy nó đã tạo ra 1 hình ảnh có đuôi .webp rồi đấy. Bước tiếp theo là hiển thị hình ảnh trên UI dựa vào đường dẫn tới hình.

Dùng thẻ picture để hiển hiển thị định dạng webp

Nào hãy tận hưởng thành quả.

<picture>

    <source type="image/webp" srcset="test.webp" />

    <source type="image/jpg" srcset="test.jpg" />

</picture>

Tóm lại

Ở trên mình đã trình bày ưu và nhược điểm khi sử dụng webp, webp giúp tăng tốc độ tải của trang web, tiết kiệm được băng thông do dung lượng webp có kích thước khá nhỏ. Bên cạnh đó thì anh em cũng cần phải lưu trữ cả định dạng gốc để trường hợp trình duyệt không hỗ trợ định dạng webp thì sẽ phải tải hình ảnh với định dạng gốc, điều này thì mình thấy khá rườm rà.

Github: link

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

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

Xem thêm các công việc CNTT hấp dẫn trên TopDev

Cài đặt Rust trên Arch Linux

cài đặt rust
Cài đặt Rust trên Arch Linux

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

Việc cài đặt Rust trên môi trường Arch Linux khá là đơn giản. pacman có sẵn gói rust và cargo, bạn có thể chọn cách cài đặt trực tiếp 2 packages này.

Tuy nhiên ở bước cài đặt công cụ hỗ trợ cho các IDE, chúng ta thường dùng racer và engine này yêu cầu chúng ta phải có source code của Rust nằm sẵn trong máy. Nếu chọn cách cài đặt từng gói, thì chúng ta có thể cài đặt Rust source code thông qua yaourt với gói rust-srcAUR, rồi phải set biến môi trường RUST_SRC_PATH khá là phiền phức.

Cho nên, cách cài đặt đơn giản nhất đó là dùng rustup. Package này gồm có: rustuprustc và cargo. Và bước cài đặt Rust source cũng đơn giản hơn.

  Dynamic typing trong Rust với std::any::Any
  Rust và Lập trình Web

Xem thêm tuyển dụng Linux lương cao trên TopDev

Các bước cài đặt cụ thể như sau:

1. Cài Rustup

Cài rustup thông qua pacman sau đó chọn phiên bản Rust cần dùng, ví dụ ở đây dùng bản stable.

$ sudo pacman -S rustup
$ rustup default stable

Sau khi cài xong thì chúng ta có toàn bộ các công cụ cần thiết để làm việc với rust. Có thể kiểm tra thông qua các lệnh:

$ rustc -V
$ cargo -V

2. Cài đặt công cụ hỗ trợ cho các IDE

Việc đầu tiên cần làm trước khi cài đặt các gói hỗ trợ cho IDE là add Rust source code vào máy, thực hiện việc này thông qua rustup như sau:

$ rustup component add rust-src

Sau khi đã có source code của Rust trong máy, các bạn có thể bắt đầu đọc source để hiểu những gì Rust làm bên dưới, từ đó sẽ nắm được toàn bộ kiến thức và không cần dùng bất cứ trình hỗ trợ nào cho IDE khi code Rust nữa… à nhầm, không phải =)))) bước tiếp theo là cài đặt racer.

$ cargo install racer

Cuối cùng, tùy theo IDE/editor mà bạn sử dụng, bạn có thể cài các plugin khác nhau cho việc support Rust. Nếu bạn xài Vim thì cài plugin rust.vim:

Plug 'rust-lang/rust.vim'

3. Cài đặt Syntastic trong Vim

Phần này chỉ là phụ, dành cho bạn nào xài Vim và muốn có chức năng kiểm tra lỗi trực tiếp trong lúc code bằng Syntastic.

Cài thêm plugin Syntastic như sau:

Plug 'vim-syntastic/syntastic'

Cấu hình cho Syntastic trong .vimrc theo như recommend trên trang chủ dự án của họ:

set statusline+=\ %#warningmsg#
set statusline+=\ %{SyntasticStatuslineFlag()}
set statusline+=\ %*

let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0

Tuy nhiên nếu chỉ đến đây, khả năng là chức năng kiểm tra lỗi vẫn chưa hoạt động được, cần thêm vào dòng sau để chỉ định Syntastic checker dành cho Rust:

let g:syntastic_rust_checkers = ['rustc']

Khởi động lại Vim và thưởng thức thành quả 😀

Đến đây thì việc cài đặt hoàn tất. Bạn có thể tham khảo thêm wiki của Arch Linux để biết thêm chi tiết về cách cài đặt Rust và các chức năng cần thiết khác.

UPDATE: Sau khi làm việc với Rust theo như setup ở trên vài ngày thì mình có gặp hai vấn đề liên quan đến cargo, đó là:

  • Syntastic không thể nhận biết được project dạng library, nên sẽ luôn xuất hiện thông báo kiểu như missing main function
  • Khi sử dụng các crate bên ngoài thì Syntastic sẽ báo lỗi ngay dòng extern crate ..., nói là không tìm thấy crate này

Hai vấn đề trên buộc lòng chúng ta phải sử dụng cargo làm checker cho Syntastic thay vì rustc, hiện tại thì cargo check đã được merge vào master của cargo nhưng việc support này vẫn chưa được merge vào plugin rust.vim (xem pull request rust.vim#132).

Cách giải quyết tạm thời là cài rust.vim trực tiếp từ repo của tác giả jlevesy thay vì từ repo của rust-lang:

Plug 'jlevesy/rust.vim'

Và chỉ định cargo làm checker:

let g:syntastic_rust_checkers = ['cargo']
Bài viết gốc được đăng tải tại snacky.blog
Có thể bạn quan tâm:
Xem thêm các công việc ngành CNTT hấp dẫn trên TopDev

Code không màu…

code
Code không màu...

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

Độ hơn 1 tháng nay thì mình chuyển sang chế độ “chay tịnh” trong Vim.

Đó là tắt luôn chức năng Syntax Highlighting… đưa màn hình code về dạng nguyên thủy nền đen chữ trắng 😆.

Okay, mình biết là bạn đang nghĩ gì, không phải tại mình bị điên đâu :)) việc làm này đem lại hiệu quả cực kì lớn đấy.

  "Code dễ đọc" là như thế nào?
  "Làm PM, theo anh không cần biết về code, nhưng phải hiểu về SQL, database, những khái niệm cơ bản của code"

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

  • Giúp bạn tập trung hơn khi code
  • Giúp tăng khả năng đọc code của bạn lên rất nhiều
  • Vì không còn màu sắc nên bạn phải chú ý hơn tới việc trình bày code cho gọn gàng sạch đẹp
  • Bạn sẽ bớt code ẩu hơn
  • Khiến bạn trông ngầu hơn khi code

Thực ra nếu để ý kĩ thì giao diện mình đang xài không hoàn toàn là không màu. Nó vẫn có 2 màu chủ đạo là trắng và ít trắng hơn :))) bên cạnh đó còn có 2 kiểu hiển thị là in đậm và in không đậm nữa.

Đây là kết quả sau quá trình sử dụng và “optimize” cái giao diện để làm việc thoải mái nhất có thể.

Và mình cũng không phải là người duy nhất làm cái trò này :v

Tất nhiên khi mới bắt đầu thì không dễ dàng gì vì gần như ngay từ lần đầu tiên bắt đầu học lập trình thì mình đã sử dụng syntax highlighting rồi. Tuy nhiên điều khá bất ngờ là mình trở nên quen với việc code không màu này rất nhanh (chưa đầy nửa ngày).

Nếu bạn nào có hứng thú thì có thể xài thử color scheme do mình modify lại từ bộ màu base16-ocean tại đây:

Hãy thử dành ra một tuần hoặc lâu hơn để sử dụng thử và tự mình cảm nhận nhé 😀

Happy vimming ^^

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

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

Xem thêm các công việc ngành CNTT hấp dẫn trên TopDev

Cách tạo hồ sơ xin việc online qua email ấn tượng

hồ sơ xin việc gồm những gì
Một Bộ Hồ Sơ Xin Việc Gồm Những Gì Khi Gửi Qua Email?

Ngày nay, hơn 80% nhà tuyển dụng đã sử dụng các kênh online để tìm kiếm ứng viên. Do đó, việc tạo một hồ sơ xin việc online ấn tượng sẽ giúp bạn nổi bật giữa hàng ngàn ứng viên khác và tăng cơ hội nhận được lời mời phỏng vấn. Hãy cùng theo dõi bài viết này để tìm hiểu cách tạo hồ sơ xin việc qua email chuẩn chỉnh và tăng cơ hội lọt vào “mắt xanh” nhà tuyển dụng

Hồ sơ xin việc online qua email là gì?

Hồ sơ xin việc online qua email là cách ứng viên nộp hồ sơ xin việc của mình bằng hình thức online thông qua địa chỉ email. Email xin việc thường được gửi trực tiếp đến địa chỉ email của nhà tuyển dụng hoặc phòng nhân sự của công ty. Đây là cách thức phổ biến trong thời đại kỹ thuật số, giúp ứng viên tiếp cận nhanh chóng và hiệu quả với nhà tuyển dụng mà không phải đến trực tiếp công ty để nộp hồ sơ như trước kia.

Email xin việc thường bao gồm một lời giới thiệu ngắn gọn về bản thân, vị trí ứng tuyển. Email xin việc thường ngắn gọn, tập trung vào việc dẫn dắt nhà tuyển dụng đến phần hồ sơ đính kèm.

Cần phân biệt email xin việc và cover letter, Thư xin việc (Cover Letter) là một tài liệu chi tiết hơn, thường được đính kèm cùng CV trong email xin việc. Thư xin việc cung cấp một cái nhìn sâu hơn về kinh nghiệm, kỹ năng và lý do ứng viên muốn ứng tuyển vào vị trí cụ thể. Thư xin việc thường dài hơn email xin việc và có cấu trúc rõ ràng, bao gồm phần mở đầu, nội dung chính và phần kết thúc.

Hồ sơ xin việc online sẽ bao gồm những gì?

CV – Công cụ tiếp thị cá nhân không thể thiếu

CV là một thứ rất quan trọng, bắt buộc phải có. Dù cho mọi thứ được “marketing hóa”, CV vẫn là công cụ giúp bạn ghi điểm hiệu quả với nhà tuyển dụng.

Ứng viên cần thể hiện rõ các khía cạnh về kỹ năng chuyên môn của mình trong CV.

Tăng hiệu quả ứng tuyển bằng cách tạo CV Online hiệu quả trên TopDev

Gửi CV qua email gồm những gì? Các thành phần cơ bản trong CV thường gồm có:

  • Thông tin cá nhân
  • Trình độ học vấn
  • Kinh nghiệm làm việc
  • Kỹ năng
  • Thành tích

Hãy thật sự đầu tư cho chiếc CV của bản thân mình chuẩn format và đủ nội dung. Nội dung CV cần truyền tải đúng trọng tâm, đầy đủ. Trong khi đó, visual của CV cũng là yếu tố thu hút nhà tuyển dụng. Hãy đảm bảo CV đầy đủ sự chân thật và tính trực quan cần có. 

hồ sơ xin việc

Một số tip đáng lưu ý:

  • Bạn nên ưu tiên sử dụng các font chữ chuyên nghiệp; phù hợp với tiêu chuẩn chung như: Time New Roman, Arial, Century Gothic,…
  • CV nên được định dạng bằng file PDF thay vì phiên bản Word hay PowerPoint. Điều này giúp hạn chế tình trạng font chữ bị lỗi hoặc các bố cục trong CV bị dịch chuyển.

Cover Letter – Thư xin việc

Cover Letter thường được mô tả dưới dạng nội dung trong email nên bạn không cần phải đính kèm. Dù bạn ứng tuyển vị trí nào như freelancer it hay Senior Developer đều phải đảm bảo những yếu tố cần thiết của một Cover Letter.

Một số nhà tuyển dụng, họ có hoặc không yêu cầu về Cover Letter. Tuy nhiên, bạn có thể đính kèm nếu bản thân muốn thể hiện sự nghiêm túc với công việc.

Đơn xin việc (Cover Letter)

Khi viết cover letter bạn cần xác định rõ vị trí bạn ứng tuyển và mục tiêu của bạn khi ứng tuyển vào vị trí này. Hãy nêu bật những điểm mạnh, kỹ năng và kinh nghiệm của bạn phù hợp với vị trí ứng tuyển. Và hãy nhớ check lại thật kỹ lỗi ngữ pháp và chính tả trước khi gửi nó đến nhà tuyển dụng.

Nội dung thông tin có thể gửi thường chỉ được giới hạn từ 300 – 500 chữ. Vì thế, bạn nên cân nhắc việc lựa chọn các thông tin nào quan trọng và cần thiết để gửi đến nhà tuyển dụng.

>> Xem thêm: Cách viết cover letter cho lập trình viên chưa có kinh nghiệm

Sản phẩm mang dấu ấn cá nhân – Portfolio

Portfolio là phần không bắt buộc phải có trong bộ hồ sơ xin việc qua email vì nó còn phụ thuộc vào ngành nghề mà bạn ứng tuyển. Portfolio là một tập hợp các công việc, dự án hoặc sản phẩm mà bạn đã thực hiện trong quá khứ. Đây là cách tốt nhất để bạn có thể giới thiệu và thể hiện khả năng và kỹ năng của mình cho nhà tuyển dụng.

Nếu bạn là ứng viên ứng tuyển các nhóm ngành thuộc lĩnh vực sáng tạo như: thiết kế, truyền thông marketing, quảng cáo, báo chí,… thì Portfolio rất quan trọng.

Portfolio có thể bao gồm nhiều loại tài liệu khác nhau như hình ảnh, video, bài viết, thiết kế,… Bạn cần lưu ý chọn lọc những sản phẩm tốt nhất, phù hợp nhất với vị trí bạn ứng tuyển để đưa vào portfolio và thường xuyên cập nhật những sản phẩm mới mà bạn đã thực hiện.

Lưu ý quan trọng, các file sản phẩm định dạng phù hợp là file dưới dạng hình ảnh JPG, PNG hay PDF.

Hình ảnh cá nhân

Một bức ảnh cá nhân là điều cần thiết giúp cho hồ sơ xin việc của bạn thêm chuyên nghiệp. Vì thế, hãy chuẩn bị ngay cho mình những bức hình đẹp nhất để đính kèm trong email nhé!

hồ sơ xin việc

Những lưu ý về một bức ảnh phù hợp:

  • Bức ảnh phải rõ mặt, thể hiện sự tự tin, không nên có sự xuất hiện của người khác.
  • Ảnh cần thể hiện sự nghiêm túc, tránh gửi hình tự sướng, ảnh đời thường hay ảnh với chất lượng kém.
  • Ảnh chuẩn là ảnh sắc nét, không dùng các phần mềm chỉnh sửa quá đà.

Các tài liệu đính kèm khác

Một số nhà tuyển dụng muốn đánh giá toàn diện hơn về các khả năng khác của ứng viên. Và vì thế, họ có thể yêu cầu thêm một số tài liệu có liên quan.

Đó có thể là những minh chứng về thành tích học thuật, ngoại khóa; các chứng chỉ khóa học, ngoại ngữ hay thậm chí là bảng điểm của bạn. Yêu cầu thêm thông tin là cách họ khai thác nhiều hơn ở bạn.

Quan trọng là, bạn hãy thật thông minh trong việc lựa chọn các minh chứng. Nên chọn lọc các thành tích khoa học, phát triển kỹ năng, ngoại khóa có liên quan đến vị trí mà bạn đang ứng tuyển để gia tăng cơ hội trúng tuyển.

Cách viết một email xin việc chuyên nghiệp

Viết một email xin việc đúng chuẩn là một bước quan trọng trong việc làm hồ sơ xin việc online để tạo ấn tượng tốt đầu tiên với nhà tuyển dụng. Dưới đây là hướng dẫn chi tiết về cách viết email xin việc đúng chuẩn:

Tạo một địa chỉ email chuyên nghiệp

Địa chỉ email của bạn cũng vô cùng quan trọng vì nó cũng giúp hồ sơ của bạn vì nó là thứ giúp bạn gây ấn tượng ban đầu với nhà tuyển dụng.

hồ sơ online

Đừng đặt một địa chỉ email quá trẻ con. Điều này hiển nhiển trở thành một điểm trừ lớn. Nhà tuyển dụng sẽ đánh giá bạn là một người thiếu chuyên nghiệp. Hoặc đơn giản họ nghĩ, bạn chưa đủ trải nghiệm do sự am hiểu về “diện mạo” của địa chỉ email – kiến thức căn bản chưa hoàn thiện. Và do đó, hồ sơ của bạn bị loại bỏ khi họ chưa kịp xem đến CV của bạn.

Tiêu đề Email xin việc

Dù chỉ là những khía cạnh về mặt hình thức song, nó rất quan trọng. Thường các nhà tuyển dụng sẽ có đề cập về cách thức đặt tiêu đề trong thông tin tuyển dụng. Bạn nên lưu ý để đảm bảo không sai hình thức.

Nếu không có format sẵn từ doanh nghiệp, bạn có thể đảm bảo tính chuyên nghiệp thông qua cách đặt tiêu đề gợi ý như sau: 

  • Vị trí ứng tuyển – Họ Tên – Năm kinh nghiệm
  • Tên Doanh nghiệp – Vị trí ứng tuyển – Họ tên
  • Họ Tên  – Vị trí ứng tuyển

Lời chào

Lời chào cần lịch sự và chính xác. Nếu biết tên của nhà tuyển dụng hoặc người phụ trách tuyển dụng, hãy sử dụng tên của họ. Nếu không biết tên, bạn có thể sử dụng chung chung như:

  • Kính gửi Ông/Bà [Tên người nhận],
  • Kính gửi Bộ phận Tuyển dụng công ty…,

Phần mở đầu

Phần mở đầu của email nên giới thiệu ngắn gọn về bản thân và lý do bạn viết email này. Bạn nên nêu rõ vị trí mình đang ứng tuyển và lý do tại sao bạn quan tâm đến công việc này.

Ví dụ: “Tôi là Nguyễn Văn A, hiện đang tìm kiếm cơ hội làm việc trong lĩnh vực [lĩnh vực của bạn]. Tôi rất hứng thú với vị trí [Tên vị trí] mà quý công ty đang tuyển dụng và tin rằng với kinh nghiệm và kỹ năng của mình, tôi sẽ đóng góp tích cực cho công ty.”

Phần nội dung chính

Trong phần này, bạn nên tóm tắt ngắn gọn về kinh nghiệm, kỹ năng và lý do bạn phù hợp với vị trí ứng tuyển. Bạn có thể nhấn mạnh những thành tựu nổi bật hoặc kỹ năng đặc biệt của mình.

Nội dung trình bày trong Email là những thông tin cơ bản. Nó như một phần níu kéo nhà tuyển dụng ở lại lâu hơn. Hình thức font chữ, màu sắc cần đồng nhất. Bạn không nên trình bày quá rườm rà, hãy nghĩ đơn giản nhưng chuyên nghiệp.

Ví dụ: “Với hơn 3 năm kinh nghiệm trong lĩnh vực [lĩnh vực của bạn], tôi đã phát triển được các kỹ năng như [kỹ năng chính], giúp tôi hoàn thành xuất sắc các dự án tại công ty cũ. Tôi tin rằng những kinh nghiệm này sẽ giúp tôi thực hiện tốt các nhiệm vụ của vị trí [Tên vị trí].”

Phần kết luận

Kết thúc email bằng việc cảm ơn nhà tuyển dụng đã dành thời gian đọc email của bạn và bày tỏ mong muốn được gặp trực tiếp để trao đổi thêm về cơ hội này.

Ví dụ: “Tôi rất mong được có cơ hội trao đổi thêm về cách mà tôi có thể đóng góp cho công ty. Xin cảm ơn quý công ty đã dành thời gian xem xét hồ sơ của tôi. Tôi rất hy vọng sẽ nhận được phản hồi từ quý công ty.”

Lời chào kết

Kết thúc email bằng một lời chào lịch sự, chẳng hạn:

  • Trân trọng,
  • Chân thành cảm ơn,

Chữ ký email

Cuối email, bạn nên để lại thông tin liên lạc chi tiết bao gồm tên, số điện thoại và địa chỉ email của bạn để thể hiện sự chuyên nghiệp và có đầu tư.

Ví dụ:

Nguyễn Văn A
Số điện thoại: 0901234567
Email: nguyenvana@example.com

Đính kèm tài liệu

Đừng quên đính kèm các tài liệu như đã liệt kê ở trên như CV và các tài liệu liên quan như thư xin việc, chứng chỉ, bảng điểm,… Kiểm tra lại lần cuối trước khi gửi để đảm bảo các file đã được đính kèm đúng cách.

Đây là phần rất nhiều ứng viên mắc lỗi, họ thường quên đính kèm CV mà gửi một email trơ trọi đến nhà tuyển dụng.

Đính kèm tài liệu trong email xin việc

Mẫu email xin việc online tham khảo

Dưới đây là một số mẫu email xin việc ấn tượng mà bạn có thể tham khảo và tùy chỉnh để phù hợp với vị trí và công ty mà bạn đang ứng tuyển:

Mẫu 1: Email xin việc cho vị trí Marketing Specialist

Tiêu đề email: Ứng tuyển vị trí Marketing Specialist – [Họ tên]

Nội dung email:

Kính gửi Anh/Chị [Tên Nhà Tuyển Dụng] và Phòng Nhân Sự Công ty [Tên Công Ty],

Tôi tên là [Họ tên], và tôi rất hào hứng được ứng tuyển vào vị trí Marketing Specialist tại [Tên Công Ty] mà Quý công ty đã đăng tuyển trên [nơi đăng tin tuyển dụng] ngày [ngày tháng]. Với kinh nghiệm [X năm] trong lĩnh vực marketing, đặc biệt là trong việc phát triển chiến lược marketing kỹ thuật số và quản lý các chiến dịch quảng cáo, tôi tin rằng mình có thể đóng góp tích cực cho đội ngũ Marketing của công ty.

Trong vai trò trước đây tại [Tên Công Ty Trước], tôi đã [tóm tắt một số thành tích nổi bật, ví dụ: “tăng 25% lượng khách hàng tiềm năng thông qua các chiến dịch email marketing và tối ưu hóa nội dung trên các kênh truyền thông xã hội”]. Tôi tin rằng với kỹ năng phân tích dữ liệu mạnh mẽ và khả năng sáng tạo trong việc triển khai các chiến dịch tiếp thị, tôi sẽ giúp [Tên Công Ty] đạt được mục tiêu kinh doanh trong thời gian tới.

Tôi đã đính kèm CV của mình trong email này và rất mong có cơ hội trao đổi trực tiếp để chia sẻ thêm về kinh nghiệm và những giá trị mà tôi có thể mang lại cho [Tên Công Ty].

Chân thành cảm ơn Anh/Chị đã dành thời gian xem xét hồ sơ của tôi. Tôi rất mong nhận được phản hồi từ Anh/Chị.

Trân trọng,

[Chữ ký mail]


Mẫu 2: Email xin việc cho vị trí Nhân viên Kinh Doanh

Tiêu đề email: Ứng tuyển vị trí Nhân viên Kinh Doanh – [Họ tên]

Nội dung email:

Kính gửi Anh/Chị [Tên Nhà Tuyển Dụng],

Tôi tên là [Họ tên], và tôi rất mong muốn được ứng tuyển vào vị trí Nhân viên Kinh Doanh tại [Tên Công Ty] mà Quý công ty đã đăng tuyển. Với hơn [X năm] kinh nghiệm làm việc trong lĩnh vực bán hàng và phát triển kinh doanh, tôi tự tin rằng mình có thể đóng góp tích cực vào việc mở rộng thị trường và nâng cao doanh số của công ty.

Trong quá trình làm việc tại [Tên Công Ty Trước], tôi đã thành công trong việc [tóm tắt một số thành tích đáng chú ý, ví dụ: “tăng 30% doanh số bán hàng trong khu vực miền Trung trong năm vừa qua nhờ vào việc phát triển mối quan hệ với các khách hàng chiến lược và mở rộng mạng lưới phân phối”]. Tôi cũng có kỹ năng đàm phán và thuyết phục tốt, giúp tôi đạt được các mục tiêu bán hàng một cách hiệu quả.

Tôi tin rằng với những kinh nghiệm và kỹ năng đã tích lũy, tôi sẽ là một thành viên hữu ích trong đội ngũ Kinh doanh của [Tên Công Ty]. Tôi rất mong có cơ hội trao đổi thêm về vị trí này cũng như đóng góp vào sự phát triển của công ty.

Tôi đã đính kèm CV chi tiết của mình trong email này. Rất mong nhận được phản hồi từ Anh/Chị.

Trân trọng,

[Chữ ký mail]


Mẫu 3: Email xin việc cho vị trí Lập trình viên

Tiêu đề email: Ứng tuyển vị trí Lập trình viên – [Họ tên]

Nội dung email:

Kính gửi Anh/Chị [Tên Nhà Tuyển Dụng] và Bộ phận Tuyển Dụng Công ty [Tên Công Ty],

Tôi tên là [Họ tên], và tôi viết email này để bày tỏ nguyện vọng được ứng tuyển vào vị trí Lập trình viên tại [Tên Công Ty]. Tôi đã tốt nghiệp ngành [Tên Ngành] tại [Tên Trường] và có [X năm] kinh nghiệm làm việc với các ngôn ngữ lập trình như [liệt kê các ngôn ngữ lập trình bạn thành thạo].

Trong quá trình làm việc tại [Tên Công Ty Trước], tôi đã tham gia phát triển nhiều dự án phần mềm, trong đó có [tên dự án hoặc sản phẩm nổi bật]. Tôi đã có cơ hội áp dụng các kỹ năng của mình vào việc [tóm tắt công việc đã làm, ví dụ: “phát triển các tính năng mới cho ứng dụng quản lý dự án, giúp cải thiện hiệu suất làm việc của người dùng lên 20%”]. Tôi luôn hướng đến việc tạo ra những sản phẩm chất lượng cao, đáp ứng tốt nhu cầu của khách hàng.

Tôi tin rằng với niềm đam mê công nghệ và khả năng học hỏi nhanh, tôi sẽ đóng góp hiệu quả cho đội ngũ phát triển phần mềm của [Tên Công Ty]. Tôi rất mong có cơ hội được gặp gỡ và trao đổi thêm về vị trí này.

CV của tôi đã được đính kèm trong email này. Rất mong nhận được sự phản hồi từ Anh/Chị.

Trân trọng,

[Chữ ký mail]


Hy vọng những mẫu email này sẽ giúp bạn tạo ấn tượng tốt với nhà tuyển dụng và tăng cơ hội thành công khi ứng tuyển.

Lời kết

Hồ sơ xin việc là một phần không thể thiếu để khi bạn muốn ứng tuyển một vị trí công việc nào. Mỗi yếu tố trong hồ sơ đều có những vai trò khác nhau. Hãy chuẩn bị cho bản thân một hồ sơ xin việc. Đồng thời, hoàn thiện nó để bạn có đủ tự tin gửi nó đến với nhà tuyển dụng. TopDev mến chúc các bạn sẽ thành công trong việc chinh phục nhà tuyển dụng nhé!

Xem thêm việc làm cho lập trình it hàng đầu tại TopDev

Message Brokers là gì? Mesage Brokers trong design system

message brokers
Message Brokers là gì?. Mesage Brokers trong design system

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

Tiếp theo chuỗi về System Design và System Architecture, bài viết này giới thiệu với anh em về khái niệm Message Brokers. Khái niệm này cũng nằm trong nhóm bài viết về Large Scale Systems Architectural Building Blocks.

Tuần trước hay trước nữa gì đó là bài viết về API Gateway – Cần biết khi thiết kế hệ thống, anh em có nhu cầu cứ feel free ghé đọc nha.

Ok, bắt đầu thôi nào!

  Digital Messaging - Giải Pháp Quản Lý Toàn Diện Dữ Liệu Người Dùng
  Discord đã lưu trữ hàng tỉ messages mỗi ngày như thế nào

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

1. Message Brokers là gì?

Applications ngày nay càng ngày càng lớn, càng ngày càng phức tạp. Thời gian và cách thức để giao tiếp giữa các Services lớn đã trở thành một bài toán lớn. Rất may ta đã có một solutions khá tốt tên Message Brokers.

Luôn bắt đầu với khái niệm loằng ngoằng lèo nghèo

message broker is a piece of software, which enables services and applications to communicate with each other using messages. The message structure is formally defined and independent from the services that send them.

Message broker là một phần của phần mềm, cho phép services và applicaiton giao tiếp với nhau thông qua messages. Cấu trúc message thông thường được định nghĩa sẵn và nó động lập hoàn toàn khỏi services gửi nó.

Thêm nữa

This allows applications to share information with one another, even if they’re written in different programming languages!

Message Brokers còn cho phép ứng dụng chia sẻ thông tin với một cái khác, kể cả là 2 con services viết trên 2 ngôn ngữ lập trình khác nhau!

Rồi kèm thêm quả 3 khái niệm chất chơi ProducerConsumer và Queue/topic nữa. Loạn hết đầu, khó hiểu nhân đôi.

May thay ở Kieblog luôn có ví dụ cụ thể tận tình cho anh em.

Thật sự phân vân – LOL

2. Message Brokers Motivation

Trước khi bắt đầu với Message Brokers thì ta điểm xuyết qua tí về Load Balancer. Anh em nào chưa biết về Load Balancer có thể tham khảo bài này.

Rồi, bắt đầu với ví dụ, đầu tiên là

2.1 Synchronous Communication

Synchoronous là đồng bộ. Synchronous Communication nghĩa là giao tiếp đồng bộ. Sender và Receiver sẽ giao tiếp với nhau thông qua Direct Communication (kết nối trực tiếp).

Message Brokers

Ngoài kết nối trực tiếp (Direct Communication), cũng có thể thông qua Load Balancer như hình dưới

Message Brokers

Giao tiếp kiểu này thường yêu cầu cả Sender và Receiver đều phải work (healthy). Trường hợp một trong hai ngủm thì tính là ngủm.

Message Brokers

2.2 Drawbacks

Trường hợp giao tiếp trực tiếp (Direct Communication), sẽ có yêu cầu cho cả 2 services

Both application instances have to remain healthy and maintain this connection to complete transaction

Cả hai application đều phải đảm bảo ổn và duy trì connection để có thể hoàn thành một transaction.

Cũng không có vấn đề gì phát sinh để ta phải dùng Message Brokers nếu cả hai services đều nhỏ, ít xử lí và cho thời gian phản hồi nhanh.

Nhưng đời không như là mơ, trường hợp receiver services xử lí cồng kềnh và tốn nhiều thời gian thì sao?

Nói là làm, ví dụ ngay và luôn cho anh em. Giả sử ta đang build một hệ thống xử lí vé (ticket), đã là vé thì có mua bán, có thanh toán online, có xử lí đặt chỗ.

Message Brokers

Fullfilment Services sẽ thực thi nhiều actions, kiểm tra thẻ, thanh toán và gửi email thông báo thành công cho user. Nếu cả 3 thứ này đều tốn thời gian?

Message Brokers

Bài toán đặt ra lúc này là user cần có response nhanh nhất?. Không thể chờ tới khi tất cả các services hoàn thành (giảm performance). Chính lúc này là lúc Message Brokers ra tay.

À tí quên, chưa kể là trường hợp có nhiều user truy cập cùng lúc và Services xử lí lần lượt từng request.

2.3 Message Brokers là gì?

Lý thuyết, không thể không đọc.

A software architectural building block that uses the queue data structure to store messages between sender and receiver

Kiến trúc phần mềm theo các khối sử dụng queue để lưu trữ message giữa người gửi là người nhận là Message Brokers

Tới đây đã rõ, Brokers có nghĩa là môi giới và siêu đúng trong trường hợp này. Đứng giữa sender và receicer để nhận messages, đem nó vào queue. Ngon

Đứng giữa hai thằng là ông Brokers, sender lúc này gửi request tới ông trung gian và có ngay kết quả. Đôi khi là ngay lập tức. Đặt hàng phát là có thông báo đặt hàng thành công luôn. Quá đã.

Sau khi đã done và Broker trả về cho Sender, lúc này Message Brokers mới giao tiếp thật sự với Receiver. Đi thực hiện nốt cho xong các công việc.

Với kiến trúc này, ta cũng có thể chia nhỏ các services với nhiều brokers

Tới đây là anh em hiểu hết rồi đúng không?. Giờ chuyển qua phần hấp dẫn không kém. Benefits

3. Message Brokers Benefits

Chính vì cơ chế đứng trung gian giữa Sender và Receiver nên:

Most message brokers implemetation offer the publish/subscrible pattern

Hầu hết các message brokers đều implement dựa trên publish/subscrible pattern.

  • Publish messages to a particular channel (gửi tin nhắn tới một kênh cụ thể)
  • Subscrible to that channel (đăng kí một kênh)
  • Get notified when a new event is published (nhận thông báo khi có event mới được publish)

4. Message Capabalities

Về những thứ Message Brokers có thể làm, hoặc gọi chung là benefit đi. Bao gồm một số điểm sau:

  • Storing/temporarily buffering the messages
  • Message routing
  • Transformation validation

Với message brokers, ta cũng có thể đăng kí với các services khác, thông báo tới end user khi một event nào đó đã hoàn thành.

4.1 Fault Tolerance

Khả năng chịu lỗi là điểm đáng ghờm mà Mesage Brokers đem lại.

It allows different services to communicate with each other white some of them maybe unavailable temporarily

Nó cho phép các services khác nhau giao tiếp với nhau trong khi một trong số chúng đã ngủm củ tỏi

Thua, vậy lại chả tăng tính chịu lỗi, hàng không có nhưng anh brokers môi giới đã cho đặt luôn rồi.

4.2 Availability và Scalabality

Tính sẵn sàng (availability) và tính mở rộng (scalabality) cũng là 2 điểm mà Mesage Brokers đem tới. Trường hợp có rất nhiều traffic, thanh niên môi giới này có thể trả về kết quả nhanh chóng, sau đó đi xử lí từ từ.

We pay a little in performance when it comes to latency

Tăng performance và giảm độ trễ của hệ thống

Tới đây mong anh em đã hiểu rõ về Message Brokers. Một số bài viết hay để ở tham khảo nha.

5. Tham khảo

My pleasure when you spend a time to read my post – Wish all the best for you and your family – Happy Coding!

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

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

Xem thêm các công việc ngành CNTT hấp dẫn trên TopDev

Rust và Lập trình Web

rust
Rust và Lập trình Web

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

“Rust có làm được Web không nhỉ?” – Đây là câu hỏi của rất nhiều người, trong đó có mình.

Một trong những mục tiêu được đặt ra khi mình bắt đầu học Rust đó chính là sử dụng Rust để làm web apps.

Và sau gần 1 năm thì mình cũng học được vài thứ. Vì thế mình viết bài này để chia sẽ lại kinh nghiệm Làm web với Rust của mình.

Xem thêm các việc làm Web developer jobs hấp dẫn trên TopDev

Có rất nhiều phương pháp để làm web dùng Rust, ví dụ như là, compile Rust code ra thành client-side JavaScript code dùng WebAssembly, viết RESTful API, hoặc xây dựng ứng dụng web được render từ phía server, giống như những năm 2012 vậy :v

Chúng ta sẽ đi vào từng phương pháp một.

1. Client-side JavaScript trong Rust

Cách đầu tiên, hoàn toàn là frontend, mà mình nghiên cứu đó là dùng Rust để viết web theo dạng component-based như là React vậy. Điều này có nghĩa là chúng ta phải tìm ra cách nào đó để chạy Rust ngay trên trình duyệt.

Và tất nhiên không phải tìm lâu, chúng ta có thể dễ dàng biên dịch code Rust ra thành JavaScript để chạy trên trình duyệt, nhờ vào các dự án như ASM.js và WebAssembly.

Rồi, giờ quay lại vụ component-based. Mình có viết một macro đơn giản để wrap các API của crate stdweb, và render các HTML elements thông qua DOM API của trình duyệt:

https://github.com/huytd/rust-webapp-template/blob/master/src/main.rs#L13-L58

Nếu mà nhìn vào đoạn code trên bạn cảm thấy mông lung không hiểu gì, thì thôi cũng đừng hoảng. Cú pháp macro của Rust vốn không được đẹp cho lắm. Mà thực ra giờ mình đọc lại cũng không hiểu mình đang viết gì nữa, tự thấy nể bản thân mình ghê gớm =)))

Chi tiết về đoạn macro trên, component! làm nhiệm vụ định nghĩa ra một HTML element mới, mount_component! làm nhiệm vụ chèn (append) cái element đó vào document, và html! làm nhiệm vụ tạo ra một element từ một chuỗi HTML bất kỳ.

Cách dùng như sau:

component!(AppComponent => {
    init: {
        let e: Element = html!("
        <div>
            <p>
                <span>Hello</span>
                <span>World</span>
            </p>
            <GreenButton />
        </div>
        ");

        let mut button = GreenButton::new();
        mount_component!(e, "GreenButton", button);

        e
    },
    render: |this: &Element| {
    }
});

component!(GreenButton => {
    init: {
        let button = document().create_element("button");
        button.add_event_listener(move |_: ClickEvent| {
            js! {
                alert("Yo! This is the Green Button!");
            }
        });
        button
    },
    render: |this: &Element| {
        this.set_text_content("This is a button");
    }
});

fn main() {
    stdweb::initialize();

    let mut app = AppComponent::new();
    mount_component!(document(), "#root", app);

    stdweb::event_loop();
}

Đấy, như thế thì ai cần xài React làm gì nữa nào? =))) (đùa tí thôi)

Các bạn có thể tham khảo mã nguồn đầy đủ để xem cách sử dụng stdweb với các macro trên để minh họa cho phương pháp biên dịch Rust sang JavaScript.

2. Dùng Rust viết RESTful API

Phương pháp thứ 2 tập trung vào backend. Đó là dùng Rust để viết một API server và kết nối nó với frontend có sẵn của bạn.

Hiện tại có một lượng kha khá framework để bạn chọn, có thể tham khảo tại AreWeWebYet.

Với những ai thích xài các framework nhỏ gọn tiny_http là sự lựa chọn hoàn hảo.

Xét về mặt đơn giản, dễ dùng thì nickel.rs, là một trong những framework tinh gọn nhất trong Rust, và lấy cảm hứng từ Express framework bên Node.js

Nếu bạn muốn hỗ trợ HTTP/2, thì solicit là sự lựa chọn duy nhất tính tới thời điểm này.

Cá nhân mình thích xài rocket.rs vì nó là một framework rất mạnh và có rất nhiều tính năng, nhưng vẫn giữ cho code của bạn đơn giản tới mức tối đa. Gần đây thì rocket.rs đã hỗ trợ luôn TLS built-in. Điểm trừ duy nhất của framework này đó là cần sử dụng phiên bản Rust Nightly.

Đây là đoạn code ví dụ việc handle một endpoint dùng GET method với rocket.rs:

[get("/posts", format = "application/json")]
fn get_posts(page: i64) -> Json<Value> {
    Json(json!({
        "result": []
    }))
}

Bên cạnh việc serve API, mình thường dùng rocket.rs để serve static files luôn, giống như khi xài Express:

#[get("/")]
fn index() -> io::Result<NamedFile> {
    NamedFile::open("www/index.html")
}

#[get("/<file..>", rank = 5)]
fn files(file: PathBuf) -> Option<NamedFile> {
    NamedFile::open(Path::new("www/").join(file)).ok()
}

Từ đây thì mình có thể đưa hết toàn bộ code frontend vào một thư mục, ví dụ như là www, và gọi tới RESTful API từ Rust. Để rõ hơn thì đây là ví dụ minh họa về cấu trúc của mộ project mà mình thường làm:

├── Cargo.toml
├── README.md
├── src
│   ├── main.rs
│   └── ...Rust code here...
└── www
    ├── index.html
    ├── main.js
    ├── package.json
    ├── webpack.config.js
    └── ...JavaScript code here...

Để kết nối với database, chúng ta có thể sử dụng các ORM như Diesel.

Nếu bạn muốn tham khảo ví dụ thực tế về 1 project sử dụng rocket.rs + Diesel (cho backend) và React (cho frontend), thì đây là mã nguồn của Kipalog Links – website đọc/tổng hợp tin bài từ các blogger công nghệ tiếng Việt mình làm cho Kipalog.

Gửi mail cho mình link RSS blog của bạn nếu bạn muốn bài viết của mình được list trên Kipalog Links 😛

  Dynamic typing trong Rust với std::any::Any
  Tại sao team Discord chuyển từ Go sang Rust?

3. Server-side rendering với Rust

Phương pháp cuối cùng, là phương pháp mình thích nhất, giống với thời kì nằm 2012, khi mình mới bắt đầu sự nghiệp lập trình với một chân code thuê PHP. :))

Không còn những khái niệm Single Page Application, client-side rendering. Không còn những trang web bể tè le hột me khi người dùng disable JavaScript nữa.

Fun fact: Hầu hết các website lớn đều hoạt động ngay cả khi bạn tắt JavaScript của trình duyệt

Cũng như nhiều framework đến từ các ngôn ngữ khác (như Rails, CakePHP, ASP.NET…), rocket.rs hỗ trợ bạn render một HTML template sau khi đã bind dữ liệu vào đó từ phía server, trình duyệt chỉ cần nhận về và hiển thị lên màn hình.

#[get("/")]
fn index() -> Template {
    let news = fetch_from(RSS_URL).ok().expect("Could not read RSS");
    Template::render("index", &news)
}

Ở bài viết trước, mình hướng dẫn cách build một ứng dụng đọc tin Hacker News dùng rocket.rs và Handlebars template, chính là áp dụng phương pháp này.

Các bạn có thể tham khảo mã nguồn đầy đủ của project để nắm rõ hơn. Phiên bản code trong mã nguồn này có áp dụng một vài kĩ thuật mới chưa được đề cập trong bài trước để giải quyết vấn đề load nội dung qua giao thức HTTPS.


Vậy là chúng ta đã điểm qua hết các phương pháp sử dụng Rust vào cho một project Web. Mỗi một phương pháp trên đều có những ưu nhược điểm khác nhau, có thể sử dụng tùy theo từng yêu cầu khác nhau của mỗi dự án, và bạn cũng hoàn toàn có thể kết hợp các phương pháp này lại với nhau trong cùng một dự án.

Hy vọng qua bài viết này, các bạn có được cái nhìn toàn cảnh về việc lập trình Web với Rust, và có được câu trả lời của riêng mình cho câu hỏi: “Rust có làm được Web không?”.

Và chúc các bạn may mắn nếu quyết định sử dụng Rust vào cho project của mình.

Bài viết được dịch lại từ bản gốc “Rust for the Web” đăng tại phiên bản blog tiếng Anh của mình.

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

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

Xem thêm các công việc ngành CNTT hấp dẫn trên TopDev

Algorithm in Frontend – Kỳ 1: Xử lý dữ liệu trên Frontend

algorithm in frontend
Algorithm in Frontend - Kỳ 1: Xử lý dữ liệu trên Frontend

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

Đối với lĩnh vực Frontend nói riêng, chuyện học hay luyện các kĩ năng phân tích thiết kế thuật toán là một kĩ năng bị xem nhẹ nhất. Vì lý do đơn giản, chúng ta không thấy nhiều về tính ứng dụng của nó vào công việc thực tế.

Nhưng đây là sai lầm lớn nhất của đại đa số Frontend Developers.

Trên thực tế, chúng ta phải đối mặt với các vấn đề cần phải sử dụng thuật toán, và cần phải vận dụng các kĩ năng phân tích thiết kế thuật toán gần như là hằng ngày. Nhưng rất ít khi chúng ta nhận ra.

Đây cũng là lý do mà mình viết sê-ri Algorithm in Frontend này, xoay quanh những kinh nghiệm thực tế mà mình đã gặp phải trong thời gian làm việc, phần lớn là trong hai lĩnh vực sản phẩm mình đã/đang làm là Realtime Infrastructure Monitoring (theo dõi hạ tầng CNTT thời gian thực) và Health Care (chăm sóc sức khỏe).

  10 Kỹ năng quan trọng cần có của Front-end để tìm công việc dễ dàng hơn
  20 công cụ và tài liệu hay ho dành cho Front-end

Xem thêm các chương trình tuyển dụng Front End trên TopDev

Bài đầu tiên nói về vấn đề Xử lý dữ liệu trên Frontend.

1. Đặt vấn đề

Nếu các bạn có đọc bài phỏng vấn của mình trên blog Tôi Đi Code Dạo, thì có lẽ các bạn đã biết, công việc chính của mình hiện nay ngoài việc fix bug  ra thì còn phải phối hợp với các team khác nhau để tạo ra bug mới xây dựng feature mới cho sản phẩm của công ty.

Một trong những chức năng mới nhất mà team mình vừa ship thành công đó là cung cấp khả năng thống kê tình trạng sức khỏe của bệnh nhân cho các bác sĩ.

Dạng đơn giản nhất của chức năng này, thì các bạn có thể hình dung thông qua hình minh họa sau (lấy từ bảng thống kê của Fitbit, không phải sản phẩm công ty mình, NDA đã ký, up bậy lên là thành homeless ngay, cũng xin các bạn đừng phán xét về mức độ siêng năng đi bộ của mình :v).

Đây là tính năng thống kê dữ liệu theo từng khoản n ngày tính từ ngày hiện tại (ở đây n=7). Lưu ý là không phải thống kê theo tuần nhé.

Như vậy, nếu hôm nay là thứ 5 bác sĩ muốn xem tình trạng sức khỏe trong 7 ngày gần đây của bênh nhân thì phía Frontend phải hiển thị được dữ liệu trong khung thời gian như hình sau:

…,T5,T6,T7,CN,T2,T3,T4,T5⏟today⏞n=7,T6,T7,…

Từ phía frontend, một request có dạng như sau sẽ được gửi lên để lấy dữ liệu:

GET /api/v0/tracker?from=14-09-2017&to=08-09-2017

Bất kỳ ngày nào có dữ liệu thì sẽ được gửi trả về, không có dữ liệu thì không xuất hiện luôn:

Date Steps
Fri 08-09-2017 5123
Mon 11-09-2017 1734
Tue 12-10-2017 5000
Wed 13-10-2017 4985
Thu 14-10-2017 3220

Và để vẽ được biểu đồ lên màn hình theo đúng n ngày thì nội dung đầu vào phải đúng n records. Thiếu hay thừa 1 record đều sẽ dẫn đến kết quả hiển thị bị sai.

Phía frontend phải làm công việc xử lý dữ liệu để với mỗi record bị thiếu, chèn vào một record mới với một giá trị mặc định, đảm bảo tính đúng đắn này.

Ví dụ với bảng dữ liệu trên, sẽ phải chèn thêm 2 record mới là:

Date Steps
Sat 09-09-2017 0
Sun 10-09-2017 0

2. Bài toán cần giải quyết

Để dễ hình dung hơn, ta có thể đơn giản hóa bài toán cần giải quyết cho vấn đề trên là:

Cho một mảng I gồm m phần tử (m>0), với mỗi phần tử là một ngày trong tuần, không liên tục, và một số n (với m⩽n), implement thuật toán trả về mảng O gồm n ngày liên tục, tính từ phần tử đầu tiên của I, và vẫn giữ được thứ tự xuất hiện trong mảng.

Ví dụ:

Input [I;n] Output [O]
[Mon; 7] [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
[Mon; 10] [Mon, Tue, Wed, Thu, Fri, Sat, Sun, Mon, Tue, Wed]
[Fri, Sun; 5] [Fri, Sat, Sun, Mon, Tue]
[Mon, Thu, Sat; 5] [Mon, Tue, Wed, Thu, Fri]

3. Phân tích và implement thuật toán

Có thể thấy đây là một bài toán hết sức đơn giản, việc cần làm chỉ là tạo ra một mảng n phần tử và lần lượt đưa vào mảng này các ngày tương ứng, tính từ ngày đầu tiên trong mảng I. Nếu một phần tử đã tồn tại ở mảng I thì chúng ta sẽ đưa phần tử đó vào mảng kết quả.

Ta cũng chú ý đến tính chất xoay vòng của các ngày trong tuần, nếu cho i là một giá trị tăng dần, với i=0 là thứ hai (Monday), i=1 là thứ ba (Tuesday), tiếp tục tăng, đến i=6 sẽ là Chủ nhật (Sunday). Tương đương với một mảng có 7 phần tử, như sau:

const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];

Ta có thể viết một hàm day_to_num() để chuyển đổi giữa giá trị ngày sang số để tiện cho việc tính toán:

const day_to_num = day => DAYS.findIndex(i => i === day);

Nếu i tiếp tục tăng, thì với việc đối chiếu thông thường, i=7 tương ứng với DAYS[7], là một giá trị không tồn tại. Để i tiếp tục tăng nhưng giá trị tham chiếu phải xoay vòng, ta có thể thay i bằng một giá trị i2 với:

i2=imod7

Ví dụ, với i=12 ta có i2=12mod7=5 tương đương với DAYS[5]=Sat.

Dựa vào đây ta có thể viết hàm num_to_day() để chuyển một giá trị số thành ngày tương ứng:

const num_to_day = num => DAYS[num % DAYS.length];

Thuật toán xử lý dữ liệu của chúng ta có thể được mô tả thông qua các bước như sau:

  • Bước 1: Tạo ra mảng result có n phần tử, với phần tử đầu tiên cũng là giá trị đầu của mảng I.
  • Bước 2: Tạo một vòng lặp với i=1→n.
    • Bước 2a: Ở mỗi lần lặp, tìm ngày tiếp theo tương ứng với vị trí i.
    • Bước 2b: Duyệt qua mảng I để tìm giá trị tương đương với giá trị vừa tính được ở bước 2a.
    • Bước 2c: Nếu tìm được giá trị ở bước 2b thì đưa giá trị này vào mảng result, nếu không thì đưa giá trị ở bước 2a vào.
  • Bước 3: Trả về kết quả của mảng result.

Implement thuật toán trên bằng JavaScript:

const fill_days = (input, n) => {
  let result = [input[0]];
  for (let i = 1; i < n; i++) {
    let previous_day = day_to_num(result[i - 1]);
    let current_day = num_to_day(previous_day + 1);
    let day_from_input = null;
    for (let j = 0; j < input.length; j++) {
      if (current_day == input[j]) {
        day_from_input  = input[j];
        break;
      }
    }
    if (day_from_input) {
      result.push(day_from_input);
    } else {
      result.push(current_day);
    }
  }
  return result;
};

Đừng quên test lại để đảm bảo thuật toán của chúng ta chạy đúng:

fill_days(["Mon"], 7); // [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
fill_days(["Mon"], 10); // [Mon, Tue, Wed, Thu, Fri, Sat, Sun, Mon, Tue, Wed]
fill_days(["Fri", "Sun"], 5); // [Fri, Sat, Sun, Mon, Tue]
fill_days(["Mon", "Thu", "Sat"], 5); // [Mon, Tue, Wed, Thu, Fri]

4. Cải thiện thuật toán

Vậy là hàm fill_days() của chúng ta đã hoạt động và trả về đúng giá trị cần tìm, tuy nhiên chúng ta không thể dừng ở bước này được vì thuật toán trên vẫn còn rất nhiều điểm cần phải cải thiện.

Cụ thể, chúng ta sẽ thực hiện các thay đổi như là cache lại những chỗ tính toán bị lặp đi lặp lại, tận dụng lại biến current_day để bỏ bớt một khối lệnh if không cần thiết,…

Hàm day_to_num() cũng có thể được tối ưu bằng cách không dùng hàm findIndex() có sẵn nữa mà tự viết vòng lặp for riêng.

const day_to_num = day => {
  for (let i = 0, len = DAYS.length; i < len; i++) {
    if (DAYS[i] == day) return i;
  }
  return -1;
};

const fill_days = (input, n) => {
  let result = [input[0]];
  for (let i = 1; i < n; i++) {
    let previous_day = day_to_num(result[i - 1]);
    let current_day = num_to_day(previous_day + 1);
    for (let j = 0, len = input.length; j < len; j++) {
      if (current_day == input[j]) {
        current_day = input[j];
        break;
      }
    }
    result.push(current_day);
  }
  return result;
};

Chúng ta có thể chạy test lại, kết quả vẫn chính xác.

fill_days(["Mon"], 7); // [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
fill_days(["Mon"], 10); // [Mon, Tue, Wed, Thu, Fri, Sat, Sun, Mon, Tue, Wed]
fill_days(["Fri", "Sun"], 5); // [Fri, Sat, Sun, Mon, Tue]
fill_days(["Mon", "Thu", "Sat"], 5); // [Mon, Tue, Wed, Thu, Fri]

Các bạn cũng có thể so sánh thử performance của 2 thuật toán trước và sau khi tối ưu tại đây.

5. Ứng dụng thuật toán vào thực tế

Vậy là chúng ta đã xây dựng thành công thuật toán xử lý lấp đầy dữ liệu cho trước bằng những ngày bị thiếu và vẫn đảm bảo được số lượng record, và thứ tự xuất hiện của các record.

Việc tiếp theo là ứng dụng thuật toán này vào với dữ liệu thực tế.

Quay lại với API request ở đầu bài:

GET /api/v0/tracker?from=14-09-2017&to=08-09-2017

Dữ liệu trả về sẽ có dạng:

let input = [
  {
    date: '2017-09-08T00:00:00.000Z',
    steps: 5123,
  },
  {
    date: '2017-09-11T00:00:00.000Z',
    steps: 1734,
  },
  {
    date: '2017-09-12T00:00:00.000Z',
    steps: 5000,
  },
  {
    date: '2017-09-13T00:00:00.000Z',
    steps: 4985,
  },
  {
    date: '2017-09-14T00:00:00.000Z',
    steps: 3220,
  }
]

Mỗi một record ở đây là một Object có dạng như sau, không đơn thuần là một chuỗi nữa.

{
  date: '<date>',
  steps: '<step>'
}

Vì vậy chúng ta phải sửa phần code logic ở thuật toán bên trên một tí để có thể làm việc được với kiểu dữ liệu thực tế:

const fill_days_with_data = (input, n) => {
  let result = [input[0]];
  for (let i = 1; i < n; i++) {
    let next_day = new Date(result[i - 1].date);
    next_day.setDate(next_day.getDate() + 1);
    let next_date = {
      date: next_day,
      steps: 0
    };
    for (let j = 0, len = input.length; j < len; j++) {
      let date = new Date(input[j].date);
      if (next_day.getDay() == date.getDay()) {
        next_date = input[j];
        break;
      }
    }
    result.push(next_date);
  }
  return result;
};

Và đây là kết quả sau khi test:

fill_days_with_data(input, 7);

[
  {
    date: '2017-09-08T00:00:00.000Z',
    steps: 5123
  },
  {
    date: '2017-09-09T00:00:00.000Z',
    steps: 0
  },
  {
    date: '2017-09-10T00:00:00.000Z',
    steps: 0
  },
  {
    date: '2017-09-11T00:00:00.000Z',
    steps: 1734
  },
  {
    date: '2017-09-12T00:00:00.000Z',
    steps: 5000
  },
  {
    date: '2017-09-13T00:00:00.000Z',
    steps: 4985
  },
  {
    date: '2017-09-14T00:00:00.000Z',
    steps: 3220
  }
]

Hoàn toàn đúng với yêu cầu đặt ra từ ban đầu.


Qua bài viết này, chúng ta đã cùng đi qua các bước: Tiếp cận vấn đề thực tế, phân tích bài toán, xây dựng thuật toán, cải thiện thuật toán để chạy tốt hơn, và cuối cùng là ứng dụng thuật toán đó để giải quyết các yêu cầu kĩ thuật từ phía frontend.

Mình biết cảm giác bây giờ của các bạn là gì, các bạn đang nghĩ là cái quần què này thì có gì đâu, đây vẫn là thứ mà các bạn vẫn làm mỗi ngày mà. Đúng là như vậy, chúng ta đã và đang áp dụng thuật toán vào cho công việc frontend mỗi ngày.

Có thể thấy, việc áp dụng, xây dựng, sử dụng thuật toán là một vấn đề chung không chỉ giới hạn trong bất kì một lĩnh vực nào của lập trình. Hy vọng bài viết này có thể giúp bạn nhận ra tầm quan trọng của thuật toán, nhất là đối với các bạn frontend developers.

Cảm ơn các bạn đã kiên nhẫn đọc đến tận đây. Hẹn gặp lại các bạn ở các phần sau của sê-ri Algorithm in Frontend.

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

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

Tìm việc IT lương cao, đãi ngộ tốt trên TopDev ngay!

Viết Đơn Xin Việc Như Thế Nào Để Gây Ấn Tượng Với Nhà Tuyển Dụng?

đơn xin việc
Viết Đơn Xin Việc Như Thế Nào Để Gây Ấn Tượng Với Nhà Tuyển Dụng?

Ngày nay việc gửi CV xin việc qua email đã trở nên quá quen thuộc, nhưng chỉ một bộ CV với thông tin cá nhân cũng như kinh nghiệm làm việc ấn tượng, bạn nghĩ đã đủ để gây ấn tượng với nhà tuyển dụng? Thực tế thì khi gửi đơn xin việc qua email, điều quan trọng và đầu tiên được các nhà tuyển dụng xem qua chính là nội dung đơn xin việc của ứng viên. Vậy nên viết đơn xin việc – cover letter như thế nào để vừa ngắn gọn lại vừa gây ấn tượng tốt trong mắt nhà tuyển dụng?

đơn xin việc
Viết Đơn Xin Việc Như Thế Nào Để Gây Ấn Tượng Với Nhà Tuyển Dụng?

1. Tiêu đề thư – Subject

Tiêu đề chính là một trong những yếu tố khá quan trọng để nhà tuyển dụng quyết định có nên xem thư xin việc của ứng viên hay không. Vậy nhưng có không ít ứng viên hiện nay lại chưa chú tâm đến việc viết email có tiêu đề thư cung cấp được thông tin chính xác. Thậm chí có không ít ứng viên còn gửi mail mà không hề có tiêu đề. Đây là một sai lầm chắc chắn không nên lặp lại.

Thông thường tiêu đề thư sẽ là tóm tắt nội dung mà bạn muốn đề cập đến trong email. Theo đó, với nội dung của đơn xin việc, ứng viên nên đặt tiêu đề gồm Họ & tên – Vị trí ứng tuyển. Tùy theo một số công ty, có thể trong JD công việc có yêu cầu chi tiết về việc ứng viên nên đặt tiêu đề thư như thế nào cùng với mã số vị trí công việc.

2. Lời chào đầu thư

Trước khi bắt đầu đề cập đến nội dung chính của đơn xin việc, lời chào đầu tư cần được nhắc đến trước tiên. Việc viết lời chào đầu thư như thế nào sẽ phụ thuộc vào những thông tin bạn có về vị trí tuyển dụng đó.

Nếu ứng viên đã biết cụ thể mình nên gửi mail cho ai và chắc chắn về thông tin thì nên viết lời chào theo công thức Dear Mr/Ms + tên nhà tuyển dụng,

Trong trường hợp bạn không biết rõ người mình cần nộp đơn xin việc cụ thể là ai thì có thể viết theo cách gọi chung như Dear HR Team, Dear Công ty…, To whom it may concern,… Hãy cân nhắc các thông tin bạn có để có thể đưa ra lời chào đầu thư phù hợp nhất với tình huống của bản thân.

Xem thêm Tổng Hợp Những Câu Hỏi Phỏng Vấn Front End Thường Xuyên Xuất Hiện Trong Các Buổi Phỏng Vấn

3. Cách viết nội dung chính của thư

Trước tiên, ứng viên cần nhớ rằng, đơn xin việc – cover letter chỉ thể hiện thành ý của bạn đang mong muốn ứng tuyển vào vị trí này, còn những vấn đề cụ thể như kinh nghiệm làm việc sẽ được đề cập chi tiết trong CV. Chính vì thế đừng nên viết quá dài dòng sẽ khiến người đọc khó chịu. Nội dung chính của một cover letter chỉ nên kéo dài trong 1 – 2 đoạn cơ bản mà thôi.

Với đoạn đầu tiên, ứng viên nên đề cập đến mong muốn và vị trí bạn đang quyết định ứng tuyển “I’m writing to you with regards to the position within your company for Marketing Executive” – “Tôi viết thư này với mong muốn được ứng tuyển vào vị trí chuyên viên Marketing tại công ty”.

Các nội dung tiếp theo, người viết cover letter nên cố gắng làm rõ những nội dung như Tại sao bạn lại ứng tuyển vào vị trí này? Bạn đã có những kinh nghiệm làm việc nào? Mong muốn của bạn khi muốn làm việc tại công ty?…

Tất cả đều nên được trình bày một cách ngắn gọn, xúc tích mà vẫn đủ ý. Đừng viết quá dài dòng vì nhà tuyển dụng sẽ không có đủ thời gian để đọc hết những gì bạn trình bày. Những nội dung chi tiết có thể được trình bày khi ứng viên đến với buổi phỏng vấn trực tiếp tại công ty.

Có một mẹo nhỏ được nhiều người áp dụng, đó là để có thể viết ngắn nhưng vẫn gây ấn tượng với người đọc thư, ứng viên nên diễn tả kinh nghiệm của mình bằng những con số. Nó vừa dễ nhìn, vừa cho thấy được những con số bạn đã trải qua trong quá trình học tập và làm việc của mình.

4. Cách kết thúc trong đơn xin việc

Trong phần kết thúc, hãy cố gắng nhấn mạnh lại một lần nữa rằng với những kinh nghiệm mà bạn đã có, bạn hoàn toàn có thể làm tốt những nhiệm vụ mà công ty đang đặt ra. Cũng như bày tỏ mong muốn rằng, bạn muốn được thông qua vòng sơ loại hồ sơ để có cơ hội được phỏng vấn và trao đổi thêm với công ty.

Bên cạnh đó, hãy nhớ đề cập với nhà tuyển dụng rằng bạn đã đính kèm thông tin CV hay portfolio cá nhân có thông tin chi tiết về quá trình làm việc của bạn. Và đừng quên dành đến nhà tuyển dụng lời cảm ơn vì đã dành thời gian đọc đơn xin việc của bạn.

Ngoài ra, có một phần cuối ở bức thư mà bạn không nên bỏ qua đó là chữ ký. Để thể hiện sự chuyên nghiệp cũng như nhà tuyển dụng có thêm thông tin liên lạc với bạn khi cần thiết, hãy đề cập đầy đủ về họ tên và thông tin như số điện thoại cá nhân của mình.

Đơn xin việc – cover letter là một trong những thông tin quan trọng bạn không nên bỏ qua khi gửi email ứng tuyển với nhà tuyển dụng. Biết cách viết cover letter chuyên nghiệp chính là bước đầu tiên để bạn có thể ghi điểm với công ty tuyển dụng. Hy vọng bài viết trên đã giúp bạn có thêm thông tin cho hành trình tìm việc của mình.


Tuyển Dụng Nhân Tài IT Cùng TopDev
Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products

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

Xem thêm tuyển dụng việc làm IT hấp dẫn trên TopDev

Một số khái niệm cần biết trong Kubernetes Architecture

kubernetes architecture
Một số khái niệm cần biết trong Kubernetes Architecture

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

Làm việc với các topics thì đã từ lâu nhưng từ nay Kieblog sẽ mở thêm chuyên mục mới viết các bài viết về Devops, bắt đầu với bài viết về Kubernetes Architecture nha anh em.

Cảm ơn anh em đã dành thời gian đọc bài. Do bên mảng Devops tui vẫn là amateur nên có gì sai sót nhờ anh em chỉ giao chó.

Nhầm, chỉ giáo cho.

1. Kubernetes là gì?

Bắt đầu luôn là khái niệm. Riết nó chán nhưng thôi ráng đọc.

Kubernetes architecture components or K8s components include the Kubernetes control plane and the nodes in the cluster. The control plane or master machine components include the Kubernetes API server, Kubernetes scheduler, Kubernetes controller manager, and etcd. Kubernetes node components include a container runtime engine or docker, a Kubelet service, and a Kubernetes proxy service.

Kiến trúc Kubernetes hoặc K8s components bao gồm phần điều khiển của Kubernetes và các nodes ở trong một cluster. Phần điều khiển của Kubernetes bao gồm Kubernetes API Server, Kubernetest scheduler, controller manager và nhiều thứ khác nữa. Trong node components thì bao gồm engine và docker, Kubelet service và Kubernetes proxy service.

Dưới đây là một số khái niệm trong Kubernestes Architecture anh em cần nắm rõ.

Trời má, chưa biết gì mà nhìn cái Architecture muốn nhức cả đầu.

Thôi thì ta đi step by step. Tìm hiểu từng thứ một anh em ạ.

2. Container

Anh em nào đã tìm hiểu hoặc làm việc với Docker chắc không còn xa lạ gì khái niệm về Container. Container không được liệt kê là một thành phần chính trong Kubernetes Architecture. Tuy nhiên bài viết này vẫn nhắc tới vì nếu không hiểu về Container, ta sẽ không thể đi tiếp các Components khác.

  Kubernetes sẽ không còn hỗ trợ Docker?
  Một số khái niệm cần biết trong Kubernetes Architecture

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

Đầu tiên.

Containers are a solution to the problem of how to get software to run reliably when moved from one computing environment to another

Containers là giải pháp giải quyết vấn đề làm sao phần mêm có thể chạy tốt khi thay đổi computing environment từ cái này qua cái kia

Đại thể có thể tưởng tượng Container như cái thùng sau xe container mà ta biết, thảy lên tàu thuỷ cỡ nào cũng chở được, cũng chạy được.

Trong Container bao gồm tất cả mọi thứ mà ta cần để chạy Software hoặc Application.

Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

Docker container image nhẹ, độc lập, bao gồm các gọi thực thi của phần mềm. Trong đó bao gồm tất cả những gì cần thiết để ta khởi chạy application: code, runtime, system tools, system libraries và cả settings (các thiết lập).

Kubernetes ArchitectureDocker Container bao gồm mọi thứ cần thiết để chạy software hoặc applications của chúng ta. Nguồn ảnh/ Source: docker.com

Container là một item nhỏ trong Kubenetes Architecture, tiếp theo đây ta sẽ nói về Pods, thằng bự hơn bao gồm một hoặc nhiều Container trong đó.

3. Pod

Pod là khái niệm quan trọng trong Kubernetes Architecture. Lý thuyết thì luôn lèo nhèo khó hiểu nhưng vẫn phải đọc để hiểu.

Một Pod là một khái niệm trừu tượng của Kubernetes, đại diện cho một nhóm gồm một hoặc nhiều ứng dụng containers (ví dụ như Docker hoặc rkt) và một số tài nguyên được chia sẻ cho các containers đó.

Vậy sau khi đã có Container với Docker thì Pods là thằng lớn hơn (có thể có một hoặc nhiều Container trên pod). Nhưng không chỉ có mỗi Container, trên Pod còn bao gồm nhiều thành phần khác như:

  • Lưu trữ được chia sẻ, dưới dạng Volumes
  • Kết nối mạng, như một cluster IP duy nhất
  • Thông tin về cách chạy từng container, chẳng hạn như phiên bản container image hoặc các ports cụ thể để sử dụng
Kubernetes ArchitectureNgoài container, pod còn bao gồm IP address, và version của container image. Nguồn ảnh/ Source: docker.com

4. Nodes

Sau khi đã hiểu về Pod và những thứ bao gồm trong Pod, tiếp đến ta sẽ tìm hiểu về khái niệm Nodes.

Trong Kubernetes Architecture, Nodes là khái niệm bắt buộc hiểu và nắm thật rõ.

Cluster nodes are machines that run containers and are managed by the master nodes. The Kubelet is the primary and most important controller in Kubernetes

Cluster nodes là máy mà chúng ta sử dụng để chạy containers và quản lý bởi master nodes. Kubelet là thành phần chính và quan trọng trong Kubernetes.

Má, khái niệm loằng ngoằng, nhưng anh em nhớ giúp Nodes là thằng chịu trách nhiệm để điều khiển lớp thực thi (execution layer), là nơi mà ta push cái Docker lên

It’s responsible for driving the container execution layer, typically Docker.

Ngoài ra, nodes có thể la virtual hoặc physical, phụ thuộc và cái cluster.

A Node is a worker machine in Kubernetes and may be either a virtual or a physical machine, depending on the cluster

Node là worker machine (máy ảo hoặc máy thật), cái này phụ thuộc vào cluster.

Kubernetes ArchitectureNguồn Ảnh/ Source: kubernetes.io

Nodes cũng được chia thành 2 loại là master node và worker node. Có điều kiện sẽ viết rõ thêm cho anh em về hai loại này.

5. Cluster

Sau khi đã biết về Nodes thì xin mời anh em đi tiếp tới Cluster, thằng mà bự hơn Nodes. Bài viết này viết về khái niệm từng thành phần trong Kubernetes Architecture nên mình sẽ đi tuần tự từ bé tới lớn.

Kubernetes cluster is a set of nodes that run containerized applications. Containerizing applications packages an app with its dependences and some necessary services. They are more lightweight and flexible than virtual machines. In this way, Kubernetes clusters allow for applications to be more easily developed, moved and managed.

Kubernetes cluster là một tập hợp các nodes để chạy ứng dụng trong vùng chứa. Bao gồm một ứng dụng và các thành phần liên quan. Chúng nhẹ và linh hoạt hơn so với máy ảo. Bằng cách này, các cụm Kubernetes cho phép các ứng dụng được phát triển, di chuyển và quản lý dễ dàng hơn.

Rồi, hiểu Cluster thì bao gồm các Nodes trong đó + một số thành phần liên quan. Có một cái nữa:

Every cluster has at least one worker node.

Mỗi cluster bắt buộc phải có ít nhất một worker node trong đó.

Trong thực tế (production) thì thông thường một cluster sẽ có nhiều nodes. Điều này đảm bảo tính ổn định (availability) và fault-tolerance.

The control plane usually runs across multiple computers and a cluster usually runs multiple nodes, providing fault-tolerance and high availability.

Control plane của Kubernetes thường chạy thông qua nhiều máy và cluster thông thường chạy nhiều nodes khác nhau.

Nguồn Ảnh/ Source: kubernetes.io

6. Câu hỏi về Kubernetes Architecture

What is a worker machine in Kubernestes known as?

1. Node or Minion
2. Minion
3. Node
4. Cluster

A Node in Kubernetes can only be a physical machine and can never be a virtual machine

1. True
2. False

Multiple Nodes together form a

1. POD
2. Group
3. Cluster
4. Swarm

Which of the following processes runs on Kubernetes Master Node

1. Kubelet
2. Kube-apiserver
3. Kube-proxy

7. Tham khảo

Thank you for your time – Happy New Year – Happy Coding too!

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

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

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

Generate API contract sử dụng Spring MVC-RAML Plugin

spring mvc
Generate API contract sử dụng Spring MVC-RAML Plugin

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

Sau khi định nghĩa API specs với RAML, chúng ta sẽ tiến hành implement API specs này. Nếu ứng dụng của các bạn đang sử dụng Spring framework thì các bạn có thể sử dụng Spring MVC-RAML Plugin để generate API contract với Spring framework và chỉ cần thêm code implementation. Cụ thể như thế nào? Chúng ta hãy cùng nhau tìm hiểu trong bài viết này các bạn nhé!

  Authentication trong Spring Security
  Bean, ApplicationContext, Spring Bean Life Cycle và Component scan

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

Đầu tiên, mình sẽ tạo mới một Spring Boot project với Web dependency như sau:

Kết quả:

 

Để làm ví dụ, mình sẽ sử dụng API specs được định nghĩa với RAML trong bài viết về API fragments với RAML. Các bạn có thể lấy nội dung của API specs này ở đây, copy tất cả các tập tin, folder vào thư muc src/main/resources/api của project của chúng ta:

 

Để bắt đầu, chúng ta sẽ khai báo Spring MVC-RAML Plugin trong project của chúng ta như sau:

<plugin>
<groupId>com.phoenixnap.oss</groupId>
<artifactId>springmvc-raml-plugin</artifactId>
<version>2.0.5</version>
</plugin>

Chúng ta sẽ thêm phần cấu hình để plugin này có thể làm việc được. Cấu hình này bao gồm đường dẫn tới tập tin RAML chúng ta sẽ sử dụng để generate các request URI, đường dẫn thư mục của class Controller sẽ được generate, … Các bạn có thể cấu hình plugin này cơ bản như sau:

<plugin>
<groupId>com.phoenixnap.oss</groupId>
<artifactId>springmvc-raml-plugin</artifactId>
<version>2.0.5</version>
<configuration>
<ramlPath>src/main/resources/api/student-management.raml</ramlPath>
<outputRelativePath>src/main/java</outputRelativePath>
<basePackage>com.huongdanjava.ramlspringmvc.web</basePackage>
<baseUri>/api</baseUri>
<rule>com.phoenixnap.oss.ramlplugin.raml2code.rules.Spring4ControllerInterfaceRule</rule>
</configuration>
</plugin>

<ramlPath> cho phép chúng ta cấu hình đường dẫn đến tập tin RAML định nghĩa API specs.

<outputRelativePath> sẽ là đường dẫn đến thư mục sẽ chứa API contract được generate. Ở đây, các bạn cũng thấy, chúng ta còn có <basePackage> để định nghĩa package cho generated Java classes.

 

<baseUri> sẽ override lại định nghĩa baseUri mà chúng ta định nghĩa trong tập tin RAML. Khi generate thì giá trị của baseUri sẽ được sử dụng để định nghĩa request URI ở đầu mỗi Controller class đó các bạn!

<rule> cho phép chúng ta định nghĩa cách mà các Controller classes sẽ được generated. Spring MVC-RAML Plugin định nghĩa một số rule như sau:

Spring4ControllerInterfaceRule sẽ generate các Controller class là những interface. Chúng ta sẽ cần tạo các class implementation cho những interface Controller này.

Spring4RestTemplateClientRule thì sẽ generate các class giúp chúng ta consume các request URI mà chúng ta định nghĩa trong API specs.

Spring4ControllerDecoratorRule sẽ generate code dựa vào decorator design pattern.

Spring4ControllerStubRule sẽ generate các Controller class và chúng ta sẽ modify những class này để thêm phần implementation.

 

Mình thì như các bạn thấy, sử dụng Spring4ControllerInterfaceRule để tách bạch định nghĩa API specs với phần implementation. Sau này có thay đổi gì đến API specs, chúng ta chỉ thay đổi code implementation khi cần thiết mà thôi.

Còn một số các cấu hình khác mà các bạn có thể tìm hiểu thêm ở đây. Trong bài viết này, mình chỉ giới thiệu với các bạn một số cấu hình cơ bản.

Sau khi cấu hình xong, chúng ta có thể cấu hình phần execution để mỗi khi chúng ta compile, build source code, Spring MVC-RAML Plugin có thể chạy để generate code cho chúng ta, ví dụ như sau:

<plugin>
<groupId>com.phoenixnap.oss</groupId>
<artifactId>springmvc-raml-plugin</artifactId>
<version>2.0.5</version>
<configuration>
<ramlPath>src/main/resources/api/student-management.raml</ramlPath>
<outputRelativePath>src/main/java</outputRelativePath>
<basePackage>com.huongdanjava.ramlspringmvc.web</basePackage>
<baseUri>/</baseUri>
<rule>com.phoenixnap.oss.ramlplugin.raml2code.rules.Spring4ControllerInterfaceRule</rule>
</configuration>
<executions>
<execution>
<id>generate-springmvc-endpoints</id>
<phase>compile</phase>
<goals>
<goal>generate-springmvc-endpoints</goal>
</goals>
</execution>
</executions>
</plugin>

Goal “generate-springmvc-endpoints” của Spring MVC-RAML Plugin sẽ giúp chúng ta generate code lúc compile.

 

Bây giờ thì nếu các bạn chạy “mvn clean install”, kiểm tra project, các bạn sẽ thấy code được generate như sau:

2 class Controller tương ứng với 2 root request URIs mà chúng ta đã định nghĩa trong tập tin RAML. Kiểm tra nội dung của các class Controller này, các bạn sẽ thấy chúng là những interface:

 

Nhiệm vụ của chúng ta là tạo mới các class khác để implement các interface này.

Khi generate các class Controller này, một số thư viện đã được sử dụng để adapt với định nghĩa trong tập tin RAML. Trong trường hợp của mình, có 2 thư viện mà Spring MVC-RAML Plugin đã sử dụng là Common Lang và Java Bean Validator, chúng ta cần phải khai báo sử dụng các dependencies này để project không bị lỗi như sau:

<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

Kết quả của mình như sau:

 

CSS cơ bản toàn tập dành cho người mới phần 1

css
CSS cơ bản toàn tập dành cho người mới phần 1

Bài viết được sự cho phép của tác giả Trần Anh Tuấn

Sau series HTML cơ bản dành cho người mới thì bây giờ mình lại tiếp tục tới một series cơ bản khác đó chính là CSS cơ bản. Sau khi học HTML cơ bản thì các bạn đã biết dùng tới các thẻ như thế nào rồi, mỗi thẻ được tạo ra với mục đích là gì, khác nhau giữa inline và block như thế nào…

Sau khi chúng ta tạo được sườn của trang web với HTML thì việc tiếp theo là làm sao cho nó đẹp lên, trang trí cho nó như thế nào, tùy biến các kiểu ra sao… thì đây chính là công việc của CSS. Vậy trong CSS có những thuộc tính gì và nó hoạt động ra sao thì hãy cùng mình tìm hiểu dưới đây nha

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

Chèn CSS vào HTML cơ bản

Để viết được CSS thì việc đầu tiên các bạn cần làm là tạo một file có đuôi mở rộng là .css là được ví dụ như mình ở đây sẽ là main.css, sau đó chúng ta sẽ chèn nó vào HTML như thế này. Việc tạo file HTML rất là đơn giản nhé, tạo file main.html rồi gõ ! thì vscode emmet sẽ gợi ý ra cấu trúc chuẩn cho các bạn

Chèn file main.css vào file main.html

Sau khi chèn CSS vào được file HTML rồi thì việc tiếp theo chúng ta cần làm đó chính là tìm hiểu về cấu trúc của một đoạn code CSS cơ bản là như thế nào nhé

  3 điều bạn có thể không biết về biến trong CSS
  9 CSS animation mới "mãn nhãn" cho các project

Selectors cơ bản cần nắm

Cấu trúc CSS

Như hình thì các bạn sẽ thấy cấu trúc mình ghi rõ ràng. Trong đó:

  • Selectors: Là các thẻ HTML đã học như div, h2, body, span, a, hoặc là class(bắt đầu với dấu chấm như .heading, .item, .header), hoặc là id(bắt đầu với dấu # như là #header, #container…)
  • Property: Là những thuộc tính CSS mà chúng ta sẽ học sắp tới đây
  • Value: Là giá trị tương ứng của Property
Cấu trúc đoạn code CSS cơ bản

Thuộc tính Color

Thuộc tính này dùng để đổi màu chữ cho trang web, chỗ nào các bạn dùng chữ thì có thể đổi màu được, và giá trị của nó là các mã màu, mã màu ở đây có thể là name(red, orange, blue…), hexa(#ffa400), rgb(255,255,255), hsl(39, 100%, 50%) tùy vào mục đích mà chúng ta sử dụng sao đó cho nó hợp lý

Nếu các bạn muốn có màu chữ trong suốt thì nên dùng rgb hoặc hsl. Ví dụ với rgb thì các bạn có thể viết như thế này rgba(rgb-color, alpha) trong đó alpha là độ trong suốt chạy từ 0 cho đến 1 tương ứng từ không thấy gì cho đến rõ dần, còn rgb-color thì sẽ là mã màu ví dụ màu đen sẽ là 0, 0, 0. Ở hình này mình đang dùng màu đen nhưng độ trong suốt của nó giảm đi một nửa nên mình truyền vào là 0.5 nè

Thay đổi màu chữ của class heading

Thuộc tính background-color

Cái này thì tương tự cho cái trên nên mình không có giải thích lại, chỉ khác cái là background-color thì sẽ áp dụng cho màu nền của một khối nào đó, ví dụ các bạn sơn tường thì đó là background-color, còn viết chữ lên đó thì sẽ là color. Giải thích vậy thì chắc các bạn sẽ dễ hiểu hơn đúng không nào?

Thay đổi màu nền trang web với background-color

Thuộc tính text-align

Thuộc tính này thì có 4 giá trị hay dùng, trong đó giá trị mặc định là left. Nếu các bạn có dùng word để soạn thảo thì không còn xa lạ gì về việc căn chữ hiển thị trái, phải, giữa, và đều 2 bên. Tương tự như vậy ở trong CSS thì thuộc tính này có 4 giá trị như sau, lưu ý là ở đây mình đang liệt kê nhen, khi dùng thì tùy vào thiết kế mà các bạn dùng 1 trong 4 cái nhé.

Thuộc tính line-height

Thuộc tính này sẽ làm tăng hoặc giảm chiều cao của dòng chữ, ví dụ các bạn có đoạn chữ có font-size là 20px thì nếu là một dòng nó sẽ có chiều cao là 20px, nhưng nếu là 2 dòng thì chiều cao sẽ là 40px. Lúc này các bạn muốn tạo khoảng trống giữa các dòng cho nó thoáng hơn chẳng hạn thì các bạn sẽ dùng line-height

Giá trị line-height càng lớn thì khoảng cách dòng càng xa, nên các bạn lưu ý điều đó. Ở đây mình ví dụ là 2 dòng sẽ có chiều cao là 40px, tuy nhiên khi mình thêm line-height: 2 vào thì nó sẽ ảnh hưởng, chúng ta sẽ lấy chiều cao nhân cho line height là 2 thì kết quả chiều cao của 2 dòng sẽ là 80px đấy nhé.

Thuộc tính letter-spacing

Ở trên thì là khoảng cách giữa các dòng, vậy thì khoảng cách giữa các kí tự trong chữ thì sao nhỉ ? Chúng ta sẽ dùng letter-spacing nhé, số càng lớn thì các kí tự càng thưa và ngược lại, số càng nhỏ thì nó càng sát lại

Thuộc tính word-spacing

Nếu có khoảng cách giữa các kí tự thì cũng sẽ có khoảng cách giữa các từ, tương tự như trên nhưng là thuộc tính khác word-spacing

Thuộc tính work-break

Sau này khi các bạn đã có kiến thức và đi làm, đôi khi các bạn sẽ làm với những giao diện mà nội dung được người dùng nhập vào, và họ cố ý nhập các chữ dính nhau và làm giao diện chúng ta bị bể, như dưới này, cái khối màu xám mình chỉ cho độ rộng là 300px và các bạn thấy là các chữ nó bị tràn ra ngoài luôn

Để giải quyết nó thì chúng ta sẽ dùng thuộc tính work-break và giá trị là break-all hoặc là `break-word` tùy vào mục đích của giao diện chúng ta

Xử lý chữ dính nhau với work-break

Thuộc tính text-overflow

Tuy nhiên có một vài trường hợp theo giao diện thiết kế thì chữ nó phải nằm trên một hàng, và nếu dài quá cho phép thì ẩn đi và hiển thị dấu 3 chấm thì phải làm sao ? Đừng lo lắng việc đầu tiên chúng ta cần làm đó chính là làm sao để hiển thị một hàng cái đã.

Để hiển thị chữ trên một hàng thì chúng ta sẽ dùng thuộc tính white-space: nowrap lúc này ta sẽ được như này

Chữ bị tràn ra ngoài khi dùng nowrap

Tuy nhiên nó lại quay lại vấn đề khi trước là chữ bị tràn ra ngoài khối làm giao diện bị bể, để giải quyết nó chúng ta sẽ kết hợp thêm 2 thuộc tính là overflow: hidden(nghĩa là nếu bị tràn ra ngoài thì sẽ ẩn đi) và text-overflow: ellipsis( để hiển thị dấu 3 chấm)

Tạm kết phần 1

Mình tạm kết phần 1 ở đây, ở phần này thì các bạn cũng đã có hiểu biết chút chút về CSS là gì rồi cũng như biết cách chèn vào file HTML như thế nào, các selectors ra sao, cấu trúc của CSS, và học được khá nhiều thuộc tính cơ bản liên quan tới chữ. Hi vọng những kiến thức mình chia sẻ sẽ có ích cho các bạn khi bắt đầu học CSS nhen. Hẹn gặp lại các bạn ở phần 2.

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

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

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