JavaRush /Blog Java /Random-VI /Quy tắc mã: sức mạnh của việc đặt tên phù hợp, nhận xét t...

Quy tắc mã: sức mạnh của việc đặt tên phù hợp, nhận xét tốt và xấu

Xuất bản trong nhóm
Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 1 Bạn có thường xuyên phải hiểu mã của người khác không? Khi, thay vì vài giờ, bạn dành nhiều ngày chỉ để hiểu logic của những gì đang xảy ra. Điều buồn cười là đối với người viết mã này, mọi thứ đều rõ ràng và rất minh bạch. Và điều này không có gì đáng ngạc nhiên: suy cho cùng, mã hoàn hảo hay lý tưởng là một khái niệm rất mơ hồ, bởi vì mỗi nhà phát triển đều có tầm nhìn riêng về thế giới và mã. Đã hơn một lần tôi gặp phải tình huống mà tôi và đồng nghiệp nhìn vào cùng một đoạn mã và có những ý kiến ​​​​khác nhau về tính chính xác và sạch sẽ của nó. Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 2Đó là một cảm giác quen thuộc phải không? Tuy nhiên, có một số điểm đã được thử nghiệm theo thời gian cần được tuân thủ, điều này cuối cùng sẽ có lợi cho chúng tôi, bởi vì nếu bạn để mã của mình ở trạng thái mà chính bạn muốn nhận nó, thế giới sẽ hạnh phúc hơn một chút và sạch hơn. Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 3Trong bài viết cuối cùng của chúng tôi về các quy tắc viết mã (hay đúng hơn là một hướng dẫn nhỏ), chúng tôi đã đề cập một chút đến các khuyến nghị để viết toàn bộ hệ thống và các thành phần của nó như đối tượng, giao diện, lớp, phương thức và biến của chúng. Ở đó tôi đã đề cập ngắn gọn về cách đặt tên chính xác của một số yếu tố. Hôm nay tôi muốn nói chính xác về điều này, bởi vì tên chính xác giúp việc đọc mã dễ dàng hơn nhiều. Chúng tôi sẽ kết thúc chủ đề về mã đúng với sự trợ giúp của các phản ánh và các ví dụ nhỏ về nhận xét trong mã - điều này tốt hay không tốt. Vậy hãy bắt đầu.

Đặt tên đúng

Tên chính xác cải thiện khả năng đọc mã, do đó tiết kiệm thời gian làm quen vì việc sử dụng một phương thức sẽ dễ dàng hơn nhiều khi tên mô tả đại khái chức năng của nó. Vì mọi thứ trong mã đều bao gồm tên (biến, phương thức, lớp, đối tượng tệp, v.v.), điểm này trở nên rất quan trọng khi tạo mã chính xác, rõ ràng. Dựa trên những điều trên, tên phải truyền tải ý nghĩa tại sao, ví dụ, một biến tồn tại, nó làm gì và nó được sử dụng như thế nào. Tôi sẽ lưu ý nhiều lần rằng nhận xét tốt nhất để mô tả một biến là tên chính xác của nó. Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 4

Giao diện đặt tên

Các giao diện thường sử dụng tên bắt đầu bằng chữ in hoa và được viết bằng chữ hoa lạc đà (CamelCase). Trước đây, cách tốt nhất là viết một giao diện bằng chữ I để đặt trước giao diện đó để chỉ định nó là một giao diện (ví dụ: IUserService), nhưng điều này khá xấu và gây mất tập trung. Trong những trường hợp như vậy, tốt hơn là viết mà không có nó (UserService) và thêm -Impl (UserServiceImpl) vào phần triển khai của nó. Chà, hoặc phương án cuối cùng là thêm tiền tố C (CUserService) vào quá trình triển khai nó.

Tên lớp

Cũng giống như giao diện, tên được viết hoa và sử dụng kiểu lạc đà (CamelCase). Cho dù ngày tận thế nào đang xảy ra, cho dù thời hạn có nhanh đến đâu, nhưng đừng bao giờ, hãy nhớ rằng, tên của một lớp không bao giờ được phép là một động từ! Tên lớp và đối tượng phải là danh từ và sự kết hợp của chúng (UserController, UserDetails, UserAccount, v.v.). Bạn không nên cung cấp tên của từng lớp cùng với tên viết tắt của ứng dụng này, vì điều này sẽ chỉ tạo thêm sự phức tạp không cần thiết (ví dụ: chúng tôi có ứng dụng Di chuyển dữ liệu người dùng và chúng tôi sẽ thêm UDM vào mỗi lớp - UDMUserDeatils, UDMUserAccount, UDMUserController ).

