Sự cân bằng đúng đắn giữa tính nhất quán của mã và cải tiến mã là gì?


53

Gần đây tôi đã có một cuộc thảo luận với một đồng nghiệp về phong cách mã. Ông đã lập luận rằng việc sử dụng API và các mẫu chung mà bạn đang sử dụng phải giống nhau nhất có thể với mã xung quanh, nếu không phải với toàn bộ cơ sở mã, giống như bạn làm với sự xuất hiện của mã (định vị dấu ngoặc, viết hoa, v.v.) . Ví dụ: nếu tôi đã thêm một phương thức vào một lớp DAO trong C #, tôi sẽ cố gắng sử dụng LINQ khi thích hợp để giúp mã của tôi sạch và dễ bảo trì, ngay cả khi không có phương thức nào khác trong lớp đó đang sử dụng nó. Tuy nhiên, đồng nghiệp của tôi sẽ lập luận rằng tôi không nên sử dụng nó trong trường hợp đó bởi vì nó sẽ trái với phong cách hiện có của lớp đó và do đó khó hiểu hơn.

Lúc đầu, tôi thấy vị trí của anh ấy khá cực đoan, nhưng sau khi suy nghĩ một lúc, tôi bắt đầu thấy quan điểm của anh ấy. Với ví dụ LINQ giả thuyết, có lẽ lớp này không chứa nó vì các đồng nghiệp của tôi không quen với LINQ? Nếu vậy, mã của tôi sẽ được duy trì nhiều hơn cho các nhà phát triển đồng nghiệp của tôi nếu tôi không sử dụng nó? Mặt khác, nếu tôi thực sự tin rằng việc sử dụng một kỹ thuật như vậy sẽ dẫn đến mã sạch hơn, thì tôi không nên sử dụng nó ngay cả khi nó khác biệt nhiều so với mã xung quanh?

Tôi nghĩ rằng mấu chốt của lập luận của đồng nghiệp của tôi là nếu tất cả chúng ta đều thực hiện chức năng tương tự trong một cơ sở mã theo những cách khác nhau và mỗi chúng ta đều nghĩ rằng cách của chúng ta là "tốt nhất", thì cuối cùng, toàn bộ mã chỉ trở nên khó khăn hơn hiểu. Tuy nhiên, hiện tại tôi vẫn nghĩ rằng nếu chúng ta mù quáng tuân theo mã hiện có quá nhiều thì chất lượng sẽ chỉ chậm lại theo thời gian.

Vì vậy, ở mức độ nào thì các mẫu là một phần của kiểu mã, và chúng ta nên vẽ ranh giới giữa việc duy trì sự nhất quán và cải tiến ở đâu?


14
Vậy làm thế nào để chất lượng mã được cải thiện, nếu mọi người tự giới hạn mình theo cách "xấu"?
Izkata


Khi bạn viết LINQ, bạn không có nghĩa là LINQ thành SQL? Nếu có thì tôi có thể đồng ý với bạn của bạn. Nếu bạn đang nói về LINQ thì tôi không đồng ý với anh ấy. Mọi người phải làm quen với LINQ những ngày này. Đó không phải là lựa chọn của họ. Họ được trả tiền để làm quen.
Piotr Perak

@Peri Ý tôi chỉ là LINQ cơ bản - Tôi đoán ví dụ của tôi nên là về làm việc với IEnumerables chứ không phải là DAO.
Robert Johnson

2
ICYMI - Truyện tranh Dilbert về chính chủ đề này: Dilbert.com/strips/2013-09-21
Jim Bethancourt

Câu trả lời:


53

Để đưa ra một câu trả lời tổng quát hơn:

