Cách cân bằng chất lượng mã với tính cách nhà phát triển mạnh


15

Về đánh giá mã tại nơi làm việc, tôi đã thấy mã & mẫu mà tôi cho là "thông minh" mặc dù không nhất thiết phải thêm vào chất lượng tổng thể hoặc khả năng bảo trì của cơ sở mã. Tôi chỉ ra điều này trên phản hồi của tôi và không bị thuyết phục bởi các phản biện. Tôi có một chút lo ngại khi mã này được đưa vào repo và sau đó để sản xuất.

Tôi muốn duy trì một nhóm gắn kết, vì vậy tôi không muốn tạo ra căng thẳng bằng cách quá lời về sự dè dặt của mình. Tôi cũng muốn tạo ra một sản phẩm tuyệt vời cho khách hàng của chúng tôi mà không quá khoan dung.

Theo truyền thống, ai có quyền "phủ quyết" về những gì được kiểm tra và làm thế nào?

Làm thế nào mã có thể hoạt động, nhưng quá liên quan / thông minh của nó có thể được loại bỏ mà không bước trên ngón chân?


7
Bạn có thể thêm một ví dụ về những gì bạn cho là "thông minh" không, vì vậy tất cả chúng ta đều trên cùng một trang?
BlackJack

Hệ thống cấp bậc của những người liên quan đến vấn đề này là gì?

2
Giải pháp thông minh là gì? Tôi sẽ không cảm thấy thoải mái khi nói với bạn cách từ chối giải pháp nếu có khả năng nó thực sự vượt trội so với ý tưởng của bạn.
jojo

Mã 'thông minh' có được tối ưu hóa sớm hay được tổng quát hóa sớm không? Thông thường mã ngắn nhất sẽ thắng, cho một thước đo thích hợp về độ ngắn (DRYness hoặc mã thông báo, không phải ký tự).
kevin cline

3
Đưa ra một phương án. Nếu không, bạn thực sự chỉ là một trở ngại cho năng suất. Thật khó để cung cấp "phản biện" cho phê bình mà không có cách tiếp cận khác. Nó giống như đặt gánh nặng bằng chứng lên bị cáo. Bạn đang yêu cầu họ bảo vệ chống lại tất cả các kịch bản phản tác dụng có thể.
Nicole

Câu trả lời:


16

Tôi thích trích dẫn này:

"Gỡ lỗi khó gấp đôi so với viết mã ở vị trí đầu tiên. Do đó, nếu bạn viết mã càng khéo léo càng tốt, theo định nghĩa, bạn không đủ thông minh để gỡ lỗi." - Brian W. Kernighan

Một mặt, điều này làm cho bạn mệt mỏi với mã quá thông minh, vì nó sẽ khó gỡ lỗi và kéo dài sau này.

Mặt khác, mã thông minh hoạt động là một cách tuyệt vời để học. Có lẽ là cho cả đội. Điều gì về việc khuyến khích tác giả đưa ra một cuộc nói chuyện không chính thức về mã cho các đồng nghiệp của họ? Chỉ cần chắc chắn rằng nó thực sự hoạt động như dự định và nó có ý nghĩa trong toàn bộ dự án. Bạn không muốn biến nó thành một cuộc cạnh tranh vô nghĩa!

Nếu bạn không nghĩ rằng nó làm tăng giá trị, thì hãy đặt câu trả lời: "Làm thế nào bạn có thể cấu trúc lại phần này (bạn có các bài kiểm tra đúng không?) Để nó dễ đọc hơn?" Hãy chắc chắn chỉ ra rằng khó hơn để tạo mã thông minh, dễ đọc để tạo ra các cố định không thể xuyên thủng.


Hầu như -1, gỡ lỗi không khó, trừ khi mã của bạn là một mớ hỗn độn và siêu mong manh. Vấn đề duy nhất với gỡ lỗi là rất nhiều nhà phát triển không biết cách sử dụng các công cụ gỡ lỗi. Viết mã rất kiên cường và nhận biết lỗi khó hơn rất nhiều.
Coder

Tôi nghĩ rằng gỡ lỗi chắc chắn là khó hơn. Hãy suy nghĩ về nó theo cách này. Nếu mã ban đầu được viết chính xác, việc gỡ lỗi sẽ không thành vấn đề vì việc kiểm tra nó (đơn vị và tích hợp) không tìm thấy lỗi.
tehnyit