Tên phương thức

Thông thường tên của các phương thức bắt đầu bằng một chữ cái nhỏ, nhưng chúng cũng sử dụng kiểu lạc đà (CamelCase). Ở trên chúng ta đã nói về thực tế là tên lớp không bao giờ nên là động từ. Ở đây, tình huống hoàn toàn ngược lại: tên của các phương thức phải là động từ hoặc sự kết hợp của chúng với động từ: findUserById, findAllUsers, createUser, v.v. Khi tạo một phương thức (cũng như các biến và lớp), để tránh nhầm lẫn, hãy sử dụng một cách đặt tên. Ví dụ: để tìm người dùng, phương thức có thể được viết là getUserById hoặc findUserById. Và một điều nữa: đừng dùng sự hài hước khi gọi tên các phương pháp, vì có thể họ sẽ không hiểu được câu đùa, cũng như công dụng của phương pháp này.

Tên biến

Trong hầu hết các trường hợp, tên biến bắt đầu bằng chữ cái viết thường và cũng sử dụng Camelcase, ngoại trừ trường hợp biến là hằng số toàn cục. Trong những trường hợp như vậy, tất cả các chữ cái trong tên được viết hoa và các từ được phân tách bằng dấu gạch dưới - “_”. Khi đặt tên biến, bạn có thể sử dụng ngữ cảnh có ý nghĩa để thuận tiện. Nói cách khác, khi có một biến là một phần của thứ gì đó lớn hơn - ví dụ: FirstName, LastName, status - trong những trường hợp như vậy, bạn có thể thêm tiền tố cho biết đối tượng mà biến này là một phần. Ví dụ: userFirstName, userLastName, userStatus. Bạn cũng cần tránh các tên biến giống nhau khi chúng có ý nghĩa hoàn toàn khác nhau. Từ trái nghĩa phổ biến cho các biến:
  • bắt đầu/kết thúc
  • đầu tiên/cuối cùng
  • đã khóa/mở khóa
  • nhỏ nhất lớn nhất
  • tiếp theo/trước đó
  • cũ mới
  • mở/đóng
  • nhìn thấy được/vô hình
  • nguồn/đích
  • điểm đến gốc
  • lên xuống

Tên biến ngắn

Khi chúng ta có các biến như x hoặc n hoặc những thứ tương tự, chúng ta không thấy ngay được ý định của người viết mã. Không rõ phương pháp n làm gì: nó đòi hỏi phải suy nghĩ chín chắn hơn (và đó là thời gian, thời gian, thời gian). Ví dụ: chúng tôi có một trường - id của người dùng có trách nhiệm và thay vì một số tên như x hoặc chỉ id, chúng tôi sẽ gọi biến này có trách nhiệmUserId, điều này ngay lập tức làm tăng khả năng đọc và ý nghĩa. Tuy nhiên, các tên ngắn như n có vai trò thay đổi cục bộ đối với các phương thức nhỏ, trong đó khối mã có thay đổi đó chỉ là một vài dòng mã và tên phương thức mô tả hoàn hảo những gì xảy ra ở đó. Một nhà phát triển khi nhìn thấy một biến như vậy sẽ hiểu tầm quan trọng thứ yếu của nó và phạm vi rất hạn chế. Kết quả là có sự phụ thuộc nhất định vào độ dài của tên biến: tên càng dài thì biến càng có tính toàn cục và ngược lại. Ví dụ: phương pháp tìm người dùng được lưu cuối cùng theo ngày:
public User findLastUser() {
   return findAllUsers().stream()
           .sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
           .findFirst()
           .orElseThrow(() -> new ResourceNotFoundException("Any user doesn't exist "));
}
Ở đây, chúng tôi sử dụng tên viết tắt x và y để sắp xếp luồng và quên chúng đi.

Độ dài tối ưu

