Home Blog Page 124

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

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

Xin chào các bạn, bài viết hôm nay mình sẽ hướng dẫn các bạn cách định dạng Ngày tháng và Thời gian trên Windows và Ứng dụng trong lập trình C#, Winform.

  10 điều bạn có thể làm với Linux mà bạn không thể làm với Windows
  Cách mạng 0.4 của Neovim: Floating Window

[C#] Set config shortDate and Short Time Windows

Khi các bạn viết ứng dụng winform hay ứng dụng nào của windows, thì mặc định các control ngày tháng hay thời gian, sẽ mặc định sẽ lấy format cấu hình của máy tính.

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Cấu hình DateTime Format ở Windows của mình:

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Theo hình trên, thì người sử dụng cài đặt mặc định Short Date Format là: MM/dd/yyyy

Thì khi chúng ta chạy ứng dụng của mình thì các control cũng format theo định dạng đó, như hình bên dưới đây:

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Các bạn xem hình ảnh trên sẽ thấy thay vì hiển thị ngày 03/12/2020 => nó lại đi hiển thị là 12/03/2020.

Nếu mặc định người dùng biết chỉnh định dạng format ngày tháng lại thì đơn giản không sao.

Nhưng mong muốn của mình là khi chạy ứng dụng của mình sẽ luôn thể hiện ở định dạng format chuẩn Việt Nam dd/MM/yyyy.

Dưới đây mình sẽ có ba cách thực hiện như sau:

Cách 1: Chỉnh Regedit của Windows về định dạng mong muốn của mình

private void button1_Click(object sender, EventArgs e)
{
    RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Control Panel\International", true);
    rk.SetValue("sTimeFormat", "HH:mm:ss"); // HH for 24hrs, hh for 12 hrs
}

private void button2_Click(object sender, EventArgs e)
{
    RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Control Panel\International", true);
    rk.SetValue("sTimeFormat", "dd/MM/yyyy"); 
}
C#

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Tuy nhiên, khi các bạn set theo Regedit bằng cách này, thì ngày tháng dưới Thanh Taskbar sẽ không thay đổi liền.

Mà nó chỉ thay đổi như số phút thời gian nhảy nó mới cập nhật lại định dạng.

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Dưới đây là kính thưa các loại định dạng ngày tháng.

1) MM/dd/yyyy 08/22/2006
2) dddd, dd MMMM yyyy Tuesday, 22 August 2006
3) dddd, dd MMMM yyyy HH:mm Tuesday, 22 August 2006 06:30
4) dddd, dd MMMM yyyy hh:mm tt Tuesday, 22 August 2006 06:30 AM
5) dddd, dd MMMM yyyy H:mm Tuesday, 22 August 2006 6:30
6) dddd, dd MMMM yyyy h:mm tt Tuesday, 22 August 2006 6:30 AM
7) dddd, dd MMMM yyyy HH:mm:ss Tuesday, 22 August 2006 06:30:07
8) MM/dd/yyyy HH:mm 08/22/2006 06:30
9) MM/dd/yyyy hh:mm tt 08/22/2006 06:30 AM
10) MM/dd/yyyy H:mm 08/22/2006 6:30
11) MM/dd/yyyy HH:mm:ss 08/22/2006 06:30:07
12) MMMM dd August 22
13) yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss.fffffffK 2006-08-22T06:30:07.7199222-04:00
14) ddd, dd MMM yyyy HH’:’mm’:’ss ‘GMT’ Tue, 22 Aug 2006 06:30:07 GMT
15) yyyy’-‘MM’-‘dd’T’HH’:’mm’:’ss 2006-08-22T06:30:07
16) HH:mm 06:30
17) hh:mm tt 06:30 AM
18) H:mm 6:30
19) h:mm tt 6:30 AM
20) HH:mm:ss 06:30:07
21) yyyy’-‘MM’-‘dd HH’:’mm’:’ss’Z’ 2006-08-22 06:30:07Z
22) dddd, dd MMMM yyyy HH:mm:ss Tuesday, 22 August 2006 06:30:07
23) yyyy MMMM 2006 August

Cách 2: Mình sẽ sử dụng hàm API 32 Windows để thực hiện thay đổi định dạng ngày tháng và thời gian.

Cách này khi các bạn thay đổi thì định dạng ngày tháng thời gian trong Windows sẽ thay đổi ngay lập tức.

public const int LOCALE_USER_DEFAULT = 0x00000400;
public const int LOCALE_SSHORTDATE = 0x0000001F;
public const int LOCALE_STIMEFORMAT = 0x1003;
public const int LOCALE_SSHORTTIME = 0x0079;

public const int BSF_QUERY = 0x00000001;
public const int BSF_IGNORECURRENTTASK = 0x00000002;
public const int BSF_FLUSHDISK = 0x00000004;
public const int BSF_NOHANG = 0x00000008;
public const int BSF_POSTMESSAGE = 0x00000010;
public const int BSF_FORCEIFHUNG = 0x00000020;
public const int BSF_NOTIMEOUTIFNOTHUNG = 0x00000040;
public const int BSF_MSGSRV32ISOK = unchecked((int)0x80000000);
public const int BSF_MSGSRV32ISOK_BIT = 31;

public const int BSM_ALLCOMPONENTS = 0x00000000;
public const int BSM_VXDS = 0x00000001;
public const int BSM_NETDRIVER = 0x00000002;
public const int BSM_INSTALLABLEDRIVERS = 0x00000004;
public const int BSM_APPLICATIONS = 0x00000008;
public const int BSM_ALLDESKTOPS = 0x00000010;

public const int WM_WININICHANGE = 0x001A;

[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern Boolean SetLocaleInfo(int Locale, int LCType, string lpLCData);

[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int BroadcastSystemMessage(int flags, ref int lpInfo, uint Msg, uint wParam, IntPtr lParam);
C#

+ Cấu hình ShortDate ta viết như sau:

if (SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, "dd/MM/yyyy"))
{
    int dwRecipients = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
    string sString = "intl";
    GCHandle GCH = GCHandle.Alloc(sString, GCHandleType.Pinned);
    IntPtr pString = GCH.AddrOfPinnedObject();
    BroadcastSystemMessage(BSF_FORCEIFHUNG | BSF_IGNORECURRENTTASK | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG, ref dwRecipients, WM_WININICHANGE, 0, pString);
}
C#

+ Cấu hình cho ShortTime:

if (SetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTTIME, "HH:mm:ss"))
{
    int dwRecipients = BSM_APPLICATIONS | BSM_ALLDESKTOPS;
    string sString = "intl";
    GCHandle GCH = GCHandle.Alloc(sString, GCHandleType.Pinned);
    IntPtr pString = GCH.AddrOfPinnedObject();
    BroadcastSystemMessage(BSF_FORCEIFHUNG | BSF_IGNORECURRENTTASK | BSF_NOHANG | BSF_NOTIMEOUTIFNOTHUNG, ref dwRecipients, WM_WININICHANGE, 0, pString);
}
C#

Cái này là mình định dạng theo chuẩn format về 24h.

Kết quả chạy như hình ảnh bên dưới đây:

Cấu hình định dạng ngày tháng, thời gian trên Windows cho ứng dụng Winform

Tuy nhiên trong ứng dụng, chúng ta nên thực hiện theo cách thứ 3 ở bên dưới đây:

Cách 3: Cài đặt ngày tháng và thời gian mặc định của ứng dụng khi chạy Current Thread

Thay vì chúng ta đi chỉnh định dạng ngày của người sử dụng, thì không hay, nhiều lúc người dùng vẫn mong muốn định dạng máy tính của họ là MM/dd/yyyy.

Hay bất kỳ định dạng nào. Tuy nhiên, chúng ta làm sao để khi mở ứng dụng của mình lên chạy đều thể hiện ở định dạng dd/MM/yyyy thì chúng ta sẽ sử dụng cách dưới đây nhé.

Các bạn cấu hình trực tiếp ở file Program.cs nhé như code bên dưới đây.

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        initCulturalFormattingChanges();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    private static void initCulturalFormattingChanges()
    {
        CultureInfo cultureDefinition = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
        cultureDefinition.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
        cultureDefinition.DateTimeFormat.ShortTimePattern = "HH:mm:ss";
        Thread.CurrentThread.CurrentCulture = cultureDefinition;
    }
}
C#

Thanks for watching!

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

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

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

Đơn xin nghỉ việc là gì? Mẫu đơn xin nghỉ việc chuẩn nhất

đơn xin nghỉ việc
đơn xin nghỉ việc

Mẫu Đơn xin việc có những điều gì đáng lưu ý? Đâu là những điểm đáng lưu ý cho một mẫu đơn xin nghỉ việc đúng chuẩn theo yêu cầu? Cách viết một đơn xin nghỉ việc như thế nào?

Như chúng ta đều biết, nhu cầu nghỉ việc, thôi việc là nhu cầu thiết yếu của người lao động. Tùy vào quy mô tổ chức, vận hành mà chế độ và hình thức nghỉ phép sẽ có điểm khác nhau. Do vậy mà đơn xin nghỉ việc thật sự rất quan trọng. Đồng thời, một lý do xin nghỉ việc chính đáng cũng rất quan trọng! Cùng TopDev tìm hiểu và giải đáp các thắc mắc xoay quanh mẫu đơn xin thôi việc nhé!

Đơn xin nghỉ việc là gì?

Đơn xin nghỉ việc là một loại giấy tờ có hiệu lực và giá trị pháp lý, đảm bảo yếu tố hiện hành về yêu cầu thôi việc của một cá nhân trong một lĩnh vực hoạt động cụ thể nào đó. Loại văn bản này là quyền lợi của mỗi nhân viên. Văn bản này giúp nhân viên trực tiếp hoặc gián tiếp phản ánh sự vắng mặt của bản thân trong một khoảng thời gian được xác định và có giới hạn.

Không khác nhiều so với CV IT hay sơ yếu lý lịch dành cho IT, mẫu đơn xin nghỉ việc cũng có những đặc điểm riêng biệt.

Chúng ta có thể xem xét nó như một loại văn bản cần có trong quy trình quản lý và phát triển tổ chức nhân sự ở mỗi cấp doanh nghiệp. Đơn xin nghỉ việc cần được thể hiện giá trị của nó đúng thời điểm. Điều này phản ánh cho tính trách nhiệm mà mỗi nhân viên thể hiện thông qua sự chuyên cần.

Tại sao cần phải viết đơn xin nghỉ việc?

Chắc hẳn khi muốn nghỉ việc, ai cũng mong muốn “đẹp lòng” cả đôi bên. Do vậy, một đơn xin nghỉ việc với đầy đủ thông tin, nội dung hợp chuẩn; được viết với thái độ chuyên nghiệp và thể hiện sự tôn trọng cần có với tổ chức sẽ giúp lưu giữ những giá trị tốt đẹp hơn. 

đơn xin nghỉ việc
Lý do xin nghỉ việc rất quan trọng

Mẫu đơn xin thôi việc thể hiện bạn là người có tính trách nhiệm với vị trí, sự tín nhiệm mà tổ chức dành cho bạn trong thời gian vừa qua.

Nó cũng là cơ sở quan trọng giúp cho quá trình nghỉ việc được thuận lợi và có tính chuẩn mực hơn. Vì thế, trong bất kỳ hoàn cảnh nào và bất cứ lý do nào, bạn cũng cần phải viết đơn xin nghỉ việc.

Phân loại mẫu đơn xin nghỉ việc

Thực tế trong tổ chức quản lý nhân sự, có rất nhiều mẫu đơn xin việc. Vậy bạn đã bao giờ biết rõ về chúng? Cùng điểm qua 3 loại mẫu đơn xin nghỉ việc, thôi việc chuẩn nhất.

  Tất tần tật về mẫu đơn xin nghỉ phép dành cho IT 

1. Đơn xin nghỉ việc thông dụng nhất

Khi cá nhân người lao động có ý định nhảy việc, muốn chấm dứt hợp đồng thì nhu cầu viết đơn thôi việc là tất yếu diễn ra.

Mục đích của đơn này là trình bày chi tiết lý do và thông báo cho công ty về việc thay đổi nhân sự. Từ cơ sở đó, họ có kế hoạch tuyển dụng kịp thời cho các vị trí còn trống.

Đồng thời, đơn xin nghỉ việc củng có ý nghĩa lớn khi là văn bản giải trình; hỗ trợ quá trình thiết lập sự minh bạch về quy chế nhân sự, tránh tình trạng vi phạm hợp đồng hay những phát sinh tiêu cực ngoài ý muốn.

Tất nhiên, để được phê duyệt và xử lý theo quy trình, đơn nghỉ việc và lý do xin nghỉ việc của cá nhân phải đảm bảo tính thuyết phục, chuyên nghiệp. 

2. Đơn xin thôi việc, nghỉ phép không lương

Nếu bạn là cá nhân thuộc các trường hợp như: ốm đau, có việc riêng cần giải quyết; hoặc không có thời gian để bàn giao các nhiệm vụ;… Đây là lúc thích hợp để bạn nêu rõ các lý do của mình.

  Top lý do xin nghỉ việc sếp không thể từ chối

Một điểm cần lưu tâm là bạn cần có thiện chí nghỉ việc không lương để có thể nhận được sự thông cảm từ nhà quản lý/tổ chức nhân sự. Đừng khiến bản thân rơi vào các tình trạng vi phạm hợp đồng!

3. Đơn xin thôi việc tạm thời (thời gian ngắn)

Đã là một nhân sự chính thức, bạn cần tuân thủ mọi điều luật và chế độ quản lý được đặt ra. Vì vậy, dù là tạm nghỉ có thời hạn và quay trở lại, bạn cũng cần viết đơn xin nghỉ việc. Điều này thể hiện bạn là người có trách nhiệm với tổ chức. 

Các bạn lưu ý, cách viết cho loại đơn xin nghỉ việc này là thông báo tới công ty về: lý do, thời gian trở lại làm việc,… Không khó để nhận được sự chấp thuận nếu ban có cách trình bày lý do chính đáng và một thái độ chuyên nghiệp.

Những lý do viết đơn xin nghỉ việc

Tùy vào từng trường hợp cụ thể mà mỗi cá nhân có lý do xin nghỉ việc tương ứng. Cùng điểm qua các lý do viết đơn thôi việc hợp lý, chính đáng và ngược lại.

1. Các do xin nghỉ việc chính đáng

Mong muốn đổi môi trường làm việc phù hợp hơn.

Những định hướng phát triển hiện tại không đúng với kỳ vọng.

Các vấn đề về di chuyển cá nhân.

Chế độ đãi ngộ không tương xứng với sự nỗ lực cá nhân.

Sự thăng tiến chậm hoặc nhận thấy không có cơ hội nào để tiếp tục phát triển trong sự nghiệp.

Những “nội chiến” từ các mâu thuẫn, bất đồng công sở.

Ảnh hưởng đa chiều từ các công việc bên ngoài.

Các lý do cá nhân: tâm lý, tình cảm.

Văn hóa công ty chưa thực sự phù hợp với cá tính.

Có những môi trường làm việc lý tưởng hơn.

2. Các lý do xin nghỉ việc không chính đáng

đơn xin nghỉ việc
Có nhiều lý do nghỉ việc được đặt ra trong lá đơn trình bày.

Hoàn cảnh gia đình không cho phép.

Bất khả khàng trong việc kết nối mọi người.

Xu hướng tâm lý và cảm xúc cá nhân chi phối.

Chưa hài lòng với lịch trình làm việc và các quy tắc của công ty.

Công việc nhàm chán, thiếu tính bức phá và các cơ hội sáng tạo.

Với những lý do chính đáng trên, chắc chắn là bạn không nên sử dụng.

Đơn giản vì nó không được nhà quản lý đánh giá cao bạn. Mọi cố gắng của bạn có thể bị mất đi. Trong việc viết đơn, bạn nên thành thật chia sẻ những lý do của bản thân. Đừng nói dối trong mọi trường hợp. Một khi sự thật được phát hiện, bạn mất đi uy tín lẫn cả những tình cảm của cấp trên, các đồng nghiệp đối với bạn. Vậy nên, hãy chân thật khi viết đơn xin thôi việc.

Nếu đã xác định rõ lý do nghĩ việc, bạn cũng nên lập ra kế hoạch trở lại; hoặc sự chuẩn bị tốt nhất cho thời gian mà bạn vắng mặt. Đồng thời, bạn hãy tìm kiếm cho bản thân những mẫu đơn xin nghỉ việc hợp lý, đúng chuẩn để có thể thuận lợi chuyển sang một môi trường làm việc thích hợp hơn. Ra đi hay ở lại thì bạn đều phải để lại ấn tượng đẹp với tổ chức/doanh nghiệp của mình.

  Top lý do xin nghỉ việc sếp không thể từ chối

Tìm hiểu về quy trình xin nghỉ việc đúng hiệu lực

1. Bước đầu tiên – Thông báo nghỉ việc

Việc cần làm đầu tiên là bạn cần thông báo cho người quản lý, ngưới giám sát hoặc các cấp cao hơn. Tùy vào mỗi công ty, bạn phải thực hiện thông báo về Team Leader hay phòng nhân sự khoảng 15-30 ngày trước khi chính thức thôi việc. Đây là khoảng thời gian tương ứng với phụ lục pháp lý được trích trong hợp đồng lao động.

Và việc bạn cần làm là tuân thủ chúng. Đây cũng là thời gian công ty có thể sắp xếp và tuyển chọn nguồn nhân sự mới cho vị trí bạn nghỉ việc. Việc báo trước cho nhân sự phản ánh bạn là một cá nhân có thái độ tốt và tính trách nhiệm cao.

2. Bàn giao công việc và những thứ có liên quan

Khi lá đơn xin thôi việc của bạn được duyệt, kế tiếp chính là bước bàn giao công việc. Trong thời gian đó, nhiệm vụ của bạn là phải hoàn tất các công việc dang dở trong thời gian quy định còn lại. Tiếp đó là hệ thống các nội dung công việc, lưu trữ và bàn giao lại cho nhân sự mới (nếu có).

Những thứ có liên quan như tài sản, giấy tờ cũng được sắp xếp theo quy trình. Đặc biệt, chính bạn là người chia sẻ, hướng dẫn lại công việc cho người mới; trao đổi và trình bày với họ nắm rõ quy chế và cách xử lý công việc trong thời gian tới.

3. Tuân thủ hiệu lực hợp đồng lao động 

Nếu rời đi không bao trước, không có đơn xin thôi việc và không nhận được sự đồng ý của công ty, bạn sẽ phải chịu trách nhiệm cho hành động của mình. Việc đơn phương chấm dứt hợp đồng mà chưa có sự chấp thuận, bạn sẽ phải thực hiện các nghĩa vụ như sau:

Không nhận được trợ cấp thôi việc.

Bạn phải bồi thường cho người sử dụng lao động từ ½ đến một tháng tiền lương.

Tùy theo từng loại hợp đồng bổ sung hay quy chế riêng từng doanh nghiệp, bạn có thể được yêu cầu hoàn trả toàn bộ chi phi đào tạo ban đầu.

Việc đơn phương chấm dứt hợp đồng khiến bạn có một “chấm đen” trong hồ sơ xin việc. Và đó là rào cản khiến bạn khó khăn trong việc tìm kiếm công việc mới.

Từ những phân tích trên cho thấy, mọi thứ đều phải tuân thủ các quy trình. Bạn cần thực hiện đầy đủ việc viết đơn xin nghỉ việc để để đảm bảo quyền lợi cũng như trách nhiệm của bản thân mình. Tất nhiên vẫn phải lưu tâm về một lý do xin nghỉ việc hợp lý.

Mẹo ứng xử “khôn khéo” khi viết đơn xin nghỉ việc

Như bạn đã biết, viết mẫu đơn xin thôi việc không phải chỉ dừng lại ở quy trình gửi đơn, chấp thuận rồi nghỉ một mạch. Mà nó cần quy trình và đôi khi là cả một nghệ thuật.

Việc khéo léo và tinh tế trong các thủ thuật viết đơn xin nghỉ việc sẽ cho thấy bạn là một nhân viên chuyên nghiệp. Hãy quan tâm và bỏ túi những cách thức dưới đây.

1. Suy nghĩ thận trọng trước khi quyết định gửi đơn

đơn xin nghỉ việc
đơn xin nghỉ việc

Đây thật sự là một bước quan trọng. Bạn không thể thích thì nghỉ. Việc tùy hứng thể hiện bạn là người thiếu trách nhiệm. Hãy đặt ra các câu hỏi, sau đó cân nhắc trước khi đi đến quyết định viết đơn xin thôi việc.

Sau đây là một vài suy nghĩ và phán đoán bạn nên tham khảo:

Liệu bạn đã giải quyết hết những công việc còn lại chưa?

Bạn có chắc chắn tìm được việc mới sau khi nghỉ việc?

Lý do xin việc ấy liệu là nhất thời? Nó có tương xứng với những công sức bạn cống hiến hay không?

Ở môi trường làm việc mới, các chế độ phúc lợi, các kỹ năng, kiến thức mới bạn học được có giúp bạn nhanh chóng thăng tiến như kỳ vọng?

Rất nhiều thứ cần bạn suy nghĩ kỹ lưỡng. Do đó, bạn không thể đưa ra các quyết định một cách vội vàng. Hãy thật sự thận trọng khi đi quyết định rời đi. Khi đã thật sự lựa chọn được hướng đi, hãy dành tâm sức đầu tư cho lá đơn xin nghỉ việc một cách hoàn hảo. Nó không đơn giản chỉ là một tờ trình, mà đó còn là sự tôn trọng với chính tổ chức nhân sự của bạn.

2. Thời điểm rời đi rất quan trọng

Sau khi đã cân nhắc và có những quyết định, bạn nên quan tâm đến tình thế hiện tại của công ty.

Ví dụ như: công ty có đang thật sự ổn về nhân lực? Các chiến lược phát triển sản phẩm, dự án hoạt động, sự kiện thường niên có đang vào thời điểm nóng hay không? Nếu là một nhân viên thật sự có tâm, bạn phải nhìn nhận rõ vấn đề này. Bạn không nên rời đi nếu công ty rơi vào khủng hoảng khó khăn. Hãy nghĩ đến công ty dù đó chỉ là vài tháng tới!

Trước khi rời đi, đây có phải thời gian thích hợp để bạn bỏ đi những mâu thuẫn vốn có với sếp, đồng nghiệp? Thật sự đó là một suy nghĩ đúng đắn! Bạn nên cởi mở, tìm kiếm cơ hội để tháo gở những nút thắt bất đồng nảy sinh. Có thế như thế, khi “tốt nghiệp” môi trường làm việc cũ, bạn sẽ cảm thấy thoải mái hơn.

