Home Blog Page 162

Viết và Deploy một Lambda Function trên Netlify

Merge vs Rebase trong Git

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

Lambda function là gì?

Giải thích về Serverless bạn đọc bài trước có đăng

Nếu bạn chỉ có một trang blog như thế này, viết bằng Gatsby, không có backend làm sao bạn có thể có được tính năng cho phép user đăng ký nhận bản tin? Ví dụ dùng dịch vụ của MailChimp đi.

Chúng ta ko thể đưa API key vào trang frontend được, hiển nhiên quá mà! Ai cũng có thể lấy được cái key này thì sao.

Chúng ta phải thông qua một bên ở giữa, là Lambda function trên Netlify, chúng ta đưa key này cho Netlify, nó sẽ có trách nhiệm bảo mật key này và truyền thông tin tới MailChimp

Chữ Lambda được phát minh đầu tiên bởi Amazon AWS, sau này Netlify cũng dùng luôn tên này, nó là kiểu các hàm trung gian, giúp chúng ta giao tiếp với phía server (vì đây là dạng serverless, chúng ta dùng dịch vụ của nó cung cấp, giống như vua chúa, nếu muốn giao tiếp với anh thì chú cứ thông qua thái dám, họ sẽ truyền tin tới cho anh)

Cứ dùng trang mặc định của Gatsby

Viết và Deploy một Lambda Function trên Netlify

Tạo một thư mục bên trong source code, nó sẽ chứa toàn bộ các hàm sẽ giao tiếp với Lambda. Thư mục này đặt đâu cũng được, cứ đặt vào dưới thư mục gốc tên functions

Mỗi file chỉ chứa 1 function

test.js

exports.handler = function(event, context, callback) {
}

Mỗi function sẽ nhận 3 parameter

  • event: chứa post data, header
  • context: function này được call ở đâu, thông tin user hiện tại
  • callback: hàm callback thôi, hàm này nhận param đâu tiền là error nếu có lỗi

Viết và Deploy một Lambda Function trên Netlify

Chạy các function Lambda ở local

Cần cài netlify-lambda để chạy test dưới local

npm install netlify-lambda

Viết và Deploy một Lambda Function trên Netlify

netlify-lambda serve <functions_directory>

<functions_directory> là thư mục chứa mấy function chúng ta viết

Thêm đoạn shortcut vào trong package.json để chạy lệnh này

Viết và Deploy một Lambda Function trên Netlify

Bước cuối cùng cần làm, tạo file config để báo với Netlify, đây không phải là thư mục chứa source code của chúng ta, đây là thư mục sau khi build. Tạo file Netlify.toml trong thư mục gốc

Viết và Deploy một Lambda Function trên Netlify

Sau khi build, file bên trong functions sẽ được đưa vào thư mục tên lambda

Chạy lại đoạn script shortcut hồi nãy khai báo npm run start:lambda, bên dưới hình này đoạn chạy bị lỗi là khi chưa tạo file Netlify.toml, chúng ta bắt buộc phải tạo file này trước khi chạy

Viết và Deploy một Lambda Function trên Netlify

Mở Postman lên gọi test thử

Viết và Deploy một Lambda Function trên Netlify

Function đầu tiên đã chạy thành công!!!

Chúng ta truyền thêm một object { "name" : "James" }, và muốn nhận được một JSON object thay vì là một string. Muốn vậy trong phần body chúng ta phải gọi JSON.stringify

callback(null, {
    statusCode: 200,
    body: JSON.stringify({ msg: "Thanks for visiting " + name })
});

// nếu không nhận được name= james

callback(new Error("You're not James"));

Viết và Deploy một Lambda Function trên Netlify

Test trên Postman

Viết và Deploy một Lambda Function trên Netlify

Trường hợp phát sinh lỗi

Viết và Deploy một Lambda Function trên Netlify

  Deploy ứng dụng web đến một máy chủ từ xa nhờ vào Git push
  Auto deploy dự án với Github Actions

Deploy lên Netlify

Nãy giờ chúng ta đang chạy các Lambda function ở dưới local bằng lệnh serve, để đưa lên Netlify, chúng ta cần build source code trước khi đẩy lên Netlify

Chúng ta phải setup chạy 2 script, một để build Gatsby, sau đó build mấy functions lambda

"props": "npm run build; npm run build:lambda"
Viết và Deploy một Lambda Function trên Netlify

Lưu ý: do đang dùng gatsby, nên cần 2 lệnh này, nếu bạn dùng một thằng khác, thì lệnh sẽ khác, tuy cách setup

Phải cập nhập lại Netlify.toml, chúng ta sẽ báo với Netlify: “Ê, khi nào tao chạy xong prop, thì mày deploy nhe”

Viết và Deploy một Lambda Function trên Netlify

Sau khi commit lên Github, Netlify sẽ bắt đầu trigger deploy, vào trang chính của Netlify, trong tab Deployment, bạn có theo dõi xem nó đang deploy tới đâu rồi

Viết và Deploy một Lambda Function trên Netlify

Sau khi deploy thành công, bạn có thể chuyển qua tab Function, các function nào đã có sẽ được liệt kê ở đây

Viết và Deploy một Lambda Function trên Netlify

Cơ bản là thế thôi, các bạn có thể làm “mọi thứ” với function mình viết (miễn là nó có cho), như gửi email, lưu dữ liệu xuống DB, gọi một API

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

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

Xem thêm các công ty HOT tuyển dụng IT tại TopDev

Báo cáo thị trường IT quý II 2020: Ngành IT khôi phục trạng thái, Việt Nam khởi sắc “xây tổ” đón “đại bàng”

thị trường thanh toán điện tử landscape 2020

Mới đây nhất, đơn vị tuyển dụng IT TopDev vừa phát hành báo cáo thị trường IT nửa đầu năm 2020, đánh giá toàn bộ thị trường Công nghệ sau đại dịch COVID cũng như nhu cầu tuyển dụng của doanh nghiệp. Nhìn chung, doanh số, tốc độ tăng trưởng, cũng như nhu cầu tuyển dụng của các công ty trong ngành IT có dấu hiệu hồi phục và tăng trưởng trở lại sau đại dịch. 

Vẫn lấy ngành IT làm đầu tàu mũi nhọn cho sự phát triển của đất nước, sự khởi sắc của IT đem lại nhiều tín hiệu mừng cho nền kinh tế của đất nước cũng như sự lan tỏa tích cực đến các lĩnh vực và ngành nghề khác. Ông Nguyễn Hữu Bình – CEO của TopDev cho rằng ngành CNTT đang nhận được rất nhiều sự quan tâm của chính phủ Việt Nam cũng như của các tập đoàn công nghệ nước ngoài (Mỹ, Nhật, Hàn Quốc và Châu Âu), chính vì vậy mà doanh nghiệp cần cùng nhau chung tay để “xây tổ” cải tiến và thúc đẩy công nghệ để sẵn sàng cho những cuộc chuyển mình lớn trong tương lai. Đón “đại bàng” hay “chim sẻ” thời gian sẽ sớm trả lời, chỉ cần chúng ta có sự chuẩn bị đầy đủ, Việt Nam chắc chắn sẽ gặt quả ngọt.

DOWNLOAD

Xu hướng doanh nghiệp ưu tiên tái đào tạo nhân viên

Ứng biến với dịch COVID, các doanh nghiệp cũng có những thay đổi trong kế hoạch tuyển dụng để phù hợp với ngân sách của công ty. Hơn 50% doanh nghiệp vẫn duy trì tuyển dụng, vì nhìn chung ngành IT không chịu sự biến động mạnh như các ngành nghề khác. Dù vậy, vẫn có khoảng 10% doanh nghiệp buộc phải đưa ra những quyết định khó khăn nhằm đảm bảo nguồn tài chính và sự sống còn của công ty.

Ngay sau đại dịch, một số vị trí nhận được sự ưu tiên trong công tác tuyển dụng. Có thể thấy, doanh nghiệp chú trọng những vị trí thuộc cấp quản lý, đáng chú ý là nhân lực có kinh nghiệm nhận được sự quan tâm rất chênh lệch so với fresher (0-2 năm kinh nghiệm).

topdevreport_hinh2

Không còn chú trọng nhiều đến việc liên tục tuyển ứng viên mới đặc biệt là fresher, các doanh nghiệp có 2 xu hướng, một là tập trung tăng cường tuyển dụng những vị trí có nhiều kỹ năng và có tính chuyên môn cũng như kinh nghiệm cao hơn, hai là tận dụng nguồn nhân lực sẵn có cùng với các giải pháp đào tạo nội bộ để nâng cấp các nhân viên cứng của mình. Trong đó, upskill nhân viên hiện tại đang rất được cân nhắc với 26% người tham gia khảo sát chắc chắn lựa chọn, theo sau đó là re-skill với tỷ lệ lựa chọn chắc chắn thay đổi là 23%.

Ngoài ra còn có khái niệm rất mới mà doanh nghiệp có thể cân nhắc với những dự án vừa và nhỏ, chính là Gig workers. Gig workers có thể hiểu là những nhân viên thời vụ, làm việc độc lập và ký biên bản thỏa thuận với doanh nghiệp để cung cấp dịch vụ cho một số dự án nhất định.

Mức Lương một số vị trí lên đến 130 triệu đồng nghĩa với nhu cầu tuyển dụng dần khắt khe hơn, nâng tiêu chuẩn ở các vị trí

topdevreport_hinh4

Ở thời điểm hiện tại, số lượng và nhu cầu về nhân sự IT vẫn luôn tăng trưởng. Dù bối cảnh có nhiều thay đổi, mức lương trung bình thị trường IT vẫn không bị ảnh hưởng quá nhiều. Tuy nhiên, thị trường dần có những sự chuyển dịch và phân hóa rõ ràng hơn ở các nhân sự IT có trình độ khác nhau. Điều này thể hiện rõ nhất ngay ở giai đoạn Covid-19, các nhân sự IT đa năng hơn, đáp ứng nhu cầu khắt khe hơn sẽ được trọng dụng với mức lương trung bình tăng nhanh hơn trung bình thị trường song song với nhu cầu tuyển dụng vị trí này cũng gia tăng đáng kể (hơn 20%) so với giai đoạn trước đó. Về phía ngược lại, các nhân sự IT thông thường có xu hướng giảm về mức lương trung bình cũng như nhu cầu tuyển dụng chững lại đáng kể.

Về khía cạnh tuyển dụng lập trình viên, các vị trí đang thuộc top nhu cầu mà doanh nghiệp tìm kiếm là: Full Stack Developer (lập trình viên đa năng, đảm nhận cả front-end và back-end) chiếm 71.5%, Back-end Developer (thiết kế công nghệ, cơ sở dữ liệu đằng sau sản phẩm) chiếm 65.1%, và Mobile Developer (Lập trình viên ứng dụng di động) chiếm 54.3%.

Mức lương trung bình cao nhất trong giới lập trình thuộc về vị trí CTO/CIO (lên đến 130 triệu đồng), người đảm nhận công việc quản lý, tối ưu công nghệ của doanh nghiệp. Công nghệ được trả lương cao nhất là Kubernetes (38 triệu đồng). Nhìn chung, so với khảo sát năm 2019 do TopDev phát hành, không có sự tăng trưởng đột biến về mức lương trung bình cho các vị trí. Tuy nhiên, đối mặt với nhu cầu, đầu tư từ các doanh nghiệp lớn quốc tế, câu chuyện về phúc lợi và thu nhập của ngành lập trình sẽ luôn thay đổi và mang tính cạnh tranh hơn.

Việt Nam đã sẵn sàng đón nhận đầu tư?

Làn sóng dịch chuyển đầu tư là có thật, đơn cử là những động thái mở nhà máy và trung tâm nghiên cứu, tuyển dụng nhân sự tại Việt Nam của những ông lớn công nghệ như HCL, Samsung, Apple, Qualcomm hay Panasonic,…

Tuy nhiên, để đón được “đại bàng” thì câu chuyện cơ sở hạ tầng tại Việt Nam đã sẵn sàng hay chưa? Theo một chuyên gia kinh tế, có hai vấn đề “nút thắt cổ chai” cần được tối ưu hóa. Thứ nhất, về các khu công nghệ chưa được khai thác đúng mức trên vốn đầu tư, còn có nhiều cơ sở bỏ hoang; các công nghệ phụ trợ chỉ mới phù hợp chào đón các hãng vừa tầm và nhỏ. Thứ hai, khả năng chuyên môn còn chưa vững, còn thiếu về cả chất và lượng. Giải pháp sâu xa không chỉ về mặt nâng cao tay nghề, mà còn về mặt tư duy của lao động, thay đổi mindset để đóng góp vào sự phát triển của hãng.

Để giải quyết được các vấn đề đã nêu cần sự phối hợp giữa chính phủ và doanh nghiệp. Về phía các chính sách, Chính phủ nên bắt đầu với chương trình PPP để tối ưu ngân sách quốc gia, sau đó là hỗ trợ các doanh nghiệp vừa và nhỏ bằng những biện pháp miễn giảm các loại thuế phí, hay ổn định giá điện nước đầu vào của doanh nghiệp, hỗ trợ doanh nghiệp vượt qua giai đoạn hậu COVID.

Nhìn chung, nền kinh tế Việt Nam được nhận định sẽ sẵn sàng bật dậy sau dịch COVID-19. Theo nhận định của nhà kinh tế Edward Teather của UBS Research, “Nền kinh tế Việt Nam chịu một số tổn thương do tác động của dịch Covid-19, nhưng vẫn có triển vọng sáng nhất khu vực châu Á. Doanh số bán lẻ, nhập khẩu và sản xuất công nghiệp của Việt Nam đều tăng trong tháng 6 so với cùng kỳ năm trước. Rõ ràng là tình hình Việt Nam tốt hơn hầu hết nền kinh tế châu Á khác.”

Tóm lại, TopDev cho rằng, đi cùng với những cơ hội lớn vẫn sẽ có những thách thức không hề đơn giản về sự thay đổi và phát triển. Đón nhận làn sóng đầu tư cũng là “mở cửa” cho những sự thay đổi mới, mà trong đó công nghệ sẽ là trợ thủ đắc lực, giúp Việt Nam “gặt” quả ngọt.

Báo cáo nửa đầu năm 2020 về thị trường và nhu cầu nhân sự IT do TopDev phát hành đã được đăng tải, độc giả tìm hiểu thêm về xu hướng các ngành Công nghệ trong nước qua bản báo cáo IT Landscape 2020 tại đây.

Làm việc với Redux trong ứng dụng lớn

Làm việc với Redux trong ứng dụng lớn
Bài viết được sự cho phép của tác giả Lưu Bình An
Cùng thảo luận xung quanh vấn đề ứng dụng thiên về dữ liệu lớn, rất lớn

Đây là những chỉ dẫn của AppNexus để tối ưu redux với lượng dữ liệu khủng. Mức độ bài viết khá chuyên sâu, bạn cần nắm thật vững redux, hoặc xem lại redux để hiểu rõ và nhớ lâu nội dung bài này.

  Redux vận hành như thế nào
  Tớ đã ăn hành với Redux như thế nào?

Lưu dữ liệu với chỉ mục. Truy cập bằng selector

Cách cấu trúc dữ liệu sẽ ảnh hưởng nhiều đến performance và việc tổ chức ứng dụng. Lưu dữ liệu trả về từ API theo chỉ mục (index) mang lại nhiều lợi ích. Nói nôm na, lưu theo chỉ mục tức là theo dạng object, theo cặp key-value. Tác giả Redux ( Dan Abramov ) có trình bài vấn đề này ở đây

Tưởng tượng chúng ta có một mảng object, được fetch từ REST API. Giả dụ chúng ta quyết định lưu toàn bộ xuống store như nó trả về. Khi chúng ta muốn lấy một object cụ thể nào đó? Phải loop qua toàn bộ, rồi muốn lưu danh sách các user đang được chọn và chưa được chọn?

Để tránh tình trạng này, lưu nó dạng chỉ mục, viết lại reducer trước khi lưu xuống store, cục dữ liệu mong muốn, (bạn nào sử dụng FireStore, NoSQL database sẽ hiểu liền tại sao)

{
  "usersById": {
    123: {
      id: 123,
      name: "Jane Doe",
      email: "jdoe@example.com",
      phone: "555-555-5555",
      ...
    },
    ...
  }
}

Dữ liệu được cấu trúc như thế này thì giải quyết vấn đề bằng cách nào? Ví dụ, chúng ta muốn truy cập đến một user object cụ thể

const user = state.usersById[userId]

Không cần loop, sử dụng key để lấy trực tiếp đến object mong muốn

Câu hỏi tiếp theo, ủa vậy sao render được danh sách user nếu dữ liệu tổ chức như vậy. Để làm chuyện đó, chúng ta viết một hàm (hàm như vậy gọi là selector) đơn giản bằng Object.keys()

const getUsers = ({userById}) => {
  return Object.keys(usersById).map(id => usersById[id]);
}

Thêm một hàm nữa cho việc lấy ra danh sách user với tham số truyền vào là mảng user id

const getSelectedUsers = ({ selectedUserIds, usersById }) => {
  return selectedUserIds.map((id) => usersById[id]);
}

Đừng lo chuyện phải viết quá nhiều hàm, viết như vậy càng dễ cho sau này maintain. Trường hợp cái model user có bị thay đổi đi nữa, chúng ta không cần phải update cả trăm cái view đang sử dụng dữ liệu này, đơn giản là update những hàm selector này lại, re-format dữ liệu một tí là xong.

View và edit nên có 2 state khác nhau

Những dữ liệu từ REST API trả về được xem là state chuẩn, giống hệt với database. State của ứng dụng chúng ta sẽ lưu thêm một số meta data khác cho từng user, bình thường chúng ta sẽ xử lý hết những dữ liệu trong cùng một reducer, vì nó tiện.

Nên tách việc xử lý state chuẩn trên reducer khác, nếu tập trong tất cả xử lý trong một reducer sẽ khó maintain hơn là tách ra thành nhiều reducer riêng biệt. (dùng combineReducers đấy mà)

Tại sao? Ví dụ chúng ta có 1 danh sách user, lưu dạng chỉ mục như ở trên

{
 "usersById": {
    123: {
      id: 123,
      name: "Jane Doe",
      email: "jdoe@example.com",
      phone: "555-555-5555",
      ...
    },
    ...
  }
}

Chúng ta có màn hình để user chỉnh sửa, user click nút Edit, chúng ta phải update lại state để render màn hình edit, chúng ta thêm một field mới vào object như sau

{
 "usersById": {
    123: {
      id: 123,
      name: "Jane Doe",
      email: "jdoe@example.com",
      phone: "555-555-5555",
      ...
      isEditing: true,
    },
    ...
  }
}

Submit lên trên API sau khi sửa. API trả về một object mới. Nhưng làm sau chúng ta merge lại vào store? Nếu replace toàn bộ object thì chúng ta mất cái field isEditing, tất nhiên là nếu muốn thì vẫn check và chỉ update những field mình muốn, nhưng như vậy rất tốn sức người sức máy. Tốt nhất chúng ta lưu dữ liệu từ API vào một nơi khác trong store bằng một reducer khác, không đụng gì vào nó, action cũng sẽ đơn giản hơn và dễ xử hơn

Thêm nữa, nếu user có nữa chừng ấn cancel chúng ta dễ dàng reverse lại nếu đưa edit state vào chổ khác

"usersByIds": {
  123: {
    id: 123,
    name: "Jane Doe",
    email: "jdoe@example.com",
    phone: "555-555-5555",
    ...
  },
  ...
},
"editingUsersById": {
  123: {
    id: 123,
    name: "Jane Smith",
    email: "jsmith@example.com",
    phone: "555-555-5555",
  }
}

