Làm cách nào để thuyết phục nhóm của tôi sử dụng các lớp / phương thức nhỏ hơn?


27

Tuyên bố miễn trừ trách nhiệm: Tôi là người mới (đây là ngày làm việc thứ ba của tôi) và hầu hết các đồng đội của tôi có nhiều kinh nghiệm hơn tôi.

Khi tôi nhìn vào mã của chúng tôi, tôi thấy một số mã có mùi và thực hành kỹ thuật xấu, như sau:

  • Một số hướng dẫn đặt tên không nhất quán
  • Thuộc tính không được đánh dấu là chỉ đọc khi có thể
  • Các lớp lớn - Tôi nhận thấy một lớp tiện ích bao gồm hàng trăm phương thức mở rộng (cho nhiều loại). Nó dài hơn 2500 dòng!
  • Các phương thức lớn - Tôi đang cố gắng cấu trúc lại một phương thức dài 150 dòng.

Hai cái sau dường như là một vấn đề thực sự. Tôi muốn thuyết phục các đồng đội của mình sử dụng các lớp học và phương pháp nhỏ hơn. Nhưng tôi có nên làm điều đó? Nếu có thì làm thế nào?

Đội của tôi có một người cố vấn từ đội chính (chúng tôi là đội vệ tinh). Tôi có nên đến gặp anh trước không?


CẬP NHẬT : Vì một số câu trả lời đã hỏi về dự án, xin vui lòng biết rằng đó là một dự án đang hoạt động. Và IMHO, các lớp / phương thức khổng lồ có kích thước đó luôn xấu.

Dù sao, tôi không bao giờ muốn chọc giận đội của tôi. Đó là lý do tại sao tôi hỏi - Tôi có nên làm điều đó không, và nếu có, thì làm thế nào để tôi làm điều đó một cách nhẹ nhàng?

CẬP NHẬT : Tôi quyết định làm một cái gì đó dựa trên câu trả lời được chấp nhận: bởi vì tôi là người mới, vì vậy tôi thấy mọi thứ trong "đôi mắt mới" tôi sẽ lưu ý về tất cả các mùi mã mà tôi tìm thấy (vị trí, tại sao nó xấu, làm thế nào chúng ta có thể làm điều đó tốt hơn, ...), nhưng hiện tại, tôi chỉ cố gắng hết sức để thu thập sự tôn trọng từ nhóm của mình: viết "mã tốt hơn", biết mọi người, biết tại sao chúng ta làm điều đó ... Khi thời điểm thích hợp, tôi sẽ cố gắng để hỏi nhóm của tôi về một số chính sách mã mới (hướng dẫn đặt tên, lớp nhỏ hơn, phương thức nhỏ hơn, ...) và nếu có thể, hãy cấu trúc lại một số mã cũ. Nó nên hoạt động, IMHO.

Cảm ơn bạn.


11
Một khuyến nghị tôi sẽ đưa ra là xem xét mã nguồn mà họ đang đăng ký ngay bây giờ, chứ không phải những gì hiện có trong dự án. Có thể là hầu hết các mã hiện tại không được viết bởi đồng nghiệp của bạn, mà là bởi các nhà quản lý hiện tại của bạn 10 năm trước.
Earl Namless

14
Bạn có thể chỉ khiến mọi người bực mình vì bạn mới chỉ làm việc được 3 ngày. Nhận biết đội đầu tiên và kiếm được một số sự tôn trọng. Mang mọi thứ lên trong cuộc trò chuyện thông thường để cảm nhận nước. Bạn đã có ý tưởng đúng, nhưng bạn có thể là một con ngựa đua trong chuồng ngựa trang trại.
kirk.burleson

4
Chào mừng đến với thế giới thực :)
fretje

Với các chức năng nhỏ hơn, trình biên dịch JIT sẽ hạnh phúc hơn và mã sẽ nhanh hơn. Hiệu quả C # Phiên bản thứ hai Mục 11. my.safaribooksonline.com/book/programming/csharp/9780321659149/ trên
Công việc

3
Tôi không thể không cười thầm khi thấy bạn cảm thấy kinh hoàng như thế nào khi chứng kiến ​​một lớp tiện ích dài 2.500 dòng. Tôi đã thấy hơn một lớp 25.000 trong sự nghiệp của mình. Mặc dù vậy, đừng hiểu sai về tôi, tôi nghĩ rằng một lớp học sẽ trở nên quá dài sau 500 dòng.
Peter ALLenWebb