10

Lời khuyên của tôi là hãy đóng vai kẻ ngốc, khi đến lúc thực hiện đánh giá mã, hãy nói rằng bạn không biết nó hoạt động như thế nào (nếu cái tôi của bạn cần được mát-xa, bạn có thể nói rằng bạn không có thời gian để tìm ra nó ) và yêu cầu nhà phát triển giải thích nó. Khi anh ta kết thúc, bạn có thể đề nghị anh ta viết tất cả những điều đó như một bình luận cho việc bảo trì trong tương lai, với gợi ý ngụ ý rằng nó quá phức tạp để được coi là mã 'tốt'.

Nếu mã tốt của nó quá phức tạp, hầu hết mọi người sẽ nhận được gợi ý, mà không có bất cứ điều gì được nói về chất lượng mã hoặc chuyên môn của nhà phát triển.

Tái bút Rõ ràng là hầu hết các mã này sẽ chủ quan, vì vậy mã thông minh không thể tin được của một người có thể là một thuật toán hợp lý và thậm chí có thể theo tiêu chuẩn công nghiệp cho một nhà phát triển khác, vì vậy bạn không thể buộc tội bất kỳ ai trực tiếp viết mã xấu (trừ khi nó rõ ràng giống như nhà thầu đã sao chép một mảng byte vào danh sách stl, chuyển nó thành một thói quen mã hóa và sau đó chuyển đổi nó thành một mảng byte!)


4
Bài kiểm tra của tôi là "một lập trình viên gradutae (có thể 1-2 năm nữa) có thể duy trì nó không?" .... Nó có thể thông minh, nhưng cũng phải rõ ràng và súc tích.
mattnz

1
@mattnz - Nếu tôi sử dụng thử nghiệm đó, một nửa mã tôi đã viết trong nhiều năm (hoặc bất kỳ ai khác cho vấn đề đó) sẽ bị coi là xấu. Lập trình viên tốt nghiệp (1-2 năm ra) không phải là tất cả mọi người đưa họ cho. Không nói rằng chúng ta nên viết mã xấu; chỉ là "kiểm tra" không có nhiều ý nghĩa.
Rook

6

Nguyên tắc cơ bản của tôi là bẻ cong các hướng dẫn chất lượng mã theo hướng có lợi cho các nhà phát triển mạnh mẽ. Tôi luôn sử dụng nó khi tôi không có thời gian để đào đủ sâu - việc đào như vậy thường khá tốn công sức (nhiều hơn ở bên dưới).

Quy tắc này dựa trên kinh nghiệm cá nhân. Tôi bắt đầu (có lẽ là bất kỳ người mới nào) với các hướng dẫn điên cuồng theo các hướng dẫn và chiến đấu triệt để từng sai lệch. Theo thời gian, tôi đã có đủ kỹ năng và học đủ các thủ thuật để giành chiến thắng như vậy một cách dễ dàng - điều này cho phép tập trung nhiều hơn vào việc học tác động tổng thể của "chiến thắng" của tôi. Và tác động theo như tôi có thể nói là khá tiêu cực - những kẻ "thua cuộc" đã phải chịu đựng và trở nên kém năng suất hơn - và, bạn biết đấy, thực tế là mã của họ tuân thủ 200% với hướng dẫn chất lượng không bù đắp cho điều đó.

Phát hiện này khiến tôi bỏ phần lớn cuộc chiến, từ đó dẫn đến việc có nhiều thời gian hơn để phân tích các trường hợp có vấn đề. Và tôi thấy rằng khi tôi đào đủ sâu , thường có một vấn đề thiết kế thú vị ở đâu đó đằng sau, một vấn đề tinh tế (hoặc không quá tinh tế) chỉ ẩn đằng sau những cuộc chiến cá tính.

  • Nó giống như, bạn biết đấy, như tôi nói tôi tìm thấy tệp nguồn 31K vượt quá giới hạn kích thước được đề xuất là 30K. Các lựa chọn của tôi là dành vài phút / giờ chiến đấu để buộc chủ sở hữu tệp bằng cách nào đó vắt kiệt lượng kilobyte đó hoặc dành một hoặc hai ngày để suy nghĩ và tìm hiểu rằng, có một số API thư viện có thể được sử dụng thay vì tất cả mã trong tệp đó (để có thể xóa nó).