Như vậy chúng ta vẫn có state chuẩn, để reverse, edit state nếu user click edit nữa. Nói chung, tách ra, đừng gọp chung

Xài chung state một cách khôn ngoan

Một khi ứng dụng phình ra, nhiều tính năng hơn, nên có cái reducer cho từng page, ví dụ trang hiển thị list user, lưu lại trong users reducer, một trang khác bao gồm tất cả post của user hiện tại. Tổ chức redux store như sau

{
  "usersPage": {
    "usersById": {...},
    ...
  },
  "postsPage": {
    "postsById": {...},
    ...
  }
}

Mỗi trang đảm trách state của chính nó, các file reducer có thể để cùng với các file page luôn.

Sẽ đến lúc chúng ta cần chia sẻ một vài state giữa 2 view. Cân nhắc các câu hỏi sau

  • Có bao nhiêu view hoặc reducer sẽ phụ thuộc vào dữ liệu này?
  • Mỗi trang có cần một bản sao dữ liệu không?
  • Dữ liệu thay đổi có thường xuyên không?

Ví dụ, thông tin user đang đăng nhập sẽ được hiển thị trên tất cả các trang. Tất cả trang đều dùng, thì nó sẽ không hợp lý với cách làm mỗi page một reducer. Thông tin user sẽ không đổi trên tất cả các trang (trừ khi nó vô sửa profile), vậy nên mỗi trang không cần phải có một bản sao thông tin này.

Tất cả các trang nên dùng chung một thông tin user đang login, cho nó một reducer riêng.

Trường hợp nào chuyện xài chung như vậy là ko hợp lý? Thí dụ trong các bài viết của user, nó có thêm danh sách các bình luận. Một trang hiển thị tất cả bình luận. Trang trang list post có tùy chọn hiển thị bình luận cho post đang chọn. Chúng ta có 2 trang đều phụ thuộc vào dữ liệu của bình luận. Trang list post sẽ bị thay đổi khá thường xuyên: user update, edit, delete, add post, bình luận tè le ở đó. Ở trang bình luận chỉ cho tương tác với API GET, PUT bình luận, có thể phân trang. Trang post thì ngược lại, nó chỉ lấy danh sách bình luận của chính nó. Rõ ràng, việc dùng chung bình luận giữa các view là không hợp lý. Mỗi trang nên lưu riêng một bản sao của bình luận.

Tái sử dụng các hàm xử lý reducer

Sau một thời gian viết reducer, sẽ có lúc mình thấy mấy cái function này xử lý na ná nhau, như vậy thì nên tái sử dụng nó đừng viết mới. Ví dụ nếu logic của việc load dữ liệu bài viết và bình luận là như nhau, khác cái endpoint thôi và object schema, phân trang cũng giống.

Để dùng chung reducer, cách thứ nhất, truyền vào scope bên trong payload của action. Để dễ hình dung, lấy vị dụ một trang chứa nhiều section khác nhau, tất cả đều load bất tuần tự từ các API endpoint khác nhau, để theo dõi tình trang load này bằng state trong store

const initialLoadingState = {
  usersLoading: false,
  domainsLoading: false,
  subDomainsLoading: false,
  settingsLoading: false,
};

Chúng ta có thể viết 4 reducer cho 4 cái action, thay vì như vậy nếu truyền thêm scope, một action SET_LOADING

// reducer
const loadingReducer = (state = initialLoadingState, action) => {
  const { type, payload } = action;
  if (type === SET_LOADING) {
    return Object.assign({}, state, {
      // tùy theo scope mà gán cho key tương ứng
      [`${payload.scope}Loading`]: payload.loading,
    });
  } else {
    return state;
  }
}

// Action
const setLoading = (scope, loading) => {
  return {
    type: SET_LOADING,
    payload: {
      scope,
      loading,
    },
  };
}

// ví dụ gọi dispatch
store.dispatch(setLoading('users', true));

Làm như vậy chúng ta khử được quá nhiều lần lập lại logic của reducer.

Còn về vấn đề phân trang, API có thể trả về gần giống như sau

{
  "users": ...,
  "count": 2500, // tổng số dòng
  "pageSize": 100, // số phần tử mỗi trang
  "startElement": 0, // giá trị index đầu tiên của phần từ đầu tiên
  ]
}

Để gọi dữ liệu trang tiếp theo, chúng ta có thể dùng tham số query startElement=100. Đây là cách chúng ta hiện thực reducer cho vấn đề phân trang

const initialPaginationState = {
  startElement: 0,
  pageSize: 100,
  count: 0,
};
const paginationReducerFor = (prefix) => {
  const paginationReducer = (state = initialPaginationState, action) => {
    const { type, payload } = action;
    switch (type) {
      case prefix + types.SET_PAGINATION:
        const {
          startElement,
          pageSize,
          count,
        } = payload;
        return Object.assign({}, state, {
          startElement,
          pageSize,
          count,
        });
      default:
        return state;
    }
  };
  return paginationReducer;
};

// Ví dụ
const postsReducer = combineReducers({
  postsData: postsDataReducer,
  paginationData: paginationReducerFor('POSTS_'),
});
const commentsReducer = combineReducers({
  commentsData: commentsDataReducer,
  paginationData: paginationReducerFor('COMMENTS_'),
});

// Action creator

const setPaginationFor = (prefix) => { 
  const setPagination = (response) => {
    const {
      startElement,
      pageSize,
      count,
    } = response;
    return {
      type: prefix + types.SET_PAGINATION,
      payload: {
        startElement,
        pageSize,
        count,
      },
    };
  };
  return setPagination;
};
// ví dụ sử dụng
const setPostsPagination = setPaginationFor('POSTS_');
const setCommentsPagination = setPaginationFor('COMMENTS_');

Nếu chúng ta dispatch ra 1 action là POSTS_SET_PAGINATION nó sẽ chỉ đụng đến postsReducer. Một kiểu viết hơi tricky nếu bạn nào chưa nắm được Closure function – mình có dịch trên MDN rồi, các bạn lên đó đọc lại.

Tích hợp với React

Ví dụ sử dụng selector và action creator

const ConnectedComponent = connect(
  (state) => {
    return {
      users: selectors.getCurrentUsers(state),
      editingUser: selectors.getEditingUser(state),
    };
  },
  (dispatch) => {
    const actions = {
      setPagination: actionCreatorFactories.setPaginationFor('USERS_'),
    };
    return bindActionCreators(actions, dispatch);
  })
)(UsersComponent);

Các component nó không cần quan tâm cái scope nào đang dùng với action và truy cập tới state bằng cách nào. Component giờ không cần quan tâm việc dữ liệu cụ thể bên trong state làm việc thế nào.

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

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

Xem thêm các việc làm it hồ chí minh, it hà nội, it đà nẵng hấp dẫn tại TopDev

Merge vs Rebase trong Git

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

Merge và Rebase là 2 công cụ để trộn 2 branch trong Git, mục đích sử dụng cho những tính huống khác nhau.

Một tình huống phổ biến khi sử dụng merge

  • Tạo nhánh my-new-feature từ nhánh master
  • Commit nhánh my-new-feature với một số thay đổi
  • Tạo Pull Request: my-new-feature vào master
  10 Vấn đề về Git thường gặp và Giải pháp
  Sự khác biệt giữa ‘git merge’ và ‘git rebase’ là gì?

Sau khi my-new-feature được merge vào master, chúng ta sẽ có

Đó là trường hợp lý tưởng rất ít khi xảy ra, 99.999999% là my-new-feature có vài điểm cần bổ sung sau khi review code, bug chẳng hạn, sai chính tả chẳng hạn.

  • Chúng ta bổ sung 2 commit C6 và C7 vào nhánh my-new-feature
  • Trong lúc đó, master cũng có thêm 2 commit C8C9 được merge vào bởi 2 bạn đồng nghiệp
  • Cuối cùng PR của chúng ta cũng được merge

Cái history lúc này (vẫn ok chứ không vấn đề gì)

Tuy nhiên, cũng là một tính huống rất hay gặp luôn, chúng ta ôm nhánh my-new-feature gần một tuần mà chưa xong, và chúng ta muốn có C8C9 đã được merge, và một cách chủ quan duy ý chí, dân dev chúng ta muốn có một cái history thật sạch đẹp, theo kiểu từng commit C4, C5, C6, C7,… là từng công việc rất cụ thể và độc lập, chúng ta không muốn gom hết một lượt đến cuối sprint rồi commit toàn bộ file là điều khiến người review code vô cùng mệt não.

Rebase giúp được gì ở tình huống này?

Năm 2016 Github giới thiệu một cách merge PR mới: Rebase and merge (Gitlab sẽ là Rebase front door). Nó cho phép chúng ta thực hiện một thao tác rebase trên commit PR rồi mới thực hiện việc merge. 2 thao tác này hoàn toàn độc lập và luôn đúng theo thứ tự rebase trước, merge sau, chứ ko có ngược lại.

Tương tự như nút Rebase and merge, nếu dùng command

git checkout my-new-feature
git rebase master
git checkout master
git merge my-new-feature --ff

Bằng cách đó, history lúc này là một đường thẳng tắp

Rebase không phải để thay thế merge, rebase dùng để thực hiện trên nhánh feature – private branch của chúng ta, merge thực hiện trên master – share branch với đồng nghiệp

Việc rebase -> merge như thế sẽ tránh mất đi những commit C4, C5, C6, C7 trên history của nhánh master, như khi chỉ dùng một lệnh merge. Chúng ta bê nguyên cái history của nhánh my-new-feature lên luôn.

Vấn đề thứ 2, làm sao để sync nhánh my-new-feature với master (có C8, C9)?

/* lấy những thay đổi mới */
git fetch
/* checkout nhánh chúng ta muốn sync với master */
git checkout my-new-feature
/* thực hiện sync với master */
git rebase origin/master

Giữ nhánh my-new-feature cập nhập với những thay đổi mới nhất ở nhánh master để tránh quá nhiều conflict xảy ra khi tạo PR

Nút Rebase and merge không được yêu thích lắm, vì nó tạo quá nhiều conflict, nên chúng ta vẫn thường ưu ái merge hơn.

Để có một history thẳng hàng, đầy đủ tốn khá nhiều mồ hôi chứ không dễ như ăn bánh.

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

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

Xem thêm các việc làm lập trình viên IT hấp dẫn tại TopDev

Chín thói quen xấu cần bỏ nếu muốn theo ngành CNTT

Chín thói quen xấu cần bỏ nếu muốn theo ngành CNTT.

1. Không chịu đọc tài liệu trước khi dùng:

Đây là một trong những thói quen tệ hại nhất nhưng lại thường gặp nhất. Có lẽ thói quen này nảy sinh từ tính thân thiện của “giao diện đồ hình” (GUI) khiến cho người dùng bồi đắp thói quen mò mẫm mà không cần đọc hướng dẫn nhưng cũng sử dụng được máy. Việc này không có gì đáng ngại đối với người dùng (rất) bình thường. Tuy nhiên, nếu bạn có ý định theo đuổi ngành CNTT một cách nghiêm túc thì hãy bỏ ngay thói quen tai hại này bởi vì đây là rào cản lớn nhất cho sự phát triển. Kiến thức vững chắc không phải… mò mà ra. Tài liệu hướng dẫn không phải vô cớ mà được viết ra.

2. Đọc lướt:

Đây cũng là một thói quen tệ hại và phổ biến không kém. Ngay trên những diễn đàn, với những ý kiến và chỉ dẫn bằng tiếng Việt rất cô đọng, rành mạch và dễ hiểu nhưng vẫn có quá nhiều người chỉ đọc lướt để rồi quay lại tiếp tục thắc mắc. Đây là thói quen cực kỳ nguy hiểm bởi vì nó rèn cho trí não thói quen đọc lướt. Việc này dẫn đến chỗ kiến thức thu thập một cách hời hợt, tạm bợ và chắp vá. Nếu những ý kiến bằng tiếng Việt rất cô đọng, rành mạch và dễ hiểu nhưng vẫn không chịu khó đọc kỹ và suy gẫm thì việc tham khảo, tổng hợp các sách tiếng nước ngoài gần như là vô khả thi.

3. Bắt chước mà không suy nghĩ:

Khi bắt đầu làm quen với những thứ trong ngành CNTT, cách dễ nhất là bắt chước làm theo từng bước. Nếu cứ nhắm mắt làm theo nhưng không hề suy nghĩ lý do tại sao mình làm như vậy, không thử đặt câu hỏi những gì xảy ra đằng sau những “bước” ấy thì không chóng thì chày sẽ tạo cho mình một thói quen tai hại: bắt chước không suy nghĩ không tư duy như một cỗ máy. Từ chỗ làm theo từng bước có sẵn mà không suy nghĩ đến chỗ biến thành thói quen thì khả năng nhận định và tư duy sẽ bị thui chột. Chẳng những vậy, thói quen này kiềm hãm sự thẩm thấu kiến thức xuyên qua hàng loạt những câu hỏi. Tự đặt câu hỏi chính là cách buộc trí não mình làm việc và là viên đá đầu tiên để dấn thân vào chỗ phát triển trí tụệ.

  10 thói quen của một lập trình viên thành công

4. Sợ khó:

Sợ khó tưởng chừng quá thông thường trên mọi lãnh vực nhưng trong lãnh vực CNTT thì thói quen “sợ khó” là thói quen giết chết ngay bước đầu làm quen và phát triển. Chẳng có ngành nghề thực thụ, đòi hỏi trí tuệ mà lại dễ dàng hết. Thói quen “sợ khó” biểu hiện từ chuyện đơn giản như học ngoại ngữ (để có thể tham khảo thêm tài liệu ngoại ngữ) cho đến chuyện tự mình đối diện với những khó khăn trong khi trau dồi kiến thức và kinh nghiệm. Thói quen này lâu dần ăn sâu và dẫn đến chỗ không muốn và không thể giải quyết được điều gì nếu chỉ cảm thấy có trở ngại. Nên tránh xa câu này: vạn sự khởi đầu nan, gian nan bắt đầu nản.

5. Viện cớ:

Quá trình tích lũy kiến thức luôn luôn có những khó khăn và trở ngại. Nếu chính bản thân mình không tự kỷ luật và tự nghiêm khắc thì chẳng còn ai trên đời này kỷ luật và nghiêm khắc giúp mình. Từ chỗ không kỷ luật và không nghiêm khắc, chỉ cần một thời gian rất ngắn có thể dẫn đến sự đổ vỡ, sợ hãi, chán nản và để bào chữa cho sự đổ vỡ thường là những viện cớ. Viện cớ chỉ để ẩn nấp sau cái cớ nhưng sự thật sụp đổ vẫn tồn tại. Tránh xa những câu như “nhà em nghèo”, “hoàn cảnh khó khăn”, “vì em là newbie” mà nên biết rằng vô số những người khác cũng như mình và thậm chí còn khó khăn hơn mình. Nên nhớ rằng, ngay khi dùng cái cớ để viện thì lúc ấy mình đã chính thức thất bại rồi.

6. “Đi tắt đón đầu”:

Trên đời này chẳng có loại tri thức đích thực nào hình thành từ “đi tắt” và “đón đầu” cả. “Mì ăn liền” có cái ngon của nó nhưng chính “mì ăn liền” không thể hình thành một bữa ăn thịnh soạn và đầy đủ. Tri thức đích thực cũng như thức ăn, nó cần điều độ, liều lượng và thời gian để… tiêu hoá. Tư duy và thói quen “đi tắt” luôn luôn dẫn đến những lổ hổng khủng khiếp trong kiến thức. Những lổ hổng ấy xem chừng không nhiều và không quan trọng khi kiến thức còn ít ỏi và nhu cầu công việc còn sơ khai. Tuy nhiên, một khi đối diện với những khó khăn và phức tạp trong công việc và trong đời sống thì những thứ “đi tắt đón đầu” là nguyên nhân sâu xa của những đổ vỡ và thất bại. Hãy nhớ: đừng đi tắt và đừng đón đầu bởi vì chẳng có cái đường tắt nào trong hành trình đi tìm tri thức.

7. “Nghe nói là…”

Cụm “nghe nói là…” là một cụm phổ biến đến độ chóng mặt. Bất cứ một ngành khoa học hay có liên quan đến khoa học không thể dựa trên “nghe nói” mà luôn luôn cần dựa trên các bằng chứng khoa học và những bằng chứng ấy cần chính xác và cụ thể. Chính vì có thói quen “nghe nói” mà đánh rớt những cơ hội tìm tòi và kiểm chứng; những cơ hội quý báu để trau dồi kiến thức và kinh nghiệm. Cái gì không rõ thì nên tìm tòi và đừng “nghe nói” mà phải được thấy, được phân tích và được kiểm chứng. Không bỏ được thói quen này thì cách tốt nhất đừng bén mảng gần bất cứ ngành khoa học nào vì chỉ chuốc lấy sự thất bại và lãng phí.

8. Niềm tin và hy vọng:

Trong khoa học, khi nói đến kết quả và sự kiến tạo hoặc thậm chí con đường đi đến sự kiến tạo và kết quả thì hoàn toàn không có chỗ cho “niềm tin” và “hy vọng” một cách mù mờ. Thói quen “restart” lại máy hay “restart” lại chương trình với “hy vọng” nó sẽ khắc phục sự cố đã trở thành thói quen cố hữu. Nếu không có điều kiện thay đổi nào khác thì có “restart” một triệu lần và hy vọng một triệu lần thì kết quả vẫn y hệt nhau. Đừng “tin” và đừng “hy vọng” vào sự thay đổi của kết quả nếu như chính bạn không kiểm soát và thay đổi để tạo thay đổi trong kết quả. Tất cả mọi hoạt động từ lập trình cho đến quản lý hệ thống, quản lý mạng, bảo mật, reverse engineering…. thậm chí đối với người dùng bình thường, khi kết quả không như ý, sự điều chỉnh là điều cần thiết thay vì lặp lại y hệt hành động và chỉ… hy vọng.

9. Không vì trí tuệ mà vì… “đẳng cấp”:

Lắm bạn lao vào ngành này không phải là vì trí tuệ, vì kiến thức, vì đóng góp một cái gì đó ích lợi cho xã hội mà là vì… đẳng cấp mơ hồ nào đó. Nếu tiếp tục lao vào và chọn lấy một muc tiêu mơ hồ thì sẽ không bao giờ đi đến đích được. “Đẳng cấp” là một thứ mơ hồ, vô ích và đầy cá nhân tính nhưng khi nó biến thành thói quen và mục tiêu để nhắm tới thì nó chẳng mang lại được gì ngoài sự thất bại ngay từ đầu vì hoàn toàn không có một phương hướng nào cả. Trau dồi kiến thức hoàn toàn khác với việc xoa dịu mặc cảm (“đẳng cấp”).

Bài viết gốc được đăng tải tại Hoàng Ngọc Diêu

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

Xem thêm các vị trí tuyển dụng IT hấp dẫn tại TopDev

Làm thế nào để giải quyết bất đồng ý kiến nơi công sở?

bất đồng

Những bất đồng về quan điểm, hiệu quả làm việc là chuyện không quá xa lạ với chúng ta. Tuy chúng có thể khiến môi trường làm việc căng thẳng, mệt mỏi, và gây ra sự khó chịu cho tất cả các bên nhưng không thể phủ nhận chính những mâu thuẫn cũng góp phần mang lại hiệu suất làm việc cao hơn. 