Câu trả lời:


19

Bạn có lợi ích của việc xem mã với đôi mắt mới. Ghi chú để ghi lại những gì bạn khám phá về thực hành xấu. Sau đó, khi bạn đã ổn định với nhóm, hãy rút các ghi chú của bạn tại một thời điểm thích hợp, như khi đó là thời gian để tái cấu trúc.


Ý tưởng thực sự tốt. Viết mọi thứ xuống bây giờ, đề xuất một số thay đổi sau.
Roman Grazhdan

3
Điều này hoạt động trên lý thuyết, nhưng trong thực tế, họ sẽ đánh bật cái túi ra khỏi anh ta.
Công việc

15

Code Complete, bởi Steve McConnell, có rất nhiều số liệu thống kê tốt về chính chủ đề bạn đang nói đến. Tôi không nhớ lại tất cả các con số, nhưng anh ấy nói về việc số lượng lỗi tăng lên như thế nào với các phương thức / lớp dài hơn, mất bao lâu để gỡ lỗi, v.v.

Bạn có thể mua một bản sao của cuốn sách và cho bạn bè xem một số nghiên cứu ... thống kê (mặc dù chúng nói dối mọi lúc) có xu hướng thuyết phục mọi người.


1
+1 cho Mã hoàn thành. Cũng nghiên cứu thuật ngữ "Nợ kỹ thuật". Tôi thấy nó rất hữu ích trong việc giải thích cho người khác tại sao đôi khi (nhưng không phải lúc nào) nó đáng để đầu tư vào việc làm cho mã đơn giản hơn. Quy tắc đầu tiên, tuy nhiên, là tạo ra các bài kiểm tra. Kiểm tra đơn vị, kiểm tra hệ thống, kiểm tra tích hợp, vv Trước khi thực hiện bất kỳ tái cấu trúc nào, hãy tạo các kiểm tra. Kiểm tra, kiểm tra, kiểm tra. Các xét nghiệm.
Ben Hocking

@Ben không thiếu tôn trọng nhưng tôi nghĩ thuật ngữ "Nợ kỹ thuật" đã được sử dụng quá mức. Ngay khi ai đó bắt đầu sử dụng điều đó như lý do của họ đằng sau một quyết định, tôi có xu hướng ngừng lắng nghe. Có thể đó là một khiếm khuyết về phía tôi nhưng khi tôi nghe rằng suy nghĩ của tôi hướng đến "người này đọc rất nhiều blog nhưng không thực sự hiểu chi phí thực sự của việc cân bằng mã làm lại so với các nhiệm vụ khác"
Gratzy

3
@Gratzy: Tôi chắc chắn rằng nó phụ thuộc vào kinh nghiệm cá nhân của bạn. Tôi không muốn đi sâu vào chi tiết, nhưng khi bạn thấy các dự án trong "nợ kỹ thuật" đến tận cổ, biểu hiện trở nên rất thích hợp. Các lập trình viên có thể dành 90% thời gian của họ để "trả lãi" cho khoản nợ. Trong những trường hợp đó, không có gì đáng ngạc nhiên khi phát hiện ra rằng không ai trong nhóm đã nghe về thuật ngữ này.
Ben Hocking

Clean Code cũng có rất nhiều thông tin về điều này (mặc dù, không có nhiều số liệu thống kê).
Steven Evers

Nếu bạn xem trang 173, McConnell trình bày một số bằng chứng thống kê có lợi cho kích thước thông thường có thể sẽ khiến hầu hết những người ủng hộ nhanh nhẹn chùn bước. Anh ta đặt 150 dòng khá rõ ràng trong cột OK (nhưng không lý tưởng), nhưng đưa ra một khuyến nghị cá nhân mạnh mẽ chống lại việc vượt quá 200.
Dan Monego

13

Tuyên bố miễn trừ trách nhiệm: Tôi là một người mới đến (đây là ngày làm việc thứ ba của tôi) và hầu hết nhóm của tôi có nhiều kinh nghiệm hơn tôi.