Trong trường hợp như thế này, bạn có hai "thực tiễn tốt nhất" đối lập với nhau: tính nhất quán của mã là quan trọng, nhưng vì vậy, chọn phương pháp tốt nhất có thể để hoàn thành nhiệm vụ của mình. Không có câu trả lời đúng cho tình huống khó xử này; nó phụ thuộc vào một vài yếu tố:

  • Làm thế nào có lợi là cách "chính xác"?

    • Đôi khi, cách thực hành tốt nhất và mới được cải thiện sẽ làm tăng đáng kể hiệu năng, loại bỏ lỗi, dễ lập trình hơn, v.v. Trong trường hợp như vậy, tôi sẽ nghiêng về sử dụng phương pháp mới. Mặt khác , "cách chính xác" có thể ít hơn một chút so với đường cú pháp, hoặc một phương pháp thành ngữ đã được thống nhất để làm một cái gì đó không thực sự vượt trội. Trong trường hợp đó, tính nhất quán của mã có lẽ quan trọng hơn.
  • Làm thế nào lớn của một vấn đề sẽ không nhất quán tạo ra?

    • Làm thế nào liên kết với nhau là mã mới với mã kế thừa? Mã mới của bạn là một phần của thư viện? Nó có tạo ra một đối tượng được truyền đến nhiều phần của chương trình không? Trong những trường hợp như thế này, tính nhất quán là rất quan trọng. Sử dụng API mới hoặc cách thức hoạt động mới nói chung, có thể tạo ra các kết quả khác nhau một cách tinh tế, phá vỡ các giả định ở nơi khác trong chương trình của bạn. Mặt khác , nếu bạn đang viết một đoạn mã khá cô lập, sự không nhất quán ít có khả năng là một vấn đề.
    • Làm thế nào lớn và trưởng thành như thế nào là cơ sở mã của bạn? Có bao nhiêu nhà phát triển cần phải hiểu nó và làm việc với nó? Đồng ý, các tiêu chuẩn nhất quán quan trọng hơn nhiều đối với các dự án lớn hơn.
    • Mã có cần chạy trong các môi trường cũ hơn có thể không hỗ trợ các tính năng mới nhất không?

Dựa trên sự cân bằng của những vấn đề này, bạn phải lựa chọn đúng về tuyến đường nào sẽ đi. Cá nhân tôi thấy ít giá trị nhất quán vì lợi ích của tính nhất quán và muốn sử dụng các phương pháp mới nhất, tốt nhất trừ khi có một chi phí đáng kể để làm như vậy.

Tất nhiên, có một tùy chọn thứ ba: viết lại mã hiện có để nó sử dụng các phương thức tốt nhất nhất quán. Có những lúc điều này là cần thiết, nhưng nó đi kèm với một chi phí cao.


7
Câu trả lời rất hay và cân bằng (+1). Theo kinh nghiệm của tôi, một nhóm có thể làm việc hiệu quả hơn nếu tất cả đồng ý về một nhóm thành ngữ được hiểu rõ tương đối nhỏ hơn nếu mỗi thành viên trong nhóm được tự do sử dụng các thành ngữ mới và khác nhau mà các thành viên khác trong nhóm có thể khó hiểu. Một điểm nhỏ liên quan đến tuyên bố "viết lại mã hiện có để nó sử dụng các thực tiễn mới nhất và nhất quán": "mới nhất" không tự động ám chỉ "tốt hơn". Người ta phải luôn luôn quyết định từ trường hợp này sang trường hợp khác.
Giorgio

1
@Giorgio, cảm ơn đã phản hồi; Tôi tinh chỉnh ngôn ngữ của điểm cuối cùng.

6
Câu trả lời tốt và nhận xét tốt từ Giorgio. Có thể đáng xem xét rằng trong ví dụ này, tùy thuộc vào nhóm / văn hóa, có thể có một nhóm áp dụng phối hợp thay vì bắt đầu một mình. Điều này giúp giảm một số rủi ro xung quanh việc bảo trì (như mọi người trên tàu). (tức là chú trọng hơn vào các kỹ năng thực tế của đội tại thời điểm này, thay vì mã họ đã viết trong quá khứ.)
Matt

+1. Đồng ý, một câu trả lời thấu đáo và cân bằng - xem xét tốt về một loạt các kịch bản. Một lần nữa, nhận xét tốt từ Giorgio.
Robert Johnson

1
Về việc áp dụng các thành ngữ mới, các công nghệ: Tôi sẽ coi việc bắt đầu một dự án mới là một điểm tốt để giới thiệu những thứ mới. Sau đó, trong suốt thời gian của toàn bộ dự án, kiểu mã phải được giữ nhất quán nhất có thể. Gần đây tôi đã phải khai thác một số mã 5 năm tuổi và tôi rất vui vì tôi vẫn có thể tìm được cách thông qua mã đó vì cả nhóm tuân thủ một kiến ​​trúc chung và các thành ngữ mà chúng tôi đã đồng ý (không phải đấu tranh! ) khi bắt đầu dự án.
Giorgio