Đôi khi một chút bất đồng có thể thúc đẩy sự đột phá, tăng động lực và ngược lại vẫn có nhiều trường hợp tạo ra rào cản lớn trong các mối quan hệ. Thông qua bài viết sau đây, TopDev sẽ chia sẻ với bạn những cách thức phù hợp để giải quyết bất đồng về ý kiến nơi công sở.

Cùng điểm qua 3 chiến lược giải quyết bất đồng nơi công sở nhé!

Nhìn nhận vấn đề trên cùng góc độ

Sự đồng điệu luôn luôn quan trọng

Chúng ta đều nhận ra được nguyên nhân dẫn đến những mâu thuẫn xuất phát từ chính cách nhìn nhận của mỗi người về vấn đề rất khác nhau. Đồng thời, cái tôi cá nhân cũng là yếu tố chi phối cách bạn thể hiện quan điểm, truyền tải thông điệp của mình đến mọi người. Nếu đủ lý trí để nhận ra, hãy thử ngẫm lại mọi thứ. Chúng ta là một đội, có cơ hội đồng hành trải nghiệm cùng nhau để thực hiện các mục tiêu chung. Bạn và các đồng nghiệp có thể bất đồng nhưng đó là tranh luận, không phải “sàn đấu ngôn ngữ” để thể hiện mình quá nhiều. Hãy nhìn nhận trên cùng một góc độ để nhận thấy sự tương đồng, cùng tìm ra sự thống nhất chung về các cách thức tổ chức để thực hiện công việc hiệu quả nhất.  

bất đồng

Một lưu ý nữa là, việc cộng tác cùng những người đồng đội cần được xây dựng trên cơ sở niềm tin. Thay vì chăm chăm phản bác ý kiến của đồng nghiệp, bạn hãy thử đặt niềm tin vào giải pháp của họ hoặc đơn giản, hãy trình bày những điểm mạnh – điểm hạn chế từ ý quan điểm của đồng nghiệp. 

  Kỹ năng giao tiếp? Làm thế nào để cải thiện giao tiếp hiệu quả?

Nếu ý kiến đó có thiếu sót, bạn có thể đóng góp một chút ít về chuyên môn để làm rõ tính khả thi của vấn đề. Đó là cách xử lý khôn khéo giúp hạn chế được những bất hòa phát sinh mà không gây nên bất kỳ sự xúc phạm nào cho đồng nghiệp của bạn. Ngoài ra, điểm cộng hoàn hảo trong việc tạo ra sự tương tác hài hòa giữa bạn và đồng nghiệp chính là sử dụng cách nói “cách nói” thay vì”tôi. Phát ngôn ấy thể hiện rằng bạn đang thật sự quan tâm đến giải pháp tích cực của họ đồng thời bộc lộ mình là một người nhìn nhận các vấn đề trên lợi ích chung của doanh nghiệp.

Bạn không cần lúc nào cũng đúng!

Khi đã vào cuộc giải quyết mâu thuẫn, cuộc khẩu chiến có thể diễn biến khá phức tạp khi bạn và đồng nghiệp đều cố tỏ ra là mình đúng và thể hiện quan điểm cá nhân thay vì lắng nghe, xác định mức độ và giải quyết vấn đề.

Khá dễ hiểu vì sao bạn lại muốn thắng trong cuộc tranh luận, nhưng nếu quá đề cao việc mình phải luôn đúng, bạn đã hoàn toàn quên mất ý nghĩa của những bất đồng này.

bất đồng

Những cuộc tranh luận là để tìm ra cách giải quyết tối ưu, không phải cuộc chiến của người thắng – kẻ thua. Bất đồng là cơ hội để hai bên bày tỏ quan điểm. Để được lắng nghe, và được học hỏi. Nếu cứ chăm chăm vào giành phần thắng, chúng ta đang ngăn cản mình gặt hái những giá trị tích cực từ cuộc thảo luận. Vì thế, trước cuộc thảo luận, bạn hãy đảm bảo những điều sau đây

  • Tính trung thực: Cam kết rằng bạn và đôi phương đều có chung mong muốn tìm ra được cái cốt lõi của vấn đề thông qua những sự thật đã diễn ra.
  • Loại bỏ những hiềm khích cá nhân: Chấp nhận thảo luận để giải quyết những bất đồng tức là bạn đã đặt lợi ích công việc lên hàng đầu. Vì thế, việc gạt bỏ đi những hiềm khích, thành kiến cá nhân về nhau là điều hết sức quan trọng.
  • Cởi mở và lắng nghe lẫn nhau: Đây là giai đoạn các nên mở lòng, lắng nghe và tiếp nhận ý kiến lẫn nhau,cùng thảo luận để đi đến sự thống nhất chung. Đừng quá thể hiện rằng mình luôn đúng trong mọi trường hợp

Hãy để mọi người giúp bạn

Việc tương tác trong các lĩnh vực xã hội, đặc biệt là trong ngành nhân sự, nhiều người có xu hướng không cho rằng việc tìm kiếm sự giúp đỡ là một ý kiến hay. Họ có phần đánh đồng đó là sự yếu đuối và chủ yếu họ đi theo hướng tự bản thân gầy dựng mọi thứ từ A đến Z. Và đôi khi, việc bạn nghĩ rằng mình đang tạo gánh nặng hay khiến người khác cảm thấy bực bội sẽ vô tình làm bạn trở nên thiếu tự tin, từ đó bạn chỉ biết thụ động tiếp thu các quan điểm, mất đi những chính kiến cá nhân về tư duy phán đoán, đánh giá các giải pháp vấn đề. Hãy nhớ rằng việc bạn để mọi người giúp bạn là bạn đang tạo cơ hội cho họ bày tỏ suy nghĩ. Đây được xem là một thủ thuật, khác với việc bạn đánh đi mất quyền lợi được nêu nhận xét về các giải pháp của đồng nghiệp.

  Cách thiết lập và duy trì mối quan hệ (networking) hiệu quả

bất đồng

Nhờ giúp đỡ cũng là một cách thể hiện bạn tin tưởng vào chuyên môn và khả năng của đồng nghiệp trong việc đưa ra những giải pháp thật sự hiệu quả. Một bí quyết dành cho bạn là thay vì mở đầu cuộc thảo luận bằng giọng điệu tranh cãi, bạn hãy thể hiện mong muốn được giúp đỡ từ đồng nghiệp. Đây là cách ứng xử thông minh và đồng thời cũng thể hiện bạn đang tôn trọng và đề cao thiện chí xây dựng mối quan hệ ý nghĩa với các đồng nghiệp của mình. 

Lời kết

Có nhiều cách thức để giải quyết bất đồng nơi công sở. Tuy nhiên, tùy vào đối tượng, hoàn cảnh và mức độ của mâu thuẫn đó mà bạn cần có cách thức xử lý phù hợp. TopDev mong rằng với bài viết này, các bạn đã có những chia sẻ bổ ích có thể vận dụng vào thực tiễn giúp bạn sớm giải quyết mọi nút thắt trong doanh nghiệp của mình.

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

Xem thêm IT Jobs for Developer trên TopDev

TopDev bị chặn

Chúng tôi bắt đầu nhận được phản hồi từ rất nhiều người dùng cũng như là khách hàng về việc không thể truy cập và sử dụng topdev.vn. Qua các bước loại bỏ nguyên nhân và xác minh, chúng tôi nhận thấy domain topdev bị chặn ở tất cả các nhà mạng. Bao gồm ba nhà mạng lớn nhất (xếp theo thứ tự alphabet) là FPT, Viettel và VNPT.

Bằng nhiều công văn với các cấp từ thấp đến cao nhất ở các nhà mạng này, các nhà mạng lần lượt bỏ chặn DNS của TopDev. Tuy nhiên còn một vài nhà mạng nhỏ khác vẫn chưa truy cập được.

Đại diện của cả 3 nhà mạng đều thông báo với chúng tôi cùng một thông điệp: Domain topdev.vn bị chặn do cơ quan bên “trên” gửi xuống. Chúng tôi thực sự không hiểu, không biết chuyện gì đã xảy ra.

Chúng tôi xin khẳng định, lỗi hoàn toàn không thuộc về các nhà mạng bởi danh sách từ “trên” đưa xuống bảo chặn thì họ phải chặn.

Lỗi cũng không thuộc về cơ quan quản lý hoặc lãnh đạo của cơ quan, vì không thể đi chặn vô cớ tên miền .VN, được khai báo pháp lý rõ ràng và đóng thuế đầy đủ. Điều đáng nói ở đây, topdev.vn là một website về tuyển dụng, nội dung hoàn toàn là các việc làm IT cho giới lập trình viên, được đăng lên bởi các doanh nghiệp công nghệ đang hoạt động hợp pháp. Chúng tôi kết nối hàng nghìn việc làm tốt cũng như là giúp các công ty công nghệ giải quyết được nhu cầu nhân lực của họ.

Chỉ cần vài giây lướt qua nội dung site đã có thể khẳng định nội dung hoàn toàn sạch sẽ của topdev.vn. Để rộng đường soi sét việc TopDev bị chặn là một điều vô cùng phi lý, chúng tôi xin chia sẻ, tuy hơi dài dòng, những chứng cứ xác thực được về chúng tôi như sau:

  • Chúng tôi đã nhận được sự công nhận của chính phủ Phần Lan và Việt Nam, bộ Khoa Học Công Nghệ thông qua chương trình IPP vì những đóng góp của mình. Để vào được chương trình này là một sự kiểm duyệt khắt khe minh bạch, vui lòng tham khảo reference letter ở cuối bài do đại diện bộ KHCN phát hành.

    Reference letter từ bộ KHCN
  • Bản thân topdev.vn đã hoàn thành tất cả các thủ tục để hoạt động hợp pháp bao gồm đăng ký Bộ Công Thương tại đây http://online.gov.vn/Home/WebDetails/24669, hiển thị đầy đủ giấy phép, mã số thuế, thông tin liên hệ và điều khoản sử dụng.
  • Chúng tôi là doanh nghiệp hoạt động hoàn toàn hợp pháp, đóng thuế đầy đủ, hoàn thành mọi nghĩa vụ với pháp luật, bằng chứng là nhận được giấy phép đầu tư nước ngoài sau quá trình kiểm duyệt gắt gao của cơ quan chính phủ, cũng như kiểm toán của nhà đầu tư, và quyết toán với cơ quan thuế https://vnexpress.net/mang-tuyen-dung-it-viet-nam-nhan-dau-tu-tu-han-quoc-4056530.html
  • Chúng tôi trực tiếp mang về nhiều triệu đô la ngoại tệ cho đất nước từ vốn đầu tư nước ngoài cũng như là doanh thu trong và ngoài nước, doanh thu sạch, nội dung sạch, không sex, không phim lậu, không lừa đảo.
  • TopDev.vn là đầu mối thông tin về nhân lực ngành IT uy tín của trong và ngoài nước trong những năm gần đây, được hầu hết các báo lớn nhỏ tại Việt Nam trích dẫn lại các số liệu nghiên cứu thị trường được public tại đây https://topdev.vn/page/bao-cao-it-viet-nam, thậm chí được các báo nước ngoài và đặc biệt là BIG4 hỏi xin số liệu, hình tham khảo cuối bài.

Sẽ còn quỹ đầu tư nào dám đầu tư vào các startup Việt Nam khi thấy rằng, một ngày nào đó, bỗng dưng khoản đầu tư của họ biến thành mây khói chỉ vì startup bị chặn bởi chẳng có một nguyên nhân hay lý do gì?

Nhà đầu tư nào sẽ dám đầu tư vào startup tại VN khi thấy rằng, kể cả bạn có trong sạch, hoàn thành nghĩa vụ thuế, tạo ra nhiều việc làm, thì vẫn có nguy cơ bị chặn không rõ lý do mặc dùng tên tuổi địa chỉ công ty rõ ràng mà không có một văn bản chính thức nào.

Một doanh nghiệp kinh doanh chân chính, vượt qua và tồn tại, chưa sa thải hay giảm lương của bất kỳ nhân viên nào sau mùa dịch Corona dù 30 triệu người mất việc.

Chúng tôi tin rằng, dù cho các nhà mạng đã gỡ chặn, thì gốc rễ của vấn đề vẫn nằm ở đó. Nếu không giải quyết tận gốc, nó vẫn sẽ sẵn sàng diễn ra với chúng tôi một lần nữa, bằng một công văn khác.

Chọn sếp tốt hay công ty tốt? – Đâu là nước đi đúng đắn?

chọn sếp

Những câu chuyện chốn văn phòng có nhiều điều thú vị, đặc biệt là câu chuyện xoay quanh vấn đề sếp và công ty. Nhiều người trẻ đã đi làm họ luôn băn khoăn rằng nên lựa chọn giữa việc làm việc cho một người sếp tệ ở một công ty tốt, hay ngược lại, đồng hành cùng một vị sếp tốt trong một công ty với nhiều tồn đọng?

Vậy theo bạn đâu là phương án tốt nhất? Sự cân đo đong đếm là điều cần thiết phải có vì nó ảnh hưởng lớn đến sự nghiệp phát triển của bạn. Với bài viết sau đây, TopDev sẽ chia sẻ những quan điểm cụ thể về vấn đề này.

Nếu ví diễn tiến hành trình tương lai của bạn là một thước phim thực tế thì cách bạn lựa chọn không khác gì việc bạn đang tìm kiếm một kịch bản phù hợp cho mình. Và theo quan điểm mà bài viết này thì chắc chắn rằng dù có bất cứ điều gì xảy ra, bạn cần phải lựa chọn một công ty tốt hơn là một người sếp tốt.

Kịch bản 1: Hãy quan tâm đến những trải nghiệm, đừng chỉ đánh giá một chiều từ sếp

Ở một công ty tốt, không sớm thì muộn, các nhà lãnh đạo nhân sự tài năng sẽ nhận ra được ai có đủ tố chất thật sự để tự hoàn thiện năng lực chuyên môn, quản lý, đồng thời có thúc đẩy sự phát triển của nhân viên mình. Từ đó, những vị sếp có uy quyền và sức nặng “tạm thời” sẽ bị loại bỏ. Tuy nhiên, việc này có thể mất thời gian đến vài tháng, một năm, một vài năm hoặc hơn thế nữa.

Trong cái rủi có may, việc bạn chấp nhận làm việc và không ngừng nỗ lực dưới sự phù phiếm (nếu có) của một người sếp không tốt sẽ giúp bạn được người khác đánh giá cao. Ở đây không đơn thuần là thể hiện sự chịu đựng, việc bạn cố gắng làm việc cho dù người sếp đó luôn áp đặt nhiều thứ chứng tỏ bạn đặt lợi ích chung là mối quan tâm hàng đầu và điều này rất quan trọng.

Dù thế nào, bạn chỉ cần nghĩ đơn giản, cuộc sống này vốn dĩ không mấy dễ dàng và việc “sống chung” với một người sếp tính khí thất thường, thiếu những phẩm chất về chuyên môn cũng không phải là điều tồi tệ nhất mà bạn gặp phải.

Có thể bạn không quá xuất sắc để được thăng chức khi sự thật về người cấp trên của bạn bị phơi bày nhưng với những nỗ lực, bạn xứng đáng có được một người sếp, người quản lý tốt hơn hoặc ít ra, bạn cũng được sắp xếp đến một phòng ban phù hợp khác tốt hơn.

Một điểm cực kỳ quan trọng mà các bạn đáng phải lưu tâm đó là hãy quan tâm đến những trải nghiệm cá nhân, đừng chỉ mãi lấy sếp ra làm thước đo mức độ đồng hành. 

chọn sếp

Đối với bạn hiện tại, thì bất kỳ một trải nghiệm nào trong công ty cũng thật sự  cần thiết. Từ những người đồng nghiệp, môi trường – văn hóa doanh nghiệp, mức độ/chỉ số danh tiếng tổ chức, các phúc lợi,..Tất cả là những giá trị bạn cần quan tâm nhiều hơn. Và nếu may mắn có được một tấm vé đặt chân vào một công ty tốt như thế thì bạn nên trân trọng và cố gắng nhiều hơn. Không có điều gì là thừa cả, công ty tốt sẽ tạo điều kiện tốt để bạn phát triển khả năng của mình.

Kịch bản 2: Sếp tốt nhưng liệu có đủ hay chưa?

Ai mà không mong muốn mình có một người sếp tốt. Những người sếp tốt sẽ biết cách hỗ trợ nhân viên phát triển một cách toàn diện hơn, giúp họ có những trải nghiệm thú vị nhất trong suốt quá trình làm việc. Có nhiều người sếp lại rất tâm lý, thấu hiểu và biết cách chia sẻ với nhân viên. Họ gần gũi và không khác gì những người anh chị lớn trong gia đình. Việc may mắn được theo dõi và đồng hành cùng một người sếp tốt, bạn sẽ có động lực nhiều hơn trong công việc và cả một phần của cuộc sống. 

Thế nhưng, bạn có biết không? Nhiều vị sếp tốt cuối cùng đều ra đi. Lý do có thể là việc họ được thăng chức, nghỉ việc hoặc tương tự như bạn, vì họ giỏi và được tín nhiệm nên được chuyển đi và nhận những trách nhiệm khác cao. Có được một người sếp tốt là may mắn và biết đâu họ cũng hạnh phúc khi những nhân viên của mình có năng lực thật sự. Tuy vậy, khả năng đồng hành lâu dài chưa thể xác định vì những sự việc bất ngờ có thể xảy đến.

  Rời bỏ công việc tại các doanh nghiệp nhỏ - Nguyên nhân và giải pháp

chọn sếp

Có thể bạn không nhận ra được một sự thật là, những vị sếp tốt khi họ làm việc trong các công ty yếu kém, họ còn phải đối mặt với rất nhiều thách thức.

Một trong những thách thức lớn nhất của họ chính là “bảo vệ” những nhân viên của mình trước những vấn đề lớn hơn của công ty. Điều này đôi khi có thể trở nên nặng nề quá sức với họ, họ mệt mỏi và một khi tiếng nói trở nên yếu thế, họ nhận thấy mình chưa hoàn thành một phần trách nhiệm nên có thể sẽ quyết định dừng lại. Chúng ta khó có thể nói trước được bất kỳ điều gì vì mọi thứ xung quanh đều khó đoán. Chỉ biết rằng, nếu là một người sếp tốt, họ sẽ chịu nhiều áp lực và một mình họ không thể nào chấp vá được những “lỗ hỏng” – một đặc thù riêng mà bất cứ doanh nghiệp nào cũng luôn tồn tại.

Chung quy lại, cái cảm giác mà mỗi nhân viên nhận thấy khi được dẫn dắt bởi một người sếp tốt chỉ mang tính chất nhất thời. Những người giỏi cứ dần rời đi và bệ phóng phát triển của công ty thì vẫn vậy – vẫn tệ và yếu kém. Tất nhiên, bạn cũng chẳng thể làm gì để thay thế được điều đó cả. Lúc đó, bạn lại hoang mang, rơi vào khoảng lặng với nhiều nỗi lo khác nhau khiến bạn mắc kẹt và không biết mình phải giải quyết như thế nào. Liệu bạn sẽ tiếp tục làm việc tại một công ty với nhiều lời đồn thổi hay rời đi để thử sức chinh phục một công ty khác. Và liệu lúc đó, còn kịp không, tất cả đều bắt nguồn từ sự lựa chọn ban đầu của bạn.

Hãy là người thông minh trong việc lựa chọn những lợi ích

Xét về sự đồng hành ngắn hạn, việc bạn lựa chọn làm việc cho một vị sếp tệ, dù được làm việc ở một doanh nghiệp với quy mô phát triển tốt, thì bạn sẽ luôn rơi vào guồng quay của những áp lực. Nhưng khi xét về khả năng dài hạn, khi người sếp tốt ấy rời đi, thì ít nhất bạn vẫn có những cơ hội riêng để bản thân bước tiếp.