Bạn có thể muốn chậm lại một chút, lắng nghe và học hỏi từ nhóm của mình trước khi bạn đề xuất quá nhiều thay đổi. Có thể có hoặc không có lý do chính đáng để mã được cấu trúc như vậy nhưng bằng cách nào đó dành thời gian để nghe và học trước chỉ có thể giúp đỡ.

Sau đó, bất kỳ đề xuất nào bạn có thể đưa ra chắc chắn sẽ được xem tích cực hơn và được đáp ứng với ít sức đề kháng hơn.

Cơ hội giới thiệu thành công thay đổi của bạn sẽ được cải thiện đáng kể nếu bạn nhận được sự tôn trọng hoặc ít nhất là không mất sự tôn trọng của đồng nghiệp trước.

Nó thế nào rồi? "Đo hai lần cắt một lần .." Một cái gì đó như thế.


1
Tôi đồng ý. Ai nói họ biết đó là thực tế xấu nhưng thời hạn rất chặt chẽ? Hoặc có thể họ đã có một nhóm người trước đó đã thực hiện một số mã và không có thời gian để tái cấu trúc? Khi bạn là người mới, hãy giữ một tâm hồn cởi mở khi cho họ biết
Spooks

12

Trừ khi bạn được thuê với mục đích cụ thể là đại tu cách nhóm của bạn viết mã, bạn có thể muốn kiểm duyệt sự nhiệt tình của mình để đại tu quyết liệt. Hầu hết các mã làm việc hoạt động vì một lý do :) cho dù đó là rác như thế nào, và đôi khi đại tu quyết liệt làm cho những trường hợp góc khó chịu thậm chí xấu hơn.

Tôi nghĩ rằng đòn bẩy dễ nhất để viết mã nhỏ hơn sẽ yêu cầu các nhà phát triển tập trung vào kiểm thử đơn vị . Không có gì buộc mã súc tích như được yêu cầu kiểm tra nó; thật đáng kinh ngạc khi các nhà phát triển đột nhiên có ác cảm với các cấu trúc dữ liệu toàn cầu, vượt qua quá nhiều đối tượng quá sâu, khi họ biết rằng họ phải viết các bài kiểm tra cho tất cả.

Tôi không phải là một fan hâm mộ lớn của TDD nhưng tôi làm yêu thực tế là nó buộc các nhà phát triển để xem xét cách họ muốn viết bài kiểm tra. Và đó thường là lý do tại sao mã tốt hơn, không phải là một phép thuật về việc thực sự các bài kiểm tra. (Mặc dù điều đó chắc chắn sẽ có ích khi bạn thực hiện các thay đổi sau này.)

May mắn nhất.


++ cho "kiểm duyệt sự nhiệt tình của bạn". IMHO, sự kịch liệt mà các nguyên tắc này được ban hành là tỷ lệ nghịch với sự biện minh của họ. (Các tôn giáo là như thế.)
Mike Dunlavey

11

Bạn không nên thuyết phục đội của bạn. Là người mới, bạn sẽ không được coi trọng - do đó lãng phí thời gian.

Thay vào đó, hãy tiếp tục và viết mã nhỏ gọn và sạch sẽ cho mình. Sau đó, hy vọng, sau một thời gian và một số đánh giá mã, một số đồng đội có thể bắt đầu bắt chước phong cách của bạn.

Nếu không, bạn vẫn sẽ làm việc hiệu quả hơn và công việc khó khăn của bạn cuối cùng sẽ đưa bạn đến một vị trí cao hơn, nơi bạn có thể bắt đầu thực thi một số quy tắc này.

Và có bằng mọi cách hiển thị nội dung từ Code Complete cho mọi người.


3
+1 cho "Thay vào đó, hãy tiếp tục và tự viết mã nhỏ gọn và sạch sẽ". Nó thường là tốt nhất để dẫn dắt bằng ví dụ. Và làm sạch một cơ sở mã được thiết lập giống như một cuộc đua marathon hơn là chạy nước rút; nó cần sự kiên nhẫn và kiên trì
JeremyDWill

8