26

Giữ sự nhất quán có ít giá trị trong quan điểm của tôi; liên tục thực hiện cải tiến là phải.

Vị trí của đồng nghiệp của bạn thực sự cản trở sự đổi mới. Đối số thống nhất đưa bạn vào tình huống bạn có thể sử dụng, ví dụ, LINQ chỉ khi bạn di chuyển tất cả mã để sử dụng LINQ. Và tốt, chúng ta không có thời gian cho việc này, phải không?

Tôi muốn có sự không nhất quán khi một số mã vẫn đang hoạt động foreachtrên ArrayLists và các phần khác sử dụng LINQ trên IEnumerable<T>, thay vì tuân theo cách làm việc lâu đời nhất cho đến hết thời gian.

Trách nhiệm của đồng nghiệp là duy trì sự liên quan và học hỏi những cách làm việc mới.


3
"Các đồng nghiệp của bạn có trách nhiệm duy trì sự liên quan và học hỏi những cách làm việc mới.": Một khả năng là sử dụng các thành ngữ và thư viện mới trong mã mới (mô-đun mới) và giữ một phong cách nhất quán trong mã kế thừa.
Giorgio

8

Tính nhất quán API là rất quan trọng, cho cả API công khai và nội bộ.

Tính nhất quán định dạng mã là quan trọng và lý tưởng nhất phải được thực thi bằng công cụ định dạng tự động với các quy tắc định dạng giống nhau cho mọi người. Làm cho việc sống với codebase được kiểm soát phiên bản chia sẻ dễ dàng hơn.

Các quy ước đặt tên phải nhất quán, cũng cho những thứ như biến cục bộ, v.v.

Các công cụ phân tích tĩnh nên được sử dụng để thực thi một số quy ước và thực tiễn tốt khác (nhưng không mù quáng tuân theo các mặc định của bất kỳ công cụ nào như vậy, mặc định đôi khi có thể biên giới điên rồ), mặc dù nếu có gì đó yêu cầu, đừng ngại vô hiệu hóa một số tạm thời kiểm tra (thường có chỉ thị bên trong một bình luận), nếu bạn có thể biện minh cho nó.

Điều gì xảy ra bên trong các hàm / phương thức , ngoài những gì được liệt kê ở trên, không cần nhất quán theo bất kỳ cách nào, miễn là bản thân nó là mã tốt . Mã tốt, dễ hiểu, được nhận xét tốt là rất quan trọng, nhưng sau đó, nếu trình biên dịch và các công cụ phân tích tĩnh nghĩ rằng đó là mã nhất quán, điều đó đủ phù hợp.


Về các tính năng ngôn ngữ mới, chẳng hạn như LINQ (tốt, điều đó không hoàn toàn mới), điều duy nhất cần được xem xét là, liệu phiên bản ngôn ngữ / thư viện đủ mới sẽ được sử dụng ở mọi nơi mà mã sẽ được sử dụng? Nếu nghi ngờ, hãy sử dụng các tính năng được biết là tương thích. Điều này tất nhiên không ngăn bạn đẩy một phiên bản nâng cấp trên toàn hệ thống, vì vậy bạn có thể bắt đầu sử dụng những thứ hay ho mới.

Và mọi nhà phát triển làm việc với mã nên luôn cập nhật, vì vậy bất kỳ nhà phát triển .NET nào cũng nên biết LINQ và nếu họ không bị buộc phải học, vì lợi ích của riêng họ (bạn sẽ không bao giờ biết khi nào bạn sẽ tìm kiếm một cái mới công việc trong doanh nghiệp này, vì lý do này hay lý do khác).


6

Câu trả lời của cái này rất đơn giản.

Tính nhất quán là rất quan trọng.

nhưng nó đi kèm với một cảnh báo ...

Bạn và đồng nghiệp của bạn có thể bị ám ảnh bởi sự nhất quán sai

Triển khai là dùng một lần. Chúng có thể được đại tu hoàn toàn với mức độ dễ dàng khác nhau tùy thuộc vào chất lượng và tính toàn diện của bộ thử nghiệm. Lo lắng về những điều như "Đây có nên là một tài sản không?", "Không nên sử dụng mã này để sử dụng LINQ thay vì cấu trúc cấp thấp hơn?" là giá trị đáng ngờ. Rất khó để buộc bất kỳ phép đo nào với giá trị của tính nhất quán ở cấp độ thực hiện. Một câu hỏi tốt hơn để hỏi ở cấp độ này là "Mã này có hoạt động như quảng cáo không?". Tính nhất quán khi thực hiện TL; DR là nơi "những bộ óc nhỏ" có được hobgoblin của họ.