Tại sao “Hãy hết mình theo đuổi đam mê” là một lời khuyên tồi?

Dĩ nhiên, khi bạn làm việc cho một vị sếp tốt trong quảng thời gian ngắn, bạn sẽ rất vui, dù cho rằng mọi thứ trong công ty đang dần có xu hướng sụp đổ dần. Ngược lại, khi đồng hành dài hạn dài hạn, liệu sự vui vẻ và hạnh phúc ấy có còn tồn tại hay không? Sếp ra đi trong khi công ty đó bản chất là có nhiều “sạn” trong công tác tổ chức, quản lý đào tạo và phát triển. Sau đó, bạn lại rơi vào trạng thái phải chạy đua để tìm kiếm cơ hội hoặc phải chấp nhận từ bỏ vì không thể chịu đựng được sức ép quá lớn từ những ánh mắt soi mói, phản ánh từ dư luận về công ty của mình.

Điều đó cho thấy, sự lựa chọn của bạn quyết định những gì bạn sẽ đối mặt sau này. Hãy thật thông minh trong việc lựa chọn những lợi ích để không phải tiếc nuối bất cứ điều gì.

Lời kết

Mỗi cá nhân đều có cho những lối suy nghĩ riêng về vấn đề này. Vì vậy, hãy suy nghĩ thật thấu đáo để có những quyết định thật thông minh. Trước khi trở thành một nhân viên giỏi có thể tạo ra giá trị vật chất, tinh thần của cá nhân hay đóng góp cho sự phát triển chung cho doanh nghiệp, bạn cần có một sự quyết định sáng suốt. TopDev chúc bạn sẽ vững tin để sớm gặt hái được thành công trên con đường mà mình đã lựa chọn.

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

Xem thêm Jobs IT for Developers hàng đầu tại TopDev

Tìm hiểu về giải thuật: Một số phương pháp sắp xếp cơ bản

tim-hieu-ve-giai-thuat-mot-so-phuong-phap-sap-xep-co-ban

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

  Cấu trúc dữ liệu và giải thuật - Thuật toán tìm kiếm
  Kỹ Thuật Phân Tích Giải Thuật

1. Sắp xếp kiểu lựa chọn (Selection Sort)

Một trong những phương pháp đơn giản nhất để thực hiện sắp xếp một bảng khóa là dựa trên phép lựa chọn.

Nguyên tắc cơ bản của phương pháp sắp xếp này là “ở lượt thứ i(i=1,2,…,n) ta sẽ chọn trong dãy khoá Ki, Ki+1,…,Kn khoá nhỏ nhất và đổi chỗ nó với Ki ”.

Như vậy thì rõ ràng là sau j lượt, j khoá nhỏ hơn đã lần lượt ở các vị trí thứ nhất, thứ hai,…, thứ j theo đúng thứ tự sắp xếp. Ví dụ:

Sắp xếp dãy số sau theo thứ tự tăng dần: “42, 23, 74, 11, 65, 58, 94, 36, 99, 87”.

Sau đây là giải thuật:

Cho dãy khóa K gồm n phần tử. Giải thuật này thực hiện sắp xếp các phần tử của K theo thứ tự tăng dần dựa vào phép chọn phần tử nhỏ nhất trong mỗi lượt.

Procedure SELECT-SORT(K, n)
For i:=1 to n-1 do
     Begin
         M:=i;
         For j:=i+1 to n do
         If K[j]<K[m] then m:=j;
             If m!= j then
             Begin {đổi chỗ}
                 X:=K[i];
                 K[i]:=K[m];
                 K[m]:=X;
             End
     End
Return;

2. Sắp xếp chèn (Insertion Sort)

Nguyên tắc sắp xếp ở đây dựa theo kinh nghiệm của những người chơi bài. Khi có i-1 lá bài đã được sắp xếp ở trên tay, nay rút thêm lá bài thứ i nữa thì sắp xếp lại như thế nào ? Có thể so sánh lá bài mới lần lượt với lá bài thứ (i-1), thứ (i-2)… để tìm ra chỗ thích hợp và chèn nó vào chỗ đó.

Dựa trên nguyên tắc này, có thể triển khai một cách sắp xếp như sau:

Thoạt đầu K1 được coi như bảng chỉ gồm có một khoá đã sắp xếp. Xét thêm K2, so sánh nó với K1 để xác định chỗ chèn nó vào, sau đó ta sẽ có một bảng gồm 2 khoá đã được sắp xếp. Đối với K3 lại so sánh với K2, K1 và cứ tương tự như vậy với K4, K5, K6,… cuối cùng sau khi xét xong Kn thì bảng khoá đã được sắp xếp hoàn toàn.

Ta thấy ngay phương pháp này rất thuận lợi khi các khoá của dãy được đưa dần vào miền lưu trữ. Đó cũng chính là không gian nhớ dùng để sắp xếp. Có thể minh hoạ qua bảng sau:

Nhưng nếu các khóa đã có mặt ở bộ nhớ trong trước lúc sắp xếp rồi thì sao ?

Sắp xếp vẫn có thể thực hiện được ngay tại chỗ chứ không phải chuyển sang một miền sắp xếp khác. Lúc đó các khoá cũng lần lượt được xét tới và việc xác định chỗ cho khoá mới vẫn làm tương tự, chỉ có khác là: để dành chỗ cho khoá mới nghĩa là phải dịch chuyển một số khoá lùi lại sau, ta không có sẵn chỗ trống như trường hợp nói trên (vì khoá đang xét và các khoá sẽ được xét đã chiếm các vị trí đằng sau này rồi), do đó phải đưa khoá mới này ra một chỗ nhớ phụ và sẽ đưa vào vị trí thực của nó sau khi đã đẩy các khóa cần thiết lùi lại.

Sau đây là giải thuật ứng với trường hợp này:

Procedure SELECT-SORT(K, n)
For i:=1 to n-1 do
     Begin
         M:=i;
         For j:=i+1 to n do
         If K[j]<K[m] then m:=j;
             If m!= j then
             Begin {đổi chỗ}
                 X:=K[i];
                 K[i]:=K[m];
                 K[m]:=X;
             End
     End
Return;

{Trong thủ tục này người ta dùng X làm ô nhớ phụ để chứa khoá mới đang được xét. Để đảm bảo cho khoá mới trong mọi trường hợp, ngay cả khi vị trí thực của nó là vị trí đầu tiên, đều được chèn vào giữa khóa nhỏ hơn nó và khoá lớn hơn nó, ở đây đưa thêm vào một khoá giả K0, có giá trị nhỏ hơn mọi khoá của bảng, và đứng trước mọi khoá đó. Ta quy ước K0 = – }.

Procedure SELECT-SORT(K, n)
For i:=1 to n-1 do
     Begin
         M:=i;
         For j:=i+1 to n do
         If K[j]<K[m] then m:=j;
             If m!= j then
             Begin {đổi chỗ}
                 X:=K[i];
                 K[i]:=K[m];
                 K[m]:=X;
             End
     End
Return;

{xác định chỗ cho khoá mới được xét và dịch chuyển các khóa cần thiết }

Procedure SELECT-SORT(K, n)
For i:=1 to n-1 do
     Begin
         M:=i;
         For j:=i+1 to n do
         If K[j]<K[m] then m:=j;
             If m!= j then
             Begin {đổi chỗ}
                 X:=K[i];
                 K[i]:=K[m];
                 K[m]:=X;
             End
     End
Return;

{đưa X vào đúng chỗ}

Procedure SELECT-SORT(K, n)
For i:=1 to n-1 do
     Begin
         M:=i;
         For j:=i+1 to n do
         If K[j]<K[m] then m:=j;
             If m!= j then
             Begin {đổi chỗ}
                 X:=K[i];
                 K[i]:=K[m];
                 K[m]:=X;
             End
     End
Return;

Bảng ví dụ minh hoạ tương ứng với các lượt sắp xếp theo giải thuật này, tương tự như bảng đã nêu ở trên, chỉ có khác là không có chỗ nào trống trong miền sắp xếp cả, vì những chỗ đó đang chứa các khoá chưa được xét tới trong mỗi lượt (người đọc có thể tự lập ra bảng minh hoạ này).

3. Sắp xếp kiểu đổi chỗ (exchange sort)

Trong các phương pháp sắp xếp nêu trên, tuy kĩ thuật đổi chỗ đã được sử dụng, nhưng nó chưa trở thành một đặc điểm nổi bật. Bây giờ ta mới xét tới phương pháp mà việc đổi chỗ một cặp khoá kế cận, khi chúng ngược thứ tự, sẽ được thực hiện thường xuyên cho tới khi toàn bộ bảng các khóa đã được sắp xếp. Ý cơ bản có thể nêu như sau:

Bảng các khóa sẽ được duyệt từ đáy lên đỉnh. Dọc đường, nếu gặp hai khoá kế cận ngược thứ tự thì đổi chỗ chúng cho nhau. Như vậy trong lượt đầu khoá có giá trị nhỏ nhất sẽ chuyển dần lên đỉnh. Đến lượt thứ hai khoá có giá trị nhỏ thứ hai sẽ được chuyển lên vị trí thứ hai… Nếu hình dung dãy khoá được đặt thẳng đứng thì sau từng lượt sắp xếp, các giá trị khoá nhỏ sẽ nổi dần lên giống như các bọt nước nổi lên trong nồi nước đang sôi. Vì vậy phương pháp này thường được gọi bằng cái tên khá đặc trưng là: sắp xếp kiểu nổi bọt (bubble sort).

Ví dụ:

Sau đây là giải thuật:

Procedure SELECT-SORT(K, n)
For i:=1 to n-1 do
     Begin
         M:=i;
         For j:=i+1 to n do
         If K[j]<K[m] then m:=j;
             If m!= j then
             Begin {đổi chỗ}
                 X:=K[i];
                 K[i]:=K[m];
                 K[m]:=X;
             End
     End
Return;

Giải thuật này rõ ràng còn có thể cải tiến được nhiều. Chẳng hạn, xét qua ví dụ ở trên ta thấy: sau lượt thứ 3 không phải chỉ có ba khóa 11, 23, 36 vào đúng vị trí sắp xếp của nó mà là 5 khoá. Còn sau lượt thứ 4 thì tất cả các khóa đã nằm đúng vào vị trí của nó rồi. Như vậy nghĩa là năm lượt cuối không có tác dụng gì thêm cả. Từ đó có thể thấy: nếu nhớ được vị trí của khoá được đổi chỗ cuối cùng ở mỗi lượt thì có thể coi đó là giới hạn cho việc xem xét ở lượt sau. Chừng nào mà giới hạn này chính là vị trí thứ n, nghĩa là trong lượt ấy không có một phép đổi chỗ nào nữa thì sắp xếp có thể kết thúc được. Nhận xét này sẽ dẫn tới một giải thuật cải tiến hơn, chắc chắn có thể làm cho số lượt giảm đi và số lượng các phép so sánh trong mỗi lượt cũng giảm đi nữa. Người đọc hãy tự xây dựng giải thuật theo ý cải tiến này.

 (Nguồn: Cấu trúc dữ liệu và giải thuât –

Đỗ Xuân Lôi – NXB Đại học quốc gia Hà Nội).

Bài viết gốc được đăng tải tại Tạp Chí Lập Trình

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

Xem thêm các IT Jobs hấp dẫn tại TopDev

SSH: Sơ lược, một số câu lệnh cơ bản (Phần 1)

SSH: Sơ lược, một số câu lệnh cơ bản (Phần 1)

Khi sử dụng một hệ điều hànhWindows, MacOS, đặc biệt là các hệ điều hành dựa trên nhân Linux như Ubuntu, CentOS,… bạn chắc hẳn đã từng sử dụng terminal để gõ các dòng lệnh cực kỳ ngầu lòi. Tới một ngày, bạn có một con server vừa mua nằm cách xa tận nửa vòng trái đất, làm thế nào bạn có thể truy cập tới và thực thi các câu lệnh, cài đặt các dịch vụ, cấu hình web server,…? Kèm theo đó là việc đảm bảo một kết nối thật an toàn ? SSH chính là thứ mà bạn đang tìm kiếm.

  Cấu hình SSH Key cho Github
  SSH: Sơ lược, một số câu lệnh cơ bản (Phần 1)
Tìm hiểu LDAP, cấu hình xác thực SSH với LDAP”]

1. Sơ lược

Secure Shell (SSH) là một giao thức mạng dùng để thiết lập kết nối mạng một cách bảo mật. SSH tạo ra một kênh kết nối được mã hóa an toàn từ một mạng không an toàn, dựa trên kiến trúc client-server, kết nối 1 SSH-client tới một SSH-server. Port mặc định đuợc sử dụng bởi SSH là 22.

Hay nói đơn giản, SSH giúp bạn có thể yên tâm truy cập tới một máy tính từ xa nhờ vào tính bảo mật của nó !

SSH ra đời như một sự thay thế cho Telnet và các giao thức điều khiển shell thiếu an toàn khác như Berkeley rsh, login và rexec . Các giao thức này trao đổi dữ liệu, mật khẩu dưới dạng plaintext, khiến chúng rất dễ bị phân tích và đánh cắp.

Điểm đặc biệt của SSH là giao thức này sử dụng các thuật toán mã hóa bất đối xứng, đối xứng và hashing để đảm bảo tính bảo mật và toàn vẹn của dữ liệu được trao đổi từ client tới server và ngược lại.

SSH có nhiều cách để xác thực một người dùng, nhưng hai cách thông dụng nhất vẫn là xác thực dựa trên mật khẩu và xác thực public-key.

Xác thực bằng mật khẩu ?

Xác thực dựa trên mật khẩu đơn giản là bạn chỉ việc sử dụng mật khẩu của user bạn tạo để truy cập, server sẽ lưu chúng, và đối chiếu với mật khẩu của bạn khi đăng nhập. Cách này thì không đủ an toàn do bạn có khả năng bị đánh cắp mật khẩu.

Còn xác thực bằng public-key?

Cách này sử dụng một cặp khóa – public-key và private-key – được tạo ra dựa trên thuật toán mã hóa public-key. Cặp khóa sau khi được tạo ra từ một máy tính, ta sẽ lấy public-key lưu vào server, khi truy cập ta sẽ dựa vào private-key lưu trên máy local và đặc tính liên quan mật thiết tới nhau của chúng để thiết lập kết nối. Kiểu xác thực này còn cho cho phép chúng ta thiết lập một kết nối an toàn một cách tự động hóa (automation).

Mô hình đơn giản cách hoạt động (Thực tế có thể phức tạp hơn)Mô hình đơn giản cách hoạt động (thực tế có thể phức tạp hơn).

Vậy thì nó hơn xác thực với mật khẩu chỗ nào ?

Quay lại khi bạn sử dụng mật khẩu, bản năng loài người của bạn trỗi dậy, trí nhớ của chúng ta là có hạn, và bạn sẽ nghĩ ra một mật khẩu sao cho dễ ghi nhớ. Và mật khẩu dễ nhớ thì khả năng cao là bạn sẽ bị đánh cắp bằng một cách nào đó (Brute-force attack, Dictionary attack,… ).

Không những vậy, mật khẩu này còn được bạn sử dụng xuyên suốt từ app này sang app khác ! Nó còn được lưu trên cả server bạn login vào, nên vẫn có thể bị đánh cắp (Man-in-the-middle attack,…). Và rất rất nhiều trường hợp cho thấy việc sử dụng mật khẩu là thiếu an toàn như thế nào.

Còn cặp khóa xác thực thì lại được tạo ra bởi máy tính, máy tính thì không như con người, máy tính sử dụng các thuật toán mã hóa cực kì phức tạp, vượt xa khả năng của con người, để sinh ra khóa. Bản thân các khóa này thì lại vừa dài (vài trăm, vài nghìn bits), vừa to… à không, vừa phức tạp và rất khó để brute-force attack. Hơn nữa, private-key mà bạn giữ không hề được gửi tới server mà bạn chỉ dùng nó để decrypt message được mã hóa từ server gửi về.

Mật khẩu có thể được sử dụng trên nhiều máy khác nhau và do bạn tự lưu trữ, còn private-key thì chỉ được lưu trên thiết bị mà bạn dùng để truy cập, dó đó bạn có thể sử dụng nhiều cặp khóa public-key private-key để truy cập vào các máy tính khác nhau, làm giảm khả năng bị đánh cắp khóa.

Ngoài ra, bạn còn có thể sử dụng thêm passphrase để tăng thêm độ bảo mật !

Các loại thuật toán mã hóa

SSH hỗ trợ nhiều loại thuật toán mã hóa public-key:

  • rsa – thuật toán được sử dụng nhiều nhất, ra đời từ năm 1977 dựa trên sự phức tạp của việc phân tích thừa số nguyên tố. Khi sử dụng nên kèm theo kích thước của khóa ít nhất là 2048 bits, tốt nhất nên là 4096 bits.
  • dsa -thuật toán dựa trên tính phức tạp của việc tính toán logarit rời rạc. Đã bị loại bỏ ở OpenSSH version 7 vì lý do bảo mật.
  • ecdsa – thuật toán dựa trên toạ độ của các điểm dựa trên đường cong Elliptic. Có thể thay thế cho RSA bởi mức an toàn và tốc độ xử lý cao hơn, kèm theo đó là việc sử dụng khoá có độ dài nhỏ hơn so với RSA. Từ đó làm tăng tốc độ xử lý một cách đáng kể. Chỉ hỗ trợ với 3 loại kích thước khóa: 256, 384, and 521 bits. Để an toàn nhất thì nên sử dụng 521 bits !
  • ed25519 – một thuật toán được thêm vào OpenSSH từ version 6.5. Là bản cải tiến của ECDSA, cung cấp bảo khả năng mật tốt hơn với hiệu suất nhanh hơn so với DSA hoặc ECDSA. Chưa thực sự phổ cập trên toàn thế giới.

2. Các câu lệnh cơ bản

Lưu ý: Các câu lệnh ta sẽ thực hiện máy tính cài hệ điều hành Linux (Ubuntu, CentOS,…).

Sau đây, chúng ta sẽ đi vào chi tiết những câu lệnh sẽ sử dụng để kết nối với một server từ xa.

Sử dụng SSH để login với password

Trên máy local của bạn:

ssh your-username@host

Ví dụ:

ssh thong@192.168.58.20

Host ở đây có thể là địa chỉ ip hoặc domain name của máy mà bạn truy cập tới

Sau đó nhập mật khẩu tương ứng với user của bạn ở host đó.

Tạo cặp khóa

Câu lệnh để tạo ra một cặp khóa xác thực SSH.

Câu lệnh đơn giản nhất, trên máy local:

ssh-keygen

Trong lúc generate, hệ thống sẽ yêu cầu bạn cung cấp passphrase. Mục đích sinh ra passphrase là để encrypt private key. Vậy khi một kẻ tấn công biết được private key của bạn cũng chưa chắc có thể sử dụng, vì nó đã bị mã hóa.

Trong thực tế, hầu hết khi tạo khóa SSH người ta thường không sử dụng thêm passphrase. Vì khi gặp vấn đề liên quan tới automation, passphrase này đâu thể đánh bằng tay mà ta phải lưu trong một kho lưu trữ hoặc là trong một đoạn script nào đó. Kết quả là bạn lại quay về xác thực bằng mật khẩu (lol !), kẻ tấn công vẫn có thể biết được passphrase của bạn !

Vậy nên để dễ dàng và thuận tiện bạn cứ nhấn Enter khi tới bước này là được !