Đây là một vài thủ thuật:

  • Tìm hiểu tình trạng và lịch sử hiện tại của đội - có vẻ như họ có một người cố vấn, người cố vấn có ảnh hưởng như thế nào? Ngoài ra, người cố vấn mới như thế nào và đã có một thời gian dài không có người cố vấn? Khi nào mã vấn đề bắt nguồn? Việc chỉ trích em bé của đội hiện tại có thể khác rất nhiều so với chỉ trích một số mã cũ mà không ai thực sự nhớ đến việc viết.

  • Một điều tại một thời điểm - đừng thả bom vào tất cả những suy nghĩ của bạn tại một cuộc họp nhóm. Bắt đầu với một số câu hỏi dự kiến ​​xuất phát từ quan điểm cụ thể của bạn. Ví dụ - "Này, với tư cách là một chàng trai mới, tôi nhận thấy rằng một số lớp tiện ích thực sự lớn, có lý do cho điều đó không?"

  • Đề xuất các bước cho em bé - hầu như không bao giờ có thể thực hiện một cuộc đại tu tổng thể ngay lập tức, vì vậy hãy tìm ra một số bước bắt đầu để đề xuất trong trường hợp mọi người đồng ý rằng đây là một kế hoạch tốt.

  • Đề xuất các cơ chế phòng ngừa trong tương lai - ví dụ, nhóm có thể đồng ý với mục tiêu rằng nó sẽ không bao giờ thêm vào một vài lớp lớn nhất hàng đầu, nhưng sẽ tái cấu trúc khi có nhu cầu phát triển chúng hơn nữa.

  • Lắng nghe những lo lắng về rủi ro. Nếu đây thực sự là mã kế thừa, có thể có đủ những ẩn số và sự phụ thuộc mà việc tái cấu trúc là vô cùng rủi ro. Đó có thể không phải là một lý do để tránh tái cấu trúc, nhưng nó có thể có nghĩa là bạn cần một số chiến lược thử nghiệm tốt hơn hoặc một số cách khác để giảm rủi ro trước khi bạn giải quyết việc làm lại thực sự.

  • Hãy nhận biết ngôn ngữ cơ thể và đi chậm. Bạn đang đưa ra một vấn đề trong một cơ sở mã mà bạn chưa có nhiều kinh nghiệm. Bạn có một cửa sổ chàng mới ngay bây giờ, nơi bạn có thể hỏi một số câu hỏi ngây thơ và nhận được câu trả lời hữu ích, và bạn có thể sử dụng những câu hỏi đó để thăm dò nhóm để xem xét lựa chọn thiết kế của riêng họ. Nhưng nó đi cả hai chiều - với tư cách là một chàng trai mới, bạn cũng chưa có nhiều "tín nhiệm", vì vậy hãy đi chậm và nhận thức được khuôn mặt hoặc tư thế khép kín. Nếu mọi người bắt đầu đóng cửa, hãy đề xuất một cách để trì hoãn mọi quyết định và tìm cách để giành chiến thắng.

Tôi có thể nói với tư cách là người quản lý và thành viên trong nhóm, tôi rất vui vì New Guy Insights. Tôi đã không chấp nhận từng lời bình luận mang tính xây dựng mà một thành viên trong nhóm mới đưa cho tôi, nhưng tôi thường sẵn sàng lắng nghe nếu những lời chỉ trích được bày tỏ là sự quan tâm và tò mò trung thực và không được đưa ra như một bài giảng. Dấu ấn của sự tôn trọng với chàng trai mới là khi anh ta có thể đưa ra cái nhìn sâu sắc và sau đó lùi lại và xử lý bất cứ điều gì đến - thật dễ dàng để cảm thấy tốt khi các quyết định của bạn được lắng nghe và đưa ra, khó khăn hơn khi nhóm nói với bạn "không". Bạn vẫn có thể đúng, mẹo là tìm ra những việc cần làm tiếp theo ... thường chờ một chút và tìm kiếm thêm thông tin là bước tiếp theo tốt trong những trường hợp đó.


6

Làm cách nào để thuyết phục nhóm của tôi sử dụng các lớp / phương thức nhỏ hơn?

Đừng.

Mua cho mình một giấy phép Resharper và dẫn bằng ví dụ. [Dựa nhiều vào tái cấu trúc ' Phương pháp trích xuất '.]

Theo thời gian, những người khác sẽ đánh giá cao mã dễ đọc hơn của bạn và được thuyết phục để làm tương tự. *


  • Có - Có một cơ hội mà họ sẽ không bị thuyết phục; nhưng đó vẫn là đặt cược tốt nhất của bạn.