Đồng thời, đó cũng là cơ sở giúp nuôi dưỡng các mối qun hệ đẹp của bạn. Từ suy nghĩ đó, bạn có thể tự tin tìm kiếm công việc mới cũng như mong đợi về một chặng đường tươi đẹp, suôn sẻ hơn.

Cách viết mẫu đơn xin nghỉ việc chuẩn nhất

1. Phần mở đầu

  • Quốc hiệu, tiêu ngữ

Bạn cần phải triển khai viết quốc hiệu, tiêu ngữ trước khi đi vào chi tiết. Cụ thể như sau:

CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM

Độc lập – Tự do – Hạnh phúc

  • Tên đơn: Đon xin nghỉ việc, đơn xin thôi việc,… (Đơn nghỉ phép sẽ gắn với mục đích cụ thể tùy trường hợp thực tế).
  • Kính gửi: Đơn xin phép được gửi cho ai? Người viết đơn cần xác định rõ đối tượng cần gửi đơn. Đó có thể là cấp trên, người quản lý, Team Lead, trưởng nhóm,…

2. Phần nội dung trọng tâm mẫu đơn xin nghỉ việc

  • Phần này rất quan trọng và cần đảm bảo đầy đủ các nội dung như sau gồm:

–  Các thông tin liên quan đến người viết đơn

–  Mục đích của việc viết đơn xin nghỉ việc

–  Lý do xin nghỉ phép: Các lý do phải thật sự chính đáng và hợp lý trong hoàn cảnh hiện thời của tổ chức/doanh nghiệp.

–  Lời cam kết về sự thật và lởi cảm ơn

– Xác nhận minh chứng thông qua chữ ký (ký và ghi rõ họ tên)

  • Đặc biệt, một phần đáng lưu tâm nữa, bạn nên trình bày thêm những nội dung sau:

– Những kinh nghiệm, các giá trị bạn có được trong thời gian làm việc tại công ty

– Chia sẻ về quá trình trưởng thành của bạn

– Gửi lời cảm ơn và sự trân trọng với những ai đã giúp đỡ bạn

– Nhắc lại những ấn tượng về các cột mốc/dấu ấn khó quên của bạn

– Trình bày lý do rời đi một cách chân thật, có chiều sâu

– Nếu có thể, hãy đề cử các ứng viên thay thế phù hợp

Những lưu ý khi viết đơn xin nghỉ việc

Sau đây là những lưu ý sẽ thật sự giúp bạn có một lá đơn xin thôi việc thật sự thuyết phục.

đơn xin nghỉ việc
Những tips cần quan tâm khi viết đơn xin thôi việc rất cần thiết.

1. Văn phong lịch sự 

Thái độ quyết định tất cả. Điều này không bao giờ là sai. Khi viết mẫu đơn xin nghỉ việc, bạn cần có một thái độ tôn trọng, lịch sự. Điều đó được thể hiện qua văn phong trình bày, ngôn ngữ bạn sử dụng. Đừng quá phô trương các cảm xúc vào lá đơn mà hãy kiếm soát tốt nó.

2. Nội dung mô tả về lý do phải chi tiết

Lý do nghỉ việc. thôi việc là nội dung trọng tâm mà bạn muốn truyền tải đến cấp trên. Và dù là loại văn bản, giấy tờ dưới hình thức nào, nội dung đều phải được chú trọng. 

Bên cạnh lý do hợp lý, cách trình bày rõ ràng, chân thật, bạn nên chia sẻ với người quản lý về thời gian mà bạn sẽ trở lại với công việc (trường hợp bạn tạm thời nghỉ việc). Đó được hiểu là lời cam kết mang dấu ấn uy tín; và trách nhiệm của bạn với công việc. Trong trường hợp đó, hãy linh hoạt để lại thông tin cá nhân, đề phòng những vấn đề phát sinh liên quan đến quyền lợi.

Tương tự, nếu bạn là cá nhân chịu trách nhiệm quản lý trực tiếp các dự án lớn, hãy nhanh chóng bàn giao. Công tác bàn giao cần được tiến hành lập tức và trong khoảng thời gian ngắn. Bạn phải đảm bảo cho dù thế nào, khi bạn rời đi, mọi quy trình vẫn được tiếp diễn. Đồng thời, chắc chắn không tạo ra sự thay đổi và ảnh hướng tiêu cực đến mọi người xung quanh bạn.

Làm gì để nghỉ việc chuyên nghiệp?

Chắc chắn rằng sau khi rời đi, việc bạn làm đầu tiên là tìm việc mới. Hãy cố gắng hoàn thiện một bộ hồ sơ xin việc để đảm bảo quá trình ấy diễn ra thuận lợi. Nếu là một cá nhân nghỉ việc chuyên nghiệp, bạn cần quan tâm đến những yếu tố xung quanh.

Cùng TopDev xem qua các thông tin dưới đây! Chúng đều là những khía cạnh nhỏ. Song, chúng có ích trong mối quan hệ với cách thức tổ chức/quản lý nhân sự.

1. Rời đi bí mật

Bí mật ở đây không phải bạn tự ý rời đi không viết mẫu đơn thôi việc. Mà nó hiểu là bạn không nên chia sẻ chúng cho những người bạn thân thiết.

Đặc biệt, trước khi tìm được công việc phù hợp mới, bạn lại không nên chia sẻ. Bởi đơn giản, việc bạn nghỉ việc có thể làm ảnh hưởng đến tâm trạng, suy nghĩ của những người xung quanh. Hệ quả tiêu cực hơn là khiến cho hiệu suất công việc của họ bị thụt lùi.

2. Hệ thống hóa và lưu lại những thứ bạn đã làm

Mọi bài học dù ở môi trường nào đều có giá trị. Nó đều có ích cho sự nghiệp phát triển riêng của bạn sau này. Vì thế, dù nghỉ việc, bạn vẫn phải có trách nhiệm lưu trữ hồ sợ, thông tin về các dự án bạn thực hiện.

Điều này vừa có lợi cho việc thiết lập tài liệu bàn giao cho nhân sự mới; vừa giúp bạn nhìn nhận lại những nỗ lực và thành quả thực tế trong hành trình dài vừa qua.

Mẫu đơn xin thôi việc chuẩn nhất

đơn xin nghỉ việc
1-đơn xin nghỉ việc
đơn xin nghỉ việc
2-đơn xin nghỉ việc
đơn xin nghỉ việc
3-đơn xin nghỉ việc
đơn xin nghỉ việc
4-đơn xin nghỉ việc

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

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

Những tựa sách nổi tiếng dành cho Software Developer – Phần 3

sách cho software developer
Những tựa sách nổi tiếng dành cho Software Developer – Phần 1

Tác giả: Andrew

Giới thiệu

Với hai bài viết được chia sẻ ở các phần trước, các Software Developer đã phần nào tìm được cho mình những nội dung tham khảo tốt nhất. Phần này sẽ chia sẻ với các dev phần còn lại của chuỗi các tựa sách nổi tiếng về phát triển phần mềm.

software developer
Chuỗi các tựa sách về kỹ năng Software Developer cho công việc build phần mềm
  Những tựa sách nổi tiếng dành cho Software Developer - Phần 1
  Những tựa sách nổi tiếng dành cho Software Developer – Phần 2

Những cuốn sách cho Software Developer được lựa chọn nhiều nhất

15. Introduction to Algorithms – Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein

Một số sách về thuật toán hiện có trên thị trường dù khá chặt chẽ nhưng không đầy đủ. Cuốn sách về các thuật toán này là sự kết hợp độc đáo giữa tính chặt chẽ và tính toàn diện. Nó bao gồm một loạt các thuật toán chuyên sâu, nhưng vẫn làm cho thiết kế và phân tích của chúng có thể tiếp cận với mọi cấp độ độc giả. Mỗi chương tương đối khép kín và có thể được sử dụng như một chủ đề nghiên cứu khá hiệu quả. Những nội dung được chia sẻ trong đó đã được giữ nguyên bản mà không làm mất đi độ sâu của nội dung hoặc tính chặt chẽ của toán học.

Xem thêm các việc làm hấp dẫn KMS Technology tuyển dụng 2020

16. Agile Software Development: Principles, Patterns, and Practices – Robert C. “Uncle Bob” Martin

Agile Software Development được viết bởi một Software Developer nên toàn bộ nội dung của cuốn sách cũng chủ yếu liên quan đến vấn đề Software Developing. Nội dung cuốn sách bao gồm các phương pháp OOD, UML, Design Patterns, Agile và XP với mô tả chi tiết về một thiết kế phần mềm hoàn chỉnh cho các chương trình có thể tái sử dụng trong C++ và Java. Sử dụng cách tiếp cận thực tế, giải quyết vấn đề, nó chỉ ra cách phát triển một ứng dụng hướng đối tượng – từ giai đoạn đầu của phân tích, thông qua thiết kế cấp thấp và triển khai.

Xem thêm Tiếng Anh dành cho lập trình viên

Cuốn sách bao gồm các phần: Tin học và Động lực học, Nguyên tắc thiết kế lớp học, Quản lý sự phức tạp, Nguyên tắc thiết kế bao bì, Phân tích và Thiết kế, Các mẫu và Giao cắt Mô hình. Giải thích các nguyên tắc của OOD, từng cái một, và sau đó tác giả chứng minh nội dung được giải thích với nhiều ví dụ, thiết kế hoàn toàn được làm việc kỹ lưỡng và nghiên cứu điển hình. Thảo luận chi tiết các phương pháp thiết kế và phát triển phần mềm lớn.

Tham khảo tuyển dụng software engineer lương cao trên TopDev

17. CODE: The Hidden Language of Computer Hardware and Software – Charles Petzold

Trong CODE các tác giả cho chúng ta thấy những cách khéo léo mà các lập trình viên có thể vận dụng ngôn ngữ và phát minh ra các phương tiện giao tiếp mới với nhau. Và thông qua CODE, chúng ta cũng sẽ nhận thấy sự khéo léo này và sự bắt buộc giao tiếp của chính con người chúng ta đã thúc đẩy những đổi mới công nghệ trong hai thế kỷ qua như thế nào.

Sử dụng các vật dụng hàng ngày và các hệ thống ngôn ngữ quen thuộc như chữ nổi Braille và mã Morse, tác giả Charles Petzold đã tạo nên một câu chuyện sáng tạo cho bất kỳ ai từng thắc mắc về cách hoạt động đầy khó hiểu bên trong máy tính và các loại máy thông minh khác.

sách cho software developer
Tham khảo thêm nhiều đầu sách kỹ năng giúp dev nâng cao tay nghề

18. Sách cho Software Developer “The Art of Computer Programming” – Donald Knuth

Đây là cuốn sách kinh điển đã được xuất bản cách đây vài thập kỷ nhưng đến thời điểm hiện tại, tác phẩm vẫn giữ được tính hiệu quả của mình với các nội dung đầy chất lượng. Một trong những điểm mạnh nhất của cuốn sách là bộ sưu tập các bài toán cực kỳ ấn tượng đi kèm với mỗi chương. Tác giả đã chọn các vấn đề một cách cẩn thận và lập chỉ mục toàn bộ nội dung theo độ khó. Giải quyết một số lượng đáng kể các vấn đề này sẽ giúp bạn có được sự hiểu biết vững chắc về các vấn đề xung quanh chủ đề đã cho. Hơn nữa, các bài tập có một loạt các bài toán kinh điển.

Xem thêm các việc làm KMS tuyển dụng Intern

19. Clean Architecture: A Craftsman’s Guide to Software Structure and Design – Robert C. “Uncle Bob” Martin

Cuốn sách này sẽ giúp bạn tìm hiểu công việc mà kiến ​​trúc sư phần mềm cần đạt được là những gì, và các nguyên tắc cũng như cách thực hiện cốt lõi để đạt được điều đó. Người viết cần nắm vững các nguyên tắc thiết kế phần mềm cần thiết để giải quyết chức năng, tách thành phần và quản lý dữ liệu. Xem cách các mô hình lập trình áp đặt kỷ luật bằng cách hạn chế những gì nhà phát triển có thể làm cũng như hiểu điều gì cực kỳ quan trọng và điều gì chỉ đơn thuần là “chi tiết”.

  Làm thế nào để sắp xếp Clean Architecture theo Modular Patterns trong 10 phút?

Ngoài ra, với Clean Architecture, các tác giả sẽ triển khai các cấu trúc cấp cao, tối ưu cho web, cơ sở dữ liệu, máy khách dày, bảng điều khiển và các ứng dụng nhúng, xác định ranh giới và lớp thích hợp, đồng thời tổ chức các thành phần và dịch vụ. Dựa vào đó, bạn sẽ xem được lý do tại sao thiết kế và kiến ​​trúc gặp lỗi và cách ngăn chặn (hoặc sửa chữa) những lỗi này như thế nào.

Xem thêm các việc làm KMS Technology tuyển dụng hấp dẫn tại TopDev

20.Sách cho Software Developer “Patterns of Enterprise Application Architecture” – Martin Fowler

Cuốn sách này thực sự được nhiều người dùng đánh giá là cuốn sách có nội dung hai trong một. Phần đầu tiên của Patterns of Enterprise Application Architecture là một hướng dẫn ngắn về phát triển ứng dụng doanh nghiệp, bạn có thể đọc từ đầu đến cuối để hiểu phạm vi bài học của cuốn sách. Phần tiếp theo, cũng là phần chính trong toàn bộ nội dung của cuốn sách, là tài liệu tham khảo chi tiết về bản thân các mẫu. Mỗi mẫu cung cấp thông tin sử dụng và triển khai, cũng như các ví dụ mã chi tiết trong Java hoặc C#. Toàn bộ cuốn sách cũng được minh họa phong phú bằng các sơ đồ UML để giải thích thêm về các khái niệm.

Khi tìm hiểu về những thông tin được cung cấp trong cuốn sách này, bạn sẽ có kiến ​​thức cần thiết để đưa ra các quyết định quan trọng trong việc xây dựng một ứng dụng doanh nghiệp và các mô hình đã được chứng minh để sử dụng khi xây dựng chúng.

Xem thêm việc làm tester đãi ngộ tốt trên TopDev

Kết luận

Chuỗi bài viết này là thông tin tổng hợp gần như đầy đủ như cuốn sách về Software Developer phổ biến và hiệu quả nhất ở thời điểm hiện tại. Tìm đọc các nguồn này chắc chắn sẽ mang đến cho bạn những kỹ năng làm việc hiệu quả hơn trong thời gian tới.

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

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

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

Seminar môn Cấu trúc dữ liệu và giải thuật

Seminar môn Cấu trúc dữ liệu và giải thuật

Bài viết được sự cho phép của tác giả Khiêm Lê

Giới thiệu

Mình vừa làm seminar kết thúc môn học Cấu trúc dữ liệu và giải thuật, mình sẽ chia sẻ với các bạn về seminar của mình. Đề tài của mình: Đánh giá hiệu suất các thuật toán tìm kiếm và so sánh.

Bình thường khi học, độ phức tạp về thời gian của các thuật toán mà các bạn được giới thiệu đều là Big O notation, nhìn vào đó các bạn có thể biết được thuật toán nhanh hay chậm. Tuy nhiên, các bạn lại không biết được thuật toán nhanh hay chậm hơn như thế nào. Do đó mình muốn tạo ra chương trình thực hiện các thuật toán và đo thời gian thực hiện, từ đó các bạn có thể dễ dàng so sánh và thấy được hiệu suất của thuật toán.

  Crawl dữ liệu bằng JavaScript ngay trên trình duyệt
  Tìm hiểu về giải thuật: Một số phương pháp sắp xếp cơ bản

Dù mỗi máy có tốc độ xử lý khác nhau, hiệu suất thuật toán phụ thuộc vào rất nhiều yếu tố, tuy nhiên, các thuật toán cùng thực hiện trên cùng một máy, tức là cùng 1 điều kiện, vậy nên chúng ta vẫn có thể thấy được sự chênh lệch hiệu suất của các thuật toán.

Mình quyết định sử dụng WPF để có thể dễ dàng custom giao diện đẹp hơn.

Tính năng

Một số tính năng của phần mềm mình viết:

  • Tạo dãy số ngẫu nhiên
  • Lưu vào file
  • Load dãy số từ file
  • Tìm kiếm theo 3 thuật toán
  • Sắp xếp theo 7 thuật toán
  • Xem kết quả thời gian thực hiện thuật toán
  • Xem kết quả dãy sau khi sắp xếp
  • Xem code thuật toán bằng C++

Demo

Một số screenshot Seminar của mình:

Seminar môn Cấu trúc dữ liệu và giải thuật
Seminar môn Cấu trúc dữ liệu và giải thuật
Seminar môn Cấu trúc dữ liệu và giải thuật

Source code

Các bạn có thể xem code seminar của mình trên Github. Có một lưu ý nhỏ là thư mục ViewCode phải được đặt cùng cấp với file exe thì tính năng View code mới có thể lấy code ra được.

Tổng kết

Seminar này mình chỉ làm sơ sài thôi, code cũng không clean, tổ chức chưa tốt lắm, các bạn tham khảo cho vui thôi nha!

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

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

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

Một ví dụ đơn giản giải thích hàm đệ quy

Một ví dụ đơn giản giải thích hàm đệ quy

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

Làm sao để in ra từ 1 đến 10 bằng hàm đệ quy?

I. Hàm đệ quy

Recursive function (hàm đệ quy) là function mà nó tự gọi chính nó. Phần định nghĩa function trông như thế này:

def foo():
    dosomething()
    foo() # gọi chính nó
    maybedosomething()
    return otherthing

Recursion là một lối suy nghĩ, một cách lập trình rất phổ biến trong functional programming (lập trình hàm) nhưng ở thế giới còn lại, nó không thực sự phổ biến hay có vẻ quen thuộc. Quan điểm về viết recursive function cũng khác nhau, có người bảo dễ, có người mãi không hiểu gì. Và nếu bạn thuộc nhóm không hiểu gì, thì không phải do bạn dốt, chỉ là chưa quen thôi.

  10 Bí quyết tuyển dụng giúp bạn tăng tỉ lệ nhận offer tức thì!
  3 chỉ số quan trọng đánh giá quy trình tuyển dụng

II. Recursive print

Đề bài: Cho số nguyên dương N, viết function in ra màn hình từ 1 đến N.

Lời giải:

Cách bình thường:

def lprint(n):
    '''
    Prints from 1 to n the loop way
    '''
    for i in range(1, n+1):
        print(i)
lprint(3)

Còn đây cách đệ quy:

def rprint(n):
    '''
    Prints from 1 to n recursive way
    '''
    if n == 0:
        return
    else:
        rprint(n-1)
        print(n)
rprint(3)

Output:

1
2
3

Nếu bạn không hiểu đoạn code trên thực sự làm gì qua từng bước, hãy xem phiên bản chỉnh sửa một chút để in ra giải thích sau:

INPUT = 10
def rprint2(n):
    pad = 3 * ' ' * (INPUT - n)
    print('%sInside function with %d' % (pad, n))
    if n == 0:
        return
    else:
        print('%s calling rprint2(%d)' % (pad + '|' + '_', n-1))
        rprint2(n-1)
        print('%s| printing %d' % (pad, n))
        print(n)
        return
rprint2(INPUT)

Output:

Inside function with 10
|_ calling rprint2(9)
   Inside function with 9
   |_ calling rprint2(8)
      Inside function with 8
      |_ calling rprint2(7)
         Inside function with 7
         |_ calling rprint2(6)
            Inside function with 6
            |_ calling rprint2(5)
               Inside function with 5
               |_ calling rprint2(4)
                  Inside function with 4
                  |_ calling rprint2(3)
                     Inside function with 3
                     |_ calling rprint2(2)
                        Inside function with 2
                        |_ calling rprint2(1)
                           Inside function with 1
                           |_ calling rprint2(0)
                              Inside function with 0
                           | printing 1
1
                        | printing 2
2
                     | printing 3
3
                  | printing 4
4
               | printing 5
5
            | printing 6
6
         | printing 7
7
      | printing 8
8
   | printing 9
9
| printing 10
10

Hãy đọc từ trên xuống dưới, chậm rãi, để hiểu chuyện gì đã xảy ra. Nếu vẫn chưa hiểu?

Hãy đọc lại từ đầu!

Ví dụ trên chỉ nhằm minh hoạ recursive function làm việc như thế nào, chứ không có lợi ích gì khi viết hàm recursive trong trường hợp này.

Recursive function sẽ trở nên rất hữu dụng nếu vấn đề được định nghĩa theo cách đệ quy (các hàm toán học), giải bài toán Tháp Hà Nội, hay chỉ đơn giản là muốn tiến gần hơn một bước đến Functional programming.

Link Jupyter notebook

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

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

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

Phân quyền người dùng với Laravel Authorization

Phân quyền người dùng với Laravel Authorization

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

Bất kể hệ thống website nào cũng có người dùng và đi kèm với nó là việc xác thực (authentication) và phân quyền (authorization) với từng người dùng. Xác thực trong Laravel là khá đơn giản với Laravel Authentication, chúng ta cũng có thể tận dụng các hệ thống khác như mạng xã hội để xác thực, ví dụ xác thực người dùng bằng FacebookGoogleTwitter…  Bên cạnh đó, chúng ta cũng rất cần phân quyền cho người dùng để đảm bảo các vấn đề về bảo mật và tuân thủ các chính sách từng hệ thống. Ví dụ như có những người dùng được phép chỉnh sửa hoặc xóa một tài nguyên nhưng cũng có những người dùng chỉ được phép đọc thông tin. Từ phiên bản Laravel 5.1 trở về trước, công việc này phải thực hiện thông qua các gói ACL (Access Control List) như Entrust, Sentinel hay Laravel-ACL thì hiện nay Laravel đã có hỗ trợ trực tiếp trong core của framework. Với việc sử dụng các gói ACL ở ngoài, các quyền cho người dùng chỉ là các cờ, nếu muốn các nghiệp vụ phức tạp trong phân quyền, bạn sẽ rất khó khăn và phải đưa vào Controller. Sử dụng Laravel Gate tránh được một số các nhược điểm của việc sử dụng các gói ACL ngoài như sau:

  • Sử dụng Laravel Gate cho bạn sự tự do, bạn có thể sử dụng cho các trường hợp cực phức tạp tùy ý do nó không bắt buộc phải implement trong các model.
  • Bạn có hoàn toàn tự chủ về các chính sách phân quyền, với Laravel Gate các xử lý truy cập có thể tách biệt với các xử lý về nghiệp vụ, loại bỏ sự phụ thuộc và code trong các controller dễ đọc hơn.