Tại sao tính nhất quán không quan trọng ở đây? Việc triển khai thường có một số lượng nhỏ những người đóng góp. Hầu hết các phương pháp được viết và không bao giờ chạm vào một lần nữa. Trong số các mã còn lại, số phương thức có hai người đóng góp gần như chắc chắn chiếm đa số. Mô hình này tiếp tục quảng cáo vô hạn . Trong bối cảnh này, tính nhất quán không quan trọng. Nếu thời hạn sử dụng của mã là khá nhỏ ( một vài năm ), lợi ích từ tính nhất quán tích cực có thể là một yếu tố không quan trọng.

Điều này không có nghĩa là bạn nên phát điên khi thực hiện. Thay vào đó, để nói rằng một thiết kế đơn giản, gọn gàng, đẹp đẽ sẽ là những mệnh lệnh có giá trị lớn hơn đối với người bảo trì tương lai giả định của bạn so với phương pháp nhất quán tấm nồi hơi ngớ ngẩn bằng phương pháp. Điều này đưa chúng ta đến điểm thực sự ...

API không dùng một lần.

Đây là tất cả các cấp mã API, dịch vụ web, SDK, v.v ... Những điều này phải, phải, PHẢI nhất quán. Tăng năng suất từ ​​sự nhất quán này là rất lớn vì nhiều lý do:

Kiểm tra tích hợp:

Nếu bạn giữ API của mình nhất quán, bạn có thể tạo các bộ kiểm tra tích hợp. Điều này cho phép các nhà phát triển tự do trao đổi các chi tiết thực hiện và đạt được xác nhận ngay lập tức. Bạn muốn trao đổi các đồng nghiệp của bạn tào lao sang LINQ? Làm các bài kiểm tra tích hợp chạy? Nó cũng cung cấp xác nhận khi chuẩn bị đi vào sản xuất. Bởi vì máy tính rất nhanh, một chiếc máy tính xách tay có thể tạo ra công việc của hàng ngàn người thử nghiệm thực hiện các nhiệm vụ trần tục. Nó tương đương với việc tăng số lượng nhân viên của tổ chức của bạn một cách đáng kể.

Năng suất

Khi API nhất quán, bạn có thể đoán về cách sử dụng API chỉ bằng cách làm theo những gì bạn đã học về cách sử dụng các phần khác của API. Điều này là do API tạo ra "giao diện" tự nhiên, nhất quán. Điều đó có nghĩa là khách hàng của bạn dành ít thời gian hơn để sàng lọc thông qua tài liệu. Lên tàu dễ dàng hơn và rẻ hơn. Những câu hỏi ít hơn được hỏi cho những người đã phát triển API. Sự nhất quán làm cho mọi người trở thành người chiến thắng

Tại sao tính nhất quán quan trọng trong kịch bản này? Bởi vì API có vấn đề hoàn toàn ngược lại với việc triển khai. Số người sử dụng chúng thường lớn hơn nhiều so với số người đóng góp cho việc triển khai của họ. Lợi nhuận nhỏ từ tính nhất quán nhỏ được nhân lên và chi phí duy trì tính nhất quán đó được khấu hao.

Phần kết luận

Tính nhất quán là đắt tiền. Trên mặt của nó làm giảm năng suất. Nó kìm hãm các nhà phát triển và làm cho cuộc sống của họ khó khăn hơn. Nó đặt ra những hạn chế về cách họ có thể giải quyết vấn đề đôi khi buộc họ phải giải quyết nó theo cách không tối ưu. Điều này thường là vì những lý do họ không hiểu, không hiểu biết hoặc họ không bí mật (hợp đồng, chính sách tổ chức lớn hơn hoặc liên tổ chức).

Raymond Hettinger đã đưa ra một số điểm xuất sắc trong bài nói chuyện về Pycon 2015 của mình về việc sử dụng hướng dẫn phong cách PEP8 cho các nhóm lập trình viên python. Ông đã chỉ ra rằng nỗi ám ảnh về tính nhất quán về phong cách trên một đoạn mã đã khiến các nhà đánh giá mã bỏ lỡ các lỗi nghiêm trọng về logic và thiết kế. Giả thuyết của ông có thể được tóm tắt là việc tìm kiếm sự không nhất quán về phong cách là dễ dàng; xác định chất lượng thực sự của một đoạn mã là khó