Một khám phá như vậy đôi khi có thể không hữu ích nhiều từ góc độ người dùng cuối (mặc dù đôi khi nó thực sự có tác động sâu sắc) nhưng phải thừa nhận niềm vui mà tôi có được khi bẻ khóa như vậy khiến nó cũng đáng nỗ lực ... và như một icing trên các hướng dẫn bánh lệch cũng biến mất mà không có một cuộc chiến. :)


2

Tổ chức của bạn nên có một tài liệu hướng dẫn / tiêu chuẩn mã hóa được cập nhật định kỳ với đầu vào từ nhóm phát triển. Tài liệu đó có thể đánh vần các chi tiết cụ thể, như: cách đặt tên biến, cách định dạng mã, v.v. Tài liệu cũng cần giải thích các giá trị mà tổ chức mong muốn các lập trình viên chấp nhận bằng cách viết mã, bao gồm tầm quan trọng tương đối của những thứ như khả năng đọc, khả năng duy trì, tính chính xác, hiệu quả và tuân thủ các tiêu chuẩn.

Đánh giá mã nên được thực hiện bằng cách sử dụng tài liệu tiêu chuẩn mã hóa đó. Nếu các tiêu chuẩn mã hóa nói rằng các lập trình viên nên thích khả năng dễ đọc hơn khi hai người xảy ra xung đột, thì bạn sẽ có một số hỗ trợ trong việc tranh luận về mã "thông minh". Nếu các tiêu chuẩn không nói điều đó và bạn nghĩ chúng nên như vậy, thì bạn có thể tranh luận về nó trong bản tóm tắt tại cuộc họp tiêu chuẩn mã hóa thay vì cố gắng tìm ra khi cái tôi của ai đó xuất hiện.

Cuối cùng, đôi khi nó đi đến một cuộc gọi phán xét, và trong những trường hợp đó, từ cuối cùng sẽ thuộc về người cuối cùng chịu trách nhiệm về mã và / hoặc sản phẩm. Đó thường là một người như nhà phát triển cấp cao, trưởng nhóm kỹ thuật, quản lý dự án hoặc giám đốc kỹ thuật. Nếu bạn là người chịu trách nhiệm và bạn cảm thấy rằng một số mã nhất định không đủ khả năng duy trì, bạn không nên ngại nói như vậy. Bạn có thể ngoại giao về điều đó:

Sam, tôi rất ấn tượng với sự khéo léo của bạn ở đây, nhưng tôi lo ngại rằng nó có thể hơi quá thông minh. Tôi sẽ cần bạn làm việc trên sự phát triển mới một năm kể từ bây giờ thay vì duy trì điều này, và tôi lo ngại rằng bất cứ ai phải duy trì nó có thể không hoàn toàn hiểu được sự tuyệt vời của nó. Tôi biết bạn ghét phải làm điều đó, nhưng tôi đánh giá cao nếu bạn quay trở lại việc thực hiện đơn giản mà chúng tôi đã thảo luận.

Mặt khác, nếu bạn không phải là người chịu trách nhiệm, thì điều tốt nhất bạn có thể làm là giải thích rõ ràng vị trí của mình và cố gắng thuyết phục những người còn lại trong đội. Nếu bạn không nhận được hỗ trợ từ người quản lý, thì hãy chấp nhận rằng đó không phải là cuộc gọi của bạn và tiếp tục.


2

Ở vị trí của bạn (và tôi, đôi khi, là một trong những người thông minh đó) tôi sẽ không loại bỏ nó, nhưng yêu cầu cá nhân tác giả thông minh / thông minh viết tài liệu rất tốt trong các bình luận, và nếu có thể, hãy đưa vào một số cuộc thảo luận về thay thế và các bài viết đơn giản hơn anh ta có thể đã sử dụng, với các ví dụ.

Tôi sẽ nhấn mạnh điều này là tốt nhất, bởi vì ngay cả anh ta cũng có thể sẽ không nhớ tất cả các bit và bobs, trong những dòng đó, trong hai tháng.

Anh ta có thể sẽ bỏ mã thông minh theo hướng đơn giản nhất, ngay khi anh ta buộc phải viết nó, làm ví dụ.