Bạn có thể tùy chỉnh thêm các options:

ssh-keygen -f ~/key-name -t ecdsa -b 521

Trong đó:

-f là key name và nơi sẽ lưu trữ key

-t là thuật toán mã hóa để sinh khóa

-b là kích thước khóa

Thêm private-key vào SSH-agent

Trên máy local:

ssh-add /PATH/TO/YOUR/PRIVATE/KEY

ssh-add là câu lệnh để thêm SSH private-keys vào SSH authentication agent, gọi là ssh-agent để quản lý việc truy cập vào các máy tính sử dụng các khóa private. Khi bạn đã thêm khóa vào ssh-agent thì lúc truy cập bạn không cần phải khai báo thêm khóa này.

Phần public của khóa private được lưu vào ssh-agent phải được đặt trong

~/.ssh/authorized_keys (authorized_keys là một file)

ở server (Xem bước bên dưới).

Thêm public-key vào server

Bạn có thể sử dụng một trong hai câu lệnh sau:

Cách 1:

cat ~/.ssh/your-key.pub | ssh username@host "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys"

Cách 2:

ssh-copy-id -i ~/.ssh/your-key.pub username@host

Ngoài ra bạn có thể truy cập trực tiếp vào máy bằng password trước và sau đó thêm key bằng cơm (mkdir, touch, rồi sau đó cat, vim…).

Vậy là bạn đã có thể truy cập vào server thành công sử dụng xác thực khóa trên SSH !

Bạn có cũng thể thêm nhiều key khác nhau vào authorized_keys sử dụng các câu lệnh tương tự như trên.

Test nào:

ssh your-username@host

Loại bỏ xác thực bằng mật khẩu trên server (Chỉ sử dụng SSH keys)

Lưu ý: Chỉ làm bước này sau khi bạn đã cấu hình và thực hiện ssh bằng khóa.

Để tốt nhất và an toàn nhất thì sau khi thêm key vào server, bạn nên loại bỏ xác thực SSH bằng mật khẩu. Lý do thì tôi đã đề cập như trên !

Trên server:

sudo nano /etc/ssh/sshd_config

Tìm dòng

PermitRootLogin yes

Sửa lại thành

PermitRootLogin no

Lưu lại và exit. Sau đó trên terminal:

sudo systemctl restart sshd

3. Kết

Vậy là ta đã đi qua sơ lược về SSH và các câu lệnh cơ bản để thiết lập kết nối giữa hai máy tính. Ở phần sau tôi sẽ đưa ra một vài ví dụ thực tế để bạn có cái nhìn rõ hơn về nó. Cảm ơn các bạn đã theo dõi !

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

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

Xem thêm các việc làm IT Jobs Developer hấp dẫn tại TopDev

Giới thiệu Fetch API trong Javascript

Giới thiệu Fetch API trong Javascript và cú pháp sử dụng

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

fetch() cho phép tạo một network request tương tự như XMLHttpRequest(XHR). Sự khác nhau chủ yếu là Fetch hoạt động theo Promises, cho phép viết gọn ràng, dễ nhớ hơn là XHR. API Fetch có trong window.fetch() giờ đã được hỗ trợ phổ biến, bạn không cần polyfill gì đâu, vĩnh biệt IE. Tạm biệt XMLHttpRequest và cách viết dài dòng, giờ đây ta đã có fetch API.

Fetch API là gì?

Fetch API là một giao diện lập trình trong JavaScript, được sử dụng để thực hiện các yêu cầu HTTP đến các máy chủ web. Đây là một phần của tiêu chuẩn JavaScript ES6 và được tích hợp trực tiếp trong các trình duyệt hiện đại. Fetch JS cung cấp một cách thức đơn giản và mạnh mẽ để thực hiện các thao tác lấy dữ liệu (fetch) từ các nguồn bên ngoài, ví dụ như lấy dữ liệu từ máy chủ hoặc API, đồng thời hỗ trợ các thao tác như GET, POST, PUT, DELETE, v.v.

Điểm mạnh của Fetch fetch Javascript API là nó thay thế cho công nghệ cũ hơn là XMLHttpRequest và cung cấp cú pháp hứa hẹn (Promise-based), giúp lập trình viên quản lý các yêu cầu bất đồng bộ (asynchronous) dễ dàng hơn.

Fetch trong JS sử dụng cú pháp Promise, có nghĩa là nó không chặn (non-blocking), cho phép xử lý các yêu cầu và phản hồi mà không cần phải dừng các thao tác khác của chương trình. Khi thực hiện một yêu cầu HTTP thông qua Fetch API, nó trả về một Promise, và bạn có thể xử lý kết quả của yêu cầu bằng cách sử dụng .then().catch().

Một câu request network bằng fetch

fetch('/api/some-url')
  .then(
    function(response) {
      if (response.status !== 200) {
        console.log('Lỗi, mã lỗi ' + response.status);
        return;
      }
      // parse response data
      response.json().then(data => {
        console.log(data);
      })
    }
  )
  .catch(err => {
    console.log('Error :-S', err)
  });

Response của câu fetch() là một đối tượng Stream, nghĩa là khi chúng ta gọi phương thức json(), một Promise được trả về, vì quá trình đọc stream sẽ diễn ra bất đồng bộ.

  9+ cách để xóa một phần tử ra khỏi JavaScript Array

Response MetaData

Bên cạnh các dữ liệu chúng ta có thể truy cập như trong ví dụ trên, chúng ta có thể truy cập đến các meta data khác

fetch('/api/some-url')
  .then(response => {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url)
  })

response.type

Khi chúng ta tạo một fetch request, response trả về sẽ chứa response.type, với một trong 3 giá trị: basiccorsopaque.

Nó cho biết resource này đến từ đâu, cho chúng ta biết cách chúng ta nên đối xử với object trả về

  • Nếu request lên cùng một nhà (ứng dụng host trên server A gửi request lên API trên server A), response.type sẽ là basic, không có bất kỳ giới hạn việc xem các thông tin trên response.
  • Nếu request dạng CORS, nhà em ở Hồ Chí Mình, em quen bạn gái Hà Nội, type trả về sẽ là cors.cors, lúc đó bên trong header chúng ta chỉ được phép truy cập đến Cache-ControlContent-LanguageContent-TypeExpiresLast-Modified và Pragma
  • Type opaque cho các request tạo ra khác nhà, và thằng server nó không chấp nhận dạng request CORS, ba má cấm chú quen gái Hà Nội, nghĩa là không trả về dữ liệu, không xem được status của request, chia tay tình yêu.

Để khai báo 1 fetch request chỉ resolve khi thỏa điều kiện mode

  • same-origin: các request nhà kế bên sẽ trả về reject
  • cors: cho phép nhà khác nếu header trả về cũng là cors
  • cors-with-forced-preflight luôn thực hiện kiểm tra preflight. Là trước khi gửi đi, để đảm bảo an toàn, tạo một request dùng phương thức OPTIONS để kiểm tra độ an toàn, (nhà anh có điều kiện ko mà đòi quen bạn gái tận Hà Nội xa xôi)
  • no-cors tạo một request không cùng nhà, không trả về CORS

Để khai báo mode

fetch('http://some-site.com/cors-enabled/some.json', {mode, 'cors'})
  .then(function(response) {
    return response.text();
  })
  .then(function(text) {
    console.log('Request successful', text);
  })
  .catch(function(error) {
    log('Request failed', error)
  });
  Crawl dữ liệu bằng JavaScript ngay trên trình duyệt

Liên kết Promise

Một trong những tính năng hay (và sinh ra rắc rối) của Promise là cho phép mắc-xích-các-Promise lại với nhau.

Khi làm việc với JSON API, chúng ta quan tâm đến status và parse JSON trả về, để đơn giản hóa, đưa phần xử lý kiểm tra status và parse này ra hàm riêng. Chúng ta chỉ lo xử lý kết quả cuối cùng và trường hợp có lỗi

function status(response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}
function json(response) {
  return response.json()
}

fetch('')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(function(error) {
    console.log('Request failed', error);
  });

Xem thêm các việc làm JavaScript hấp dẫn tại TopDev

POST Request

Set giá trị method và body để tạo một POST request

fetch(url, {
  method: 'POST',
  headers: {
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
  },
  body: 'foo=bar&lorem=ipsum'
})
.then(json)
.then(data => {
  console.log('Request succeeded with JSON response', data);
})
.catch(error => {
  console.log('Request failed', error);
  });
})

Gửi lên dữ liệu dạng JSON

var data = {username: 'example'};

fetch(url, {
  method: 'POST', 
  body: JSON.stringify(data), 
  headers:{
    'Content-Type': 'application/json'
  }
})
.then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error))

Gửi thông tin xác thực với Fetch

Để gửi kèm thông tin xác thực cookie (user là ai), chúng ta truyền tham số credentials: include

fetch(url, {
  credentials: 'include'
})

Nếu muốn gửi credentials khi request URL là cùng nhà*, truyền giá trị same-origin

fetch(url, {
  crendentials: 'same-origin'
})Không cho

Không cho trình duyệt gửi thông tin xác thực, dùng omit

fetch(url, {
  crendentials: 'omit'
})

Upload file

Sử dụng cùng <input type='file' />FormData()

var formData = new FormData();
var fileField = document.querySelector("input[type='file']");

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.then(response => console.log('Success:', JSON.stringify(response)));
.catch(error => console.error('Error:', error))

Upload nhiều file

var formData = new FormData();
var photos = document.querySelector("input[type='file'][multiple]");

formData.append('title', 'My Vegas Vacation');
formData.append('photos', photos.files);

fetch('https://example.com/posts', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));

Kết luận

Fetch API là một công cụ mạnh mẽ và hiện đại giúp các lập trình viên thực hiện các yêu cầu HTTP một cách đơn giản và hiệu quả. Với cú pháp dựa trên Promise, Fetch API Javascript giúp mã nguồn trở nên dễ đọc hơn và phù hợp với các ứng dụng JavaScript hiện đại. Khi xây dựng các ứng dụng web, đặc biệt là khi làm việc với API hoặc các dịch vụ bên ngoài, Fetch API JS là lựa chọn tối ưu để lấy dữ liệu hoặc gửi dữ liệu từ/đến máy chủ.

Link bài viết gốc

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

Xem thêm các việc làm IT hấp dẫn tại TopDev

Debug và khắc phục lỗi hiển thị ký tự Unicode của ứng dụng Web

Debug và khắc phục lỗi hiển thị ký tự Unicode của ứng dụng Web

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

Tác giả: Nguyễn Bình Sơn

Bài viết này ngầm định rằng bạn biết “bảng mã” nghĩa là gì, và bạn quen thuộc với các thành phần của mô hình ứng dụng web cũng như mô hình trình diễn MVC. Mặc dù mã ở đây được trình bày dưới dạng thức của ngôn ngữ Java, framework Spring MVC và database MySQL, các vấn đề được nhắc đến là chung, các khái niệm được nhắc đến là phổ biến, và các cách giải quyết là tổng quát. Hãy cùng tìm hiểu về Debug và khắc phục lỗi hiển thị ký tự Unicode của ứng dụng Web nhé!

  Debug và khắc phục lỗi hiển thị ký tự Unicode của ứng dụng Web
”]

  Một số tip debug trong Laravel

Model mang dữ liệu Unicode nhưng View thì không

Bạn có model như thế này.

Nhưng bạn nhận được kết quả như thế này:

Là vì View của bạn có nội dung như thế này:

CREATE DATABASE IF NOT EXISTS cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Bạn cần làm cho view engine render cho bạn một view mà trong đó các ký tự unicode của template và model được bảo toàn. Ví dụ sau đây là cấu hình cho view engine Thymeleaf.

@Bean
public ViewResolver viewResolver() {
    // ...
    viewResolver.setCharacterEncoding("UTF-8");
    return viewResolver;
}

Template mang ký tự Unicode nhưng View thì không

Bạn có view template như thế này:

<tr>
  <td>Tên</td>
  <td>
    <input type="text" name="name" th:value="${customer.name}">
  </td>
</tr>
<tr>
  <td>Email</td>
  <td>
    <input type="text" name="email" th:value="${customer.email}">
  </td>
</tr>
<tr>
  <td>Địa chỉ</td>
  <td>
    <input type="text" name="address" th:value="${customer.address}">
  </td>
</tr>

Nhưng bạn nhận được view như thế này:

Nếu bạn đã xử lý vấn đề encoding trong lúc render như ở trên rồi, thì có thể vấn đề là do template resorver đã dùng một encoding khác để đọc tài liệu template. Hãy cấu hình lại cho cả template resolver nữa.

@Bean
public ITemplateResolver templateResolver() {
    // ...
    templateResolver.setCharacterEncoding("UTF-8");
    return templateResolver;
}

Không thể chuyển tải ký tự Unicode qua tầng giao vận

Giả sử cần submit form sau:

Tầng giao vận TCP/IP không quan tâm với bảng mã, nó đơn giản và vận chuyển gói tin, từng byte một. Phần lớn web server, trừ khi là web server do bạn tự viết, decode các bytes này để có các parametter theo lối như thể rằng các bytes đó trước kia là ký tự của bảng mã ISO-8859–1. Nếu bạn nhìn các ký tự đã được decode ra dưới con mắt của bảng mã UTF-8 (trớ trêu rằng, phần lớn các ngôn ngữ lập trình làm như thế), bạn sẽ nhận được kết quả không mong muốn.

Cách xử lý luôn luôn là encode chuỗi ký tự ngược lại thành dòng bytes (theo bảng mã ISO-8859–1, tất nhiên), và sau đó decode lại theo bảng mã UTF-8. Cho dù là thủ công như sau:

public String createCustomer(Customer customer) {
    try {
        byte[] bytes = customer.getName().getBytes("ISO-8859-1");
        String decodedName = new String(bytes, "UTF-8");
        customer.setName(decodedName);
        customerService.save(customer);
        return "redirect:/customers";
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        return "500";
    }
}

… hay tự động, bằng cách sử dụng filter, như sau chẳng hạn:

public class AppInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    // ...    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        FilterRegistration.Dynamic filterRegistration =
            servletContext.addFilter("endcoding-filter", new CharacterEncodingFilter());
        filterRegistration.setInitParameter("encoding", "UTF-8");
        filterRegistration.setInitParameter("forceEncoding", "true");
        
        //make sure encodingFilter is matched most first, by "false" arg
        filterRegistration.addMappingForUrlPatterns(null, false, "/*");
        
        super.onStartup(servletContext);
    }
}

Entity mang thông tin Unicode, vào đến Database thì mất dấu

Bạn có form như thế này:

Entity ngon nghẻ như thế này:

Vào tới database thì loạn cào cào hết cả:

Hầu hết các client của các dbms, khi kết nối tới dbms server, đều chọn mặc định một bảng mã để làm việc với nhau. “Mặc định” này đôi khi là một giá trị cố định, đôi khi là lấy dynamic. Dù là trường hợp nào đi chăng nữa, đôi khi charset đó hoàn toàn khác với charset được dùng cho Schema/Table/Column. Nghĩa là “anh nói tiếng của anh, nhưng tôi hiểu theo tiếng của tôi”.

Cách xử lý luôn là cố định lại bảng mã dùng trong cuộc nói chuyện giữa client và dbms server:

CREATE DATABASE IF NOT EXISTS cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Và đồng thời (điều này rất quan trọng), sử dụng cùng một bảng mã đó cho Schema/Table/Column:

CREATE DATABASE IF NOT EXISTS cms CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Nếu database cùng với dữ liệu đã tồn tại, theo một bảng mã khác, cách xử lý luôn là sử dụng một kỹ thuật nào đó được dbms hỗ trợ để convert dữ liệu từ bảng mã cũ sang bảng mã mong muốn.

Bài viết gốc được đăng tải tại Tạp Chí Lập Trình

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

Xem thêm các  IT Jobs for Developer hấp dẫn tại TopDev

Tìm việc làm IT mùa dịch không hề khó như bạn nghĩ

tam viec lam

Tình hình doanh nghiệp

Tim viec lam mùa dịch là việc không hề dễ dàng vì dịch đã làm ảnh hưởng nặng nề rất nhiều đến việc kinh doanh của nhiều công ty, dù là thời điểm trong dịch hay hiện giờ thì cũng có khá nhiều công ty trong và ngoài nước cắt giảm nhân sự. Chính vì vậy, cơ hội tìm kiếm việc làm của người lao động thông thường khá khó khăn. Tuy nhiên đối với những ngành nghề đặc thù liên quan đến công nghệ như IT thì lại không bị ảnh hưởng quá nhiều, và các kỹ sư kỹ thuật có tỷ lệ % bị cắt giảm nhân sự rất thấp.

Doanh nghiệp về du lịch là bị ảnh hưởng nhiều nhất, rất nhiều công ty du lịch đóng cửa vì không có khách du lịch. Ngoài ra các ngày liên quan đến sản xuất như may mặc ở các xí nghiệp cũng bị ảnh hưởng nặng nề và buộc phải cắt giảm rất nhiều nhân viên

Dù là sau dịch như hiện tại thì nhu cầu tuyển dụng cũng không nhiều, rất nhiều công ty phải đóng băng hoặc phá sản, hàng quán thì trả mặt bằng, bán nhà trong khi đó nhu cầu tim viec lam thì lại tăng… Theo thống kê, gần 8 triệu người mất việc, nghỉ việc luân phiên do Covid-19, trong đó số người bị ảnh hưởng do giảm thu nhập lên tới hơn 17 triệu người. 

tim viec lam

Đó là tình hình không mấy lạc quan đối với những xí nghiệp sản xuất, tiêu thụ thông thường. Còn các ngành công nghiệp hiện đại có liên quan đến công nghệ thì vẫn có nhu cầu cấp thiết đối với nguồn lực công nghệ, từ duy trì cơ sở hạ tầng đám mây cho đến thiết kế các trang thương mại điện tử. Việc hạn chế những nơi đông người và tăng cường mua sắm trực tuyến khiến các doanh nghiệp chuyển đổi hành vi mua sắm tại điểm bán sang đẩy mạnh phát triển các nền tảng mua sắm online, dẫn đến nhu cầu tuyển dụng IT, lập trình viên hay các vị trí liên quan đến phát triển thương mại điện tử tăng cao. 

Lấy ví dụ như các vị trí lập trình viên như System Engineer, Developer hay Technical Product… đều đóng vai trò quan trọng trong các công ty Startup, công ty thiên về công nghệ, sàn thương mại điện tử, các vị trí đó được đăng tuyển khá nhiều để có thể hỗ trợ, điều chỉnh cho tình hình mua sắm tại nhà như hiện nay. 

Các kỹ sư công nghệ trở nên quan trọng hơn bao giờ hết khi Việt Nam và thế giới đang đối đầu với dịch bệnh. Ngành lập trình viên vẫn hoạt động và phát triển rất tốt như chưa hề có dịch Covid.

Không những thế, thậm chí trong tình hình dịch bệnh như thế này nhưng ngành lập trình vẫn còn đang thiếu hụt nhân sự vì nhu cầu nhân sự, nhu cầu tim viec lam của các lập trình viên thì vẫn có. Tuy nhiên, trong tình hình dịch ứng viên lại ngại các cuộc phỏng vấn trực tiếp sẽ là nguyên nhân gây lây nhiễm dịch bệnh. 

tim viec lam

Giải pháp tim viec lam mùa dịch