Gate và Policy giống như Route với Controller, Gate cũng cấp một giải pháp dựa trên Closure để phân quyền trong khi các policy giống với controller nhóm các logic nghiệp vụ liên quan đến Model hoặc các tài nguyên. Chúng ta cùng tìm hiểu về Gate trước khi tìm hiểu về Policy. Phần lớn các ứng dụng sẽ sử dụng cả Gate và Policy, Gate được áp dụng cho các hành động không liên quan đến Model hoặc các tài nguyên như việc truy nhập vào trang quản trị dashboard. Ngược lại, policy được sử dụng khi bạn muốn cho phép một hành động truy nhập vào một model hoặc nguồn tài nguyên.

  API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth
  Các Laravel route tips giúp bạn cải thiện routing

Laravel Gate

Gate là các Closure được xác định nếu một người dùng được xác thực để thực hiện một hành động, nó được định nghĩa trong App\Providers\AuthServiceProvider sử dụng facade Gate. Gate luôn nhận một thực thể user là tham số thứ nhất và có thể có các tham số tùy chọn khác như Eloquent Model:

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    Gate::define('update-post', function ($user, $post) {
        return $user->id == $post->user_id;
    });
}

Gate cũng có thể định nghĩa sử dụng dạng callback string giống như Controller:

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    Gate::define('update-post', 'PostPolicy@update');
}

Resource Gates Bạn có thể định nghĩa nhiều Gate sử dụng phương thức resource

Gate::resource('posts', 'PostPolicy');

Với phương thức resource nó tương tự như định nghĩa thủ công các phương thức sau:

Gate::define('posts.view', 'PostPolicy@view');
Gate::define('posts.create', 'PostPolicy@create');
Gate::define('posts.update', 'PostPolicy@update');
Gate::define('posts.delete', 'PostPolicy@delete');

Mặc định view, create, update và delete được định nghĩa. Bạn có thể override các khả năng này bằng cách truyền vào một mảng như là tham số thứ 3 cho phương thức resource. Key của mảng này định nghĩa tên khả năng trong khi giá trị định nghĩa tên phương thức.

Gate::resource('posts', 'PostPolicy', [
    'photo' => 'updatePhoto',
    'image' => 'updateImage',
]);

Phân quyền Để phân quyền thực hiện một hành động, bạn có thể sử dụng các phương thức allows và denies, chú ý rằng bạn không cần truyền người dùng đã được xác thực vào các phương thức này. Laravel sẽ tự động xử lý việc đó trong các gate Closure:

if (Gate::allows('update-post', $post)) {
    // The current user can update the post...
}

if (Gate::denies('update-post', $post)) {
    // The current user can't update the post...
}

Nếu bạn muốn xác định một người dùng nào đó có được phân quyền để thực hiện một hành động hay không, bạn có thể sử dụng phương thức forUser trên facade Gate:

if (Gate::forUser($user)->allows('update-post', $post)) {
    // The user can update the post...
}

if (Gate::forUser($user)->denies('update-post', $post)) {
    // The user can't update the post...
}

Policy

Tạo policy

Policy là các class quản lý logic trong phân quyền liên quan đến một Model hoặc tài nguyên nào đó. Ví dụ, nếu ứng dụng của bạn là một blog, bạn có thể có một model Post và một policy là PostPolicy để phân quyền các hành động người dùng như tạo hay cập nhật các bài viết. Bạn có thể tạo ra một policy bằng cách sử dụng câu lệnh Artisan make:policy, các policy được tạo ra sẽ được đặt trong thư mục app\Policies. Nếu thư mục này không tồn tại trong project, Laravel sẽ tự động tạo nó cho bạn:

php artisan make:policy PostPolicy

Câu lệnh make:policy sẽ sinh ra một class policy rỗng, nếu bạn muốn sinh ra một CRUD policy bạn cần thêm tham số –model khi thực thi câu lệnh artisan:

php artisan make:policy PostPolicy --model=Post

Đăng ký Policy

Một policy muốn sử dụng cần được đăng ký, AuthServiceProvider được đưa vào trong project Laravel chứa một thuộc tính policies để map Eloquent model với các policy tương ứng. Đăng ký một policy sẽ chỉ dẫn cho Laravel policy nào sẽ được sử dụng để phân quyền hành động cho model nào:

<?php

namespace App\Providers;

use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    /**
     * Register any application authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        //
    }
}

Logic nghiệp vụ trong Policy

Phương thức Policy Khi Policy được đăng ký, bạn có thể thêm các phương thức cho mỗi hành động cần cấp quyền. Ví dụ, định nghĩa phương thức update trên PostPolicy để xác định một user có thể cập nhật một thực thể Post. Phương thức update sẽ nhận được một User và Post như là tham số và nó trả về true hoặc false để nhận diện xem người dùng này có được phân quyền để cập nhật Post không? Trong ví dụ dưới đây, chỉ có người dùng đã viết bài mới có quyền cập nhật bài viết

<?php

namespace App\Policies;

use App\User;
use App\Post;

class PostPolicy
{
    /**
     * Determine if the given post can be updated by the user.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return bool
     */
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
}

Bạn có thể tiếp tục định nghĩa các phương thức khác trên policy này nếu cần phân quyền cho các hành động. Ví dụ, bạn có thể định nghĩa phương thức view hoặc delete để phân quyền các hành động Post khác và nhớ rằng tên các phương thức trong policy là hoàn toàn bạn có thể đặt thoải mái nếu thích.

Route Model Binding

Có những phương thức policy chỉ nhận người dùng được xác thực hiện tại và không cần một thực thể của một Model. Tình huống này dùng khi phân quyền một hành động create. Ví dụ, nếu bạn tạo một blog, bạn có thể muốn kiểm tra nếu một người dùng có được phân quyền để tạo một post bất kỳ không. Khi định nghĩa phương thức trong policy nó sẽ không nhận một thực thể của Model, như phương thức create, nó sẽ không nhận một thực thể của model. Thay vào đó, bạn nên định nghĩa phương thức chỉ với người dùng đã được xác thực.

/**
 * Determine if the given user can create posts.
 *
 * @param  \App\User  $user
 * @return bool
 */
public function create(User $user)
{
    //
}

Policy Filter

Với người dùng hiện tại, bạn muốn cấp quyền thực hiện các hành động trong một chính sách, để thực hiện bạn định nghĩa phương thức before trong policy. Phương thức before sẽ thực thi trước bất kỳ phương thức nào trong policy, nó cho bạn cơ hội để cho phép thực hiện hành động trước khi phương thức của policy mong muốn được gọi. Tính năng này rất thông dụng để cho phép các administrator có thể thực hiện bất kỳ hành động nào:

public function before($user, $ability)
{
    if ($user->isSuperAdmin()) {
        return true;
    }
}

Nếu bạn muốn một user không được phép thực hiện bất kỳ gì bạn chỉ cần trả về false trong phương thức before. Nếu null được trả về, việc cấp quyền sẽ được tiếp tục trong phương thức policy.

3. Cho phép thực hiện hành động sử dụng Policy

Thông qua User Model Model User được tạo sẵn trong project Laravel chứa hai phương thức có sẵn là can và cant. Phương thức can nhận hành động bạn muốn cấp phép và model liên quan. Ví dụ, để xác định một người dùng được phép cập nhật model Post không?

if ($user->can('update', $post)) {
    //
}

Thực hành Laravel Authorization

Chúng ta cùng xem xét một ví dụ về phân quyền trong một tờ báo điện tử bao gồm hai chức danh là phóng viên và biên tập viên.

  • Phóng viên có thể viết một bài báo mới
  • Phóng viên có thể cập nhật nội dung bài báo của họ.
  • Biên tập viên có thể cập nhật nội dung bài báo.
  • Biên tập viên có thể phát hành bài báo.

Như vậy phóng viên không thể tự phát hành bài báo và biên tập viên không thể tạo ra bài báo mới mà chỉ có quyền cập nhật và xuất bản. Chúng ta sẽ từng bước thiết kế và phát triển ứng dụng web này, nó sẽ giúp bạn hiểu cạn kẽ về Laravel Authorization.

Cài đặt môi trường Laravel

Cài đặt môi trường Laravel rất đơn giản, bạn tham khảo bài Cài đặt Laravel dễ dàng với Laragon (trong bài này sẽ lấy tên project là allaravel nhé). Tiếp theo, chúng ta thực hiện cài đặt xác thực với Laravel Authentication. Đây là những phần rất cơ bản của Laravel, bạn nên làm quen vì hầu hết các dự án mới sẽ bắt đầu bằng bước này. Kiểm tra xem môi trường hoạt động tốt chưa, mở đường dẫn http://allaravel.dev.

Tạo database, dữ liệu test với Laravel Migrate và Laravel Seeding

Việc đầu tiên của dự án báo điện tử là thiết kế database, chúng ta sẽ có 4 bảng như sau:

  • Posts: chứa các bài báo
  • Users: chứa thông tin người dùng hệ thống, được tạo khi sử dụng Laravel Authentication.
  • Roles: chứa các chức danh và quyền hạn của từng chức danh
  • Role_users: gán từng người dùng với chức danh.

Thiết kế cơ sở dữ liệu

Bạn nên tham khảo về Laravel Migrate và Laravel Seeding nếu chưa làm quen các khái niệm này.

Tạo file migrate cho cơ sở dữ liệu

Đầu tiên, chúng ta sử dụng câu lệnh artisan để tạo ra model Post kèm theo với controller PostController và file migrate bằng cách sử dụng các tùy chọn -m và -c.

php artisan make:model Post -m -c

Với câu lệnh này chúng ta có:

  • Model Post trong file app\Post.php.
  • Post Controller trong file app\Http\Controllers\PostController.php.
  • File migrate nằm trong databases\migrations\yyyy_mm_dd_xxxxxx_create_post_table.php.

Xử lý file migrate để tạo bảng post trong cơ sở dữ liệu, thiết lập các trường của bảng post như sau:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('slug')->unique();
            $table->text('body');
            $table->boolean('published')->default(false);
            $table->unsignedInteger('user_id');
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

Tiếp đến chúng ta tạo model Role kèm theo controller và file migrate:

php artisan make:model Role -m -c

Tạo các trường cho bảng roles với file migrate databases\migrations\yyyy_mm_dd_xxxxxx_create_roles_table.php:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateRolesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('slug')->unique();
            $table->jsonb('permissions')->default('{}');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('roles');
    }
}

Chú ý: trường permission chúng ta sẽ chứa một dữ liệu json thay vì tách ra thành một bảng riêng. Tiếp theo là bảng role_users chỉ cần tạo bảng do đó sử dụng câu lệnh artisan make:migrate

php artisan make:migration create_role_users_table

và định nghĩa các trường của bảng role_users trong file migrate databases\migrations\yyyy_mm_dd_xxxxxx_create_role_users_table

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateRoleUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('role_users', function (Blueprint $table) {
            $table->unsignedInteger('user_id');
            $table->unsignedInteger('role_id');
            $table->timestamps();

            $table->unique(['user_id','role_id']);
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('role_users');
    }
}

Thiết kế model map từ database sang class

Trong phần 4.1 chúng ta đã cài đặt phần xác thực cho Laravel, nó tạo ra bảng user, model User tuy nhiên model này chưa có phần phân quyền. Chúng ta sẽ thêm hai phương thức cho model User:

  • hasAccess(): kiểm tra xem người dùng có quyền thực hiện một hành động nào đó không.
  • inRole(): kiểm tra xem một người dùng có thuộc về một chức danh nào đó không.
<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'role_users');
    }

    /**
     * Checks if User has access to $permissions.
     */
    public function hasAccess(array $permissions) : bool
    {
        // check if the permission is available in any role
        foreach ($this->roles as $role) {
            if($role->hasAccess($permissions)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks if the user belongs to role.
     */
    public function inRole(string $roleSlug)
    {
        return $this->roles()->where('slug', $roleSlug)->count() == 1;
    }
}

Model User có quan hệ nhiều – nhiều với model Role thông qua bảng role_users (Xem bài xử lý quan hệ trong database với Laravel ORM Eloquent). Tiếp theo, chúng ta thay đổi model Role

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    protected $fillable = [
        'name', 'slug', 'permissions',
    ];
    protected $casts = [
        'permissions' => 'array',
    ];

    public function users()
    {
        return $this->belongsToMany(User::class, 'role_users');
    }

    public function hasAccess(array $permissions) : bool
    {
        foreach ($permissions as $permission) {
            if ($this->hasPermission($permission))
                return true;
        }
        return false;
    }

    private function hasPermission(string $permission) : bool
    {
        return $this->permissions[$permission] ?? false;
    }
}

và cuối cùng là model Post

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    protected $fillable = [
        'title', 'slug', 'body', 'user_id'
    ];

    public function owner()
    {
        return $this->belongsTo(User::class);
    }

    public function scopePublished($query)
    {
        return $query->where('published', true);
    }

    public function scopeUnpublished($query)
    {
        return $query->where('published', false);
    }
}

Trong model Post sử dụng hai local scope là published và unpublished để tiện cho các truy vấn sau này.

Tạo dữ liệu test

Chúng ta đã tạo xong các file migrate, chúng ta thêm dữ liệu kiểm thử vào bằng Laravel Seeding. Tạo các file seeder cho Role, User và Post như sau:

php artisan make:seeder RolesSeeder
php artisan make:seeder UsersSeeder
php artisan make:seeder PostsSeeder

Chúng ta sẽ tạo dữ liệu kiểm thử trong file vừa tạo ra databases\seeds\RolesSeeder.php như sau:

<?php

use Illuminate\Database\Seeder;
use App\Role;

class RolesSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $author = Role::create([
            'name' => 'Phóng viên', 
            'slug' => 'author',
            'permissions' => [
                'post.create' => true,
            ]
        ]);
        $editor = Role::create([
            'name' => 'Biên tập viên', 
            'slug' => 'editor',
            'permissions' => [
                'post.update' => true,
                'post.publish' => true,
            ]
        ]);
    }
}

Role author sẽ sử dụng cho phóng viên còn role editor sẽ sử dụng cho biên tập viên. Tiếp đến là databases\seeds\UsersSeeder.php:

<?php

use Illuminate\Database\Seeder;
use App\User;
use App\Role;

class UsersSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $author = Role::where('slug', 'author')->first();
        $editor = Role::where('slug', 'editor')->first();

        $user1 = User::create([
            'name' => 'Phóng viên 1', 
            'email' => 'pv1@allaravel.dev',
            'password' => bcrypt('123456')
        ]);
        $user1->roles()->attach($author);

        $user2 = User::create([
            'name' => 'Phóng viên 2', 
            'email' => 'pv2@allaravel.dev',
            'password' => bcrypt('123456')
        ]);
        $user2->roles()->attach($author);

        $user3 = User::create([
            'name' => 'Biên tập viên 1', 
            'email' => 'btv1@allaravel.dev',
            'password' => bcrypt('123456')
        ]);
        $user2->roles()->attach($editor);
    }
}

và databases\seeds\PostsSeeder.php:

<?php

use Illuminate\Database\Seeder;
use App\User;
use App\Post;

class PostsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $author1 = User::where('email', 'pv1@allaravel.dev')->first();
        $author2 = User::where('email', 'pv2@allaravel.dev')->first();
        $faker = Faker\Factory::create();
        for ($i=0; $i < 10; $i++) { 
          $title = $faker->sentence($nbWords = 6, $variableNbWords = true);
          $post = Post::create([
              'title' => $title, 
              'body' => $faker->text($maxNbChars = 1000),
              'slug' => str_slug($title),
              'published' => rand(0,1),
              'user_id' => $author1->id
          ]);
          $title = $faker->sentence($nbWords = 6, $variableNbWords = true);
          $post = Post::create([
              'title' => $title, 
              'body' => $faker->text($maxNbChars = 1000),
              'slug' => str_slug($title),
              'published' => rand(0,1),
              'user_id' => $author2->id
          ]);
        }
    }
}

Chú ý, gọi đến các Seeder này trong databases\seeds\DatabaseSeeder.php:

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $this->call(\RolesSeeder::class);
        $this->call(\UsersSeeder::class);
        $this->call(\PostsSeeder::class);
    }
}

Ok, vậy là phần chuẩn bị khung cho cơ sở dữ liệu và đưa vào dữ liệu kiểm thử đã xong, để thực hiện các công việc này trên database sử dụng lệnh artisan migrate với tùy chọn –seed

php artisan migrate --seed

Thiết lập chính sách phân quyền

Câu lệnh make:policy giúp tạo ra một class policy để chứa các logic về phân quyền. Trong ví dụ hiện tại, chúng ta có model Post tương ứng với class PostPolicy để phân quyền các hành động của người dùng như tạo mới bài viết, cập nhật bài viết.

php artisan make:policy PostPolicy --model=Post
Policy created successfully.

Thiết lập các chính sách truy cập trong file app\Policies\PostPolicy.php

<?php

namespace App\Policies;

use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    public function view(User $user, Post $post)
    {
        //
    }

    public function create(User $user)
    {
        return $user->hasAccess(['post.create']);
    }

    public function update(User $user, Post $post)
    {
        return $user->hasAccess(['post.update']) or $user->id == $post->user_id;
    }

    public function delete(User $user, Post $post)
    {
        //
    }

    public function publish(User $user)
    {
        return $user->hasAccess(['post.publish']);
    }

    public function draft(User $user)
    {
        return $user->inRole('editor');
    }
}

Đăng ký chính sách với hệ thống trong app\Providers\AuthServiceProvider.php:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use App\Policies\PostPolicy;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Gate::resource('post', PostPolicy::class);
        Gate::define('post.publish', PostPolicy::class . '@publish');
        Gate::define('post.draft', PostPolicy::class . '@draft');
    }
}

Định nghĩa các route liên quan đến post và có kiểm tra quyền truy xuất trong routes\web.php

Route::get('/', 'PostController@index');
Route::get('/posts', 'PostController@index')->name('list_posts');
Route::group(['prefix' => 'posts'], function () {
    Route::get('/drafts', 'PostController@drafts')
        ->name('list_drafts')
        ->middleware('auth');
    Route::get('/show/{id}', 'PostController@show')
        ->name('show_post');
    Route::get('/create', 'PostController@create')
        ->name('create_post')
        ->middleware('can:post.create');
    Route::post('/create', 'PostController@store')
        ->name('store_post')
        ->middleware('can:post.create');
    Route::get('/edit/{post}', 'PostController@edit')
        ->name('edit_post')
        ->middleware('can:post.update,post');
    Route::post('/edit/{post}', 'PostController@update')
        ->name('update_post')
        ->middleware('can:post.update,post');
    Route::get('/publish/{post}', 'PostController@publish')
        ->name('publish_post')
        ->middleware('can:post.publish');
});

Các phần phát triển ứng dụng khác

Trong phần này, chúng ta sẽ xử lý các công việc còn lại là tạo ra các view và chuẩn bị dữ liệu cho các view này thông qua controller. Trong phần 4.2 khi tạo ra model Post chúng ta cũng đã tạo ra PostController, thực hiện xử lý logic cho từng route trước khi định tuyến đến view.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;
use App\Http\Requests\StorePost as StorePostRequest;
use App\Http\Requests\UpdatePost as UpdatePostRequest;
use Auth;
use Gate;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::published()->paginate();
        return view('posts.index', compact('posts'));
    }

    public function create()
    {
        return view('posts.create');
    }

    public function store(StorePostRequest $request)
    {
        $data = $request->only('title', 'body');
        $data['slug'] = str_slug($data['title']);
        $data['user_id'] = Auth::user()->id;
        $post = Post::create($data);
        return redirect()->route('edit_post', ['id' => $post->id]);
    }

    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    public function update(Post $post, UpdatePostRequest $request)
    {
        $data = $request->only('title', 'body');
        $data['slug'] = str_slug($data['title']);
        $post->fill($data)->save();
        return back();
    }

    public function show($id)
    {
        $post = Post::published()->findOrFail($id);
        return view('posts.show', compact('post'));
    }

    public function publish(Post $post)
    {
        $post->published = true;
        $post->save();
        return back();
    }

    public function drafts()
    {
        $postsQuery = Post::unpublished();
        if(Gate::denies('post.draft')) {
            $postsQuery = $postsQuery->where('user_id', Auth::user()->id);
        }
        $posts = $postsQuery->paginate();
        return view('posts.drafts', compact('posts'));
    }
}

Tiếp theo, thực hiện tạo master layout và các view phục vụ cho các route liên quan. Tạo file app\resources\views\layouts\app.blade.php:

<!DOCTYPE html>
<html lang="vi">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="description" content="Ví dụ phân quyền trong báo điện tử sử dụng Laravel Authorization">
        <meta name="author" content="FB [allaravel.com]">
        <title>Ví dụ Laravel Authorization - Allaravel.com</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
        <link href="https://getbootstrap.com/docs/3.3/examples/jumbotron/jumbotron.css" rel="stylesheet">
    </head>
    <body>
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="">Allaravel</a>
                </div>
                <div class="collapse navbar-collapse" id="app-navbar-collapse">
                    <ul class="nav navbar-nav navbar-right">
                        @if (Auth::guest())
                            <li><a href="{{ route('login') }}">Đăng nhập</a></li>
                            <li><a href="{{ route('register') }}">Đăng ký</a></li>
                        @else
                            <li class="dropdown">
                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
                                    {{ Auth::user()->name }} <span class="caret"></span>
                                </a>

                                <ul class="dropdown-menu" role="menu">
                                    <li>
                                        <a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();"> Đăng xuất </a>
                                        <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                                            {{ csrf_field() }}
                                        </form>
                                    </li>
                                    <li>
                                        <a href="{{ route('list_drafts') }}">Bài chưa đăng</a>
                                    </li>
                                </ul>
                            </li>
                        @endif
                    </ul>
                </div>
            </div>
        </nav>
        <div class="container" style="margin-top: 50px;">
            @yield('content')
            <hr>
            <footer>
                <p>© 2017 <a href="https://allaravel.com">Allaravel.com</a>.</p>
            </footer>
        </div>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    </body>
</html>

Các view cho các hành động với user như đăng nhập, đăng ký. app\resources\views\auth\login.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Đăng nhập</div>
                <div class="panel-body">
                    <form class="form-horizontal" method="POST" action="{{ route('login') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">Địa chỉ email</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Mật khẩu</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <div class="checkbox">
                                    <label>
                                        <input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Ghi nhớ
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-8 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Đăng nhập
                                </button>

                                <a class="btn btn-link" href="{{ route('password.request') }}">
                                    Quên mật khẩu?
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