Tại sao điều đó sẽ làm việc.

  • Bạn thừa nhận bạn quan tâm đến những gì anh ấy viết ,
  • bạn cho anh ấy thấy sự tôn trọng bằng cách hỏi ,
  • bằng cách trích dẫn các vấn đề về bộ nhớ / tập trung mà bạn nghĩ ra và phân tích cho anh ta một kịch bản trong đó mã đó phải được thay đổi và không thể trong khi anh ta vẫn làm việc cho công ty hoặc nhóm

(không có sự ám chỉ cuối cùng, loại yêu cầu này có thể được nhận dưới dạng thử, về phía công ty, để thương mại hóa lập trình viên , khiến nó có thể hoán đổi với bất kỳ con khỉ mã nào khác bất cứ lúc nào)


1

Theo kinh nghiệm của tôi, thông thường rất khó để có được mã đáp ứng tất cả các yêu cầu ngoài cơ sở mã.

Tuy nhiên, lần tới khi mã được duy trì, bạn có thể dễ dàng tranh luận về việc thay thế nó như một biện pháp tiết kiệm chi phí trong tương lai vì mã cũ khó bảo trì hơn.

Theo như quyền phủ quyết, quản lý rõ ràng có điều đó.
Đôi khi, họ là các nhóm hoặc ủy ban chịu trách nhiệm về chất lượng mã, trong trường hợp đó họ cũng sẽ có quyền lực này.

Nó cũng sẽ hữu ích nếu bạn đưa ra một ví dụ về mẫu 'thông minh'. Có lẽ bạn đang phản ứng thái quá ...

"Thông minh" gần như không bao giờ là một điều xấu trong cuốn sách của tôi, nhưng tôi có thể đồng ý rằng có thể có một con dốc trơn trượt giữa thông minh và hỗn độn.


0

Giống như nhiều thực hành khác tôi nghĩ rằng câu trả lời là nó phụ thuộc .

  • Nếu nó là một khiếm khuyết thì nó chắc chắn cần phải được sửa chữa.
  • Nếu mã hoạt động, bạn phải cân bằng giá trị của việc nhấn mạnh mã được thay đổi so với chi phí tương lai của mã thông minh. Mặc dù có các quy tắc liên quan đến tỷ lệ giữa công việc phát triển và công việc bảo trì, chúng sẽ thay đổi rất nhiều từ dự án này sang dự án khác. Hợp lý.
  • Xem xét tại sao bạn không thể thuyết phục đồng đội của mình rằng mã cần được đơn giản hóa?
  • Bạn không phải luôn luôn có được mọi thứ hoàn hảo. Điều đó có nghĩa là đánh giá mã trong một vòng lặp vô hạn và không có gì được kiểm tra vì không có gì (ngoại trừ mã của tôi, haha) là hoàn hảo.
  • Sở thích cá nhân của tôi là cho tác giả của mã để có tiếng nói cuối cùng. Rõ ràng nếu họ liên tục làm một công việc rất kém thì phải thực hiện một số hành động khác nhưng như bạn nói giá trị tiêu cực của việc buộc nhà phát triển thay đổi mã có thể cao hơn mức tăng được thực hiện bằng cách sửa nó nếu đây là một tình huống rất hiếm .

0

Tôi chắc chắn có thể liên quan đến câu hỏi này. Tôi hiện đang dẫn đầu về kỹ thuật cho 2 đội và công việc của tôi là đảm bảo mã chúng tôi sản xuất có thể đọc và duy trì được nhất có thể. Đồng thời tôi đã được biết là tạo ra một số mã "thông minh" và tôi biết hầu hết các đồng đội của tôi sẽ rất khó khăn để theo dõi nó.