Hãy tiếp tục chủ đề về độ dài tên. Độ dài tên tối ưu nằm ở khoảng giữa độ dài tên tối đaNumberOfUsersInTheCurrentGroup và n. Nghĩa là, những đoạn quá ngắn sẽ thiếu ý nghĩa, còn những đoạn quá dài sẽ kéo dài chương trình mà không thêm khả năng đọc, và đơn giản là họ quá lười để viết chúng mỗi lần. Không tính đến trường hợp trên, đối với các biến có tên ngắn như n, bạn cần giữ độ dài trong khoảng 8-16 ký tự. Đây không phải là một quy tắc nghiêm ngặt: giống một hướng dẫn hơn.

Sự khác biệt nhỏ

Tôi không thể bỏ qua những khác biệt nhỏ trong tên, bởi vì đây cũng là một thói quen không tốt, vì bạn có thể bị nhầm lẫn hoặc mất nhiều thời gian để nhận ra những khác biệt nhỏ trong tên. Ví dụ: khó có thể nhận ra ngay sự khác biệt giữa InvalidDataAccessApiUsageException và InvalidDataAccessResourceUsageException. Ngoài ra, thông tin sai lệch thường có thể phát sinh khi sử dụng chữ L và O nhỏ, vì chúng có thể dễ bị nhầm lẫn với 1 và 0: ở một số phông chữ, sự khác biệt rõ ràng hơn, ở những phông chữ khác thì ít hơn.

Phần ngữ nghĩa

Chúng ta cần đặt phần ngữ nghĩa vào các tên, nhưng không lạm dụng các từ đồng nghĩa, vì chẳng hạn, UserData và UserInfo thực sự có cùng một ý nghĩa và chúng ta sẽ phải tìm hiểu sâu hơn một chút về mã để hiểu đối tượng cụ thể mà chúng ta cần . Tránh các từ không mang tính thông tin, ví dụ: firstNameString: tại sao chúng ta cần chuỗi từ? Tên có thể là một đối tượng loại ngày không? Tất nhiên là không: do đó, chỉ đơn giản là - firstName. Để ví dụ, tôi muốn đề cập đến các biến boolean, ví dụ: flagDelete. Cờ từ không mang bất kỳ ý nghĩa ngữ nghĩa nào. Sẽ hợp lý hơn nếu gọi nó là - isDelete.

Thông tin sai lệch

Tôi cũng muốn nói vài lời về việc đặt tên sai. Giả sử chúng ta có tên userActivityList và đối tượng được đặt tên như vậy không thuộc loại Danh sách mà là một số vùng chứa hoặc đối tượng tùy chỉnh khác để lưu trữ. Điều này có thể gây nhầm lẫn cho lập trình viên bình thường: sẽ tốt hơn nếu gọi nó là userActivityGroup hoặc userActivities.

Tìm kiếm

Một trong những nhược điểm của tên ngắn và đơn giản là khó tìm thấy chúng trong một lượng lớn mã, bởi vì cái gì sẽ dễ tìm hơn: một biến có tên là tên hoặc NAME_FOR_DEFAULT_USER? Tất nhiên, lựa chọn thứ hai. Cần tránh các từ (chữ cái) xuất hiện thường xuyên trong tên, vì điều này sẽ chỉ làm tăng số lượng tệp được tìm thấy trong quá trình tìm kiếm, điều này không tốt. Chúng tôi muốn nhắc bạn rằng các lập trình viên dành nhiều thời gian để đọc mã hơn là viết mã, vì vậy hãy lưu ý đến việc đặt tên cho các thành phần trong ứng dụng của bạn. Nhưng nếu bạn không đặt tên thành công thì sao? Điều gì sẽ xảy ra nếu tên của một phương thức không mô tả rõ chức năng của nó? Đây là lúc nó phát huy tác dụng, mục tiếp theo của chúng ta là nhận xét.