Điểm ở đây là rất quan trọng. Xác định nơi nhất quán là quan trọng và bảo vệ nó tích cực. Trường hợp không quan trọng đừng lãng phí thời gian của bạn. Nếu bạn không thể cung cấp một cách khách quan để đo lường giá trị của tính nhất quán (trong các trường hợp trên là "số lượng hiệu quả", chi phí là một hàm của năng suất) và bạn không thể chứng minh lợi nhuận là đáng kể thì có khả năng bạn đang thực hiện một sự bất đồng tổ chức của bạn.


4

Không quen thuộc với LINQ? Nếu vậy, mã của tôi sẽ được duy trì nhiều hơn cho các nhà phát triển đồng nghiệp của tôi nếu tôi không sử dụng nó?

Ngôn ngữ C # vẫn đang phát triển. Nếu mọi người không học được những thay đổi từ C # 1, họ sẽ bỏ lỡ:

  • Generics
  • Hạt
  • Phương pháp ẩn danh
  • Lặp đi lặp lại
  • Các loại không thể
  • Tính chất tự động
  • Các loại ẩn danh
  • Phương pháp mở rộng
  • Linh
  • Chiên
  • Phương pháp không đồng bộ

Đây chỉ là một lựa chọn nhỏ của các tính năng phổ biến được tìm thấy trong bài viết Wikipedia. Điểm tôi đang làm là nếu các nhà phát triển không học, cơ sở mã sẽ ở trong chân không. Một người sẽ hy vọng rằng các nhà phát triển của bạn liên tục cải thiện và cơ sở mã phát triển, được hỗ trợ bởi một bộ thử nghiệm hoàn chỉnh. Bạn có nhớ nó tệ như thế nào với .NET 1 khi thực hiện các thuộc tính theo cách thủ công.

Linq làm cho cuộc sống dễ dàng hơn. Sử dụng nó ở nơi bạn có thể. Bạn có thể thúc đẩy các thành viên trong nhóm của bạn.

Vì vậy, ở mức độ nào thì các mẫu là một phần của kiểu mã, và chúng ta nên vẽ ranh giới giữa việc duy trì sự nhất quán và cải tiến ở đâu?

Cải tiến là dần dần. Đối với tôi, thật vô nghĩa khi giữ mã kiểu cũ ít đọc và có khả năng bảo trì ít hơn. Các thành viên trong nhóm của bạn ít nhất có thể biết được chuyện gì đang xảy ra, ngay cả khi họ không thể viết nó.


2
Tôi hoàn toàn đồng ý với những gì bạn đang nói, nhưng câu hỏi của tôi ít hơn về các tính năng ngôn ngữ mới và trách nhiệm của các nhà phát triển để tìm hiểu chúng, mà là câu hỏi chung hơn về việc giải quyết các vấn đề tương tự theo các cách khác nhau trong một khu vực tương đối nhỏ của một cơ sở mã. Tôi đã đề cập đến LINQ vì đây là một ví dụ điển hình về việc sử dụng một cách khác để giải quyết vấn đề. Đồng nghiệp của tôi rất vui khi sử dụng các tính năng ngôn ngữ mới, nhưng chỉ khi họ không đi ngược lại với mã hạt mà anh ta đang làm việc.
Robert Johnson

@RobertJohnson Tôi sẽ chỉ ra cho đồng nghiệp của bạn sau đó rằng tính duy trì vượt qua tính nhất quán, vì vậy ngay cả khi một cái gì đó "đi ngược lại" của mã hiện tại, nếu nó dễ bảo trì hơn, bạn nên làm điều đó. Tôi nghi ngờ sử dụng DAO cũ sẽ có thể duy trì nhiều hơn Linq.
Andy

3

Bạn nên nhất quán, nhưng không nhất thiết phải với mã cũ. Đó là, nhóm của bạn nên đồng ý về cách thức làm việc đúng đắn và sử dụng cách đó bất cứ khi nào mã mới được viết hoặc thay đổi đáng kể được thực hiện.