Vì để tránh tình trạng thiếu hụt nhân sự công nghệ, nhiều doanh nghiệp đưa ra giải pháp phỏng vấn online để có thể dễ dàng tiếp cận ứng viên hơn trong tình hình dịch bệnh như hiện nay. Ứng viên chỉ cần gửi so yeu ly lich kèm cv tiếng Việt hoặc cv tieng anh tùy vào yêu cầu của công ty ứng tuyển. Sau đó, nếu cv của ứng viên có thể lọt vào mắt xanh của nhà tuyển dụng nào đó thì sẽ nhận được mail mời phỏng vấn online.

Điểm thuận lợi của phỏng vấn online là có thể giúp cả đôi bên tiết kiệm thời gian, thời gian hẹn phỏng vấn cũng sẽ linh hoạt hơn vì không cần phải chuẩn bị quá nhiều thứ như khi gặp mặt nhau. Bên cạnh đó, ứng viên cũng có thể chủ động chọn lựa vị trí thuận tiện nhất để có cuộc phỏng vấn với nhà tuyển dụng mà không phải đi ra ngoài, chỉ cần nơi phỏng vấn của ứng viên chọn có wifi mạnh, backgound sáng sủa, gọn gàng.

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

  CEO TopDev ra mắt công nghệ AI/Computer Vision trợ giúp kết nối doanh nghiệp với người mất việc vì Covid

  Các công ty công nghệ Việt Nam và thách thức trong việc chuyển mình thời Covid - 19

  Tái tuyển dụng IT hiệu quả? Thách thức và cơ hội cho các công ty hậu Covid-19

 

Xem thêm Top IT Jobs lương cao trên TopDev

Mẫu CV xin việc Free cho các bạn IT

cv online

Với nhiều năm hoạt động trong ngành tuyển dụng lập trình viên TopDev tự tin rằng có thể cung cấp cho các bạn IT mẫu cv online chuẩn đẹp, free và đặc biệt là phù hợp nhu cầu ứng tuyển các vị trí khác nhau trong ngành lập trình.

Tại sao cần viết cv online?

Để có thể sở hữu được một bản cv online hoàn hảo, đầu tiên bạn cần hiểu được CV là gì và nó có ý nghĩa gì trong việc xin việc làm. Có thể hiểu nôm na CV là một bản tóm tắt sơ lược những công việc mà bạn đã làm qua, một bản CV luôn thể hiện được cho người đọc kinh nghiệm làm việc, học vấn, trình độ cá nhân…

Trước đây, khi công nghệ và nhu cầu tìm việc qua mạng còn ít thì những bản CV thường được viết tay hoặc đánh máy trên nền giấy A4. Sau này hiện đại hơn 1 tí thì có thể tạo CV bằng powerpoint, tuy nhiên khi bạn tự tạo CV thì sẽ mất khá nhiều thời gian vào nó, đặc biệt là những CV tự tạo đôi khi sẽ không được thẩm mỹ vì trình độ powerpoint của bạn có hạn, điều này sẽ gây ra ấn tượng xấu với nhà tuyển dụng.

Chính vì thấu hiểu những điều đó nên hiện nay có rất nhiều nền tảng cung cấp mẫu CV trên mạng với mẫu cv đa dạng, chỉnh chu hơn để hỗ trợ ứng viên tìm việc. Tuy nhiên điểm yếu của các mẫu CV này là sau khi hoàn thành xong phải tải về máy ngay, đôi khi muốn chỉnh sửa hay bổ sung một chi tiết nào đó thì phải làm lại từ đầu và tải lại thêm lần nữa, điều này rất phiền phức và làm rối tung folder của bạn.

  Cách viết CV giúp lập trình viên ghi điểm với nhà tuyển dụng

  5 mẹo và mẫu CV IT để gây ấn tượng với nhà tuyển dụng!

Mẫu CV online ra đời để giảm thiểu những khó khăn đó. Làm cv online sẽ giảm thiểu được tình trạng thường xuyên phải tải file về và việc sửa chữa cũng đơn giản tiện dụng hơn vì bạn chỉ cần điền theo form mẫu có sẵn cho từng ngành nghề. Bên cạnh đó các mẫu template CV onl hiện nay cũng rất đẹp, được các trang web đầu tư chỉnh chu, đặc biệt là các mẫu CV này hoàn toàn free ở 1 số mẫu và web. Ví dụ ở topcv thì free những mẫu cơ bản, cao cấp, đa dạng nhóm ngành…còn những mẫu chuyên nghiệp thì chỉ có tài khoản VIP được nạp tiền vào thì mới sử dụng được. Ở TopDev thì được tạo CV online free hoàn toàn và điểm mạnh ở TopDev là những mẫu CV này được thiết dựa theo form đơn xin việc chuyên biệt dành cho dân lập trình.

  Tổng hợp một số mẫu CV đẹp mắt dành cho lập trình viên

  Top 5 website giúp thiết kế CV chuẩn format, đủ nội dung

Viết cv online thu hút nhà tuyển dụng

Khi bắt tay vào viết CV onl thì bạn nên chú ý điền đầy đủ thông tin cần điền bên phần thông tin cá nhân như hình ảnh, số điện thoại, mail… Tiếp theo mới bắt đầu điền các thông tin về kinh nghiệm làm việc có liên quan đến vị trí đang muốn ứng tuyển. Tất cả bạn chỉ cần điền theo form có sẵn, thêm bớt các thông tin sao cho CV của bạn trở nên thật hoàn hảo nhé! Ngoài ra nếu bạn muốn ver cv bằng tiếng anh thì hãy chọn từ đầu nhé.

Ngoài ra bạn cũng có thể điều chỉnh font chữ, size trên đó, vì vây hãy chắc chắn rằng font chữ của bạn đồng nhất. Bạn cũng nên kiểm tra lại lỗi chính tả trong CV online của bạn, đừng liệt kê quá nhiều sở thích cá nhân vì nhà tuyển dụng sẽ không quan tâm đến những điều đó và nếu liệt ra ra quá nhiều sở thích không cần thiết thì sẽ làm CV của bạn rối nùi.

Một mẹo nhỏ nữa để làm cv online của bạn được nhà tuyển dụng lựa chọn là bạn nên trung thực, đừng vì quá tham mà liệt kê những kỹ năng cũng như kiến thức bạn chưa bao giờ làm qua. Đúng là 1 nhân viên giỏi, biết nhiều thứ thì ai cũng thích nhưng nổ quá cái gì cũng biết từ sale đến design, marketing, lập trình cái nào cũng biết thì sẽ được đặt dấu chấm hỏi! Nguy hiểm hơn là nhà tuyển dụng còn nghĩ bạn viết dối chỉ để được phỏng vấn nên sẽ loại bạn ngay từ vòng lọc CV Online.

Tạo CV IT online, chuẩn ATS miễn phí trên TopDev

Thêm một điều nên nhớ nữa là bạn không nên dùng 1 CV cho tất cả ngành nghề, mỗi ngành khác nhau sẽ cần những kinh nghiệm công việc khác nhau. Ví dụ như mẫu CV dành cho dân lập trình viên rất đặc thù vì cần phải có thiết kế phù hợp để show ra được những đường link dự án sao cho thật bắt mắt, điều đó khác hẳn so với những CV của dân sale hay marketing….

Nhìn chung, việc viết cv không còn là nỗi ám ảnh khi đi xin việc nữa vì hiện nay ứng viên đã được hỗ trợ rất nhiều từ các template CV online của các trang web tìm việc. Việc duy nhất các ứng viên cần quan tâm đó là chọn cho mình 1 mẫu CV phù hợp với ngành và trang bị kiến thức thật vững vàng trước khi đi gặp nhà tuyển dụng.

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

Xem thêm Top Việc làm IT trên TopDev

6 ví dụ để bạn yêu luôn observable

6-vi-du-de-ban-yeu-luon-observable
Bài viết được sự cho phép của tác giả Lưu Bình An

Thêm những lý do để dụ dỗ bạn xài Observable

Observable mình dịch ra tiếng việt thế này cho bạn dễ hình dung. Một khi bạn bật chế độ observable với một đứa con gái nào đó, là bạn đang trong giai đoạn bị nó ám ảnh, nhất cử nhất động của nó bạn điều để ý, nó hắc xì bạn cũng biết, một tuần nó mặc mấy bộ đồ bạn cũng biết. Chỉ cần nghe tiếng bước chân là bạn biết được hôm nay nó mang đôi dép gì (mức độ này hơi kinh khủng lắm rồi) là bạn có những phản xạ vô điều kiện bộc phát nơi cửa miệng “Chiều nay trời mưa nhe em, mang dép lào đi cho chuẩn”. Phản xạ này là gọi là subscription

Rồi quay lại với vấn đề kỹ thuật, bài này không giải thích rõ Observable pattern, các khái niệm chính của nó, nếu muốn bạn đọc lại bài này trước đây có viết rồi, như cái tựa bài viết nó spoil hết cái nội dung rồi “Ví dụ để thấy tại sao chúng ta nên bật chế độ Observable với một em gái nào đó”

Thần chú mình muốn bạn thuộc lầu

Lập trình Reactive là làm việc với luồng dữ liệu bất đồng bộ

Lại phải giải thích câu này chút, Nếu những gì diễn ra trên ứng dụng đang xảy ra một cách bất đồng bộ, khả năng rất cao là Observable sẽ giúp ích cho cuộc sống của anh em chúng ta bớt khổ hơn.

Có nhiều cách làm và thư viện handle vụ luồng dữ liệu bất đồng bộ này, tuy nhiên, Observable có gì mà cool, sắp được chuẩn hóa và đưa vào ECMAScript. Thư viện RxJS đang được sử dụng rộng rãi và quá ngon rồi.

Rồi vô luôn ví dụ nhe

Handle các event bằng Observable

Chúng ta có 1 button, khi button này click tạo ra một chuỗi ngẫu nhiên. Viết bằng cả 2 cách javascript thuần, và sử dụng RxJS

const button = document.querySelector('button');
const output = document.querySelector('output');

button.addEventListener('click', e => {
    output.textContent = Math.random().toString(36).slice(2);
})

Bằng RxJS nè

const button = document.querySelector('button');
const output = document.querySelector('output');

Rx.Observable
    .fromEvent(button, 'click')
    .subscribe(() => {
        output.textContent = Math.random().toString(36).slice(3);
    })

Nó dài hơn khi viết javascript thuần mà man 😂. Chi mà phức tạp vậy? Đúng luôn, nhưng giờ thêm yêu cầu này vào thì sao: Ở mỗi lần click đến bội số của 3 ( 3,6,9,12,…) thì mới random một string mới

Rx.Observable
    .fromEvent(button, 'click')
    .bufferCount(3) // một dòng duy nhất
    .subscribe(() => {
        output.textContent = Math.random().toString(36).slice(3);
    })

Vậy bạn viết JS thôi thì sao, khỏi nói cũng biết nó sẽ dài dòng hơn.

Operator, operator

Trong ví dụ trên, .bufferCount *đã cho thấy sức mạnh vượt trội** so với cách thông thường. Có thể nói thế này, chúng ta xài Observable này là vì những gì chúng ta làm được bằng operator. Trong thư viện RxJS nó cả tá Operator tha hồ mà chơi.

Một ví dụ khác, cũng là vụ random string ở trên, mà giờ chỉ muốn random khi nó là một cú triple click (một phát 3 nháy, không phải double click nhoa)

const click$ = Rx.Observable.fromEvent(button, 'click');

click$.Observable
    .bufferWhen(() => {
        click$.delay(400);
        // kkhoảng thời gian của một cú 3 click
    })
    .filter(events => events.length >= 3)
    .subscribe(() => {
        output.textContent = Math.random().toString(36).slice(3);
    })

DỊch ra ngôn ngữ con người nó sẽ như thế này, trong khoảng thời gian là 400ms, trong đám event được emit (tụi này được đưa vào mảng events), nếu mảng này lớn hơn hoặc bằng 3, thực hiện đống việc đã đăng ký bên dưới subscribe

Bạn đã bắt đầu yêu Observable chưa? Mình đã khoái khoái rồi đó.

Ai có thể là Observable

Đơn giản, bất kể già trẻ lớn bé, trai gái, nếu RxJS có hàm ( khi nãy là .fromEvent) thì chúng ta có thể biến nó thành đối tượng bị theo dõi liên tục.

Observable cho các HTTP request

Một sức mạnh siêu nhiên khác của RxJS: xử lý mấy em HTTP request rất mượt mà

Ví dụ, fetching một danh sách album và render.

const albumsApiUrl = 'https://jsonplaceholder.typicode.com/albums';

Rx.Observable
    .ajax(albumsApiUrl)
    .subscribe(
        res => console.log(res),
        err => console.log(err)
    )

Trộn chung với ví dụ ở trên, chúng ta làm cái tính năng awsome sau, click là có danh sách album ngẫu nhiên

Rx.Observable
    .fromEvent(button, 'click')
    .flatMap(getAlbums)
    .subscribe(
        render,
        err => console.error(err)
    )

function getAlbums() {
    const userId = Math.round(Math.random() * 10);
    return Rx.Observable.ajax(
        `https://jsonplaceholder.typicode.com/albums?userId=${userId}`
        )
}

Ví dụ trên có sử dụng operator flatMap, 1 trong những operator siêu kinh điển của RxJS, cho phép merge 2 mảng kiểu Observable thành 1

Nếu chúng ta click liên tục trong thời gian ngắn, là có vấn đề, re-render nhiều lần, chúng ta cũng ko xác định được request nào được resolve cuối cùng. Cụ thể là thế này, có thể thằng xuất phát trước lại về đích sau cùng, chuyện của network ai mà biết được thời điểm đó nó download film gì làm chậm mạng, thằng request sau có khi lại về đích trước, như vậy thì dùng cục response lúc nào để render, mình muốn response của thằng request cuối cùng.

Bạn muốn, trong công cuộc tán gái, đứa nào ở lại đến giây phút cuối cùng là đứa chiến thắng, bạn sẽ dẹp luôn những đứa nào thả thính trước đó? Ví von như vậy cũng chưa chuẩn, phải là đứa nào đến sau cùng thì dữ lại, dẹp mẹ tụi tới trước (thế này thì bất công vl mấy bạn)

RxJS làm được chuyện đó không? Có chứ, mọi thứ đã có operator, chuyển qua dùng switchMap, sẽ chỉ có response cuối cùng được render, mấy request trước đó sẽ bị cancel hết

Rx.Observable
    .fromEvent(button, 'click')
    .switchMap(getAlbums)
    .subscribe(
        render,
        err => console.error(err)
    )

Kết hợp các Observable

Một use case khác mà chúng ta gặp hoài. Chức năng filter hoạt động như sau: cho tụi user nhập vào user id bằng <input />, và chọn thể loại âm nhạc nó muốn bằng <select />. Điều quan trọng là chỉ tạo request mới khi cả 2 giá trị trong đó điều có dữ liệu, và re-render khi một trong 2 giá trị này bị thay đổi.

Tạo Observable trước nhé

const id$ = Rx.Observable
    .fromEvent(input, 'input')
    .map(e => e.target.value)

const resource$ = Rx.Observable
    .fromEvent(select, 'change')
    .map(e => e.target.value)

Chúng ta phải hợp thể 2 thằng trên vào một, để khi một trong 2 thằng có thay đổi chúng ta lấy được giá trị sau cùng của cả 2. mọi thứ đã có operator, nhiều lắm, ở đây dùng combineLatest

Rx.Observable
    .combineLatest(id$, resource$)
    .switchMap(getResource)
    .subscribe(render)

Kết

Bạn đã thấy sử dụng Observable thú vị dường nào chưa? Nếu câu trả lời là “Có ❤️, trọn đời yêu em”, bạn hãy nhào vô document của nó để nghiên cứu chuyên sâu hơn.

Nếu câu trả lời là “No 💩, anh éo care mấy đứa ạ”. Thì bạn cũng nên bớt bớt đối xử tệ với nó đi, vì trong tương lai JS sẽ đưa nào vào như một object chính thức luôn, không chạy đằng trời được đâu các bạn ạ.

Hy vọng anh em hôm nay đã học thêm được cái gì đó thú vị, hẹn gặp lại anh em vào một viết thú vị khác.

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

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

Xem thêm các việc làm JavaScript hấp dẫn tại TopDev

Dùng Px, Em hay Rem để viết media query

Dùng Px, Em hay Rem để viết media query
Bài viết được sự cho phép của tác giả Lưu Bình An
Khi viết media query, bạn có bao giờ thắc mắc nên dùng đơn vị nào: px, em hay rem? Các bạn đọc bài này mình mặc định bạn đã phân biệt được sự khác nhau giữa em và rem

Setup để thử nghiệm

Chúng ta sẽ dùng 3 div tô 3 màu khác nhau để thấy được kết quả dễ dàng

.pixel { background: red; }
.em { background: green; }
.rem { background: blue; }

Chúng ta viết query min-width trên 3 element này, thay đổi opacity để thấy được khi nào css này được áp dụng

.pixel {
	background: red;
	@media (min-width: 400px) {
		opacity: .5
	}
}

Chúng ta sẽ đặt font-size cho html là 16px = 1em = 1rem. Như vậy 400px = 25em = 25rem

.em {
  background: green;  
  @media (min-width: 25em) {
    opacity: 0.5
  }
}

.rem {
  background: blue;  
  @media (min-width: 25rem) {
    opacity: 0.5
  }
}

Tất cả đều được trigger ở chính xác kích thước 400px

Dùng Px, Em hay Rem để viết media query

  Tối ưu hóa việc thực thi query trong MYSQL
  Những gợi ý sử dụng jQuery bạn nên biết

Thay đổi font size ở HTML

Trường hợp phổ biến nhất chúng ta hay gặp là thay đổi font-size trên HTML

html {
	font-size: 200%;
}

Khi thay đổi font-size lên 200%, nghĩa là 1em = 1rem = 32px. Nếu sự thay đổi font-size này tác động lên em và rem, chúng ta sẽ thấy 2 element bên dưới trigger ở 800px

Kết quả trên Chrome, Firefox và IE11, cả 3 thằng đều trigger ở 400px

Dùng Px, Em hay Rem để viết media query

Nếu chạy đúng, em và rem không nên bị ảnh hưởng bởi thay đổi font-size trên HTML, nó chỉ được phụ thuộc vào font-size mặc định của trình duyệt.

Tuy nhiên, trên Safari lại cho kết quả không như mong đợi, nó trigger ở 800px

Dùng Px, Em hay Rem để viết media query

Với kết quả này chúng ta có thể bỏ qua việc sử dụng rem với media query vì nó ko đảm bảo chạy đúng trên mọi trình duyệt.

Tuy nhiên, các thí nghiệm bên dưới chúng ta vẫn đưa rem vào cho vui!

User gọi Zoom In

Đây cũng là tình huống thường thấy, chữ quá nhỏ, user có xu hướng zoom to lên xem.

Nguyên nhân chính có đơn vị em là vì các trình duyệt cũ không thể update giá trị pixel khi user gọi zoom

Trên Chrome, Firefox và IE, pxemrem xảy ra cùng lúc

Dùng Px, Em hay Rem để viết media query

Và đương nhiên Safari tiếp tục không giống ai

Dùng Px, Em hay Rem để viết media query

Điều này có nghĩa là, đơn vị pixel không đúng trên mọi browser, bạn nên dừng sử dụng pixel trong câu media query, trừ khi bạn thuộc kiểu sống bất chấp sự tồn tại của safari

User thay đổi giá trị font mặc định của trình duyệt

Rất nhiều developer tin rằng user chả đứa nào thay đổi font size mặc định của trình duyệt, tìm cái thiết đặt này trong trình duyệt đã đủ khó khăn làm user nản chí