Vài quan sát tôi có thể cung cấp:

  1. Nhóm của bạn cần một người dẫn đầu, người sẽ đưa ra quyết định cuối cùng khi có bất đồng. Trong lần phát hành trước, tôi đã ở trong một đội không có sự lãnh đạo và điều đó thật tồi tệ. Mọi thứ trở thành một cuộc tranh cãi, và nếu bạn có ít người có cá tính mạnh mẽ thì không ai trong số họ sẽ nhúc nhích. Nếu bạn có một người dẫn đầu, bất kể quyết định nào được chọn, mọi người trong nhóm PHẢI hiểu rằng những gì người lãnh đạo nói sẽ đi. Đó là lý do tại sao quản lý làm cho anh ấy dẫn đầu.

  2. Giữ cho mọi người hạnh phúc là rất quan trọng. Do đó, thay vì đẩy toàn bộ đội về phía quan điểm của bạn, chỉ cần huých họ ở đó. Giải thích các nguyên tắc RẮN, giải thích tầm quan trọng của các lớp / phương thức / giao diện nhỏ và gắn kết và lặp lại những điều này mỗi khi bạn thấy chúng bị vi phạm (ví dụ như trong đánh giá mã). Đồng thời, đừng bắt họ viết lại mọi điều bạn không thích. Vào cuối ngày, bạn cần cân bằng giữa biểu hiện cá nhân so với các tiêu chuẩn nhóm. Hy vọng, cả hai sẽ hội tụ khi sở thích cá nhân thay đổi theo cách nhóm nói chung đang hoạt động.

  3. Tôi tin rằng điều quan trọng hơn là phải có các giao diện lớp rõ ràng, dễ hiểu, hơn là không bao giờ có bất kỳ mã "thông minh" nào. Ví dụ, chúng tôi có một lớp duy trì một danh sách các mục được tìm kiếm theo 3 cách khác nhau. Hiện tại nó chỉ đơn giản là sử dụng tìm kiếm tuyến tính cho tất cả các tra cứu hoạt động ở quy mô nhỏ, nhưng vì lớp này ở mức rất thấp, tôi thấy nó không mở rộng rất tốt. Tôi sắp thay thế nó bằng một lớp khác, sử dụng các thùng chứa Boost Intrusive. Mỗi phần tử sẽ hỗ trợ được đặt vào từng chỉ mục đồng thời và tất cả các tra cứu sẽ được thực hiện trong O (sqrt (N)). Vâng, nó sẽ phức tạp hơn nhiều ở bên trong và rất nhiều người không thích Boost, nhưng ở bên ngoài nó sẽ vẫn là 3 phương thức: Thêm, Xóa, Nhận. Điểm mấu chốt là mọi người có thể viết bất kỳ mã nào họ muốn (trong lý do),

  4. Duy trì ý tưởng sở hữu mã. Mặc dù đôi khi rất khó để đạt được vì những người khác nhau có thể cần thêm / sửa đổi một số mã. Khi mã được viết, nhà phát triển ban đầu là người giữ cuối cùng của mã đó. Điều đó không có nghĩa là không ai khác có thể chạm vào nó. Nếu những người khác sửa đổi mã của họ, điều đó tốt, nhưng vào cuối ngày, nhà phát triển ban đầu sẽ xem xét nó và vẫn chịu trách nhiệm cho bất kỳ điều gì xảy ra trong đó. Cho dù mã đó là đơn giản hay thông minh, đó là con của anh ấy. Nếu / khi, như bạn dự đoán, các lỗi bắt đầu chồng chất vì các quyết định thiết kế / mã hóa được đưa ra, thay vì chỉ sửa các lỗi đó khi chúng đến, hãy ngồi xuống với nhà phát triển đó (người btw nên sửa tất cả các lỗi đó) và suy nghĩ về những quyết định đó để xem làm thế nào chúng có thể được thực hiện khác nhau.


0

Tôi đã dành nhiều năm lãnh đạo và quản lý các nhóm phát triển. Về bản chất, tôi là một chút OCD về mã và rất trắng đen. Tôi đã học được qua kinh nghiệm rằng chọn các trận đánh của bạn là một trong những kỹ năng khó nhất để học khi làm đội trưởng. Vâng, tiêu chuẩn rất quan trọng. Vâng, khả năng đọc và bảo trì là vô cùng quan trọng. Có, tất cả chúng ta nên cố gắng viết mã thống nhất, tuân thủ tiêu chuẩn. Các nhà phát triển là con người mặc dù ... không phải là công cụ tạo mã. Chúng tôi có cá tính, ý kiến, chúng tôi chán, và chúng tôi muốn học những điều mới.

Về đánh giá mã tại nơi làm việc, tôi đã thấy mã & mẫu mà tôi cho là "thông minh" mặc dù không nhất thiết phải thêm vào chất lượng tổng thể hoặc khả năng bảo trì của cơ sở mã.