IMO - Không đáng để bạn cố gắng thuyết phục các đồng đội của mình trở thành những lập trình viên giỏi hơn, đọc ' Hoàn thành mã ', theo dõi @Uncle Bob. Nguyên tắc RẮN và trở thành lập trình viên tốt hơn nếu họ chưa bị thuyết phục.

Hãy nhớ rằng: Bạn không thể sử dụng logic để tranh luận ai đó ra khỏi vị trí mà họ không sử dụng logic để vào vị trí đầu tiên.


4
+1 và thỏa thuận. Điểm thứ hai của bạn là những gì tôi thấy là đúng nhất; Những lập trình viên giỏi biết những thứ đó đã hoặc sẵn sàng bắt đầu học và áp dụng nó ngay lập tức, những lập trình viên xấu hoặc giả vờ quan tâm hoặc hoàn toàn không hiểu tại sao những điều đó lại tốt (nếu họ hiểu, họ đã làm xong rồi). Rất có thể bạn đang chiến đấu một trận thua. Thật đáng buồn khi có nhiều "lập trình viên" không hiểu một chút về phát triển phần mềm thích hợp.
Wayne Molina

4

Đây dường như là một câu hỏi quản lý nhiều hơn là câu hỏi kỹ thuật. Tất cả những gì bạn nói là hợp lệ, điều mà nhóm của bạn thực sự cần là một kiến ​​trúc sư giỏi, người có thể đảm bảo mọi người đều thích nghi với một mẫu thiết kế duy nhất và thực thi nó, nhóm cần phải liên tục và thường xuyên cấu trúc lại mã.

Tuy nhiên, có một hiệu trưởng "bạn sẽ không cần nó", nếu những gì đã tồn tại hoạt động trong một thời gian khá dài, cho dù nó xấu thế nào, thay đổi nó luôn không phải là một ý tưởng tốt. Thay vào đó nếu nhóm của bạn cần xây dựng lại toàn bộ hoặc xây dựng lại một phần của nó, hãy tích lũy một tài liệu về các thực tiễn và vấn đề xấu trước khi thực hiện mã hóa.


3
Và chắc chắn, bạn nên tiếp cận với cố vấn của đội, nhưng trước khi làm điều đó, bạn nên tham khảo và thảo luận với các đồng nghiệp của mình một cách lịch sự, đừng khiến họ cảm thấy bị bỏ rơi. Nó sẽ làm cho cuộc sống của bạn khó khăn trong tương lai.

4

Một số nhóm không thực hiện bất kỳ loại kiểm soát chất lượng nào cho mã vì họ không biết các công cụ phù hợp cho mã đó. Có rất nhiều công cụ có thể giúp mã nhóm tốt hơn.

Visual Studio có "Phân tích mã" có thể giúp với các quy ước đặt tên.

Ngoài ra số liệu mã có thể được sử dụng, như độ phức tạp chu kỳ. Điều này giúp chỉ ra các lớp và phương thức quá phức tạp.

Giữ hồ sơ cũng là một ý tưởng tốt. Nếu các thành viên trong nhóm chỉ thể hiện bằng lời nói những gì cần phải làm, thì mọi người chắc chắn sẽ quên. Con người có những ký ức rất yếu đuối! =)

Tôi sẽ không gây ồn ào về điều này ... Đội ngũ phát triển của một lập trình viên giống như gia đình của anh ấy ... Nếu bạn chỉ ra những sai lầm, mọi người có thể tức giận với bạn. Kiểu thay đổi văn hóa này không chỉ đòi hỏi nhiều mã hóa, mà còn đòi hỏi một sự tiếp xúc tinh tế với con người.


3

Là người quản lý tôi chỉ muốn thêm, rằng tôi muốn nhóm của mình viết mã tốt ngay lần đầu tiên. Mã đánh giá, TDD và tất cả những thứ đó. Nhưng một khi nó được sản xuất và nó hoạt động, bạn sẽ phải tạo ra một trường hợp mạnh mẽ để khiến chúng tôi quay lại với nó.

Tôi làm theo lời khuyên của chú Bob để luôn để lại mã tốt hơn bạn đã tìm thấy. Vì vậy, nếu chúng tôi có lỗi để sửa chữa hoặc cải tiến nhỏ, tôi hy vọng chúng tôi sẽ thực hiện một số công việc dọn dẹp.