Tuy nhiên đó là niềm tin không có căn cứ, không có dữ liệu chứng minh được, user vẫn có thể google tìm cách thay đổi font size mặc định của trình duyệt, đặc biệt các thanh niên bị cận như mình.

Nếu chưa biết cách thay đổi font-size mặc định của trình duyệt, mình chỉ cho

Chrome: Settings > Show advanced settings > Web content Firefox: preferences > content > fonts and colors IE: page > text-size

Safari thì mình chưa biết thay đổi font-size của nó bằng cách nào.

Dùng Px, Em hay Rem để viết media query

Như có thể thấy, câu query dùng px trigger sớm hơn em và rem

Cái này không phải là bug, vì px là đơn vị chính xác đến từng pixel!!! Nó chỉ cần biết kích thước độ rộng màn hình, không liên quan họ hàng gì tới font-size

Ngược lại 2 đơn vị rem và em phụ thuộc hoàn toàn vào font-size của trình duyệt

Chúng ta phải nói lời chia tay với pixel khi viết media query

Ví dụ bạn setup để màn hình dưới 600px có một cột, ngược lại có 2 cột. Mọi thứ đẹp nếu font size là 16px, tuy nhiên nếu user đổi font size thành 20px và xem ở màn hình 650px. Đơn vị rem và em sẽ cho ra giao diện 1 cột, trong khi pixel vẫn lì lợm 2 cột bất chấp cái font chữ giờ đã to đùng.

Kết luận

Đơn vị cho kết quả chấp nhận được ở mọi tình huống là em

Nếu từng thắc mắc khi đang dùng một thư viện nào đó, như bootstrap, tại sao nó lại dùng đơn vị em trong câu media query, thì giờ bạn đã có câu trả lời rồi đó.

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

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

Xem thêm các IT Jobs for Developer hấp dẫn tại TopDev

Những ứng dụng tuyệt vời của Renderless component trong Vue

Những ứng dụng tuyệt vời của Renderless component trong Vue
Bài viết được sự cho phép của tác giả Lưu Bình An
Để tái sử dụng component trong Vue mà không biết tới slot thì quá thiếu sót. Một vài ví dụ để bạn sử dụng slot nhiều hơn.
  Tạo web siêu dễ với VuePress và Github Pages
  Viết Unit Test cho Vue component cho người mới bắt đầu

Slot

Slot trong vue là dạng “đặt gạch” trong component, sau này khi sử dụng ta có thể đưa nội dung khác vào những vị trí đã đặt gạch

Vue không chỉ có thể đặt một mà đặt nhiều gạch, số lượng tùy thích, viên gạch đó được Vue gọi tên là slot

<!-- mother.vue --> Mẹ đặt gạch 2 chỗ header và body cho con nha
<template>
  <div class="card">
    <div class="card-header">
      <slot name="header"></slot>
    </div>
    <div class="card-body">
      <slot name="body"></slot>
    </div>
  </div>
</template>
<!-- con.vue: Cho con dùng 2 chỗ header và body bằng nội dung mới nhé-->
<mother>
	<template #header>
	  <h1>Special Features</h1>
	</template>
	<template #body>
		<div>
		    <h5>Fish and Chips</h5>
		    <p>Super delicious tbh.</p>
		</div>
	</template>
</mother>

Đây là những viên gạch có đặt tên <slot name="header"/>, có một viên gạch không cần đặt tên, chỉ cần <slot />, khi đó component ném gạch sẽ được viết

<mother>
  Toàn bộ phần này nằm trong slot không đặt tên
</mother>

Slot scope

Đề truyền dữ liệu từ mẹ sang con, chúng ta bind dữ liệu muốn truyền qua slot <slot :ten-bien="du-lieu"/>

<!-- mother.vue -->
<template>
  <div class="card">
    <div class="card-header">
      <slot name="header" :close="close"></slot>
    </div>
    <div class="card-body">
      <slot name="body"></slot>
    </div>
  </div>
</template>

Component con sẽ nhận dữ liệu thông qua từ khóa slot-scope

<!-- con.vue-->
<mother>
	<template #header slot-scope="{close}">
		<h1>{{ close ? ‘Closed’ : ‘Open’ }}</h1>
	</template>
	<template #body>
		<div slot="body">
		  <h5>Fish and Chips</h5>
		  <p>Super delicious tbh.</p>
		</div>
	</template>
</mother>

Sử dụng làm modal

Lấy structure của bootstrap nhé, chúng ta sẽ cho Modal component có 3 chỗ có thể thay đổi là

  • <slot name="header" />
  • <slot name="body" />
  • <slot name="footer" />
<!-- my-modal.vue -->
<template>
<div class="modal" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <slot name="header"></slot>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">×</span>
        </button>
      </div>
      <div class="modal-body">
        <slot name="body"></slot>
      </div>
      <div class="modal-footer">
        <slot name="footer"></slot>
      </div>
    </div>
  </div>
</div>
</template>

Với 3 cục gạch đã đặt sẵn trong my-modal.vue,

<template>
  <my-modal>
    <!-- kiểu viết tắt của `v-slot` là # -->
    <template #header>
      <h5>Awesome Interruption!</h5>
    </template>
    <template #body>
      <p>Say something....</p>
    </template>
    <template #footer>
      <em>Ahihi</em>
    </template>
  </my-modal>
</template>

Bổ sung thêm một tính năng năng nữa cho component <my-modal/>, mặc định khi click nút close, nó sẽ gọi đến hàm close bên trong component <my-modal/>, chúng ta dùng scope slot để thằng con có thể truyền vào một function khác, đè lên function nhận được (tức không gọi hàm closeModal bên trong <my-modal/>)

<!-- my-modal.vue -->
<template>
<div class="modal" tabindex="-1" role="dialog">
	//...
	<div class="modal-footer">
	  <slot name="footer" :closeModal="closeModal"></slot>
	</div>
	//...
</div>
</template>

<script>
export default {
  //...
  methods: {
	closeModal () {	}
  }
}
</script>

Chúng ta có thể truyền hàm closeModal khác

<template #footer="{closeModal}">
	<button @click="closeModal">
		I'm here
	</button>
</template>

Composing Component (siêu nhân hợp thể)

Sự kết hợp của nhiều component thành một component mới, dữ dội hơn, như siêu nhân GAO, được gọi là hợp thể component. Từ khoa học của nó là Composing Components

Tại sao cần hợp thể?

Component được sinh ra là để chúng ta nhai đi nhai lại

<!-- BaseButton.vue -->
<template>
  <button class="nice-button" type="button">
    {{ text }}
  </button>
</template>

<script>
export default {
  props: ['text']
}
</script>

Nhu cầu thêm mắm, bớt muối cho một món phải nhai đi nhai lại là có. Giả dụ ta đã có sẵn một component BaseIcon để làm chuyện hiển thị icon, giờ cái Button cùng muốn thêm chút icon cho đời tươi mới, chúng ta xào chung hai món lại để nhai

<template>
  <button class="nice-button" type="button">
    <BaseIcon v-if="leftIcon" :icon="leftIcon"/>
    {{ text }}
    <BaseIcon v-if="rightIcon" :icon="rightIcon"/>
  </button>
</template>

<script>
export default {
  props: ['text', 'leftIcon', 'rightIcon']
}
</script>

Trong đó chúng ta đã thêm hai điều kiện để đặt icon nằm bên trái hay bên phải. Component Button bây giờ cũng được thêm 2 prop rightIconleftIcon.

Thí dụ như có thêm yêu cầu đưa cái spinner vào trong button, khi nào đang loading thì hiện cái spinner này

<template>
  <button class="nice-button" type="button">
    <BaseSpinner v-if="isLoading"/>
    <template v-else>
      <BaseIcon v-if="leftIcon" :icon="leftIcon"/>
      {{ text }}
      <BaseIcon v-if="rightIcon" :icon="rightIcon"/>
    </template>
  </button>
</template>

Chỉ mới thêm chút đường sữa thôi, mà món ăn sắp thành cháo heo thập cẩm khó nuốt. Với nhiều gia vị được yêu cầu bỏ vào của bọn khách hàng không biết gì về nấu nướng. Món ngon bây giờ thành đặc sản mà đứa nào đó muốn nấu tiếp, sửa đổi do quá mặn, thì cũng bất lực vì không biết đã thêm quá nhiều muối hay nhiều nước mắm.

Một cách nấu khác với slot

Trong cuốn bí kíp 100 cách nấu ngon của Vue.js, nó cho chúng ta cách làm khác gọi là slot

<template>
  <button class="nice-button" type="button">
    <slot/>
  </button>
</template>

Đây là kiểu món tao đã nấu xong, nếu mày muốn bỏ thêm bất cứ gì đó, dùng món này tao đã nấu xong như một nguyên liệu cho món mới, chứ tao ko sửa lại món của tao.

<BaseButton>
  Submit
  <BaseIcon icon="arrow-right"/>
</BaseButton>

Việc này tạo ra một tranh cãi trong giới đầu bếp, nếu tao phải phục vụ món ăn đó cho một trăm thực khách, tức là tao phải lặp lại việc order 100 gia vị Button về rồi tự nấu thêm 100 lần nữa, vi phạm nguyên tắc nghề nghiệp DRY (DON’T REPEAT YOURSELF) của tao. Đúng là vi phạm nguyên tắc nghề, nhưng nó lại đảm bảo KISS (Keep it simple stupid – NGU NHẤT CÓ THỂ)

<template>
  <BaseButton @click="sendForm">
    <BaseSpinner v-if="isLoading"/>
    <template v-else>
      Submit
      <BaseIcon icon="arrow-right"/>
    </template>
  </BaseButton>
</template>

Renderless Component (người vô hình chỉ mang logic)

Một component trong Vue có thể không render bất cứ gì cả, nếu chỉ đơn giản là chứa các function, thực hiện logic tính toán. Nó giống như cái ổ điện, nó chỉ biết làm một chuyện là cấp điện cho chui cắm, còn cái chui đó nối tới bóng đèn, máy tính, tủ lạnh, máy quạt là chuyện của người cắm điện.

<template>
	<transition name="fade" v-bind="$attrs" v-on="$listeners">
		<slot></slot>
	</transition>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s;
}
.fade-enter, .fade-leave-to {
  opacity: 0;
}
</style>

Một component để làm transition như trên không render html, không quan tâm cái nó hiển thị là gì. Nó chỉ bổ sung hiệu ứng fade cho component.

Có thể viết nó ở dạng này, truyền thêm ít dữ liệu cho đứa con

Vue.component('renderless-component-example', {
	render() {
		return this.$scopedSlots.default({
			exampleProp: 'vuilaptrinh.com'
		})
	}
})

Tại sao dùng Renderless component mà không dùng mixin hay directive?

Để tái sử dụng code trong Vue, ngoài renderless component ra còn có thể dùng Mixin hoặc 1 custom Directive. Cả 3 cách đều có thể dùng thay thế cho nhau được, vấn đề là mức độ tường minh của 3 thằng khác nhau, thằng directive là kém tường minh nhất, với mixin và renderless component chúng ta import độc lập trên từng component muốn xài, xem như bằng nhau. Mixin thì bị vấn đề, nếu khai báo một số state, hoặc hàm bên trong mixin, sau đó trộn chung với 1 component, không rõ ràng trực quan như là dùng một renderless component với prop

Ứng dụng renderless component làm ổ cắm mạng cấp dữ liệu internet

Chúng ta thường xuyên làm việc này, tạo một network request lúc component mounted() để lấy dữ liệu, chúng ta tạo ra một component chuyên làm nhiệm vụ này

// src/components/DataList.js
import axios from 'axios'

export default {
	props: {
		baseUrl: {
			type: String,
			default: 'https://jsonplaceholder.typicode.com'
		},
		endpoint: {
			type: String,
			required: true
		},
		// dùng để giới hạn kết quả query
		filter: {
			type: Object
		}
	},
	data() {
		return {
			api: axios.create({ baseURL: this.baseUrl }),
			data: null,
			error: null,
			loading: false,
		}
	},
	watch: {
		// load dữ liệu từ endpoint trong lần render đầu tiên
		// và khi giá trị filter thay đổi
		filter: {
			immediate: true,
			handler: 'load'
		}
	},
	methods: {
		// xử lý tất cả type: post, update, delete, get, put bằng một hàm duy nhất
		async query(type, ...params) {
			// tránh việc gọi load liên tục
			if (this.loading) return;

			this.loading = true;

			try	{
				const response = await this.api[type](...params);
				this.data = response.data;
				this.error = null;
				this.$emit('success', response);
			} catch (error) {
				this.data = null;
				this.error = error.response;
				this.$emit('error', error);
			}
			this.loading = false;
		},
		load() {
			return this.query('get', this.endpoint, { params: this.filter })
		}
	},
	render() {
		// đưa toàn bộ dữ liệu và phương thức xuống con thông qua slot scope
		return this.$scopedSlots.default({
			data: this.data,
			error: this.error,
			load: this.load,
			loading: this.loading
		})
	}
}

Renderless component <DataList/> sẽ làm nhiệm vụ fetch dữ liệu từ một API, endpoint được cung cấp qua prop, sau đó nó sẽ quăng kết quả, lỗi, trạng thái hiện tại về cho component con

<data-list endpoint="posts">
	<div slot-scope="{ data: posts, error, laoding }">
		<span v-if="loading">Loading...</span>
		<span v-else-if="error">Error while fetching data!</span>
		<ul v-else>
			<li v-for="post in posts" :key="post.id">
				<h3>{{ post.title }}</h3>
				<p>{{ post.body }}</p>
			</li>
		</ul>
	</div>
<data-list>

Thêm phần phân trang, chúng ta dùng giá trị filter

<data-list endpoint="posts" :filter="{ page }">
	<div slot-scope="{ data: posts, error, laoding }">
		<span v-if="loading">Loading...</span>
		<span v-else-if="error">Error while fetching data!</span>
		<ul v-else>
			<li v-for="post in posts" :key="post.id">
				<h3>{{ post.title }}</h3>
				<p>{{ post.body }}</p>
			</li>
		</ul>
		<button @click="page = 1">1</button>
    <button @click="page = 2">2</button>
    <button @click="page = 3">3</button>
	</div>
<data-list>

Bởi vì đã setup watch trên giá trị filter, nên khi thay đổi giá trị của page, nó sẽ gọi lại hàm load()

Xong phần Rờ trong CRUD, giờ đến Create-Update-Delete

Chúng ta cần tách phần code ở trên ra thành một mixin để sử dụng vào component detail. Chúng ta sẽ đưa nó vào một mixin là query.js

// src/components/mixins/query.js
import axios from 'axios';

export default {
  props: {
    baseUrl: {
      type: String,
      // The JSONPlaceholder API is a fake API
      // basically a Lorem Ipsum JSON API.
      default: `https://jsonplaceholder.typicode.com`,
    },
    endpoint: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      // Create a new axios instance.
      // See: https://github.com/axios/axios#creating-an-instance
      api: axios.create({ baseURL: this.baseUrl }),
      data: null,
      error: null,
      loading: false,
    };
  },
  methods: {
    // The `query` method will handle
    // different query types for us.
    async query(type, ...params) {
      // If we're currently loading content
      // we don't submit an additional request.
      if (this.loading) return;

      this.loading = true;
      try {
        const response = await this.api[type](...params);
        this.data = response.data;
        this.error = null;
        this.$emit(`success`, response);
      } catch (error) {
        this.data = null;
        this.error = error.response;
        this.$emit(`error`, error);
      }
      this.loading = false;
    },
  },
};

Với component để thêm-xóa-sửa

// src/components/DataModel.js
import queryMixin from './mixins/query'

export default {
	mixins: [queryMixin],
	props: {
		entity: {
			type: Object,
		},
		id: {
			type: [Number, String]
		}
	},
	data() {
		return {
			data: this.entity || null,
		}
	},
	create() {
		// nếu có id và chưa có dữ liệu, chúng ta gọi fetch dữ liệu
		if (this.id && !this.data) this.find();
	},
	methods: {
		create(data) {
			return this.query('post', this.endpoint, data)
		},
		destroy() {
			return this.query('delete', `${this.endpoint}/${this.id}`)
		},
		find() {
      return this.query('get', `${this.endpoint}/${this.id}`);
    },
    update(data) {
      return this.query('patch', `${this.endpoint}/${this.id}`, data);
    },
	},
	render() {
		return this.$scopedSlots.default({
			create: this.create,
			data: this.data,
			destroy: this.destroy,
			loading: this.loading,
			update: this.update
		})
	}
}

Create

<data-model endpoint="posts">
	<div slot-scope="{ data: post, loading, create }"></div>
	<span v-if="loading">Loading...</span>
  <template v-if="post">
    <h3>{{ post.title }}</h3>
    <p>{{ post.body }}</p>
  </template>
  <form @submit.prevent="create(newPost)">
  	<label>
      Title: <input v-model="newPost.title">
    </label>
    <label>
      Body: <input v-model="newPost.body">
    </label>
    <button :disabled="loading">
      <template v-if="loading">Loading...</template>
      <template v-else>Create</template>
    </button>
  </form>
</data-model>

Với component để Create, chúng ta không truyền dữ liệu và id, vì thế nó không gọi API để lấy dữ liệu, nếu sau khi tạo, chúng ta sẽ nhận giá trị post và id.

Cập nhập, giống hệt với tạo ở trên, có điều có thêm id

<data-model endpoint="posts" :id="1">
  <div slot-scope="{ data: post, loading, update }">
    <span v-if="loading">Loading...</span>
    <template v-if="post">
      <h3>{{ post.title }}</h3>
      <p>{{ post.body }}</p>
    </template>

    <form @submit.prevent="update(post);">
      <label>
        Title: <input v-model="post.title">
      </label>
      <label>
        Body: <input v-model="post.body">
      </label>
      <button :disabled="loading">
        <template v-if="loading">Loading...</template>
        <template v-else>Update</template>
      </button>
    </form>
  </div>
</data-model>

Delete

<data-model endpoint="posts" :id="1" @success="deleted = true">
  <div slot-scope="{ delete }">
    <p v-if="deleted">
      The post was successfully deleted.
    </p>
    <button :disabled="loading">
      <template v-if="loading">Loading...</template>
      <template v-else>Delete</template>
    </button>
  </div>
</data-model>

Tài liệu tham khảo

Building Renderless Components to Handle CRUD Operations in Vue.js

Vue.js Pattern for Async Requests: Using Renderless Components

Renderless Components in Vue.js

Composing Components in Vue.js

Using Slots In Vue.js

Creating Reusable Transitions in Vue

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

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

Xem thêm các việc làm VueJS lương cao hấp dẫn tại TopDev

“Sống sót” qua những áp lực trong tuyển dụng IT – lập trình, có dễ không?

ngành lập trình

Phải chăng bạn từng nghe luyên thuyên trong những cuộc trò chuyện của người lớn, những cuộc thoại của đám bạn rằng ngành lập trình là một ngành dễ thở, công việc thì thú vị, không những ngồi máy lạnh mà lại còn được hưởng mức lương cao. 

Liệu lối nghĩ mặc định ấy có đúng không và sự thật thế nào? Bạn có biết rằng ngành IT cũng giống như những ngành khác, đều có hai mặt của nó, việc phải thu nạp một lượng kiến thức khủng, gặp đủ thứ áp lực khác nhau là những mặt tối mà chỉ được chính dân lập trình giấu nhẹm đằng sau bề nổi hào nhoáng kia mà thôi.

Hôm nay, TopDev sẽ bật mí cho các bạn vô vàn những áp lực xoay quanh ngành lập trình IT khi đã quyết định dấn thân theo đuổi nó. Tất nhiên, bài viết sẽ chia sẻ thêm những cách thức giúp thích ứng và sống sót khi những áp lực bủa vây.