OK ... vì vậy họ không thêm, nhưng họ có làm mất tập trung không? Có phải chúng ta đang nói chỉ là vấn đề sở thích cá nhân trong các kiểu mã hóa, hay mã được viết hoàn toàn không cần thiết (ví dụ: sử dụng cây biểu thức và phản xạ chỉ vì sử dụng cây biểu thức và phản xạ) rất thú vị? Nếu nó là trước đây, hãy để nó đi. Một phần của niềm vui trở thành nhà phát triển là đưa ra các giải pháp sáng tạo cho các vấn đề. Có lẽ (và hầu hết chúng ta không muốn thừa nhận điều này), đôi khi chúng ta cảm thấy bị đe dọa bởi những cách tiếp cận mà chúng ta không hiểu và không muốn hỏi hoặc không có thêm năng lượng để học cách tiếp cận mới.

Bây giờ, khi sự sáng tạo dẫn đến mã không cần thiết và sự phức tạp hoàn toàn vô lý, thì bằng mọi cách hãy là giọng nói và làm cho trường hợp của bạn. Trở thành một người chơi trong đội rất quan trọng, nhưng việc (và giữ người khác) cũng có trách nhiệm. Mã đánh giá là về trách nhiệm giải trình cũng như đảm bảo chất lượng và học tập. Bạn sẽ bước lên một số ngón chân, nhưng nếu bạn cảm thấy mình có một lý lẽ mạnh mẽ thì tại sao phải bỏ ra công sức để viết lại mã làm việc VÀ một cái tôi nên bị bầm dập trong quá trình VÀ bạn muốn mạo hiểm phá vỡ sự nhiệt tình của ai đó đối với nghề của họ , sau đó bạn không nên ngại đặt nó lên bàn. Nếu bạn là trưởng nhóm, đây là công việc của bạn. Hãy nhận thức về tác động, và làm điều đó. Nếu bạn không phải là người lãnh đạo nhóm và không có thẩm quyền, thì hãy đưa nó lên nhóm để quyết định.

Cách tốt nhất để thấm nhuần trách nhiệm trong nhóm của bạn là khuyến khích người khác giữ bạn có trách nhiệm. Nếu bạn giữ một quan điểm cởi mở và không đóng cửa mọi người khi họ đề xuất cải tiến mã của bạn, bạn có thể thấy họ dễ tiếp nhận đề xuất của bạn hơn.


0

Từ kinh nghiệm cá nhân, khi điều này xảy ra, tôi sẽ xin phép trở thành người thử nghiệm đơn vị tình nguyện để viết bài kiểm tra nhằm tra tấn việc thực hiện không quen thuộc.

Tôi sẽ rất cố gắng để thực sự hiểu cách thức hoạt động của mã, và cũng cố gắng thăm dò nó theo nhiều cách khác nhau.

Lưu ý rằng đây là một cam kết về thời gian. Nó có thể là giờ, hoặc hàng chục giờ, hoặc thậm chí là một phần tốt của một tuần. Việc nó có hợp lý hay không phụ thuộc vào độ phức tạp của mã có tương xứng với độ phức tạp của yêu cầu hay không.

Nếu tôi không thắng thế, tức là nếu mã tồn tại qua nhiều thử nghiệm, tôi sẽ tự thuyết phục bản thân rằng có lẽ việc triển khai thực sự được khai sáng hơn tôi và tôi sẽ hỗ trợ đưa nó vào sản phẩm chính.

Tùy thuộc vào phương pháp kiểm soát nguồn, mã có thể phải được cam kết tạm thời vào hệ thống kiểm soát nguồn (có thể trong một nhánh) trước khi giai đoạn thử nghiệm này có thể bắt đầu.

Câu trả lời của tôi được tô màu bởi kinh nghiệm sử dụng OpenCV của tôi. Có những thuật toán phức tạp hơn bất kỳ lập trình viên nào có thể tự thực hiện; thậm chí không phải là tiến sĩ - có thể là vài phần trăm tiến sĩ hàng đầu. Nếu mã đó tốt, bạn phải tin vào điều đó, hành động chống lại bản năng và định kiến ​​của chính bạn, ngay cả khi bạn không có phương tiện hiệu quả để định lượng mức độ tin cậy đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.