Nhưng như hiện tại, doanh nghiệp thực sự xem đó là tiền. Tôi phải đưa ra một trường hợp với họ rằng tái cấu trúc mang lại lợi ích cho họ đủ để họ cung cấp cho nhóm của tôi thời gian và nguồn lực. Chỉ không thích cách mã trông không đủ.

Vì vậy, nếu nó hoạt động, nhiều như bạn có thể ghét nó, bạn có thể phải để nó một mình.

Bây giờ mã mới, đó là khác nhau. Đó phải là mã tốt.


2

Các phương thức có 150 dòng ... Tôi đã thấy các phương thức có 10.000 dòng mã.

Hai trong số các vấn đề của bạn có thể được giải quyết bằng các công cụ bên ngoài :

  • Một số hướng dẫn đặt tên không nhất quán
  • Các thuộc tính không được đánh dấu là chỉ đọc khi có thể

Trong C # Resharper có thể kiểm tra cả hai vấn đề. Tên không theo hướng dẫn của bạn được đánh dấu là lỗi. Các thuộc tính không được đánh dấu là chỉ hiển thị là lỗi. FxCop cũng có thể là một trợ giúp.

Những công cụ này cũng có thể giúp chia nhỏ các phương thức lớn thành nhiều phương thức nhỏ hơn nhờ vào việc tái cấu trúc.


2

Tôi không biết rằng các lớp lớn luôn tệ đến mức nếu chúng được cấu trúc tốt với các phương thức được đặt tên tốt. Tôi sử dụng Eclipse làm IDE của mình để nó có cái gọi là khung nhìn "phác thảo", đó là thứ mà tất cả các IDE chỉ có một tên khác, rất có thể, cung cấp tên và liên kết đến từng phương thức trong lớp, bạn có thể sắp xếp theo thứ tự bảng chữ cái , v.v. Khi sử dụng điều này dễ dàng điều hướng một lớp lớn, việc tôi có các phương thức thực sự dài sẽ rất tệ, tôi nghĩ bởi vì việc điều hướng thông minh trong phương thức đó khó hơn trừ khi bạn thực sự quen thuộc với nó. Tôi không ủng hộ các lớp học dài nhưng tôi nghĩ rằng chúng có thể quản lý được trong một số trường hợp và không nhất thiết phải chia thành nhiều lớp.


1

Đưa đối tượng lên với một số thành viên trong nhóm của bạn và nhận ý kiến ​​của họ về quy mô của các phương pháp. Bạn có thể ngạc nhiên khi thấy họ đồng ý với bạn. Những gì bạn đang thấy có thể là kết quả của các thực tiễn tồi tệ trước đây, các nhà phát triển trước đây không còn với công ty hoặc phần đó là một công việc gấp rút và bây giờ họ đã thuê một người có thời gian để cấu trúc lại nó;)


1

Bạn vẫn là chàng trai mới. Xây dựng danh tiếng bằng cách thực hiện các nhiệm vụ đầy thách thức và hoàn thành chúng một cách nhanh chóng và không có lỗi. Nếu bạn cố gắng bắt đầu thay đổi mọi thứ trước khi bạn nhận được sự tôn trọng của đồng nghiệp, bạn có thể gặp khó khăn hơn nhiều trong việc mua hàng (và có thể khiến đồng nghiệp xa lánh).

Nếu bạn có thể tìm cách giới thiệu thói quen mã hóa tốt hơn trong công việc của chính mình, thể hiện hiệu quả cách họ giảm thời gian phát triển và đưa ra các giải pháp mạnh mẽ hơn, bạn thậm chí có thể nhờ họ đến với bạn để xem bạn đã đạt được điều này như thế nào.


1

Hơn nữa với tất cả các câu trả lời tuyệt vời khác, có thể bạn có thể giết hai con chim bằng một hòn đá và thực hiện một số công việc dọn mã như một dự án nhằm mục đích hiểu biết về cơ sở mã. Bạn có thể bán nó cho nhóm / người quản lý của mình như một cơ hội học tập cho bạn và bạn sẽ nhận được phản hồi từ các đồng nghiệp khi họ xem xét các thay đổi của bạn, điều này sẽ hướng dẫn bạn cách tiếp cận tốt nhất để giải quyết vấn đề thiết kế kém.


Làm thế nào để trả lời câu hỏi này?
gnat
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.