app\resources\views\auth\register.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Đăng ký tài khoản</div>
                <div class="panel-body">
                    <form class="form-horizontal" method="POST" action="{{ route('register') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                            <label for="name" class="col-md-4 control-label">Họ và tên</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required autofocus>

                                @if ($errors->has('name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">Địa chỉ Email</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Mật khẩu</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="password-confirm" class="col-md-4 control-label">Nhập lại mật khẩu</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('role') ? ' has-error' : '' }}">
                            <label for="role" class="col-md-4 control-label">Chức danh</label>

                            <div class="col-md-6">
                                <select id="role" class="form-control" name="role" required>
                                @foreach($roles as $id => $role)
                                    <option value="{{$id}}">{{$role}}</option>
                                @endforeach
                                </select>

                                @if ($errors->has('role'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('role') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Đăng ký
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Các view cho việc tạo, cập nhật bài viết và các hành động khác như danh sách bài viết chưa đăng, hiển thị chi tiết app\resources\views\posts\index.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        @foreach($posts as $post)
        <div class="col-md-4">
            <h2>{{ $post->title }}</h2>
            <p>{{ str_limit($post->body, 100) }}</p>
            <p><a class="btn btn-default" href="{{ route('show_post', ['id' => $post->id]) }}" role="button">Chi tiết »</a></p>
        </div>
        @endforeach
    </div>
</div>
@endsection

app\resources\views\posts\create.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">Bài viết mới</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ route('store_post') }}">
                        {{ csrf_field() }}
                        <div class="form-group{{ $errors->has('title') ? ' has-error' : '' }}">
                            <label for="title" class="col-md-3 control-label">Tiêu đề</label>
                            <div class="col-md-9">
                                <input id="title" type="text" class="form-control" name="title" value="{{ old('title') }}" required autofocus>
                                @if ($errors->has('title'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('title') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group{{ $errors->has('body') ? ' has-error' : '' }}">
                            <label for="body" class="col-md-3 control-label">Nội dung</label>
                            <div class="col-md-9">
                                <textarea name="body" id="body" cols="30" rows="8" class="form-control" required>{{ old('body') }}</textarea>
                                @if ($errors->has('body'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('body') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-md-9 col-md-offset-3">
                                <button type="submit" class="btn btn-success">
                                    Tạo bài viết mới
                                </button>
                                <a href="{{ route('list_posts') }}" class="btn btn-success">
                                    Hủy bỏ
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

app\resources\views\posts\edit.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">Cập nhật bài viết</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ route('update_post', ['post' => $post->id]) }}">
                        {{ csrf_field() }}
                        <div class="form-group{{ $errors->has('title') ? ' has-error' : '' }}">
                            <label for="title" class="col-md-3 control-label">Tiêu đề</label>
                            <div class="col-md-9">
                                <input id="title" type="text" class="form-control" name="title" value="{{ old('title', $post->title) }}" required autofocus>
                                @if ($errors->has('title'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('title') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group{{ $errors->has('body') ? ' has-error' : '' }}">
                            <label for="body" class="col-md-3 control-label">Nội dung</label>
                            <div class="col-md-9">
                                <textarea name="body" id="body" cols="30" rows="8" class="form-control" required>{{ old('body', $post->body) }}</textarea>
                                @if ($errors->has('body'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('body') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-md-9 col-md-offset-3">
                                <button type="submit" class="btn btn-success">
                                    Cập nhật
                                </button>
                                @can('post.publish')
                                <a href="{{ route('publish_post', ['post' => $post->id]) }}" class="btn btn-success">
                                    Xuất bản
                                </a>
                                @endcan
                                <a href="{{ route('list_posts') }}" class="btn btn-default">
                                    Hủy bỏ
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

app\resources\views\posts\drafts.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        @foreach($posts as $post)
        <div class="col-md-4">
            <h2>{{ $post->title }}</h2>
            <p>{{ str_limit($post->body, 100) }}</p>
            <p>
                <a class="btn btn-success" href="{{ route('edit_post', ['id' => $post->id]) }}" role="button">Chỉnh sửa</a>
                @can('post.publish')
                    <a class="btn btn-success" href="{{ route('publish_post', ['id' => $post->id]) }}" role="button">Xuất bản</a>
                @endcan
            </p>
        </div>
        @endforeach
    </div>
</div>
@endsection

app\resources\views\posts\show.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h2>{{ $post->title }}</h2>

            <p>{{ $post->body }}</p>
        </div>
    </div>
</div>
@endsection

app\resources\views\errors\403.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h2>Bạn không có quyền truy nhập đường dẫn này.</h2>
        </div>
    </div>
</div>
@endsection

Chạy thử ứng dụng

Khi vào màn hình trang chủ http://allaravel.dev, chúng ta sẽ thấy một số các bài viết đã được xuất bản

Phân quyền người dùng với Laravel Authorization

Khi đăng nhập vào bằng user pv1@allaravel.dev và pv2@allaravel.dev chúng ta thấy các tài khoản này chỉ được tạo mới và cập nhật bài viết.

Phân quyền người dùng với Laravel Authorization

Phóng viên 1 có thể chỉnh sửa bài viết có id 32 và sửa đường dẫn thành http://allaravel.dev/posts/publish/32 để xuất bản bài viết nhưng do Phóng viên 1 không có quyền xuất bản do đó sẽ gặp thông báo lỗi “Bạn không có quyền truy nhập đường dẫn này”.

Phân quyền người dùng với Laravel Authorization

Đăng nhập vào user Biên tập viên 1, chúng ta thấy user này không có quyền tạo bài viết mới.

Phân quyền người dùng với Laravel Authorization


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

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

Xem thêm Việc làm lập trình Laravel hấp dẫn trên TopDev

Thực thi kiểm thử tự động Selenium với Selenium-Grid

Thực thi kiểm thử tự động Selenium với Selenium-Grid

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

Selenium-Grid là một chế độ thực thi kiểm thử của Selenium mà ban đầu chỉ hỗ trợ cho Selenium RC như mình có nói ở bài trước. Tuy nhiên, sau này, đội ngũ phát triển của Selenium đã phát triển công cụ này cho cả Selenium WebDriver (Selenium 2).

Selenium-Grid cho phép người dùng thực thi kiểm thử trên nhiều máy khác nhau với nhiều trình duyệt khác nhau. Đặc biệt hơn nữa là, Selenium-Grid còn cho phép chúng ta thực thi kiểm thử với chế độ phân tán.

  Selenium là gì? Một số kinh nghiệm làm việc với Selenium
  Selenium – Xác Định Đối Tượng UI

Thiết lập môi trường cho Selenium-Grid

Để thiết lập môi trường cho Selenium-Grid, đâu tiên chúng ta cần cài đặt Java. Để kiểm tra PC có Java hay không, chúng ta có thể chạy câu lệnh này ở Command Line:

java –version

Thực thi kiểm thử tự động Selenium với Selenium-Grid

Nếu máy các bạn có Java thì version hiện tại của Java sẽ được trả về. Các bạn cố gắng lấy version mới nhất của Java nha.

Selenium Server

Kế tiếp là chúng ta cần có Selenium Server. Các bạn có thể download phiên bản mới nhất của Selenium Server ở đây.

Sau khi download Selenium Server về máy, chúng ta cần kiểm tra để chắc chắn rằng chương trình này có thể được sử dụng trên PC của chúng ta.

java –jar selenium-server-standalone-*.jar

Thực thi kiểm thử tự động Selenium với Selenium-Grid

Nếu mọi chuyện OK, INFO: Launching a standalone server sẽ được trả về.

Hub và Node

Hub

  • Hub là trung tâm phân phối nơi mà chúng ta gửi lệnh đến.
  • Chúng ta chỉ có một và chỉ một Hub trong một Selenium-Grid
  • Hub chỉ có thể được thiết lập trên một máy
  • Máy được thiết lập cho Hub là nơi kịch bản kiểm thử được thực thi, nhưng mà chúng ta sẽ thất trình duyện chạy ở trên Node

Node

  • Node là nơi các trình duyện chạy các kịch bản kiểm thử mà chúng ta đưa vào hub
  • Có thể có nhiều node trong một Grid
  • Node có thể được thiết lập trên nhiều máy với nhiều trình duyệt khác nhau

Thiết lập Hub và Node

Khởi động Hub với câu lệnh:

java –jar selenium-server-standalone-*.jar -role hub

Thực thi kiểm thử tự động Selenium với Selenium-Grid

Sau khi thực thi câu lệnh khởi tạo Hub, chúng ta có thể vào http://localhost:4444/grid/console để kiểm tra Hub được khởi tạo thành công.

Thực thi kiểm thử tự động Selenium với Selenium-Grid

Thiết lập Node với câu lệnh

java -jar selenium-server-standalone-*.jar -role node  -hub [Hub URL]/register

Thực thi kiểm thử tự động Selenium với Selenium-Grid

Như vậy là chúng ta đã thiết lập được một node trên một hub và sẵn sàng để sử dụng Selenium-Grid thực thi các kịch bản kiểm thử Selenium.

Mã nguồn để sử dụng Selenium-Grid

URL hubUrl = new URL(“http://[Hub URL]:4444/wd/hub”);
DesiredCapabilities capabilities = DesiredCapabilities.Firefox();
driver = new RemoteWebDriver(hubUrl, capabilities);

Như vậy, chúng ta đã có thể sử dụng Selenium-Grid cho việc thực thi kiểm thử tự động.

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

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

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

Khám phá phong cách hợp tác của bạn

phong cách hợp tác

Bạn đã bao giờ tìm hiểu về phong cách hợp tác cá nhân chưa? Nó thật sự là một điều quan trọng đấy. Tại sao? Vì hiệu quả của sự kết nối, tương tác trực tiếp, làm việc nhóm đều chịu sự chi phối của phong các hợp tác.

Phong cách hợp tác là yếu tố cần khai thác trước khi bạn tiến hành thực hiện công việc, đặc biệt là giải quyết nhiệm vụ với tư cách là một nhóm. Mỗi phong cách hợp tác sẽ thể hiện các đặc trưng dấu ấn về cá tính của từng cá nhân. Đó là cơ sở để bạn có thể lựa chọn ra những người cộng sự phù hợp nhất.

Cùng TopDev tìm ra phong cách của riêng bạn thông qua bài viết sau nhé.

Người “độc tài”

Nếu thuộc nhóm này, bạn sẽ dễ dàng nhận ra các lợi ích tốt nhất cho dự án của bạn. Và tất nhiên, bạn rất chủ động trong việc lập kế hoạch; muốn chia sẻ và trình bày cụ thể chúng với những cộng sự của bạn.

phong cách hợp tác

Bạn là người có một sự tập trung cực kỳ cao, luôn theo sát các thông số báo cáo mô tả tiến trình hoạt đồng. Đồng thời, bạn chủ động tìm kiếm các thông tin cập nhật từ nhóm. Do có sự kỳ vọng quá lớn, đôi lúc bạn cảm thấy một dự án nào đó có thể bị ảnh hưởng nếu thiếu đi sự cảnh giác của bạn. Một freelancer IT là người biết vận dụng nhiều kỹ năng. Và tất nhiên, năng lực tập trung tuyệt đối là rất quan trọng.

Xem thêm các việc làm về tuyển dụng Data Scientist 

Đồng ý rằng việc giám sát và quản lý chặt chẽ các đầu công việc là một điều tốt. Đó cũng là cách để hạn chế những sai sót có thể xảy ra. Và bạn cũng cho thấy được, bạn thật sự là một cá nhân có trách nhiệm với nhóm của mình. Tuy nhiên, bạn nên thảo luận, đánh giá và tạo cơ hội cho các thành viên trong nhóm phản hồi.

Có như vậy, một chiến dịch sẽ được theo dõi chặt chẽ và hiệu quả hơn do được đảm bảo về tính minh bạch, tính thống nhất về quan điểm thiết lập quy trình giải quyết công việc. 

Người “tích trữ”

Với phong cách cộng tác này, bạn thuộc tuýp người thích ghi chú lại một cách chi tiết, lưu trữ và thống kê thông tin về từng giai đoạn, tiến độ phát triển. Để tối ưu hóa, bạn đã có thể lưu tất cả các email, tạo liên kết. Ngoài ra, bạn có thể cập nhập, chỉnh sửa – bổ sung các nội dung có liên quan đến dự án.

phong cách hợp tác

Đặc biệt, với cách phân bổ hợp lý, không quá khó để bạn tra cứu các thông tin. Chính điều này đã giúp nhóm của bạn sở hữu nguồn tư liệu đa dạng hơn. Thế nhưng, bạn không nên  quá tập trung vào việc quản lý dữ liệu của riêng bạn. Hãy quan tâm đến các đồng đội vì các bạn là một team.

Người “phân tích”

Với khả năng tư duy nhanh nhạy và nhiều đa dạng về góc nhìn, bạn tự thúc đẩy bản thân muốn tìm hiểu và thực hiện khai thác, phân tích dự án một cách chi tiết. Vì là phân tích nên bạn thường sử dụng những kiến thức được minh chứng cụ thể về số liệu. Do vậy, hầu như trong mọi trường hợp, bạn đều nhận được sự tin tưởng từ mọi người. Ngược lại, bạn cũng sẽ phản bác các quan điểm thiếu xác thực, chưa đảm bảo về những minh chứng. 

phong cách hợp tác

Xem thêm các việc làm NTQ Solution tuyển dụng

Nếu bạn phát hiện ra một vấn đề nào đó, đừng ngần ngại mà trao đổi mối quan tâm của bạn với các đồng đội của mình. Đừng tự ý xử lý một mình! Bình tĩnh thảo luận và nhận ý kiến để tránh tình trạng làm nổ tung do sự mất kiểm soát bất ngờ từ các số liệu đáng báo động.

Người “nuôi dưỡng”

Bạn là một người luôn tìm kiếm các tài liệu hữu ích cho các thành viên. Đồng thời, bạn cũng là người đầu tiên nhận phản hồi và chia sẻ các cập nhật. Là một freelancer it, bạn cũng thường xuyên hợp tác và giúp đỡ tra cứu tài liệu cùng các cộng sự. Chính việc quá “chăm sóc” cho nhu cầu đồng đội mà đôi khi, bạn lọt thõm trong chính nhiệm vụ của cá nhân mình.

phong cách cộng tác

Bạn là kiểu người hữu ích và quá nhiệt tình. Tuy vây, hãy chú ý đến bất kỳ nguyên tắc giao tiếp nào mà nhóm của bạn có thể chia sẻ một cách hiệu quả nhất. Cách tốt nhất chính là loại bỏ các đồng nghiệp không phản hồi các đề xuất ra khỏi dự án của bạn. 

Thực tập sinh/hướng đạo sinh

Nếu thuộc phong cách này, bạn là kiểu người ham học hỏi. Bạn sẵn sàng giúp đỡ các đồng nghiệp khi họ khó khăn. Quan trọng, bạn thật sự yêu thích làm việc trong một nhóm. Đối với bạn, việc nhận được những phản hồi, đánh giá của người khác về bản thân mình là một điều rất tuyệt vời.

Bạn có thể kiểm tra đặc điểm tính cách của bản thân để lựa chọn công việc phù hợp thông qua công cụ trắc nghiệm tính cách tại TopDev

Nếu bạn là người thuộc kiểu phong cách cộng tác này, hãy thật sự cởi mở với những ý tưởng nghe có vẻ như chúng hoàn toàn bất hòa với chính bạn. Và đừng quá ôm đồm nhiều thứ nếu giới hạn khả năng không cho phép. 

Xem ngay các tin tuyển dụng thực tập sinh IT mới nhất

Lời kết

Phong cách cộng tác không áp định bất cứ ai. Chính bạn thể hiện phong cách bản thân. Cá tính bạn ra sao, xu hướng hợp tác của bạn thế nào? Tất cả đều tạo nên giá trị con người trong bạn. Để hòa nhập với một môi trường làm việc hiện đại, bạn nên cân bằng tận dụng tốt; biết phát huy những phong cách cá nhân một cách phù hợp để đạt hiệu quả tốt trong công việc. TopDev hi vọng bạn sẽ vận dụng tốt phong cách hợp tác của bản thân và có những người cộng sự tuyệt vời.

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

Xem thêm tuyển dụng it lương cao hàng đầu tại TopDev

Functors trong JavaScript là gì?

functors là gì

Functors là gì? Đôi khi, logic chính xác sẽ là bất khả thi bởi sự phức tạp của data trong thế giới lập trình. Do đó, data trừu tượng (data abstraction) là một tool rất hữu ích giúp ta tạo một đại diện đơn giản cho data.

Để có thể đạt được điều này, chúng ta tạo ra ‘Containers’, những container này sẽ chỉ chứa data và không làm gì khác. Ta cũng không cung cấp cho chúng những properties hoặc methods như trong lập trình hướng đối tượng OOP.

Tìm hiểu 4 thuộc tính cơ bản của OOP là gì?

Khi cho một giá trị vào container thì nó sẽ giúp giữ giá trị đó được an toàn, trong khi được pass qua functional logic. Và ta chỉ lấy nó khi rất cần thiết. Như vậy, container có 2 task chính:

  • Chứa giá trị bên trong chính nó
  • Trả giá trị lại khi chúng ta cần

Và nó cũng không làm biến đổi giá trị.

Thật ra, những container này cũng không có gì mới, chúng ta đã sử dụng chúng kể từ khi bắt đầu JavaScripting.

Khi làm về functional programming, những containers này cực kì quyền năng, bởi chúng góp phần vào nền tảng cho cấu trúc của functional, và giúp chúng ta với những kĩ thuật như Pure Functional Error Handling và Asynchronous Actions (cùng nhiều cái khác nữa).

>>> Xem thêm về tính trừu tượng đuợc nhắc đến trong Bí thuật đơn giản hóa code của bạn

functors là gì

Trước khi đi sâu vào những container này thì mình sẽ nói về một loại container đặc biệt là Functors.

Functors là gì? Functors chính là container có thể được dùng với ‘map’ function.

Trước khi chúng ta tạo ra container cho riêng mình, hãy nhìn lại những loại container mà ta thường dùng trước đây:

Các loại container thường dùng

Arrays

functor là gì
Array

Arrays là loại container phổ biến nhất mà chúng ta thường dùng trong lập trình hàng ngày, thay vì chỉ chứa duy nhất một giá trị thì chúng chứa được nhiều hơn. Array là dạng đơn giản nhất của Data trừu tượng nhưng lại vô cùng mạnh mẽ.

const arr = [ 8, 10, 23, 35, 54 ];

Vậy giá trị ta có thể lấy ra giá trị trong như như sau

const b = a[1];

Giờ, nếu bạn hứa là chỉ dùng những operation này trong array, thì nó sẽ trở thành trợ thủ trung thành nhất của bạn.

Đừng bao giờ modify array như thế này:

arr.push(45) 
or
arr[1] = 45

Nhưng bạn có thể dùng nó để tạo ra các array mới

const arr2 = [ ...arr, 38, 52 ]
or
const even = filter(x => x%2 === 0, arr)

Chúng ta không thay đổi bất cứ giá trị nào trong array, mà chỉ đơn giản là tạo ra array hoặc lấy giá trị ra từ nó.

Và Array cũng chính là một Functor.

  9+ cách để xóa một phần tử ra khỏi JavaScript Array
  Các phương thức trên array cần nhớ

Một Functor là một container mà có thể được map lên bởi một Unary function.

Nói cách khác, container có thể sử dụng với những function đặc biệt (fmap hoặc map) và nó cũng áp dụng lên mọi unary function cho đến các nội dung trong container này.

functor là gì
Xe tải này là functor

Với array, function đặc biệt được gọi đơn giản là map function.

Map Function

Functor là gì
Tất nhiên không phải map này nha

Map function lấy một array và áp dụng một vài function cụ thể lên toàn bộ yếu tố của nó từng cái một và trả về một array khác.

[1,2,3,4].map(multiplyBy2) 
//=> [2,4,6,8]
or
map(multiplyBy2, [1,2,3,4]) 
//=> [2,4,6,8]
where multiplyBy2 = x => x * 2 and map = (fn, arr) => arr.map(fn)

Từ đó, chúng ta sẽ luôn có một array mới từ map, ta cũng có thể map nó để tạo ra một chain của array.

[1,2,3].map(x => x * 3).map(x => x * 2).map(x => x / 6)

Map function không chỉ đơn thuần là một iterator function, nên nhớ rằng, với giá trị trong một container ta không thể cứ trực tiếp áp dụng một function lên nó và chờ đợi giá trị thay đổi. Ví dụ:

const a = [1, 2, 3]
String(a) = ‘[1 ,2, 3]’ and not [‘1’, ‘2’, ‘3’]

Một map function sẽ cho function truy cập vào nội dung của content

map(String, [1, 2, 3]) = [‘1’, ‘2’, ‘3’]

Ngoài ra, map function không bao giờ thay đổi container, thay vào đó nó chỉ hành động dựa trên nội dung của container..

functor là gì

Một map sẽ không thay đổi loại của container nhưng nó sẽ thay đổi loại content bên trong.

Type của content có thể thay đổi, và chúng ta có thể xem từ type definition của map function.

map :: a -> b -> [a] -> [b]
or
fmap :: a -> b -> F a -> F b

Với  a và b có thể cùng hoặc khác loại.

Nếu bạn để ý kỹ thì map function đang lấy một function từ  a -> b  trả lại một function từ  Fa -> Fb

Tại đây, a -> b  có nghĩa là bất cứ unary function nào lấy a và trả lại b  như

multiplyBy2(3) = 6 // is a -> b as 3 -> 6

và Fa -> Fb ám chỉ bất kì unary function nào lấy một Container với a bên trong và trả lại một Container  với b bên trong.

multiplyArrBy2([1]) = [2] // is Fa -> Fb as [1] -> [2], F is []

Giờ map function đã thay đổi từ multiplyBy2 to multiplyArrBy2

const multiplyBy2 = no => no * 2

// We need to partially apply our map function to explain this

const map = mappingFn => arr => arr.map(mappingFn) 

// Now we create our new Function now that can act upon arrays

const multiplyArrBy2 = map(multiplyBy2)

Kể từ giờ, function multiplyBy2, vốn được dùng cho integer, sẽ hành động với array của integer. Nói cách khác, map function đã promote hoặc nâng function lên để nó có thể hành động trên containers hoặc arrays trong trường hợp này.

Ta thường áp dụng một phần map function khi có thể để tạo ra các function mới hoặc dùng nó với compose function, và khi có trường hợp cực kỳ khẩn cấp của Data thì ta sẽ dùng map function bình thường.

Vậy sao lại áp dụng một phần map function?

Trước khi đi xa hơn, hẳn bạn cũng đã hiểu là ta dùng container để chứa giá trị. Ta cũng biết về Functor, vốn là những container đặc biệt mà ta có thể dùng map operation lên nó. Mặt khác, ta cũng biết cách thức map function được dùng trên Arrays, ngoài bạn cũng đã biết cách tạo ra một Container và Functor từ những ví dụ trên.

Bây giờ, Tôi xin giới thiệu container tiếp theo vốn cũng là một functor. Container đã đi cùng chúng ta ngay từ khi cuộc phiêu lưu vừa mới băt đầu.

Functions

Thế nào mà Functions lại là container?

Container chứa data, nhưng function rõ ràng là chứa logic, thế thì làm sao function có thể là container?

Đó là bởi function, khi được called sẽ trả lại một giá trị. Thế nên ta có thể hiểu là nó chứa giá trị nhưng chỉ là giá trị đó được dynamically computed.

aFunction(45) // => 90
So aFunction gives the value 90, when it is passed 45

Hãy nghĩ chúng là những arrays chứa vô hạn các value và khi bạn muốn một giá trị nào đó thì phải call function như sao:

functor trong js
Funtion là array với value vô hạn

Vậy Function cũng chính là container như Array?

Đúng vậy! Như array đưa giá trị khi index được pass, function đưa kết quả khi một argument được pass

const a = [ 8, 10, 23, 35, 54 ]
const f = z => z * 2 
a[1] = 10
f(2) = 4

Chỉ có điều là Array yếu hơn khi nó chỉ cho kết quả khi các số nguyên là index. Còn function thì có thể lấy bất cứ type nào của arguments bởi không hề có một giới hạn nào. Thậm chí nó còn lấy những function khác làm arguments luôn.

Vậy nếu chúng là Functors thì hẳn cũng có map luôn đúng không?

Chính xác, nó là như thế này:

const fnMap = (f, mappingFn) => (x => f(mappingFn(x)))

Cũng như map function lấy array, áp dụng function vào content và trả lại array. Tương tự, fnMap lấy một function, áp dụng một function vào kết quả của nó và return lại function, theo cách mà nó kết hợp 2 function sao cho kết quả của một function là  argument của function thứ hai.

Được rồi hãy dùng thử cái này

const multiplyBy6 = fnMap(multiplyBy2, multiplyBy3)

Nhìn quen đúng không, đó là vì nó chính là Compose function.

Vậy function cũng có một map function và nếu ta mapping một function tới function khác, ta sẽ như đang kết hợp chúng lại và cho ra Compose function.

  • Ví dụ ta có một function là  multiplyBy2 
  • Trước khi lấy giá trị hay làm gì khác thì ta sẽ map nó với multiplyBy3
  • Vậy là toàn bộ giá trị trong  multiplyBy2 sẽ được nhân 3.
  • Do đó, khi ta call multiplyBy2  với giá trị  x thì kêt quả thu được sẽ là  x * 3 * 2

Như vầy thì hẳn bạn sẽ dễ hiểu hơn

const fnMap = (f, mappingFn) => (x => f(mappingFn(x)))

Functions cũng là arrays, một dạng data trừu tượng. Chỉ có function tính toán data theo yêu cầu của ta.

Nói cách khác, Array giống như function nhưng chỉ đưa giá trị ngay lập tức khi ta dùng ‘[]’ lên chúng.

Chỉ cần nhớ một điều rằng giá trị chỉ có ý nghĩa khi nó nằm trong một container. Do đó trong lập trình, đừng bao giờ sử dụng Data một cách thô sơ, hãy luôn cho nó vào trong container.

Vậy đấy! Tôi hi vọng bạn đã học được thêm nhiều điều từ bài viết này!

Tham khảo bài viết gốc tại hackernoon

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

Tham khảo việc làm javascript lương cao tại TopDev

System Design Cơ Bản: Message Broker

Message Broker

Bài viết được sự cho phép của tác giả Edward Thiên Hoàng

Trong kiến trúc cloud (hay microservices), các ứng dụng được chia thành những khối độc lập nhỏ hơn để có thể dễ dàng develop, deploy và maintain. Hãy thử tưởng tượng bạn có một kiến trúc cloud có nhiều service và nhiều request mỗi giây, bạn phải đảm bảo rằng không có bất cứ một request nào bị mất và web service của bạn luôn luôn sẵn sàng tiếp nhận request mới thay vì locked bởi đang xử lí request trước đó cũng như phải đảm bảo rằng các service giao tiếp với nhau một cách trơn tru và hiệu quả.

  Discord đã lưu trữ hàng tỉ messages mỗi ngày như thế nào
  Xây dựng ứng dụng realtime messaging bằng Firebase như TikTok, Bigo...

Vậy bạn làm thế nào? Câu trả lời đó chính là Message Broker!

MESSAGE BROKER LÀ GÌ?

Message broker (hay còn gọi là integration broker hoặc interface engine) là một module trung gian trung chuyển message từ người gửi đến người nhận. Nó là một mô hình kiến trúc (architentural pattern) để kiểm tra, trung chuyển và điều hướng message; làm trung gian giữa các ứng dụng với nhau, tối giản hóa giao tiếp giữa các ứng dụng đó và để tăng hiệu quả tối đa cho việc tách ra các khối nhỏ hơn. Nhiệm vụ chính của một Message broker là tiếp nhận những message từ các ứng dụng và thực hiện một thao tác nào đó.

Hiện tại có rất nhiều các message broker software có thể kể đến như: Amazon Web Services (AWS) Simple Queue Service (SQS), Apache Kafka, Apache ActiveMQ. Nhưng phổ biến nhất trong số những cái tên kể trên đó là RabbitMQ!

PHÂN LOẠI GIỮA CÁC HỆ THỐNG MESSAGE QUEUE

Nếu bạn là một backend-developer chắc hẳn bạn không còn xa lạ gì với những hệ thống message-queue. Hầu như project nào của mình cũng có sự xuất hiện của message-queue và việc khó khăn nhất là lựa chọn nên dùng cái nào và không nên dùng cái nào.

Thử tưởng tượng một ngày sếp của bạn muốn tích hợp một hệ thống message queue hoặc bạn cảm thấy nên sử dụng một hệ thống message queue để giải quyết bài toán mà team đang gặp phải. Bạn bắt đầu tìm kiếm và nhận ra rằng có quá nhiều hệ thống message queue tồn tại. Mình có thể liệt kê một số loạt mà mình biết dưới đây :

  • RabitMQ
  • ActiveMQ
  • Kafka
  • SQS
  • ZeroMQ
  • MSMQ
  • IronMQ
  • Kinesis
  • RocketMQ
  • Redis Pub/sub

Trong quá khứ mình đã có không ít lần lựa trọn sai và mọi sai lầm đều phải trả giá không ít thì nhiều.

Sau những sai lầm đó thì mình nhận ra một điều, đó là mặc dù cùng là message queue nhưng lại được chia làm 2 loại có mục đich sử dụng và những tính năng liên quan hoàn toàn khác nhau.

Mình tạm chia thành 2 loại như sau:

Message Base Data Pipeline
RabitMQ Kafka
ActiveMQ Kinesis
SQS RocketMQ
ZeroMQ
MSMQ
IronMQ
Redis Pub/sub

SO SÁNH CÁCH HOẠT ĐỘNG CỦA 2 LOẠI:

System Design Cơ Bản: Message Broker

Dựa vào bảng trên, ta có thể thấy được sự khác nhau cơ bản giữa 2 loại, cũng như cách sử dụng trong tưng bài toán cụ thể.

Đối với loại “message base”: là những loại message queue truyền thống, thích hợp làm hệ thống trao đổi message giữa các service. Việc đảm bảo mỗi consumer đều nhận được message và duy nhất một lần là quan trọng nhất.

Đối với loại “data-pipeline”, có cách lưu trữ message cũng như truyền tải message đến consumer hoàn toán khác với hệ thống message queue truyền thống. Việc đảm bảo mỗi consumer đều phải nhận được message và duy nhất một lần không phải là ưu tiên số một, mà thay vào đó là khả năng lưu trũ message vả tốc độ truyền tải message. Khi có message mới, consumer sẽ lựa chọn số lượng message mà mình muốn lấy, chính vì thế mà cùng một message consumer có thể nhận đi nhận lại nhiều lần. Những hệ thống sử dụng message queue loại này thường là hệ thống Event Sourcing, hoặc hệ thống đồng bộ dữ liệu từ những database khác nhau như Debezium.

Khi các bạn lựa chọn message queue cho hệ thống của mình, các bạn nên xác định rõ mục địch của hệ thống messague queue để xem mình cần loại trong hai loại trên. Việc xác định được loại message queue nào mình cần sẽ giúp các bạn giảm bớt thời gian tìm hiểu cũng như tìm được chính sác cái mà mình cần.

Đôi khi chúng ta cũng thấy một số hệ thống sẽ sử dụng nhiều loại message queue, thường sẽ là 1 của “message base” và 1 của “data pipeline” để tận dụng tối đa ưu điểm của từng loại vào giải quyết bài toán cụ thể.

MỘT SỐ MESSAGE BROKER PHỔ BIẾN

RABBITMQ

RabbitMQ là một message broker ( message-oriented middleware) sử dụng giao thức AMQP(Advanced Message Queue Protocol — Giao thức giao nhận tin nhắn sử dụng hàng đợi). Đây là chương trình đóng vai trò trung gian lưu trữ cũng như điều phối các yêu cầu (message) giữa người nhận(consumer) và người gửi(producer).

KAFKA

Kafka là nền tảng streaming phân tán, có thể mở rộng và là sản phẩm mã nguồn mở. Dự án Kafka ban đầu được phát triển bởi Linkedin sau đó trở thành dự án Apache mã nguồn mở vào năm 2011. Kafka được viết bằng ngôn ngữ Scala và Java. Nó được viết ra nhằm mục đích cung cấp một nền tảng mà có độ trễ thấp và thông lượng cao cho việc xử lý các nguồn cấp dữ liệu theo thời gian thực.

Kafka là gì? Tìm hiểu và ứng dụng Kafka cho hệ thống message tối ưu

REDIS PUB/SUB

Redis hỗ trợ Transaction, hỗ trợ Pub/Sub vì vậy nó cũng được sử dụng làm hệ thống Message Broker, kinh điển là RabbitMQ sử dụng Redis là core của hệ thống.

READ MORE:

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

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

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

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

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

Adobe Flash Player (hay còn gọi tắt là Flash) là một chương trình điện toán được cung cấp bởi Adobe System, công ty này cũng rất có tiếng nhờ làm ra phần mềm Photoshop và hàng loạt các phần mềm nổi tiếng khác nữa.

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Quay trở lại với Flash thì nó dùng kỹ thuật đồ họa Vector và đồ họa điểm với ngôn ngữ ActionScript để truyền tải các luồng âm thanh và hình ảnh trên trang web.

  12 plugin nên dùng trong Adobe XD
  Hadoop là gì? Kiến trúc của Hadoop

Khi sử dụng Flash các tập tin đồ họa, ảnh động có kích thước khá nhỏ nên nó rất phù hợp với thời kỳ Internet tốc độ chậm mà lại có nhiều người sử dụng. Nhờ vậy mà Flash đã phát triển vượt bậc trong khoảng thời gian từ năm 2000 đến năm 2010.

Hơi khó hiểu khi tên Flash được dùng để chỉ chương trình tạo ra các tập tin Flash (*.swf) và cũng được dùng để chỉ ứng dụng có nhiệm vụ thi hành hay hiển thị các tập tin Flash đó.

Tuy Flash có nhiều chức năng như vậy nhưng cuộc chơi nào cũng đến lúc tàn, Adobe Flash Player giờ đã hết đất sống. Và…

Sau ngày 31 tháng 12 năm 2020 thì Adobe sẽ không còn hỗ trợ Flash Player nữa, chính vì thế Adobe cũng sẽ chặn nội dung Flash chạy trong Flash Player kể từ ngày 12 tháng 1 năm 2021.

=> Vậy nên Adobe khuyên tất cả người dùng ngay lập tức gỡ cài đặt Flash Player để giúp bảo vệ hệ thống. Tránh bị hacker lợi dụng khai thác.

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Để tìm hiểu kỹ hơn về Adobe Flash Player thì bạn có thể đọc chi tiết hơn trong bài viết này nhé !

#1. Lý do Adobe khai tử Flash?

Về lý do khai tử Flash thì có khá nhiều lý do, nhưng chủ yếu là do bảo mật kém nên các trình duyệt web phổ biến hiện tại đều không còn hỗ trợ Flash nữa, cộng với sự phát triển quá tốt của HTML5, WebGL và WebAssembly đã đủ để thay thế cho Flash với nhiều cơ chế bảo mật tốt hơn.

Mặt khác, tốc độ Internet ngày càng nhanh nên lợi thế tiêu tốn ít băng thông của Flash dần dần không còn quá nhiều ý nghĩa nữa.

Những điểm mạnh của Flash đều được thay thế bởi những công nghệ mới như HTML5 dùng để thiết kế website, thẻ <video> trong HTML5 cùng với tốc độ Internet nhanh hơn đã giúp việc phát video có chất lượng cao hơn.

Thẻ <canvas> trong HTML5 giúp trình duyệt web vẽ và tạo hiệu ứng hoạt hình cho đồ họa bằng JavaScript.

WebGL giúp trình duyệt web hiển thị đồ họa 2D và 3D. ActionScript thì có JavaScript thay thế. Hầu như chẳng còn lý do nào để Flash nên tiếp tục tồn tại cả.

Việc khai tử Flash sẽ ảnh hưởng tới những trang web cũ đã lâu không cập nhật, vì Adobe đã ra thông báo từ năm 2017 để nhiều trang web có thời gian chuyển đổi nội dung từ Flash sang các tiêu chuẩn mới.

Còn lại thì hầu như những website lớn hiện nay đều đã loại bỏ Flash khỏi mã nguồn của trang web và thay vào đó là HTML5. Điển hình như Youtube đã thay thế Flash bằng HTML5 từ năm 2015.

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Thật ra thì tương lai của Flash đã được Apple dự đoán trước, khi vào năm 2007, Apple ra mắt iPhone nhưng lại không hỗ trợ Flash trên nền tảng này, mặc dù vào thời điểm đấy Flash vẫn còn rất phổ biến.

Sau vài đời iPhone tiếp theo, vì sự phổ biến của iPhone và nhiều nhà phát triển web muốn website của họ có thể hoạt động tốt trên mọi nền tảng nên dẫn đến Flash đã có dấu hiệu suy giảm.

Vào năm 2012, Flash được coi là một rủi ro bảo mật khiến Google phải cô lập Flash với Google Chrome bằng Sandbox. Cách này khá hiệu quả khi đặt nội dung flash trong một không gian ảo của riêng mình và cô lập nó với phần còn lại của hệ thống.

Nhưng vì phải tạo ra sandbox nên đã ảnh hưởng đến hiệu năng khi sử dụng Chrome, điều này khiến cho nhiều người khó chịu và về lâu dài thì trải nghiệm người dùng Chrome sẽ bị ảnh hưởng.

Vậy nên tốt nhất vẫn là để các trang web loại bỏ Flash thì mọi thứ sẽ ổn thỏa hơn.

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

#2. Làm thế nào để gỡ bỏ hoàn toàn Adobe Flash Player?

Microsoft đã lên tiếng sẽ có một bản cập nhật để loại bỏ hoàn toàn Adobe Flash Player ra khỏi hệ điều hành Windows 10.

Trên Windows 10 thì Flash được Microsoft tích hợp sẵn vào hệ thống, chính vì thế bạn sẽ không thể tìm thấy phần gỡ cài đặt Flash trong phần Uninstall của Windows được. Mà nó nằm tại đường dẫn này:

C:\Windows\System32\Macromed\Flash

Đương nhiên là bạn không nên gỡ Flash bằng cách truy cập vào đường dẫn trên và xóa các file trong đó đi. Điều này có thể gây ra lỗi hệ thống. Vậy nếu bạn muốn thực hiện gỡ bỏ ngay bây giờ thì phải làm thế nào?

Cách 1: Sử dụng Adobe Flash Uninstaller

Phương pháp này là do Adobe cung cấp (hàng chính chủ). Bạn chỉ cần truy cập vào đây để tải về (link dự phòng)

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Vâng, sau khi bạn tải về => chạy file => và nhấn vào UNINSTALL để thực hiện gỡ bỏ Adobe Flash Player thôi.

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Cách 2: Sử dụng bản vá Windows KB4577586

Đây là bản vá do Microsoft cung cấp, tác dụng duy nhất của bản vá này là loại bỏ hoàn toàn Adobe Flash khỏi hệ thống.

Hiện tại thì bản vá KB4577586 (link truy cập bản vá tại đây) vẫn chưa được hỗ trợ thông qua Windows Update. Tuy nhiên bạn có thể tải xuống và cài đặt thủ công theo hướng dẫn chi tiết trong bài viết này:

NOTE: Bạn hãy chọn bản vá tương ứng với hệ điều hành Windows mà bạn đang sử dụng nhé. Rất đơn giản thôi !

#3. Lời kết

Okay, như vậy là trong bài viết này mình đã hướng dẫn rất chi tiết với các bạn cách gỡ bỏ Adobe Flash khỏi Windows một cách sạch sẽ và an toàn rồi nhé.

Mặc dù Flash còn nhiều hạn chế, nhưng nó đã là một phần không thể thiếu trong tuổi thơ của nhiều người.

Mình biết, từng có một thời các webgame, web xem video đều yêu cầu các trình duyệt web phải có Flash thì mới chơi hoặc xem được nội dung, vậy nên có thể nói Flash là một huyền thoại.

Adobe Flash Player trước đây có thể nói là một  phần mềm/ tiện ích mặc định phải có trên bất kỳ một máy tính nào. Nhưng giờ đây nó đã bị khai tử !

Kể từ bây giờ, tuy không còn Flash nữa nhưng những tính tăng mà nó đem lại đã khởi nguồn cho một thế giới Internet với đa dạng các nội dung và tràn đầy sức sống như hiện nay.

Cách gỡ bỏ Adobe Flash. Tại sao Flash bị Adobe khai tử?

Tạm biệt Flash !

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

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

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

Thay đổi tư duy về kiểm thử theo Nguyên lý Agile

Thay đổi tư duy về kiểm thử theo Nguyên lý Agile

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

Nguyên lý Agile – QA ngày nay đã phát triển từ “Tim lỗi” đến “Ngăn ngừa lỗi”. Những kỹ sư kiểm thử cần thêm nhiều kỹ năng khác như kiểm thử tự động, TDD, BDD và kiểm thử hộp trắng (không chỉ làm duy nhất kiểm thử hộp đen). Kỹ sư kiểm thử cần hướng đến hướng-giải-pháp, cộng tác nhiều hơn với nhóm phát triển và các bên nghiệp vụ.

  Agile là gì? Scrum là gì? Các công cụ quản lý dự án theo Agile mà bạn nên biết
  Quản lý dự án theo Agile và Scrum cho người mới bắt đầu

Thay đổi tư duy kỹ sư kiểm thử với Nguyên lý Agile

Agile nghĩa là “Linh động”, “khả năng thay đổi nhanh chóng”.

Kiểm thử trong Agile không có nghĩa là một kỹ thuật kiểm thử mới, mà đi theo Agile nghĩa là phát triển một khả năng thay đổi trong tư duy để triển khai/tiến hành những gì có thể kiểm thử.

Trước khi bàn luận về kiểm thử trong Agile, hãy nhìn lại và xem xét nguồn gốc và nguyên lý bên trong Agile.

Câu chuyện xưa cũ

Trước khi thế giới làm việc với Agile, Thác nước (Waterfall) là một phương pháp có ưu thế trong công nghiệp phần mềm. Ở đây, chúng ta không giải thích mô hình Thác nước, nhưng có ghi chú vài điểm đáng chú ý trong làm việc thực tế.

Những điểm này là dựa vào kinh nghiệm của cá nhân. Có thể có khác biệt đôi chút với mọi người.

  • Kỹ sư phát triển (dev) và QA làm việc như những nhóm riêng lẻ (Đôi khi còn là đối thủ)
  • Các tài liệu liên quan được cả kỹ sư phát triển và QA xem xét cùng một lúc. Kỹ sư phát triển thiết kế và viết mã trong khi QA làm các kịch bản kiểm thử cho các tài liệu đó. Kế hoạch và việc thực thi được làm tuần tự.
  • Việc xem xét các kịch bản kiểm thử được tiến hành bởi trưởng nhóm QA. Việc chia sẻ các kịch bản kiểm thử cho kỹ sư phát triển không phải là một việc được khuyến khích. (Lý do: kỹ sư phát triển sẽ viết mã dựa trên các kịch bản kiểm thử và nhóm QA sẽ không thể tìm thấy lỗi).
  • Việc kiểm thử được xem như là công việc cuối cùng trong vòng lặp phát triển phần mềm. Hầu hết mọi lúc, QA nhận phiên bản phần mềm ở giai đoạn cuối và được mong đợi sẽ hoàn thành việc kiểm thử trong một khoảng thời gian giới hạn. (Và tất nhiên, QA đã làm được việc đó).
  • Mục tiêu duy nhất của QA là tìm lỗi và các khuyết điểm. Đồng thời, việc đánh giá hiệu suất làm việc của QA cũng dựa vào số lượng lỗi/khuyết điểm hợp lý mà QA tìm ra.
  • Chu trình kiểm thử phần mềm (STLC) và vòng đời của lỗi (Bug lifecycle) được đi theo trong quá trình thực thi. Giao tiếp qua email được khuyến kích.
  • Kiểm thử tự động được xem như là công việc cuối cùng và tập trung chủ yếu ở phần giao diện. Bộ kiểm thử qui hồi được xem như là ứng viên tốt nhất cho kiểm thử tự động.

Những điều trên cũng có những khuyến điểm của riêng nó

  • Vì kỹ sư phát triển và QA làm việc độc lập nên việc giao tiếp giữa hai bên chỉ là lỗi và khuyết điểm.
  • Phạm vi làm việc của QA bao gồm viết và thực thi các kịch bản kiểm thử trên sản phẩm hoàn chỉnh.
  • Có rất ít (hoặc không có) cơ hội cho QA xem mã nguồn hay tương tác với kỹ sư phát triển hay nhóm nghiệp vụ.
  • Bởi vì toàn bộ sản phẩm được đưa đến QA một lúc, trách nhiệm của QA là cực kỳ to lớn trên vòng đời của sản phẩm. QA thường được xem như “người gác đền”, và bất kể trên sản phẩm có vấn đề gì, mọi chỉ trích đều chỉ vào QA.
  • Như một phần của kiểm thử chức năng, kiểm thử qui hồi trên toàn bộ sản phẩm cũng là một trách nhiệm của QA, nơi mà có một lượng khổng lồ kịch bản kiểm thử cần thực thi.
  • Ngoài những khuyết điểm ở trên, vấn đề lớn nhất chính là “Thiếu sự tập trung vào việc cung cấp một sản phẩn với chất lượng tốt với một tốc độ hợp lý”.

Mục tiêu cuối cùng của nhóm

(cả kỹ sư phát triển và kỹ sư kiểm thử) là đưa ra một sản phẩm với chất lượng tốt, đáp ứng các yêu cầu nghiệp vụ của khách hàng và dễ sử dụng. Nhưng bởi vì những khoảng thời gian giữa những giai đoạn bị tăng lên khi đưa sản phẩm ra thị trường, trọng tâm đã bị xao lãng, mục tiêu duy nhất được duy trì là hoàn thành việc viết mã và chuyên giao cho nhóm kiểm thử để tiến hành UAT (User Acceptance Testing).

Khi đó, QA chỉ tập trung vào việc thực thi các kịch bản kiểm thử (đánh dấu vào một bảng kiểm tra), đảm bảo mọi lỗi/khuyết điểm đã được chỉnh sửa, và chuyển qua kiểm thử các chức năng khác trong hệ thống. Vậy nên, trên quan điểm của QA, trọng tâm không ở vấn đề tốc dộ và chất lượng của sản phẩm, mà là hoàn thành việc thực thi các kịch bản kiểm thử (và, tất nhiên là bao gồm cả các kiểm thử tự động, nếu có).

Nguyên lý Agile

Bắt đầu từ năm 2001, khi một nhóm gồm 17 chuyên gia gặp gỡ ở Utah (Mỹ) để trượt tuyết, ăn uống, nghĩ ngơi và có một thảo luận về chất lượng; kết quả chính là Nguyên lý Agile.

Là một chuyên gia về chất lượng, chúng ta cũng nên hiểu về bản chất của các Nguyên lý Agile và định hình lại cách suy nghĩ của chúng ta cho phù hợp với mô hình mới này.

Trước khi định hình lại cách suy nghĩ của chúng ta trong việc kiểm thử phần mềm với các nguyên lý Agile, hãy cùng làm rõ một việc: trong Agile, nhóm làm việc cần đa nhiệm và mỗi một thành viên trong nhóm đều đóng góp để phát triển sản phẩm/chức năng.

Do đó, nhóm thường được gọi là “Nhóm phát triển”, bao gồm cả lập trình viên, kỹ sư kiểm thử và phân tích nghiệp vụ. Và, các thuật ngữ lập trình viên và kỹ sư kiểm thử được dùng thay cho kỹ sư phát triển và QA.

Phần mềm hoạt động quan trọng hơn các tài liệu toàn diện về sản phẩm

Mục tiêu cuối cùng của nhóm phát triển Agile là chuyển giao ứng dụng/bản nâng cấp có khả năng sử dụng trong khoảng thời gian nhanh nhất, nghĩa là, thời gian là nhân tố chính. Nói vậy, không có nghĩa chất lượng không quan trọng. Bởi vì thời gian để đưa sản phẩm ra thị trường là giới hạn, điều quan trọng chính là một chiến lược và kế hoạch thực thi kiểm thử cần tập trung nhiều hơn vào chất lượng tổng quát của ứng dụng.

Kiểm thử là một công việc không có điểm dừng, nó có thể tiếp tục và tiếp tục, kỹ sư kiểm thử cần xác định các thông số chính mà họ có thể bật đèn xanh để sản phẩm có thể đưa ra thị trường. Để làm được điều đó, điều quan trọng là kỹ sư kiểm thử cảm thấy phù hợp khi quyết định các khái niệm “định nghĩa sự sẵn sàng” (Definition of Ready) và “định nghĩa sự hoàn thành” (Definition of Done – DoD), và cũng không nên bỏ qua “Tiêu chuẩn chấp nhận cho một tình huống/chức năng” (Acceptance Criteria of the story – AC).

Các chiến lược và kịch bản kiểm thử nên xoay quanh DoD và AC. Thay vì cố gắng viết đầy đủ các kịch bản cũng như bao gồm các thông tin mà hiếm khi được sử dụng, hãy tập trung hơn vào sự rõ ràng và các điểm chính yếu.

Điểm quan trọng ở đây là, chỉ bao gồm những thông tin mà kịch bản kiểm thử cần và có giá trị đối với kịch bản đó.

Cộng tác với khách hàng quan trọng hơn đàm phán hợp đồng

Nên có những cuộc tiếp xúc trực tiếp với khách hàng về cách tiếp cận kiểm thử và cố gắng minh bạch trong việc chia sẽ các kịch bản kiểm thử, dữ liệu kiểm thử và kết quả.

Cũng nên có những buổi họp mặt để lấy phản hồi từ khách hàng và chia sẽ kết quả kiểm thử. Hỏi khách hàng nếu họ đánh giá tốt các kết quả kiểm thử hay họ muốn có thêm những kịch bản đặc biệt. Đừng tự giới hạn bản thân trong việc đặt câu hỏi và tìm kiếm sự xác nhận từ khách hàng/nhóm nghiệp vụ để hiểu hơn về chức năng cũng như nghiệp vụ.

Càng hiểu sâu về chức năng, kỹ sư kiểm thử càng rõ ràng hơn trong việc kiểm thử.

Phản hồi với sự thay đổi quan trọng hơn bám theo kế hoạch

Thứ bất biến duy nhất chính là sự thay đổi.

Chúng ta không thể kiểm soát sự thay đổi và chúng ta hiểu và chấp nhận sự thật là, luôn luôn có sự thay đổi trong chức năng cũng như các yêu cầu; chúng ta phải thích ứng và thực hiện nó.

Tốc độ thay đổi yêu cầu được nhấn mạnh trong Agile, giống với thời trang, như một kỹ sư kiểm thử, chúng ta cần giữ cho kế hoạch kiểm thử và các kịch bản linh động đủ để thích ứng với sự thay đổi.

Theo truyền thống, chúng ta tạo kế hoạch kiểm thử và mọi thứ đi theo vòng đời của dự án. Ngược lại, trong Agile, kế hoạch cần linh động với từng yêu cầu. Một lần nữa, hãy tập trung vào DoD và AC.

Không cần thiết phải tạo ra kế hoạch kiểm thử cho từng tình huống/chức năng; thay vào đó, có thể tạo các kế hoạch kiểm thử ở mức độ Epic. Khi một Epic được thiết lập và tiến hành, có thể đồng thời tiến hành tạo ra kế hoạch kiểm thử cùng lúc. Quan trọng là, kỹ sư kiểm thử cần bao phủ chất lượng của toàn bộ Epic với kế hoạch kiểm thử đó.

Có thể sử dụng PI (Product Increment) để xác định các kịch bản kiểm thử tổng quát cho từng tình huống dựa vào DoD và AC.

Truyền thông giao tiếp và sự tương hỗ quan trọng hơn quy trình và công cụ

Kỹ sư kiểm thử thường có xu hướng nghiên về quá trình (process-oriented), nhưng chúng ta cần nhớ rằng, thay vì đi theo chu trình, thời gian đáp ứng không nên bị ảnh hưởng.

Với trường hợp nhóm làm việc cùng địa điểm, bất kỳ vấn đề nào cũng có thể giải quyển thông qua đối thoại trực tiếp. Có lẽ việc họp mặt hằng ngày (daily stand-ups) cung cấp một giải pháp tốt để giải quyết các vấn đề. Việc ghi nhận/tài liệu hóa lỗi/khuyết điểm là quan trong, nhưng nó chỉ nên được làm cho mục đích ghi dấu (tracking) mà thôi.

Tester nên làm việc chung với Dev và hợp tác để giải quyết các khuyết điểm. Nếu cần, khách hàng cũng nên tham gia chung. Kỹ sư kiểm thử nên chủ động tham gia vào quá trình TDD và cũng nên cộng tác với lập trình viên để chia sẽ các kịch bản và cố gắng xác định lỗi ở ngay mức độ đơn vị.

Kết luận

Kiểm thử trong Agile không phải là kỹ thuật mới. Nó là sự thay đổi trong suy nghĩ, và sự thay đổi diển ra một cách liên tục. Nó yêu cầu các kiến thức, kỹ năng và sự hướng dẫn đúng đắn.

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

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

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

Những tính năng Load Balancer

Những tính năng Load Balancer

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

Quá nhiều người dùng truy cập sẽ dẫn đến lượng request khổng lồ, server trở nên quá tải, ảnh hưởng không hề nhỏ đến công suất hoạt động của website, ứng dụng nói riêng và kết quả kinh doanh nói chung. Trong các tình huống như vậy, áp dụng load balancer để cân bằng tải cho server sẽ là giải pháp tối ưu.

  9 mã nguồn mở cho file upload field
  Giải mã bí ẩn "system load" trên Linux

1. Sticky session

Những tính năng Load Balancer

Khái niệm

Một router hay hoặc load balancer hỗ trợ sticky session có thể gán một máy chủ đơn lẻ cho một người dùng cụ thể, dựa trên HTTP session hoặc địa chỉ IP của họ. Máy chủ được chỉ định sẽ được router ghi nhớ trong một khoảng thời gian nhất định, đảm bảo rằng tất cả các yêu cầu trong tương lai cho cùng một session sẽ được gửi đến cùng một máy chủ.

Sticky session là một trong các tính năng cơ bản của nhiều giải pháp load balancer nhằm cân bằng tải cho các website. Tính năng này route các yêu cầu cho một session cụ thể đến cùng một máy tính vật lý, và máy tính này phục vụ yêu cầu đầu tiên cho session đó. Tính năng này chủ yếu được sử dụng để đảm bảo một in-proc session nào đó sẽ không bị mất bởi các yêu cầu cho session được route đến các máy chủ khác nhau. Vì yêu cầu từ 1 người dùng luôn được route đến cùng một máy đã phản hồi yêu cầu lần đầu cho session đó, các sticky session có thể gây ra phân phối tải không đồng đều trên các máy chủ.

Ngoài ra, load balancer cũng có thể duy trì các sticky session thay vì phải nhớ địa chỉ ip của máy khách và máy chủ backend mà máy khách đã gửi đến lúc đầu.

Lợi ích

– Không quá phức tạp để triển khai đối với quản trị viên mạng có kinh nghiệm.

– Giảm nhu cầu triển khai chuyển đổi dự phòng, vì yêu cầu người dùng sẽ chỉ được gửi tới các máy chủ khác nếu một máy chủ offline.

– Load balancer/router thường chịu trách nhiệm phát hiện các máy chủ offline, cung cấp yêu cầu chuyển đổi dự phòng nhanh hơn so với round robin của load balancing dựa trên DNS.

2. Tính năng Health check backend

Server Load Balancer sẽ kiểm tra tính khả dụng dịch vụ của các backend server bằng cách thực hiện health check. Chức năng health check giúp cải thiện tính sẵn sàng cho toàn bộ dịch vụ và tránh tác động xấu từ các lỗi trên server backend.

Sau khi kích hoạt health check, Server Load Balancer sẽ ngừng phân phối các request đến các phiên bản được xác minh là không đạt yêu cầu hoặc lỗi và chỉ khởi động lại việc chuyển tiếp request đến phiên bản đó khi nó được khai báo là đã đạt yêu cầu.

Tính năng này giúp kiểm tra trạng thái máy chủ ở backend để đẩy request vào các server group không bị lỗi.

Quy trình hoạt động của health check

Server Load Balancer thường được triển khai theo cụm/cluster. Chuyển tiếp dữ liệu và health check sẽ được xử lý đồng thời bởi các node servers trong LVS cluster và Tengine cluster.

Các node servers trong cluster độc lập sẽ thực hiện health check song song, theo cấu hình của health check. Nếu một node server phát hiện ra một khu vực nào đó bị lỗi, node server sẽ ngừng phân phối request tới khu vực đó. Thao tác này sẽ được đồng bộ hóa trên tất cả các node server như trong sơ đồ dưới đây.

Những tính năng Load Balancer

3. Tính năng theo dõi giám sát hoạt động (Operational Monitoring)

Một số các thông số trong Load balancer cần theo dõi, giám sát:

Healthy host count: Số lượng các trường hợp không bị lỗi trong load balancer. Một trường hợp được coi là “healthy” – đạt tiêu chuẩn nếu nó đáp ứng ngưỡng tiêu chuẩn được cấu hình cho health check.

Unhealthy host count: Số lượng các trường hợp lỗi trong load balancer. Một trường hợp được coi là lỗi nếu nó vượt quá ngưỡng tiêu chuẩn lỗi được cấu hình cho health check. Số này không được lớn hơn 0 trừ khi máy chủ đang trong thời gian bảo trì.

Request Count: Số lượng request trọn vẹn được nhận và chuyển đến các phiên bản đăng ký. (The number of completed requests that were received and routed to the registered instances.)

Latency: Thời gian tính từ sau khi request rời khỏi load balancer cho tới lúc nhận được phản hồi (được tính bằng giây và không được lớn hơn 0 trừ khi máy chủ đang được bảo trì).

Lỗi kết nối Backend: Số lượng kết nối không thành công giữa load balancer và phiên bản đăng ký. Số này không được lớn hơn 0 trừ khi máy chủ đang trong thời gian bảo trì.

Độ dài Surge Queue Length: Tổng số request đang chờ gửi đến phiên bản đăng ký. Số này không được lớn hơn 0 trừ khi máy chủ đang trong thời gian bảo trì.

Spillover Count: Tổng số request bị từ chối khi quêu đã full. Số này không được lớn hơn 0 trừ khi máy chủ đang trong thời gian bảo trì.

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

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

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

4 thói quen bạn cần thay đổi để thành công

thói quen

Nhiều nghiên cứu cho thấy, những người thành công hầu như đều sở hữu cho mình những thói quen tích cực. Chúng cũng có ý nghĩa lớn, chi phối đến những quyết định quan trọng của họ. Song, quá trình ấy cần họ chọn lọc và nỗ lực rèn luyện bởi có rất nhiều thói quen tiêu cực bủa vây. Cùng TopDev tìm hiểu về 4 thói quan bạn cần thay đổi nếu muốn trở thành người thành công!

Dấu hiệu sinh hoạt chưa khoa học

Những dấu hiệu cụ thể mà một người khó thành công đó là: Ngủ quá nhiều, nghĩ quá nhiều về mọi thứ; hoặc thậm chí là ăn quá nhiều.

thói quen
Những thói quen tiêu cực sẽ tác động nếu bản thân bạn không nhận ra chúng!

Điều bạn cần làm để thay đổi là việc tự rèn luyện và chủ động cải thiện thay đổi các thói quen. Hãy tập ra khỏi giường đúng giờ. Đừng “nướng” qáu lâu để rồi ảnh hưởng đến chất lượng và hiệu quả của công việc.

Quan tâm nhiều đến khối óc của bạn. Đừng suy nghĩ quá nhiều nếu bạn cảm thấy có dấu hiệu của sự căng thẳng. Việc làm cho tâm trí bạn thư giãn là có ý nghĩa rất quan trọng đến sưc khỏe tinh thần của bạn.

Ngưng hóng hớt “chuyện đời – chuyện người”

Đây là biểu hiện của một người sẽ khó thành công. Khi hóng hớt tức là bạn đang soi mói, “tìm tòi” những khía cạnh tiêu cực của người khác.

Xem thêm các việc làm về tuyển dụng Data Scientist 

Điều này vô tình tạo ra một sự lãng phí năng lượng tinh thần khổng lồ. Đồng thời, bạn khó có thể tập trung vào việc phát triển bản thân. Từ đó dẫn đến việc bạn dậm chân tại chỗ.

Những mục tiêu phi thực tế

Không một người nào thành công nào mà không xác lập mục tiêu cho mình cả. Tuy nhiên, nếu bạn có mục tiêu thì nó phải đảm bảo tính khả thi.

Xem thêm các việc làm NTQ Solution tuyển dụng

thói quen
thói quen

Mục tiêu, kế hoạch cần dược chuẩn hóa xây dựng một cách khoa học. Cụ thể, nó được thiết lập dựa trên các hệ giá trị như năng lực, tính cách, môi trường,… Nếu không bạn sẽ dễ dàng rơi vào trạng thái căng thẳng. Và tất nhiên, bạn khó có thể thực hiện bất cứ điều gì cả.

Áp lực từ việc trở thành người đa nhiệm

Nhiều người thành công họ không chỉ đơn thuần ở việc chỉ làm một công việc, một nhiệm vụ nào đó. Họ thực hiện rất nhiều task, các dự án thậm chí quản lý rất nhiều dự án lớn nhỏ khác nhau.

Tuy nhiên, nếu chưa có đủ sự trải nghiệm về kỹ năng chuyên môn cùng việc áp dụng thực tế, bạn khó có thể thành công.

Một freelancer IT không thể tự tin nhận nhiều job nếu chuyên môn của họ không thật sự giỏi. Trở thành người đa nhiệm thật sự không hề dễ dàng. Đó là một quá trình dài và vì thế, đừng cố sức nếu bạn chưa đủ sức thực hiện.

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

Xem thêm Top Việc làm ngành it trên TopDev

Xử lý SSL Certificate trong Selenium WebDriver

Xử lý SSL Certificate trong Selenium WebDriver

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

Khai bút đầu xuân, cũng là đánh dấu sự trở lại sau một thời gian kha khá dài không có bài viết thường xuyên cập nhật. Với mục tiêu cho năm mới đó là cống hiến nhiều hơn, mặc dù dạo gần đây và trong tương lai gần thì mình không có nhiều thời gian rảnh buổi tối để làm anh hùng bàn phím như này nữa.

Bài viết đầu tiên đậm chất kỹ thuật, khô khan nhưng lại chứa hàm lượng kiến thức vừa đủ để có thể áp dụng vào thực tế. :))) Hi vọng rằng bài viết sẽ có chút hữu ích cho các bạn nào cần thông tin – cũng là làm phong phú thêm kết quả tìm kiếm hiển thị trên Google search! – Cũng là một cách cống hiến đúng không nào! 😀

  System Design Cơ Bản: HTTPS, SSL, AND TLS
  Các kiểu “đợi chờ” trong Selenium Webdriver: Implicit wait, Explicit wait và Fluent wait

Đầu tiên tìm hiểu một chút về SSL Certifycate, mình nói sơ qua lý thuyết thôi, vì thực tế là cả tài liệu tiếng Việt và tiếng Anh đều cung cấp rất đầy đủ và chi tiết về cái này rồi, như nó là gì, phân loại ra sao, mục đích sử dụng như thế nào, những lợi ích mà nó đem lại cho người dùng là gì… và cùng rất nhiều thông tin khác nữa, nói ra thì dài lắm, nên các bạn cần thì tự tìm hiểu thêm, ở đây là mức vừa đủ để khỏi bỡ ngỡ thui nha!

SSL Cetificate là gì?

SSL là viết tắt của Secure Socket Layer, là một tiêu chuẩn an ninh công nghệ toàn cầu tạo ra một liên kết được mã hóa giữa máy chủ web và trình duyệt. Liên kết này đảm bảo tất cả các dữ liệu trao đổi giữa máy chủ web và trình duyệt luôn được bảo mật và an toàn.

Chứng thư số SSL tích hợp trên ứng dụng client để người dùng khi truy cập có thể xác minh được tính xác thực, tin cậy của website, đảm bảo mọi dữ liệu, thông tin trao đổi giữa ứng dụng và người dùng được mã hóa, tránh nguy cơ bị can thiệp. Các bạn xem qua cách thức hoạt động theo sơ đồ phía dưới:

Xử lý SSL Certificate trong Selenium WebDriver
Source: SSL Sertificate

Ví dụ:

  1. Truy cập trang Web: https://www.vietcombank.com.vn/
  2. Enter
  3. Chúng ta sẽ quan sát thấy thông tin chứng chỉ SSL như vùng khoanh ở hình ảnh phía dưới, khi click vào sẽ hiển thị popup thông tin nhỏ phía dưới:

Xử lý SSL Certificate trong Selenium WebDriver

Liên quan đến SSL Certification, trên các trình duyệt sẽ có thông báo hiển thị khác nhau như:

Chrome:

Xử lý SSL Certificate trong Selenium WebDriver

FireFox:

Xử lý SSL Certificate trong Selenium WebDriver

IE:

Xử lý SSL Certificate trong Selenium WebDriver

Trên thực tế khi viết các automation script, không phải sẽ gặp phải tình huống này quá thường xuyên, nhưng cũng là một trường hợp tương đối đặc biệt mà mình nghĩ là nếu hiểu và biết cách xử lý thì sẽ có hướng tiếp cận nhanh và phù hợp hơn.

Đối với từng loại trình duyệt thì sẽ có những điều chỉnh tương ứng với trình duyệt đó, tùy thuộc vào trình duyệt mà bạn dự định sẽ thực thi test, lý do vì sao thì chính là mấy hình ảnh phía trên kia chính là câu trả lời đó! :)))

Ở đây mình sẽ tổng hợp lại các bước để xử lý được trường hợp này, cơ bản là cũng không có đưa ra được cụ thể một link ví dụ nào để thực hành, nếu gặp trong thực tế, thì các bạn có thể thử áp dụng luôn, nếu có vướng mắc gì thì có thể liên hệ với mình để cùng tìm cách giải quyết nhé! 😀

Trên trình duyệt Chrome:

//Chrome
	DesiredCapabilities ch=DesiredCapabilities.chrome();
	ch.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true);
	ch.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
		
	System.setProperty("webdriver.chrome.driver", "D:\\Program\\Webdriver\\chromedriver.exe");
	WebDriver driver = new ChromeDriver(ch);

Trên trình duyệt FireFox:

//FireFox:

    FirefoxProfile ffProfile = new FirefoxProfile();
    ffProfile.setAcceptUntrustedCertificates(true);
    ffProfile.setAssumeUntrustedCertificateIssuer(false);
     
    FirefoxDriver driver = new FirefoxDriver(ffProfile)

Trên trình duyệt IE:

Điểm khác với hai trình duyệt phía trên, ta phải thực hiện một bước trước khi thực hiện tương tác với Certificate, thì sẽ phải thực hiện bước điều hướng bằng cách sử dụng Javascript executor:

driver.navigate ().to ("javascript:document.getElementById('overridelink').click()");

Xử lý SSL Certificate trong Selenium WebDriver

Sau đó thực hiện tương tự như thực hiện phía trên với Chrome/Firefox:

DesiredCapabilities cap= new DesiredCapabilities();
cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
cap.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
System.setProperty("webdriver.ie.driver","IEDriverServer.exe");
WebDriver driver = new InternetExplorerDriver(capabilities);

Trên đây là các bước thực hiện giúp bạn xử lý SSL certificate với Selenium đối với các trình duyệt Chrome, FireFox và IE. Các bạn có thể thử và nếu có vấn đề gì thì để lại bình luận phía dưới hoặc liên hệ trực tiếp với mình nhé. Mình không chắc sẽ đưa ra ngay được đáp án chính xác tuy nhiên sẽ hứa cùng các bạn tìm hiểu vấn đề và giải quyết vấn đề :))))

Chúc mừng năm mới, nhiều điều mới mẻ và tốt đẹp sẽ chào đón chúng ta! <<tung hoa, tung hoa>>

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

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

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

Avalability vs Consistency

Avalability vs Consistency

Bài viết được sự cho phép của tác giả Edward Thiên Hoàng

CÁC PATTERNS VỀ SỰ NHẤT QUÁN (CONSISTENCY)

Với nhiều bản sao của cùng một dữ liệu, chúng ta phải đối mặt với các tùy chọn về cách đồng bộ hóa để client có một cái nhìn nhất quán về dữ liệu.

TÍNH NHẤT QUÁN LỎNG LẺO (WEAK CONSISTENCY)

Sau một lệnh ghi, có thể đọc được hoặc không được ngay lập tức.

Cách tiếp cận này được thấy trong các hệ thống như memcached. Tính nhất quán yếu, lỏng lẻo hoạt động tốt trong các use cases thời gian thực như VoIP, trò chuyện video và trò chơi nhiều người chơi trong thời gian thực. Ví dụ: nếu bạn đang thực hiện một cuộc gọi điện thoại và mất liên lạc trong vài giây, khi bạn lấy lại kết nối, bạn không nghe thấy những gì được nói trong khi mất kết nối.

  Bài toán đồng thuận trong Distributed Systems
  System Design Cơ Bản - Phần 5: Indexes

TÍNH NHẤT QUÁN CÓ ĐỘ TRỄ (EVENTUAL CONSISTENCY)

Sau một lệnh ghi, các lệnh đọc sẽ thấy được data cùng với một độ trễ (thường trong vòng một phần nghìn giây). Dữ liệu được nhân rộng không đồng bộ.

Cách tiếp cận này được nhìn thấy trong các hệ thống như DNS và email. Tính nhất quán cuối cùng hoạt động tốt trong các hệ thống có sẵn cao.

TÍNH NHẤT QUÁN CHẶT (STRONG CONSISTENCY)

Sau khi ghi, sẽ đọc được dữ liệu ngay lập tức. Dữ liệu được nhân rộng đồng bộ.

Cách tiếp cận này được nhìn thấy trong các hệ thống file và RDBMS. Tính nhất quán mạnh mẽ hoạt động tốt trong các hệ thống cần bảo đảm tính ACID.

THAM KHẢO THÊM TẠI:

Transactions across data centers

CÁC PATTERNS VỀ TÍNH KHẢ DỤNG, SẴN SÀNG (AVAILABILITY)

Có hai patterns chính để hỗ trợ tính khả dụng cao (high availability): fail-over (chuyển đổi dự phòng) và replication (nhân bản).

FAIL-OVER

ACTIVE-PASSIVE

Với chuyển đổi dự phòng dạng active-passive, các lệnh check heartbeats được gửi giữa máy chủ active và máy chủ passive ở chế độ standby. Nếu heartbeats bị gián đoạn, máy passive sẽ chiếm địa chỉ IP của máy active và tiếp tục dịch vụ.

Thời gian ngừng hoạt động được xác định bởi liệu máy passive đã chạy ở chế độ ‘hot’ standby hay liệu nó có cần khởi động từ chế độ ‘cold’ standby hay không. Chỉ có máy chủ active xử lý request.

Chuyển đổi dự phòng dạng active-passive cũng có thể được gọi là chuyển đổi dự phòng master-slave.

ACTIVE-ACTIVE

Trong active-active, cả hai máy chủ đều xử lý request, phân tán tải giữa chúng.

Nếu các máy chủ được công khai ra internet, DNS sẽ cần biết về IP công khai của cả hai máy chủ. Nếu các máy chủ nằm trong nội bộ, logic ứng dụng sẽ cần biết về cả hai máy chủ.

Chuyển đổi dự phòng hoạt động active-active cũng có thể được gọi là chuyển đổi dự phòng master-master.

NHƯỢC ĐIỂM CỦA CHUYỂN ĐỔI DỰ PHÒNG

Chuyển đổi dự phòng thêm phần cứng và tăng độ phức tạp.
Có khả năng mất dữ liệu nếu hệ thống hoạt động bị lỗi trước khi bất kỳ dữ liệu mới được ghi nào có thể được nhân rộng (replicate) sang máy passive.

NHÂN RỘNG (REPLICATION)

MASTER-SLAVE REPLICATION

14-1

Máy chủ master phục vụ đọc và ghi, sao chép ghi vào một hoặc nhiều máy slave chỉ phục vụ đọc. Các slave cũng có thể sao chép thêm các slave theo kiểu giống như mô hình cây. Nếu master ngừng hoạt động, hệ thống có thể tiếp tục hoạt động ở chế độ chỉ đọc cho đến khi một máy slave được thăng cấp thành master hoặc có một master mới được cung cấp.

Nhược điểm:

  • Cần logic để thăng cấp một máy slave thành máy master.
  • Có khả năng mất dữ liệu nếu máy master bị lỗi trước khi bất kỳ dữ liệu mới được ghi nào có thể được sao chép sang các máy salve khác.
  • Việc nhân rộng yêu cầu phải thêm phần cứng và tăng thêm độ phức tạp.

MASTER-MASTER REPLICATION

14-2

Cả hai máy master phối hợp với nhau phục vụ đọc ghi. Nếu một trong hai chủ bị hỏng, hệ thống có thể tiếp tục hoạt động với cả đọc và ghi.

Nhược điểm:

  • Sẽ cần đến một bộ cân bằng tải hoặc sẽ cần thay đổi logic ứng dụng để xác định nơi ghi.
    Hầu hết các hệ thống master-master đều có tính nhất quán lỏng lẻo (vi phạm ACID) hoặc tăng độ trễ ghi do đồng bộ hóa.
  • Giải quyết xung đột xuất hiện nhiều hơn khi nhiều nút ghi được thêm vào và do đó sẽ làm tăng độ trễ (latency).
  • Và tất nhiên, việc nhân rộng yêu cầu phải thêm phần cứng và tăng thêm độ phức tạp.

CÁC TÍNH KHẢ NĂNG KHẢ DỤNG

Tính khả dụng thường được định lượng theo thời gian hoạt động (hoặc thời gian chết) theo phần trăm thời gian dịch vụ có sẵn. Tính khả dụng thường được đo bằng số lượng các số 9 – một dịch vụ có 99,99% khả dụng được mô tả là có bốn số 9.

99.9% AVAILABILITY – 3 SỐ 9

Duration Acceptable downtime
Downtime per year 8h 45min 57s
Downtime per month 43m 49.7s
Downtime per week 10m 4.8s
Downtime per day 1m 26.4s

99.99% AVAILABILITY – FOUR 9S

Duration Acceptable downtime
Downtime per year 52min 35.7s
Downtime per month 4m 23s
Downtime per week 1m 5s
Downtime per day 8.6s

KHẢ DỤNG SONG SONG VS THEO TRÌNH TỰ

Nếu một dịch vụ bao gồm nhiều thành phần dễ bị lỗi, tính khả dụng chung của dịch vụ phụ thuộc vào việc các thành phần đó theo trình tự hay song song.

THEO THỨ TỰ

Tính khả dụng chung giảm khi hai thành phần có sẵn < 100% theo thứ tự:

Tính khả dụng (tổng) = Tính khả dụng (Foo) * Tính khả dụng (Bar)

Nếu cả Foo và Bar đều có sẵn 99,9%, tổng số khả dụng của chúng theo thứ tự sẽ là 99,8%.

SONG SONG

Tính khả dụng chung tăng khi hai thành phần có sẵn < 100% song song:

Tính khả dụng (tổng) = 1 – (1 – khả dụng (Foo)) * (1 – khả dụng (Bar))

Nếu cả Foo và Bar đều có sẵn 99,9%, thì tổng khả dụng song song của chúng sẽ là 99.9999%.

Theo system-design-primer

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

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

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

Máy tính lượng tử là gì? Tìm hiểu về máy tính lượng tử

Máy tính lượng tử là gì? Tìm hiểu về máy tính lượng tử

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

Như các bạn đã biết, các máy tính hiện đại ngày nay có bộ xử lý trung tâm là CPU (hay còn gọi là Chip) đang dần đạt đến giới hạn vật lý có thể đạt được.

Hiện tại là tiến trình 7nm, tương lai các CPU chỉ còn 2nm thậm chị là 1nm. Khi các bóng bán dẫn đạt tới mức này, việc thu nhỏ thêm là vô cùng khó khăn.

Nhiều chuyên gia và người yêu công nghệ cho rằng, để thay cho giải pháp bóng bán dẫn, các nhà khoa học sẽ nghiên cứu tới các máy tính lượng tử (cấp độ phân tử).

#1. Máy tính lượng tử là gì?

Khác với máy tính kỹ thuật số, máy tính lượng tử hoạt động dựa trên hoạt động của cơ học lượng tử, để xử lý dữ liệu đầu vào. Như vậy, hiểu đơn giản máy tính lượng tử là máy tính hoạt động trên cơ sở của những hạt lượng tử.

Các hoạt động chủ yếu của lượng tử được áp dụng vào máy tính lượng tử là tính chồng chập và vướng víu lượng tử.

Không giống với các máy tính kỹ thuật số thông dụng ngày nay, dữ liệu được mã hóa thành số nhị phân (bit) và gán cho nó 2 giá trị TẮT và MỞ tương ứng là 0 và 1. Và nó chỉ có thể nhận được 1 trong 2 giá trị 0 hoặc 1.

Còn các máy tính lượng tử sử dụng đơn vị là “qubits” (quantum bits, bits lượng tử ) với các giá trị nằm trong khoảng từ 0 tới 1. Nó có thể nhận được cả 2 giá trị 0 và 1 cùng một lúc.

Để có thể giải thích thì nguyên lý hoạt động của máy tính lượng tử dựa trên 2 hoạt động cơ học là tính chồng chập và vướng víu lượng tử là rất khó hiểu với đại đa số chúng ta, nên mình xin phép không đề cập đến.

Chúng ta chỉ cần biết rằng máy tính lượng tử là máy tính từ những hạt cơ bản (lượng tử) và nó hoạt động nhờ trên các hoạt động của cơ học lượng tử.

#2. Khả năng tính toán gấp nhiều lần so với máy tính kỹ thuật số

Theo nghiên cứu, các máy tính lượng tử có khả năng xử lý theo cấp số nhân (theo số lượng qubits). Chỉ với việc tăng một số lượng nhỏ qubits thì ta sẽ có gấp nhiều lần năng lực xử lý của máy tính.

Tuy nhiên, đó là chỉ là trên lý thuyết, việc thêm một lượng qubits phải đảm bảo không có lỗi nào trong quá trình xảy ra rối lượng tử và chỉ vài sai lệnh nhỏ trong vấn đề tính toán là mọi việc đều công cốc.

  Kỹ thuật phần mềm vs Khoa học máy tính - Nên chọn ngành nào/
  Tại sao có rất ít người chọn ngành Khoa học máy tính?

#3. Máy tính lượng tử có hình dạng như thế nào?

Không giống với các máy tính thông thường, các máy tính lượng tử có hình dáng khá là đặc biệt, chúng trông giống như một chiếc đèn chùm khổng lồ và các chuyên gia cũng gọi đó là kiến trúc đèn chùm.

Máy tính lượng tử là gì? Tìm hiểu về máy tính lượng tử
Hình dạng máy tính lượng tử

Cũng giống như các máy tính thông thường, máy tính lượng tử cũng có một nhân trung tâm là một siêu chip với các qubit được sắp xếp theo dạng bàn cờ vua.

Nhân chip và cụ thể là các qubits có cấu tạo là các vi tụ điện được làm từ Niobium với độ cứng ngang với Titan.

Các cực của qubit được làm để dao động, và không duy trì một trạng thái cố định nào, chính vì lý do này nên máy tính lượng tử có khả năng xử lý mạnh hơn máy tính thông thường.

Máy tính lượng tử là gì? Tìm hiểu về máy tính lượng tử
Nhân chip máy tính lượng tử

Con chip này được đặt trong một trường vi sóng điện từ, hoạt động trong điều kiện lạnh, cực lạnh, thậm chí ở mức gần 0oK.

Để đạt được ngưỡng nhiệt này, cách hiệu quả và ít tốn kém nhất hiện tại là  máy tính sẽ được nhấn chìm trong một bể Heli lỏng.

#4. Phần mềm của máy tính lượng tử

Nếu bạn trông chờ máy tính lượng tử cũng chạy hệ điều hành, hay các soft như máy tính thông thường thì đã làm các bạn thất vọng rồi. Thực tế thì hiện nay không có một phần mềm nào hoạt động được trên máy tính lượng tử.

Để kiểm tra khả năng xử lý của máy tính, các chuyên gia đã phải nghiên cứu ra các tác vụ công cụ riêng đặc biệt có thể nói là độc nhất vô nhị để chạy trên siêu máy tính này.

Có thể thấy rõ, tuy chúng ta đã đạt được những bước tiến lớn trong ngành này nhưng vẫn chưa thể áp dụng lên thực tiễn được.

Nếu so sánh với việc sản xuất máy bay thì chúng ta chỉ đang ở giai đoạn những chiếc máy bay đầu tiên trên thế giới, chỉ nhấc lên khỏi mặt đất chứ không thể gọi là bay đúng nghĩa.

Sẽ còn quá sớm để nói rằng máy tính lượng tử sẽ được ứng dụng vào cuộc sống, ít nhất cũng cần 40 tới 50 năm nữa chúng ta mới có được những chiếc máy lượng tử ứng dụng vào phổ thông.

Trong khoảng thời gian đó, máy tính kỹ thuật số sẽ đứng trước chướng ngại vật lý về kích thước bóng bán dẫn, chúng ta chỉ có thể chờ xem liệu tiến bộ khoa học sẽ làm gì với rào cản này.

Trên đây là bài viết cơ bản nhất về máy tính lượng tử, một ngành khoa học mới và vô cùng phức tạp. Bài viết nhằm đem lại cho các bạn những kiến thức cơ bản và dễ hiểu nhất về máy tính lượng tử nên không tránh khỏi những thiếu sót.

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

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

Xem thêm Tìm việc IT hấp dẫn trên TopDev

Kỹ sư phát triển và kỹ sư kiểm thử đều test app giỏi như nhau?

Kỹ sư phát triển và kỹ sư kiểm thử đều test app giỏi như nhau?

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

Câu hỏi này là đề tài tranh luận phức tạp. Kỹ sư phát triển kiểm thử mã của họ. Kết quả của quá trình kiểm thử này là gì? Phải chăng là toàn bộ những luồng làm việc  của hệ thống? Thông thường, kỹ sư phát triển chỉ nhìn thấy những luồng làm việc chính và cơ bản của sản phẩm, và thường không đi sâu vào chi tiết từng luồng làm việc khác nhau. Kỹ sư kiểm thử giỏi sẽ giúp app không bị crash ở những luồng không mong muốn.

  Biện hộ: Vì sao các Developer không test phần mềm của họ?
  5 app dù bị đánh giá thấp nhưng không nên bỏ qua

It’s not a bug, it’s a feature

Vấn đề chính trong việc kiểm thử do kỹ sư phát triển tiến hành là việc không nắm rõ, hiểu nhầm các yêu cầu chức năng. Nếu một yêu cầu chức năng bị hiểu nhầm bởi kỹ sư phát triển, bất kế kỹ sư phát triển tiến hành kiểm thử sâu đến mức độ nào, lỗi sẽ không bao giờ được tìm thấy. Và lỗi sẽ được kỹ sư phát triển nhìn nhận, ngay từ ban đầu, như một chức năng – It’s not a bug, it’s a feature 🙂

Những kỹ sư phát triển cho rằng: mã do tôi viết và tôi tự tin nó hoạt động một cách chính xác. Không cần phải kiểm thử luồng làm việc này, không cần kiểm thử cách ứng xử kia, và tôi biết là nó/ứng dụng làm việc một cách chính xác và hợp lý. Kết quả là, kỹ sư phát triển bỏ qua khả năng xảy ra lỗi.

Kỹ sư phát triển và kỹ sư kiểm thử

Kỹ sư phát triển luôn cảm thấy mã hoạt động chính xác. Và anh ta sẽ làm kiểm thử để khẳng định mã hoạt động chính xác. Nhưng, lý do gì đển kỹ sư kiểm thử tiến hành kiểm thử ứng dụng? Để tìm ra lỗi ở một điểm nào đó và kỹ sư kiểm thử tiến hành kiểm thử để chứng minh ứng dụng không làm việc một cách chính xác. Đây chính là điểm khác biệt chính trong cách tiến hành kiểm thử của kỹ sư phát triển và kỹ sư kiểm thử.

Kỹ sư phát triển có nên làm kiểm thử với mã của họ?

Về cá nhân, tôi không có vấn đề gì nếu kỹ sư phát triển kiểm thử mã của họ. Sau tất cả, đó là sản phẩm của họ. Họ biết mã rất rõ. Họ biết các bẫy trong mã. Nơi mã có thể có lỗi, nơi nào cần chú ý nhiều hơn, đâu là luồng làm việc quan trọng của ứng dụng. Kỹ sư phát triển có thể tiến hành các kiểm thử đơn vị và có thể thiết lập những trường hợp biên – boundary cases.

Kỹ sư phát triển và kỹ sư kiểm thử đều test app giỏi như nhau?

Đó là tất cả những gì để kỹ sư phát triển có thể trở thành một kỹ sư kiểm thử tốt. Nhưng, hầu hết kỹ sư phát triển nhìn nhận kiểm thử là một công việc mệt mỏi, bất kể họ hiểu hệ thống tốt như thế nào họ cũng sẽ bỏ qua nhiều luồng kiểm thử khác nhau. Nếu một kỹ sư phát triển tìm thấy lỗi trong mã của họ khi đang tiến hành kiểm thử đơn vị, lỗi sẽ tương đối dễ chỉnh sửa, một phần vì mã vừa mới được viết ra; hơn là chỉnh mã để sửa lỗi do nhóm kiểm thử tìm thấy vài ngày sau đó. Nhưng, việc này cũng chỉ hiệu quả khi mà kỹ sư phát triển cảm thấy hứng thú với việc kiểm thử.

Trách nhiệm của kỹ sư kiểm thử là đảm bảo tất cả các luồng làm việc của hệ thống đều được kiểm thử. Kỹ sư kiểm thử nên chỉ ra sự quan trọng của từng vấn đề khả dĩ để kiểm tra rằng hệ thống không bị thiếu sót ở bất kỳ đâu.

Mỗi người trong nhóm đều là chuyên gia trong từng lĩnh vực của họ. Kỹ sư phát triển thường nghĩ về cách phát triển ứng dụng trong khi kỹ sư kiểm thử nghĩ về cách người dùng cuối sử dụng ứng dụng đó.

Kết luận

Vậy nên, về cơ bản, sẽ không có vấn đề gì nếu kỹ sư phát triển tiến hành những bài kiểm thử đơn vị cơ bản. Kỹ sư phát triển có thể kiểm thử vài điều kiện đặc biệt mà họ biết là nghiêm trọng và không thể bỏ qua. Nhưng vẫn còn những kỹ sư kiểm thử giỏi trong nhóm. Đừng phí thời gian của kỹ sư phát triển. Để dự án thành công, cần có đội ngũ kiểm thử độc lập để kiểm thử ứng dụng. Và, sau cùng, trách nhiệm của kỹ sư kiểm thử là làm cho sản phẩm tốt hơn cho người dùng.

Bạn nghĩ sao?

Dịch từ softwaretestinghelp

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

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

Xem thêm Tuyển tester lương cao hấp dẫn trên TopDev

Cách tạo các biểu mẫu cơ bản bằng React Hooks

Cách tạo các biểu mẫu cơ bản bằng React Hooks

Trong Dự án React cho người mới bắt đầu này, chúng ta sẽ học cách xây dựng các biểu mẫu cơ bản bằng cách sử dụng React hook. Chúng ta sẽ tìm hiểu cách quản lý state biểu mẫu, xử lý xác thực và làm việc với trình xử lý gửi.

Kiểm tra thử nào:

Bắt tay xử lý vấn đề

Nếu bạn muốn tự mình thực hiện trước, đây là các tình huống (bạn cũng có thể lấy CSS / source code bên dưới):

  • Người dùng có thể nhập các giá trị vào biểu mẫu React Hooks
  • Khi người dùng nhấp vào gửi, nếu bất kỳ trường nào trống, thì thông báo lỗi sẽ xuất hiện màu đỏ
  • Nếu biểu mẫu được gửi và hợp lệ, thông báo thành công sẽ xuất hiện

Video hướng dẫn

Source code tham khảo

Source code trên GitHub

Bắt đầu thôi! Add state

Chúng ta sẽ bắt đầu bằng cách thêm một đối tượng state để giữ biểu mẫu của React Hooks. Chúng ta sẽ lấy một dòng mới ở đầu App function trong App.js và thêm phần sau:

const [values, setValues] = useState({
	firstName: '',
	lastName: '',
	email: '',
});

Chúng ta có ba trường trên biểu mẫu mà chúng ta cần biết state.

Bây giờ, state ban đầu sẽ là một đối tượng. Và đối tượng này sẽ có ba giá trị, một giá trị cho mỗi trường này. Vì vậy, chúng ta sẽ gọi chúng một cái gì đó tương tự như những gì chúng được gọi trong biểu mẫu.

firstName sẽ được đặt thành trống ban đầu, giống với lastName và giống với email.

Và bây giờ, bạn sẽ nhận thấy lỗi “useState is not defined”, vì vậy bạn cần nhập nó từ React tại đây. Thực hiện việc này ở đầu tệp như một phần của quá trình nhập:

import React, { useState } from "react";

Được rồi, bây giờ nó cho chúng ta biết rằng các biến này chưa được sử dụng. Điều này là tốt vì chúng ta chưa áp dụng các giá trị này cho biểu mẫu của React Hooks. Nhưng tất cả những gì chúng ta đã làm cho đến nay là chúng ta đã tạo một đối tượng state và đối tượng state này kéo firstName, lastNameemail.

Bây giờ chúng ta có một số giá trị ở state, nên áp dụng chúng vào các trường input. Thêm một thuộc tính value vào mỗi trường input của bạn như sau:

<input
    id="first-name"
    class="form-field"
    type="text"
    placeholder="First Name"
    name="firstName"
    value={values.firstName}
/>

<input
    id="last-name"
    class="form-field"
    type="text"
    placeholder="Last Name"
    name="lastName"
    value={values.lastName}
/>

<input
    id="email"
    class="form-field"
    type="text"
    placeholder="Email"
    name="email"
    value={values.email}
/>

Tất cả những gì chúng ta đã làm ở đây là nói, “Được rồi, đối với input này, giá trị sẽ là bất kỳ giá trị nào ở state.” Hãy lưu điều này và xem những gì đang diễn ra trong các biểu mẫu trong React Hooks, để đảm bảo mọi thứ vẫn hoạt động.

Xem thêm các việc làm React hấp dẫn lương cao

Nếu bạn chọn một input và bắt đầu gõ mạnh trên bàn phím, không có gì xuất hiện trên màn hình. Vậy điều gì đang xảy ra ở đây?

Cập nhật input states

Chà, chúng ta đã nói rằng giá trị của input này sẽ là bất kể nó ở state nào.

Ví dụ: firstName hiện được đặt thành trống vì đó là những gì chúng ta đặt nó thành, nhưng chúng ta chưa nói với input, “Được rồi. Bất cứ khi nào tôi nhập hoặc input thay đổi, tôi muốn bạn tiếp tục và cập nhật state mới các giá trị. “

Bất cứ khi nào chúng ta làm những việc như thế này, nó sẽ cho phép React hooks kiểm soát một cách hiệu quả. Vì vậy, chúng ta phải yêu cầu React hooks cập nhật các giá trị.

Điều này có nghĩa là chúng ta phải cập nhật các giá trị state bất cứ lúc nào chúng ta nhập vào các trường này.

Được chứ. Cách đơn giản nhất để làm điều này là tạo một trình xử lý cho mỗi trường input này, trình xử lý này sẽ cập nhật state bất kỳ khi nào xảy ra sự kiện thay đổi.

Hãy tiếp tục và thêm phần sau ngay bên dưới các đối tượng state:

const handleFirstNameInputChange = (event) => {
	event.persist();
	setValues((values) => ({
		...values,
		firstName: event.target.value,
	}));
};

Điều này diễn ra sự kiện mà chúng ta nhận được từ onChange. Về cơ bản chúng ta đang cập nhật đối tượng này và sau đó lưu nó trở lại state.

Chúng ta sẽ sao chép các giá trị cũ bằng cách thực hiện dấu ba chấm, còn được gọi là toán tử chênh lệch. Và sau đó, chúng ta sẽ chỉ nhập các giá trị và thêm dấu phẩy.

Tiếp theo, chúng ta sẽ nói rằng firstName sẽ bằng event.target.value. chúng ta muốn thêm điều này vào input của chúng ta. Vì vậy, trong JSX của chúng ta trong input cho tên, chúng ta sẽ lấy một dòng mới ở đâu đó (ở bất kỳ đâu, điều đó không thực sự quan trọng) và thêm thuộc tính onChange như sau:

<input 
    id='first-name' 
    class='form-field' 
    type='text' 
    placeholder='First Name' 
    name='firstName' 
    value={values.firstName} 
    onChange={handleFirstNameInputChange} />

Bây giờ, nếu chúng ta truy cập trình duyệt của mình và bắt đầu nhập, bạn có thể thấy rằng mọi thứ hoạt động. Phần còn lại của chúng không hoạt động vì chúng ta chưa thêm trình xử lý cho chúng. chúng ta sẽ xem xét điều đó trong một phút.

Chỉ để tóm tắt lại những gì đang xảy ra: bất cứ khi nào chúng ta nhập vào ô này, sự kiện onChange sẽ xảy ra cho mọi lần nhấn phím. Điều này được gọi mọi lúc.

Sự kiện được React hooks chuyển vào và chúng ta muốn cập nhật đối tượng state của mình. Vì vậy, để làm điều đó, chúng ta gọi hàm setValues và truyền vào một đối tượng mới với các giá trị được cập nhật.

Bây giờ, chúng ta chỉ muốn làm điều tương tự cho lastNameemail. Thêm một trình xử lý khác cho mỗi:

const handleLastNameInputChange = (event) => {
	event.persist();
	setValues((values) => ({
		...values,
		lastName: event.target.value,
	}));
};

const handleEmailInputChange = (event) => {
	event.persist();
	setValues((values) => ({
		...values,
		email: event.target.value,
	}));
};

Và đừng quên thêm các thuộc tính onChange vào các trường input cho mỗi:

<input
    id="last-name"
    class="form-field"
    type="text"
    placeholder="Last Name"
    name="lastName"
    value={values.lastName}
    onChange={handleLastNameInputChange}
/>
<input
    id="email"
    class="form-field"
    type="text"
    placeholder="Email"
    name="email"
    value={values.email}
    onChange={handleEmailInputChange}
/>

Bây giờ là thời điểm của sự thật. Mọi thứ đang hoạt động hay chúng ta đã làm hỏng thứ gì đó trong quá trình? Hãy thử tìm nó và xem. Điền vào một số dữ liệu và các trường input sẽ hoạt động ngay bây giờ.

Mặc dù các trường input của chúng ta đang hoạt động, chúng ta vẫn gặp một vấn đề nếu chúng ta nhập nội dung trong biểu mẫu và cố gắng gửi, nó sẽ không làm được gì cả. Nó sẽ chỉ làm mới trang và tất cả dữ liệu biểu mẫu của React Hooks sẽ bị mất.

Hiển thị thông báo thành công

Sau khi nhấp vào đăng ký, nó sẽ hiển thị thông báo thành công nếu biểu mẫu hợp lệ. Những gì chúng ta muốn làm là truy cập JSX của chúng ta và ngay bên dưới biểu mẫu thêm một div mới. Một lần nữa, tôi đã thêm các lớp cho bạn để có một thông báo thành công:

<div class='success-message'>Success! Thank you for registering</div>

Tất nhiên, bây giờ, điều này sẽ không đi đến đâu. Nó chỉ giả vờ rằng chúng ta đã gọi một máy chủ hoặc một điểm kết thúc ở đâu đó. Và nó quay lại với một thông báo thành công, vì vậy chúng ta sẽ hiển thị thông báo này cho người dùng.

Nhưng hiện tại nó xuất hiện mọi lúc. Những gì chúng ta muốn là chỉ hiển thị điều này nếu người dùng đã gửi biểu mẫu bằng React Hooks thành công.

Vì vậy, chúng ta sẽ thêm một đối tượng state khác như sau:

const [submitted, setSubmitted] = useState(false);

Chúng ta sẽ giữ phần này tách biệt với các giá trị vì nó là một phần khác của biểu mẫu. Không muốn trộn mọi thứ vào đây và gây ra toàn bộ kết xuất lại. Điều này sẽ cho chúng ta biết liệu biểu mẫu đã được gửi hay chưa.

Ban đầu, nó sẽ được đặt thành false vì lần đầu tiên người dùng truy cập vào trang, nó sẽ không được gửi.

Và bây giờ, chúng ta chỉ muốn thực hiện một số nội dung thông minh trong JSX để nói, “Nếu được gửi là đúng, thì chúng ta muốn hiển thị thông báo thành công.”

Cập nhật dòng mà chúng ta vừa thêm vào như sau:

{showSuccess && <div class='success-message'>Success! Thank you for registering</div>}

Chúng ta sẽ gói gọn thông điệp thành công của mình trong một toán tử bậc ba. Về cơ bản, đó là một câu lệnh if viết tắt cho phép chúng ta hiển thị động mọi thứ trên trang.

Giờ đây, thông báo thành công sẽ chỉ xuất hiện nếu showSuccess là đúng. Như bạn có thể thấy bây giờ trong trình duyệt, điều này đã biến mất.

Nếu chúng ta quay trở lại đối tượng state của chúng ta để submitted và thay đổi điều này thành true, nó sẽ xuất hiện lại. Và nó có

Chúng ta sẽ thay đổi điều này trở lại thành false. Và sau đó, chúng ta sẽ làm mới Chrome của mình và chỉ cần xem điều gì sẽ xảy ra ngay bây giờ.

Chúng ta chưa cho nút đăng ký hoặc biểu mẫu biết điều gì sẽ xảy ra trên hội nghị, vì vậy nó vẫn sẽ làm mới trang. Bây giờ, chúng ta chỉ cần một trình xử lý mới để xử lý việc nhấp vào nút đăng ký.

Nếu chúng ta chuyển sang trình xử lý sự kiện của mình và thêm những thứ sau:

const handleSubmit = (e) => {
	e.preventDefault();
	setSubmitted(true);
};

event.preventDefault sẽ ngăn quá trình làm mới xảy ra mà chúng ta đã thấy.

Chúng ta sẽ thêm một số logic nữa vào đây trong một phút nữa về xác thực và các thứ. Nhưng hiện tại, chúng ta chỉ nói “setSubmitted” là đúng.

Tiếp theo, chúng ta cần yêu cầu biểu mẫu gọi hàm này khi nó được gửi. Cập nhật JSX để bao gồm thuộc tính onSubmit trong thẻ biểu mẫu như sau:

<form class='register-form' onSubmit={handleSubmit}>
	//... other code
</form>

Bây giờ nếu chúng ta chạy mã trên trình duyệt, bấm vào nút đăng ký, thông báo hiện ra.

Thêm Validation và hiển thị thông báo lỗi

Biểu mẫu của chúng ta cho đến nay trông rất ổn, nhưng chúng ta thiếu một thành phần quan trọng của bất kỳ biểu mẫu nào và đó là xác thực. Nếu chúng ta xem xét ví dụ làm việc của mình, nếu tôi gửi điều này với bất kỳ trường trống nào, một lỗi sẽ xuất hiện cho biết, “Vui lòng nhập thông tin chi tiết của bạn”.

Bên dưới mỗi input, chúng ta sẽ thêm một <span> sẽ chứa thông báo lỗi. JSX của bạn sẽ trông giống như sau:

<input
    id="first-name"
    class="form-field"
    type="text"
    disabled={showSuccess}
    placeholder="First Name"
    name="firstName"
    value={values.firstName}
    onChange={handleInputChange}
/>
<span id="first-name-error">Please enter a first name</span>

<input
    id="last-name"
    class="form-field"
    type="text"
    placeholder="Last Name"
    name="lastName"
    value={values.lastName}
    onChange={handleInputChange}
/>
<span id="last-name-error">Please enter a last name</span>

<input
    id="email"
    class="form-field"
    type="text"
    placeholder="Email"
    name="email"
    value={values.email}
    onChange={handleInputChange}
/>
<span id="email-error">Please enter an email address</span>

Bạn có thể thấy những lỗi này luôn xuất hiện, bởi vì chúng ta không có bất kỳ logic điều kiện nào cho biết “không xuất hiện”.

Bây giờ, chúng ta chỉ muốn các thông báo lỗi này hiển thị nếu nút đăng ký đã được nhấp.

Quay lại code. Chúng ta muốn thêm một số logic có điều kiện vào và xung quanh các thông báo lỗi để chúng chỉ xuất hiện nếu nút đã được nhấp và trường trống:

{submitted && !values.firstName && <span id='first-name-error'>Please enter a first name</span>}

Những gì chúng ta đang làm ở đây là kiểm tra xem biểu mẫu đã được gửi và đối tượng state firstName có trống không. Nếu vậy, chúng ta muốn hiển thị thông báo lỗi. Một lần nữa, chúng ta chỉ sử dụng một toán tử bậc ba, không có gì lạ!

Làm tương tự cho các lỗi khác:

{submitted && !values.lastName && <span id='last-name-error'>Please enter a last name</span>}

//...other code

{submitted && !values.email && <span id='email-error'>Please enter an email address</span>}

Nếu chúng ta để trống biểu mẫu và nhấp vào đăng ký, lỗi sẽ xuất hiện. Nếu chúng ta bắt đầu nhập mọi thứ, chúng ta có thể thấy rằng lỗi sẽ biến mất. Và nếu chúng ta xóa những gì chúng ta đã nhập, lỗi sẽ quay trở lại.

Hãy thử và gửi một số thứ. Được rồi, vì vậy điều này có vẻ đang hoạt động.

Điều cuối cùng chúng ta muốn làm là đảm bảo rằng thông báo thành công này chỉ xuất hiện nếu biểu mẫu hợp lệ. Hãy tiếp tục và thêm một giá trị state mới:

const [valid, setValid] = useState(false);

Điều này được sử dụng để cho chúng ta biết liệu biểu mẫu của chúng ta có hợp lệ hay không – hãy nhớ rằng, sử dụng các đối tượng state là một cách tốt để giữ “state” của các phần khác nhau trong ứng dụng của bạn (ai có thể đoán được?).

Thông báo thành công sẽ chỉ xuất hiện nếu đã gửi là đúng và theo dõi cũng đúng. Vì ban đầu chúng ta đã đặt giá trị hợp lệ là false, nên nó sẽ không hiển thị.

Xem thêm các việc làm về tuyển dụng Business Analyst

Trong hàm handleSubmit của chúng ta, chúng ta muốn nói rằng giá trị là true nếu một biểu mẫu hợp lệ. Chúng ta có thể làm điều này bằng cách kiểm tra từng giá trị state của chúng ta cho các trường biểu mẫu, đảm bảo rằng chúng là một giá trị trung thực.

Thêm những điều sau:

const handleSubmit = (event) => {
event.preventDefault();
if(values.firstName && values.lastName && values.email) {
    setValid(true);
}
setSubmitted(true);
}

Nếu bất kỳ trường nào trong số này là false, thì valid hợp lệ sẽ vẫn là false. Điều này có nghĩa là div thông báo thành công sẽ không được hiển thị. Hãy xem nó hoạt động. Nếu chúng ta nhấp vào đăng ký mà không có trường, thông báo lỗi của chúng ta sẽ hiển thị. Hãy nhập một số nội dung hợp lệ, nhấn đăng ký và thông báo xuất hiện!

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

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

Tập chấp nhận và khắc phục sai lầm

Chấp nhận sai lầm và đạt thành công từ chúng

Sai lầm thường được xem là một danh từ mang tính tiêu cực, nhưng bạn hoàn toàn có thể nhìn nhận nó theo hướng tích cực hơn. Đơn giản vì chúng ta luôn mắc lỗi, nên ít nhất hãy biến chúng thành bài học để có thể khắc phục sai lầm.

Không ai là hoàn hảo – chúng ta luôn mắc lỗi và điều hoàn toàn tạo nên con người chúng ta. Chúng ta không sống trong một thế giới hoàn hảo, và chính sự không hoàn hảo là điều khiến cuộc sống trở nên năng động hơn.

Đôi khi, ngay cả một sai sót nhỏ cũng có thể dẫn đến những tổn thất lớn về tài chính, đặc biệt là đối với các bạn lập trình viên ngoài kia.

Nhưng thay vì chỉ cảm thấy tồi tệ khi mắc sai lầm, bạn có thể làm một vài điều để khắc phục sai lầm đó.

1. Học từ sai lầm

Chấp nhận sai lầm và đạt thành công từ chúng

Nguyên tắc vàng khi bạn mắc sai lầm là bạn phải học được gì từ đó.

Tôi chắc rằng tất cả các bạn đã nghe qua điều này (và đang nghĩ “Ờ cảm ơn ông, nói điều ai cũng biết”). Nhưng những bạn đã nghe qua khái niệm này đã từng thực sự áp dụng nó chưa?

Ông bà ta có rất nhiều câu ca dao tục ngữ, đại ý là bạn không nên mắc cùng một sai lầm hai lần. Nhưng trên thực tế, mọi người đều có thể mắc những sai lầm giống nhau lặp đi lặp lại. Học hỏi từ sai lầm không đảm bảo rằng bạn sẽ không mắc phải sai lầm tương tự nữa.

Xem thêm các việc làm Citigo tuyển dụng

Có rất nhiều điều bạn có thể học được từ sai lầm của mình: Nó đã xảy ra như thế nào? Nó đã ảnh hưởng đến gì? Nó nghiêm trọng ra sao?

Những bài học sẽ không bao giờ là đủ cả.

Nhưng điều quan trọng nhất là bạn cố gắng hiểu về sai lầm đó một cách đầy đủ. Ít nhất thì giảm tối thiểu khả năng nó xảy ra lần nữa hoặc khắc phục sai lầm. Và hãy chắc rằng bạn mắc phải sai lầm theo cách hoàn toàn khác lúc đầu.

2. Đưa ra giải pháp thay vì bào chữa

Chấp nhận sai lầm và đạt thành công từ chúng

Bất cứ khi nào có chuyện gì đó xảy ra vì một sai lầm, điều đầu tiên mà hầu hết mọi người làm là đưa ra lời bào chữa. Thậm chí còn có một số câu trả lời và đổ lỗi cho qua chuyện, mà họ quên mất điều quan trọng nhất là: giải quyết vấn đề.

Thay vì viện lý do, thì việc tìm giải pháp nên là ưu tiên hàng đầu của bạn. Tất nhiên, có thể có một lý do chính đáng nào đó khiến bạn mắc lỗi, nhưng điều đó có thể đợi cho đến khi bạn tìm ra giải pháp phù hợp.

Hãy sử dụng thời gian của bạn một cách hiệu quả. Khi mọi thứ được xử lý ổn thỏa, bạn có thể giải thích những gì đã xảy ra một cách cẩn thận và đưa ra phân tích để khắc phục sai lầm.

3. Không biết thì không sao, nhưng cố tình lờ đi thì không đượcChấp nhận sai lầm và đạt thành công từ chúng

Thường chúng ta mắc sai lầm vì chúng ta không biết điều gì đó. Nhưng những sai lầm kiểu đó có ổn không?

Mọi người mắc sai lầm khi bước vào lãnh thổ không xác định là điều bình thường. Nhưng câu hỏi thực sự bạn cần đặt ra là nếu người đó không biết hoặc không cố gắng biết, bởi vì những điều đó hoàn toàn khác nhau.

Đôi khi trong cuộc sống, chúng ta đi đường tắt và tìm ra cách dễ dàng để thực hiện một điều gì đó. Chẳng có vấn đề gì với việc đấy cả.

Nhưng những gì mọi người thường quên là các phím tắt có thể gây hiểu lầm, và vâng, có thể là từ mạnh ở đây. Mọi người có xu hướng bỏ qua khả năng xảy ra sự cố và không nghĩ nhiều về hậu quả.

Khi ai đó nói “Tôi không biết”, điều này thường được dịch thành “Tôi không buồn biết.” Mọi người có xu hướng tìm cách dễ dàng để làm điều gì đó và tiếp tục không biết về những gì họ đang làm. Họ không buồn nhìn sâu hơn vì mọi thứ có vẻ ổn.

Khi bạn vô tình gây ra sai lầm vì bạn thực sự không biết điều gì đó, điều đó là tốt. Nhưng khi bạn gây ra sai lầm do cố tình thiếu hiểu biết, điều đó không ổn. Bởi vì cho dù bạn mắc phải sai lầm bao nhiêu lần, bạn cũng sẽ không bao giờ rút ra được bài học từ nó.

4. Đừng quên chia sẻ sai lầm của bạn

Chấp nhận sai lầm và đạt thành công từ chúng

Thường khi chúng ta mắc lỗi, chúng ta chỉ cố gắng khắc phục sai lầm và tiếp tục học tập từ đó. Chúng tôi quên rằng điều rất quan trọng là phải chia sẻ những sai lầm của chúng tôi.

Chúng ta có thể bối rối trước viễn cảnh trông thật ngớ ngẩn. Nhưng may mắn thay, lợi ích vượt xa điều đó.

Đầu tiên và quan trọng nhất, nó sẽ giúp người khác tránh mắc phải những sai lầm như bạn đã làm. Và trong sâu thẳm họ sẽ thực sự biết ơn vì điều đó.

Không chỉ vậy, chia sẻ những sai lầm của bạn có thể mang lại cho bạn một cái nhìn mới và khác biệt về những gì người khác có thể nghĩ về nó. Họ có thể cho bạn một góc nhìn mới hoặc có thể là một giải pháp tốt hơn để xử lý nó.

Đừng quên chia sẻ những sai lầm của bạn, bởi vì chia sẻ là quan tâm.

5. Đúc kết từ hậu quả

Chấp nhận sai lầm và đạt thành công từ chúng

Hãy nhớ rằng mọi sai lầm đều đi kèm với hậu quả. Chúng có thể gây tổn thất tài chính, hoặc thậm chí ảnh hưởng đến uy tín của bạn.

Cần phải xác định rõ ràng và hiểu rõ hậu quả, vì hiểu rõ hậu quả sẽ trở thành yếu tố răn đe khi tiếp cận bất kỳ tình huống nào. Nó cũng sẽ giúp bạn xem xét tốt hơn cách bạn sẽ giải quyết vấn đề.

Xem thêm các việc làm về tuyển dụng Business Analyst

Đôi khi, hậu quả có thể ở lại với bạn trong một thời gian dài. Và bạn phải chịu đựng nó và chịu mọi hậu quả vì đó là trách nhiệm của bạn.

Nhưng dù hậu quả có lớn đến đâu thì cũng đừng quá khắt khe với bản thân. Giữ một tinh thần tốt và sự tích cực là chìa khóa để giải quyết hậu quả.

Kết bài

Sai lầm không phải là dấu chấm hết cho mọi thứ. Cuộc sống vẫn tiếp diễn và mọi thứ không ngừng vận động. Một số thứ bị bỏ lại phía sau và những thứ mới phát sinh.

Điều tốt nhất bạn có thể làm với bất kỳ sai lầm nào là học hỏi từ nó một cách tốt nhất có thể và biến nó thành một sai lầm thành công.

Cuộc sống là một hành trình quá dài để bạn có thể mắc kẹt vì một sai lầm. Hãy tiếp tục và tận hưởng chuyến đi.

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

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