Bình luận

Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 5Không có gì giống như một nhận xét có liên quan, nhưng không có gì làm xáo trộn mô-đun như những nhận xét vô nghĩa, lỗi thời hoặc gây hiểu lầm. Đó là con dao hai lưỡi phải không? Tuy nhiên, bạn không nên coi nhận xét là một điều tốt rõ ràng: đúng hơn, hãy coi đó là một điều ít xấu xa hơn. Xét cho cùng, về bản chất, một nhận xét là sự đền bù cho một ý nghĩ được thể hiện không thành công trong mã. Ví dụ, chúng tôi sử dụng chúng để truyền đạt bản chất của phương pháp bằng cách nào đó nếu nó quá khó hiểu. Trong tình huống như vậy, tốt hơn là bạn nên cấu trúc lại mã một cách chính xác hơn là viết ghi chú mô tả. Nhận xét càng cũ thì càng tệ, vì mã có xu hướng phát triển và phát triển, nhưng nhận xét có thể vẫn giữ nguyên, và càng đi xa thì những ghi chú này càng trở nên đáng ngờ. Những nhận xét không chính xác còn tệ hơn nhiều so với việc không có nhận xét nào, vì chúng gây nhầm lẫn và lừa dối, đưa ra những kỳ vọng sai lầm. Và ngay cả khi chúng ta có một đoạn mã rất phức tạp, bạn vẫn không nên bình luận về nó mà hãy viết lại nó.