Áp lực từ các mối quan hệ: Sếp và đồng nghiệp

Không phải ai xa lạ, áp lực lớn nhất mà bạn phải đối mặt chính là từ sếp của bạn. Điều này khá dễ hiểu vì sếp là người trực tiếp phân bổ các đầu công việc mà bạn phải thực hiện, quản lý đồng thời hỗ trợ bạn tự đánh giá hiệu suất làm việc của bản thân.

Nếu không may mắn gặp phải một người sếp khó tính, những áp lực bạn phải đối mặt có thể là gì? 

  • Task quá khó nằm ngoài năng lực chuyên môn 
  • Buộc làm thêm ngoài giờ để đảm bảo tiến độ công việc, kết quả cho ra hoàn hảo nhất có thể
  • Làm khó làm dễ nhân viên, đánh giá thấp việc xem xét tăng lương làm giảm cơ hội cho việc phát triển sự nghiệp

Chính vì thế, điều bạn cần làm trường hợp này là cho sếp một khoảng riêng, giao tiếp trao đổi ý kiến và quan trọng là nắm bắt tâm lý và thấu hiểu được sếp của bạn. Sếp của bạn có rất nhiều việc cần giải quyết và đôi khi việc bộc phát những cơn giận chỉ là cách thúc đẩy bạn và team làm việc hiệu quả hơn. Vì thế đừng giận và đừng áp lực về công việc. 

Ngoài ra, khi giao tiếp, bạn nên cẩn trọng với từng phát ngôn của mình. Nếu có những phát sinh hay các tồn đọng tạo ra nguy cơ dẫn đến sự tiêu cực, bạn đừng vội đi sâu vào vấn đề chuyên môn hay kỹ thuật. Thay vào đó, hãy khai thác những khía cạnh mà sếp quan tâm đồng thời cũng là cách giúp tiếp cận cơn giận từ sếp.

  Kỹ năng giao tiếp? Làm thế nào để cải thiện giao tiếp hiệu quả?

ngành lập trình

  • Diễn tiến thực hiện dự án như thế nào?
  • Làm sao để cải thiện năng suất làm việc hiệu quả?
  • Sếp có lời khuyên nào cho em trong việc giải quyết vấn đề này không?

Việc thấu hiểu sếp còn phụ thuộc vào nhiều yếu tố, vì nếu đối với một người sếp không tốt, lúc nào cũng kiếm chuyện với nhân viên thậm chí không tuân thủ các quy định thì việc bạn nhảy việc, bắt đầu sự nghiệp  tại một công ty khác là điều sớm muộn.

Đồng nghiệp là người sẽ tiếp xúc, làm việc với bạn nhiều hơn là sếp. Vì thế, những áp lục xảy ra có liên quan đến đồng nghiệp cũng khiến bạn đau đầu đó.

Bạn có thể sẽ gặp phải những người đồng nghiệp khoác lác về năng lực hoặc quá tự kiêu về bản thân có thể khiến bạn cảm thấy phiền phức. Khi làm việc nhóm đòi hỏi sự bàn luận về dự án và trình bày những ý kiến đóng góp, đồng nghiệp của bạn tỏ thái độ thiếu hợp tác; đùn đẩy trách nhiệm cho người khác. Hoặc khi chung team với những đồng nghiệp giỏi khiến bạn cảm thấy tự ti và thua kém về nhiều mặt.

“Mỗi người một vẻ” nên có đồng nghiệp này, đồng nghiệp khác. Ai cũng có điểm mạnh điểm yếu riêng. Ví dụ một số người chưa thật sự giỏi về lập trình IT, nhưng bù lại họ có chí cầu tiến và khả năng tiếp nhận kiến thức một cách nhanh chóng. Điều bạn cần nhớ và thực hiện là hãy học cái hay của những người đồng nghiệp giỏi.

Bộc lộ sự ngờ vực về chính bản thân

Có lẽ nỗi ám ảnh về chuyên đề nhập môn lập trình hay các bài giảng về thuật toán và cấu trúc dữ liệu có thể bạn sẽ không thể nào quên. Khoảng thời gian đầu đã trôi qua nhưng khi nhìn nhận lại, những rào cản ấy đã phần nào khiến bạn nhận ra sự không phù hợp với đặc thù ngành hoặc đơn giản khiến bạn nghi ngờ về khả năng và chính sự lựa chọn của bản thân mình. Sai ngành thật à? Tồn thời gian học làm chi vậy? Bao nhiêu câu hỏi sẽ được đặt ra và chúng dường như quay cuồng xung quanh bạn.

Thời học C++, nhiều bạn phải điên cuồng làm những bài tập, đôi khi không tha thiết mấy những vẫn cố mà cày nó. Vấn đề nằm ở chỗ việc bạn có nhìn nhận được hiện thực chung hay không thôi. 

ngành lập trình

Một lập trình viên không tự sinh ra được, cái gì cũng phải có quá trình khổ luyện. Tất nhiên trong quá trình ấy phải có sự cộng hưởng giữa nhiều yếu tố về năng lực, tiềm năng, sự cố gắng và cả sự may mắn. Vì vậy, khi gặp những khó khăn trong ngành học hay công việc, dù nó là gì thì nó cũng chỉ là một phần, một khía cạnh nhỏ trong cuộc sống này mà thôi. Điều bạn cần nhớ là đừng bao giờ nghĩ mình không có khả năng, mà đơn là mình cố gắng chưa đủ nhé.

Liệu bạn đã bắt kịp xu thế công nghệ? – Áp lực đặc thù của ngành IT

Công nghệ có nghĩa quan trọng vì nó không thể tách rời khỏi công việc của ngành lập trình. Chính mối quan hệ chặt chẽ ấy đã vô tình tạo ra áp lực đặc thù của ngành IT

Bạn thử nghĩ xem liệu những giải pháp xưa cũ có còn ứng dụng được vào bộ máy vận hành hoạt động của các tổ chức vừa áp dụng các mô hình công nghệ hiện đại? Nhiều yếu tố trong ngành IT như các công cụ công nghệ, thuật ngữ ngôn ngữ lập trình, framework,.. dường như mọi thứ đều được thay đổi.

Chính áp lực đó đã tạo nên cho dân IT một nỗi lo lớn. Họ rất sợ kiến thức của mình bị lạc hậu và khó khăn trong vấn đề tìm kiếm việc làm do thị trường đầy cạnh tranh và rủi ro bị đào thải nếu không đáp ứng được cầu. Những developer lâu năm chắc chắn thấm thía những áp lực này rồi.

  6 giải pháp công nghệ hữu ích cho phòng nhân sự của bạn

ngành lập trình

Đúc kết từ kinh nghiệm thực tế, dưới đây là những cách mình dùng để tránh những áp lực này. 

  • Tập trung nắm vững những kiến thức căn bản trước vì nó là cơ sở giúp bạn dễ dàng hơn trong việc tiếp cận công nghệ
  • Trải nghiệm thực tế thông qua việc tham gia và thực hiện những dự án lớn nhỏ để áp dụng những kiến thức IT đã tích lũy
  • Đừng lo lắng quá nhiều về công nghệ. Hãy rèn luyện về tính tư duy độc lập và tư duy hệ thống để nắm bắt cơ chế đồng thời liên tục cập nhật những thông tin mới về ngành lập trình IT

Áp lực nảy sinh từ quá trình thực hiện công việc/dự án

Cuộc sống này không quá dễ dàng đối với chúng ta. Khi bạn có một người sếp hoàn hảo và những đồng nghiệp tuyệt vời thì bạn nghĩ chắc mình không cần phải lo nghĩ nhiều về những áp lực xoay các mối quan hệ. Tuy nhiên, đừng vội vui mừng vì vẫn còn tổn tại một loại áp lực mà dù bạn có muốn trốn tránh cũng không thể tránh được. Đó là áp lực nảy sinh từ quá trình thực hiện công việc hoặc dự án.

ngành lập trình

Nếu đối với dự án nhỏ, khối lượng công việc không quá nhiều nên bạn khá thảnh thơi. Tuy nhiên, với các dự án lớn đòi hỏi độ phức tạp cao, bạn sẽ khó thể chối từ lời mời “đồng hành” của người bạn mang tên áp lực. 

Dự án quá phức tạp, quá khó khăn khi code; team chịu trách nhiệm thực hiện dự án lại không đủ về nguồn lực và chuyên môn. Trong khi thời gian hoàn thành dự án quá gấp rút và vượt tầm kiểm soát khiến nhân lực phải thực hiện trong điều kiện chạy hết tố lực. Cảm giác khó chịu và tất nhiên việc phải OT (OverTime) “điên cuồng” là điều khó tránh khỏi.

Nếu cố gắng, bạn có thể thoát khỏi nó được không? Tất nhiên là được chứ, nhưng bạn phải buông bỏ suy nghĩ của việc trốn chạy, phải đối diện với áp lực vì đó là cách tốt nhất để “lật bài ngửa” giúp giảm thiểu những áp lực có thể diễn ra. Bạn có thể tham khảo một số cách thức làm bạn với những áp lực như sau:

  • Hãy thảo luận với các anh chị Leader hoặc quản lý dự án (Project Manager) xem có cách nào đàm phán với khách hàng (Clients) để kéo dài được deadline hay không?
  • Ngoài ra, việc chăm sóc sức khỏe là điều quan trọng để ứng phó với các áp lực. Ăn uống điều độ, ngủ không quá khuya, không cố gắng làm việc khi cơ thể có dấu hiệu mệt mỏi.

Lời kết

Áp lực trong ngành IT dễ hay khó vượt qua là do bản thân bạn quyết định vì đơn giản không riêng gì ngành lập trình mà rất nhiều ngành/lĩnh vực đều tồn tại những áp lực. Điều quan trọng là bạn có biết nhận ra được áp lực, đối mặt và tìm cách vượt qua nó. Mong rằng với bài viết vừa rồi, các bạn sẽ có những hình dung cụ thể về những áp lực diễn ra trong thực tế của những người làm về IT.

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

Xem thêm việc làm ngành cntt hàng đầu tại TopDev

8 thủ thuật khi làm việc với Object sử dụng resting và spreading

8 thủ thuật khi làm việc với Object sử dụng resting và spreading
Bài viết được sự cho phép của tác giả Lưu Bình An
Những đoạn code bỏ túi hay xài nhất khi đụng tới object
  JavaScript đã tạo ra Object từ Function như thế nào?
  Object Relational Mapping

Merge object

part1 và part2 sẽ được merge vào user1

const part1 = { id: 100, name: 'An Luu' }
const part2 = { id: 100, password: 'Password!' }

const user1 = { ...part1, ...part2 }
//=> { id: 100, name: 'An Luu', password: 'Password!' }

Thêm property

Clone một object đồng thời thêm một số property mới vào object mới clone

const user = { id: 100, name: 'An Luu'}
const userWithPass = { ...user, password: 'Password!' }

user //=> { id: 100, name: 'An Luu' }
userWithPass //=> { id: 100, name: 'An Luu', password: 'Password!' }

Thêm property khi thỏa điều kiện

Trường hợp này hay dùng nhất là lúc chúng ta truyền lên API một object, nếu thõa điều kiện, sẽ thêm một số property vào trong object

const user = { id: 100, name: 'An Luu' }
const password = 'Password!'
const userWithPassword = {
  ...user,
  id: 100,
  ...(password && { password })
}

userWithPassword //=> { id: 100, name: 'An Luu', password: 'Password!' }

Xóa property khỏi object

// hàm này sẽ trả về object mới ko bao gồm password
const noPassword = ({ password, ...rest }) => rest

const user = {
  id: 100,
  name: 'An Luu',
  password: 'Password!'
}

noPassword(user) //=> { id: 100, name: 'An Luu' }

Xóa property với key chỉ định

const user1 = {
  id: 100,
  name: 'An Luu',
  password: 'Password!'
}

const removeProperty = prop => ({ [prop]: _, ...rest }) => rest
//                     ----       ------
//                          \   /
//                dynamic destructuring

const removePassword = removeProperty('password')
const removeId = removeProperty('id')

removePassword(user1) //=> { id: 100, name: 'An Luu' }
removeId(user1) //=> { name: 'An Luu', password: 'Password!' }

Sắp xếp property

Đôi khi chúng ta sẽ muốn thay đổi các property theo một thứ tự nào đó, nếu sắp xếp toàn bộ luôn thì chắc dùng Object.keys rồi thay xếp cái mảng key này lại.

Để di chuyển id lên đầu, trước hết gán giá trị undefined cho nó trước, sau đó, override lại giá trị này bằng cách resting

const user3 = {
  password: 'Password!',
  name: 'An Luu',
  id: 300
}

const organize = object => ({ id: undefined, ...object })
//                            -------------
//                          /
//  dời id lên đầu

organize(user3)
//=> { id: 300, password: 'Password!', name: 'An Luu' }

Còn di chuyển xuống dưới cùng

const user3 = {
  password: 'Password!',
  name: 'An Luu',
  id: 300
}

const organize = ({ password, ...object }) =>
  ({ ...object, password })
//              --------
//             /
// dời password xuống cuối

organize(user3)
//=> { name: 'An Luu', id: 300, password: 'Password!' }

Property mặc định

Ví dụ, user2 không có chứa quotes, hàm setDefaults đảm bảo tất cả object đều chứa property là quotes, nếu ko nó thêm vào []

const user2 = {
  id: 200,
  name: 'An Luu'
}

const user4 = {
  id: 400,
  name: 'You',
  quotes: ["I've got a good feeling about this..."]
}

const setDefaults = ({ quotes = [], ...object}) =>
  ({ ...object, quotes })

// hoặc nếu muốn dời thằng quotes lên đầu
// const setDefaults = ({ ...object}) => ({ quotes: [], ...object })

setDefaults(user2)
//=> { id: 200, name: 'An Luu', quotes: [] }

setDefaults(user4)
//=> {
//=>   id: 400,
//=>   name: 'You',
//=>   quotes: ["I've got a good feeling about this..."]
//=> }

Đổi tên property

Thí dụ bạn ko muốn trong object chứa property ID, nó phải viết thường id, đầu tiên chúng ta remove ID ra khỏi object, sau đó add lại bằng tên là id

const renamed = ({ ID, ...object }) => ({ id: ID, ...object })

const user = {
  ID: 500,
  name: "An Luu"
}

renamed(user) //=> { id: 500, name: 'An Luu' }

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

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

Xem thêm các vị trí tuyển dụng IT hấp dẫn tại TopDev

for vs forEach vs for/in vs for/of trong javascript

for-vs-foreach-vs-for-in-vs-for-of-trong-javascript
Bài viết được sự cho phép của tác giả Lưu Bình An
Trong javascript có rất nhiều cách để loop qua một array, chúng ta cùng bàn qua 4 cách chính hay sử dụng nhất
  • for (let i = 0; i < arr.length; ++i)
  • arr.forEach((v, i) => { /* ….. */})
  • for (let i in arr)
  • for (const v of arr)

2 phương thức là for và for/in cho phép chúng ta truy cập đến giá trị index trong array, ko phải giá trị của element trong array

const arr = ['a', 'b', 'c'];
// sau đó chúng ta dùng truy cập element bằng giá trị index
for (let i = 0; i < arr.length; ++i) {
  console.log(arr[i]);
}

for (let i in arr) {
  console.log(arr[i]);
}

Trong khi đó hai phương thức for/of và forEach sẽ truy xuất đến phần tử trong element, cũng có thể truy xuất vào index, nếu thích.

arr.forEach((v, i) => console.log(v));
for (const v of arr) {
  console.log(v);
}

Có thể bạn chưa biết, array trong javascript cũng là một dạng đặc biệt của object, chúng ta có thể gán một property cho nó

const arr = ['a', 'b', 'c'];
console.log(typeof arr); // 'object'

arr.test = 'bad';
console.log(arr.test); // bad

arr[1] === arr['1']; // true,

Nếu loop qua bằng 4 phương thức trên, chỉ duy nhất thằng for/in sẽ chạy qua

const arr = ['a', 'b', 'c'];
arr.test = 'bad';

// "a, b, c, bad"
for (let i in arr) {
  console.log(arr[i]);
}

Đó là lý do tại sao chúng ta ko nên dùng for/in để loop qua array

Đối với một element trống như thế này

const arr = ['a',,'b']
console.log(arr.length); // 3

Xem thêm các tin đăng tuyển dụng lập trình viên javascript trên TopDev

Không chỉ vậy thôi đâu, nếu loop qua mảng ['a',,'b'] nó cũng sẽ khác với ['a', undefined, 'c']. 2 thằngfor/infor/eachsẽ bỏ qua phần tử trống như vậy, nhưngforfor/of` vẫn tính

const arr = ['a',, 'c']
// Prints "a, undefined, c"
for (let i = 0; i < arr.length; ++i) {
  console.log(arr[i]);
}

// Prints "a, c"
arr.forEach(v => console.log(v));

// Prints "a, c"
for (let i in arr) {
  console.log(arr[i]);
}

// Prints "a, undefined, c"
for (const v of arr) {
  console.log(v);
}

Tuy nhiên, nếu là ['a', undefined, 'c'], cả 4 phương thức trên đề print hết giá trị trong array.

  10 câu hỏi JavaScript để tăng cường kỹ năng của bạn
  Giới thiệu về Reactive Programing trong javascript

Một cách để chèn phần tử trống vào array

const arr = ['a', 'b', 'c'];
arr[5] = 'e';

Tuy nhiên là trường hợp [a, , c] này sẽ rất rất ít khi xảy ra, vì căn bản là file JSON như thế là không hợp lệ. Chúng ta cũng không cần lo lắng lắm

> JSON.parse('{"arr":["a","b","c"]}')
{ arr: [ 'a', 'b', 'c' ] }
> JSON.parse('{"arr":["a",null,"c"]}')
{ arr: [ 'a', null, 'c' ] }
> JSON.parse('{"arr":["a",,"c"]}')
SyntaxError: Unexpected token , in JSON at position 12

Với từ khóa thisforfor/infor/of sẽ dùng chung scope với thằng cha, trong khi forEach thì nó là scope của nó.

forEach cũng xảy ra nhiều tình huống ko đúng khi dùng với async/await hoặc generator. Code bên dưới là không chạy, không dùng await cho callback của forEach cũng như yield

async function run() {
  const arr = ['a', 'b', 'c'];
  arr.forEach(el => {
    // SyntaxError
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log(el);
  });
}

function* run() {
  const arr = ['a', 'b', 'c'];
  arr.forEach(el => {
    // SyntaxError
    yield new Promise(resolve => setTimeout(resolve, 1000));
    console.log(el);
  });
}

Dùng với for/of thì ok

async function asyncFn() {
  const arr = ['a', 'b', 'c'];
  for (const el of arr) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log(el);
  }
}

function* generatorFn() {
  const arr = ['a', 'b', 'c'];
  for (const el of arr) {
    yield new Promise(resolve => setTimeout(resolve, 1000));
    console.log(el);
  }
}

Túm lại, for/of có thể dùng gần như mọi lúc. Mặc dù performance ko bằng for, nhưng dễ xài hơn, cũng ko dính nhiều trường hợp đặc biệt như for/in và forEach. Nếu ko cần dùng đến giá trị index, thì for/of sẽ được dùng. Còn nếu muốn truy xuất tới giá trị index với for/of

for (const [i, v] of arr.entries()) {
  console.log(i, v); // Prints "0 a", "1 b", "2 c"
}

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

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

Xem thêm các việc làm IT tại Hồ Chí Minh, Hà Nội hấp dẫn tại TopDev