Bằng cách đó, bạn gặt hái hầu hết các lợi ích của tính nhất quán (đặc biệt, sẽ không có vấn đề ai viết mã), nhưng vẫn có thể cải thiện nếu nhóm thấy lợi ích rõ ràng bằng cách thực hiện theo cách khác.

Trong một thế giới lý tưởng, chúng tôi sẽ viết lại tất cả các mã cũ để phù hợp với cách thức mới. Mặc dù điều này không hiệu quả về mặt kinh tế, nhưng nó nên có ý nghĩa kỹ thuật (hoặc nếu không, cách mới không phải là cách tốt hơn), và kế hoạch dài hạn của bạn nên là nâng cấp nó. Nếu điều đó không đáng, đừng bận tâm với cách mới. Đặt khác nhau, phải có một lợi thế rõ ràng cho cách mới để xem xét tuyên bố nó là đúng.


1

Tôi nghĩ điều quan trọng là phải tuân theo một kiểu mã trong một dự án, vd. quy ước đặt tên, thụt lề, vv

Tôi không đồng ý rằng bạn nên hạn chế sử dụng các cấu trúc ngôn ngữ hoặc mẫu thiết kế mới chỉ vì các đồng nghiệp của bạn không hiểu chúng hoặc chúng chưa được sử dụng trong dự án trước đó.

Tất nhiên những điều này nên có lý do tốt để sử dụng chúng, ví dụ. hiệu suất hoặc ngắn gọn, nếu thích hợp.


Điểm trừ là gì?
ozz 16/03/13

0

Tôi sẽ cực kỳ cẩn thận mù quáng theo các mẫu thiết kế hiện tại. Tất nhiên, khi không có nhược điểm đáng chú ý, người ta phải luôn cố gắng làm theo các mẫu tương tự trên cơ sở mã.

Tuy nhiên, thật dễ dàng để đi vào hoàn cảnh mà phần lớn các nhà phát triển cảm thấy như thể đó là "cách thực hành tốt nhất" để tuân theo các mẫu xấu hiện có dẫn đến tình huống các nhà phát triển tốt đang viết mã xấu, không thể nhận ra.

Mặt khác, tính nhất quán là quan trọng. Khi xử lý các cơ sở mã khổng lồ, sẽ rất hữu ích khi cố gắng tuân theo các mẫu tương tự để mặc dù các nhà phát triển không đọc từng inch của cơ sở mã, họ biết những gì sẽ xảy ra.

Do đó, tôi tin rằng tốt nhất là thiết lập và cập nhật các hướng dẫn về những mẫu mà các nhà phát triển nên tuân theo nếu có thể. Bằng cách này, bất kỳ mã mới nào phù hợp với mã mới khác.


-1

Chúng tôi có các cuộc họp kỹ thuật thường xuyên, khá không chính thức mà bất kỳ ai trong chúng tôi cũng có thể điều hành. Nếu chúng tôi tìm thấy một kỹ thuật mới, chúng tôi trình bày nó tại cuộc họp. Bạn thường có một cảm giác tốt về việc ý tưởng được đồng nghiệp chấp nhận và hiểu như thế nào. Điều này giúp bạn quyết định liệu có khôn ngoan khi đưa nó vào mã của bạn hay không, giúp người khác giải mã nó nếu bạn làm và cũng thiết lập người 'đi tới' nếu người khác cần giúp đỡ với phong cách đó. Nếu không ai phát minh lại bánh xe, chúng ta vẫn sẽ kéo mọi thứ xung quanh vào nhật ký.


Downvote để làm gì?
Kiến

Tôi không phải là người hạ cấp, nhưng điều này dường như không thực sự nhắm đến câu hỏi. Đó là một quy trình nhóm có thể được áp dụng cho bất cứ điều gì, thay vì thảo luận về các vấn đề về phong cách mã hóa. Ngoài ra, bạn không có nghĩa là "phát minh ra bánh xe" chứ không phải là "phát minh lại bánh xe"?

Tôi cho rằng đó là ngữ nghĩa cho dù khúc gỗ có phải là một loại bánh xe hay không nhưng nó quay, giảm ma sát, có bề mặt tiếp xúc với mặt đất và có hình tròn. Tôi chắc chắn có những ví dụ tốt hơn về ý tôi muốn nói - tôi sẽ để nó như một bài tập cho người đọc.
Kiến
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.