Các loại bình luận

  • nhận xét pháp lý là các nhận xét được để lại ở đầu mỗi tệp mã nguồn vì lý do pháp lý, chẳng hạn như:

    * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.

  • nhận xét mang tính thông tin - nhận xét cung cấp giải thích về mã (cung cấp thông tin bổ sung hoặc mục đích của một phần mã nhất định.

    Như một ví dụ:

    /*
    * Объединяет пользователя из бд и пришедшего для обновления
    * Когда в requestUser поле пустое, оно заполняется старыми данными из foundUser
    */
    private User mergeUser(User requestUser, User foundUser) {
           return new User(
           foundUser.getId(),
           requestUser.getFirstName() == null ? requestUser.getFirstName() : foundUser.getFirstName(),
           requestUser.getMiddleName() == null ? requestUser.getMiddleName() : foundUser.getMiddleName(),
           requestUser.getLastName() == null ? requestUser.getLastName() : foundUser.getLastName(),
           requestUser.getAge() == null ? requestUser.getAge() : foundUser.getAge()
           );
           }

    Trong trường hợp này, bạn có thể thực hiện mà không cần nhận xét, vì tên của phương thức và các đối số của nó, cùng với chức năng rất minh bạch, tự mô tả khá rõ.

  • nhận xét cảnh báo - nhận xét có mục đích cảnh báo các nhà phát triển khác về hậu quả không mong muốn của một số hành động (ví dụ: tại sao thử nghiệm được đánh dấu là @Ignore):

    // Слишком долго отрабатывает
    // Не запускайте, если не располагаете избытком времени
    @Ignore
    @Test
    public void someIntegrationTest() {
           ……
           }
  • TODO - những bình luận là những ghi chú cho tương lai sẽ cần phải thực hiện nhưng vì lý do nào đó không thể thực hiện được ngay bây giờ. Đây là một cách làm tốt nhưng vẫn cần được xem xét thường xuyên để loại bỏ những nội dung không liên quan nhằm tránh tình trạng lộn xộn.

    Примером послужит:

    //TODO: Add a check for the current user ID (when will be created security context)
    
    @Override
    public Resource downloadFile(File file) {
           return fileManager.download(file);
           }

    Тут мы помечаем, что нужно добавить проверку юзера, который скачивает (id которого мы вытащим из security контекста) с тем, кто сохранил.

  • усorвающий комментарий — комментарий, подчеркивающий важность Howого-то обстоятельства, что на первый взгляд может показаться несущественным.

    Как пример, кусочек метода, заполняющий тестовую БД, некими скриптами:

    Stream.of(IOUtils.resourceToString("/fill-scripts/" + x, StandardCharsets.UTF_8)
           .trim()
           .split(";"))
           .forEach(jdbcTemplate::update);
    // Вызов trim() очень важен, убирает возможные пробелы в конце скрипта
    // чтобы при считке и разбивке на отдельные requestы не было пустых

  • javaDoc — комментарии, которые описывают API определенного функционала для общего пользования. Наверное, самые полезные комментарии, так How с documentированным API в разы легче работать, но они также могут устаревать, How и любые другие. Поэтому не забываем, что главный вклад в documentацию вносится не комментариями, а хорошим codeом.

    Пример вполне обычного метода обновления пользователя:

    /**
    * Обновляет передаваемые поля для пользователя по id.
    *
    * @param id  id обновляемого пользователя
    * @param user пользователь с заполненными полями для обновления
    * @return обновленный пользователь
    */
           User update(Long id, User user);

Плохие сценарии комментариев

Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 7
  • бормочущий комментарий — комментарии, которые обычно пишут на скорую руку, смысл которых понятен только разработчику, писавшего их, так How только он видит ту ситуацию с теми нюансами, на которые он и ссылается.

    Рассмотрим данный пример:

    public void configureSomeSystem() {
           try{
           String configPath = filesLocation.concat("/").concat(CONFIGURATION_FILE);
           FileInputStream stream = new FileInputStream(configPath);
           }  catch (FileNotFoundException e) {
           //В случае отсутствия конфигурационного file, загружается конфигурация по умолчанию
          }
    }

    Кто загружает эти настройки? Были ли они загружены ранее? Метод предназначен для перехвата исключений и вызова дефолтных настроек? Слишком много вопросов возникает, ответы на которые можно получить лишь углубившись в изучение других частей системы.

  • избыточный комментарий — комментарий, который не несёт смысловой нагрузки, так How и так понятно что происходит в заданном участке codeа (он читается не проще, чем code).

    Смотрим пример:

    public class JdbcConnection{
    public class JdbcConnection{
       /**
        * Журнальный компонент, связанный с текущим классом
        */
       private Logger log = Logger.getLogger(JdbcConnection.class.getName());
    
       /**
        * Создаёт и возвращает connection с помощью входящих параметров
        */
       public static Connection buildConnection(String url, String login, String password, String driver) throws Exception {
           Class.forName(driver);
           connection = DriverManager.getConnection(url, login, password);
           log.info("Created connection with db");
           return connection;
       }

    Какой смысл таких комментариев, если мы и так всё прекрасно видим

  • недостоверные комментарии — комментарии, не соответствующие истине и лишь вгоняющие в заблуждение (дезинформирующие). Как например:

    /**
    * Вспомогательный метод, закрывает соединение со сканером, если isNotUsing истинно
    */
    private void scanClose(Scanner scan, boolean isNotUsing) throws Exception {
       if (!isNotUsing) {
           throw new Exception("The scanner is still in use");
       } scan.close();
    }

    What в этом комменте не так? А то, что он немножко врёт нам, ведь соединение закрывается, если isNotUsing = false, но ниHow не наоборот, How нам вещает пометка.

  • обязательные комментарии — комментарии, которые считают обязательными (Javadoc), но кои по факту иногда бывают излишне нагромождающими, недостоверными и ненужными (нужно задуматься, а нужны ли здесь такие комментарии).

    Пример:

    /**
    *  Creation пользователя по переданным параметрам
    * @param firstName Name созданного пользователя
    * @param middleName среднее Name созданного пользователя
    * @param lastName фамorя созданного пользователя
    * @param age возраст созданного пользователя
    * @param address addressс созданного пользователя
    * @return пользователь который был создан
    */
    User createNewUser(String firstName, String middleName, String lastName, String age, String address);

    Смогли бы вы понять, что делает метод без этих комментариев? Скорее всего да, поэтому комментарии в этом случае стают бессмысленными.

  • журнальные комментарии — комментарии, которые иногда добавляют в начало модуля, при каждом его редактировании (что-то вроде журнала вносимых изменений).

    /**
    *  Записи ведутся с 09 января 2020;
    **********************************************************************
    *  09.01.2020  : Обеспечение соединения с БД с помощью Jdbc Connection;
    *  15.01.2020  : Добавление интерфейсов уровня дао для работы с БД;
    *  23.01.2020  : Добавление интеграционных тестов для БД;
    *  28.01.2020  : Имплементация интерфейсов уровня дао;
    *  01.02.2020  : Разработка интерфейсов для сервисов,
    *  согласно требованиям прописанным в user stories;
    *  16.02.2020  : Имплементация интерфейсов сервисов
    *  (реализация бизнес логики связанной с работой БД);
    *  25.02.2020  : Добавление тестов для сервисов;
    *  08.03.2020  : Празднование восьмого марта(Миша опять в хлам);
    *  21.03.2020  : Рефакторинг сервис слоя;
    */

    Когда-то этот проход был оправдан, но с появлением систем управления исходным codeом (например — Git), это стало лишним нагромождением и усложнением codeа.

  • комментарии ссылки на авторов — комментарии, преднаmeaningм которых является, указание человека, писавшего code, чтобы можно было связаться и обсудить, How что и зачем:

    * @author  Bender Benderovich

    Опять же, системы контроля версий прекрасно запоминают, кто и когда добавил данный code, и подобный подход излишен.

  • mã nhận xét là mã đã được nhận xét vì lý do này hay lý do khác. Một trong những thói quen tồi tệ nhất, bởi vì bạn đã nhận xét nó và quên mất, và các nhà phát triển khác chỉ đơn giản là không đủ can đảm để xóa nó (nếu nó là thứ gì đó có giá trị thì sao).

    //    public void someMethod(SomeObject obj) {
    //    .....
    //    }

    Kết quả là nó tích tụ như rác. Trong mọi trường hợp không nên để lại mã như vậy. Nếu bạn thực sự cần nó, đừng quên hệ thống kiểm soát phiên bản.

  • những bình luận không rõ ràng là những bình luận mô tả điều gì đó một cách phức tạp không cần thiết.

    /*
        * Начать с массива, размер которого достаточен для хранения
        * всех byteов данных (плюс byteы фильтра) с запасом, плюс 300 byte
        * для данных заголовка
        */
    this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];

    Một nhận xét nên giải thích mã, không cần giải thích. Cái gì đây? "byte lọc" là gì? +1 có liên quan gì đến nó? Tại sao chính xác là 300?

Nếu bạn quyết định viết bình luận, đây là một số mẹo để sử dụng chúng:
  1. Sử dụng những phong cách dễ bảo trì: duy trì những phong cách quá cầu kỳ và kỳ lạ có thể gây khó chịu và tốn thời gian.
  2. Không sử dụng nhận xét ở cuối dòng đề cập đến các dòng đơn: điều này tạo ra một lượng lớn nhận xét và khó đưa ra nhận xét diễn cảm cho từng dòng.
  3. Khi tạo nhận xét, hãy cố gắng trả lời câu hỏi “tại sao” thay vì “làm thế nào”.
  4. Tránh viết tắt. Như mình đã nói ở trên, chúng ta không cần giải thích cho comment: comment chính là giải thích.
  5. Bạn có thể sử dụng các nhận xét để đánh dấu đơn vị đo lường và phạm vi giá trị có thể chấp nhận được.
  6. Đặt các bình luận gần với mã mà chúng mô tả.
Do đó, tôi vẫn muốn nhắc bạn: những bình luận tốt nhất là không có bình luận và thay vào đó là đặt tên thích hợp trong ứng dụng. Theo quy định, hầu hết thời gian chúng ta sẽ làm việc với mã tạo sẵn, duy trì và mở rộng nó. Sẽ thuận tiện hơn nhiều khi mã này dễ đọc và dễ hiểu, bởi vì mã xấu sẽ cản trở, đặt nan hoa vào bánh xe và sự vội vàng là người bạn đồng hành trung thành của nó. Và chúng ta càng có nhiều mã xấu thì hiệu suất càng giảm, vì vậy thỉnh thoảng chúng ta cần phải cấu trúc lại. Nhưng nếu ngay từ đầu bạn cố gắng viết mã mà các nhà phát triển tiếp theo sẽ không muốn tìm ra và giết bạn, thì bạn sẽ cần phải cấu trúc lại nó ít thường xuyên hơn. Nhưng nó vẫn sẽ cần thiết, vì các điều kiện và yêu cầu đối với sản phẩm liên tục thay đổi, được bổ sung bằng cách bổ sung thêm các kết nối và không có lối thoát nào khỏi điều này. Cuối cùng, tôi sẽ để lại một vài liên kết thú vị để bạn làm quen với chủ đề này ở đây , ở đâyở đây Tôi đoán đó là tất cả đối với tôi hôm nay, cảm ơn mọi người đã đọc)) Quy tắc viết code: sức mạnh của việc đặt tên đúng, nhận xét tốt và xấu - 8
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION