نامگذاری صحیح
نامهای صحیح خوانایی کد را بهبود میبخشد و در نتیجه در زمان آشنایی صرفهجویی میکند، زیرا زمانی که نام تقریباً عملکرد آن را توصیف میکند، استفاده از یک روش بسیار آسانتر است. از آنجایی که همه چیز در کد از نام ها (متغیرها، متدها، کلاس ها، اشیاء فایل و غیره) تشکیل شده است، این نکته هنگام ایجاد کد صحیح و تمیز بسیار مهم می شود. بر اساس موارد فوق، نام باید بیانگر این باشد که مثلاً چرا یک متغیر وجود دارد، چه کاری انجام می دهد و چگونه از آن استفاده می شود. من بارها و بارها متذکر می شوم که بهترین نظر برای توصیف یک متغیر، نام صحیح آن است.نام گذاری رابط ها
رابطها معمولاً از نامهایی استفاده میکنند که با حرف بزرگ شروع میشوند و با حروف شتر (CamelCase) نوشته میشوند. زمانی که یک رابط را مینویسید، پیشوند آن با یک I برای تعیین آن به عنوان یک رابط (مثلاً IUserService) تمرین خوبی بود، اما این بسیار زشت و حواسپرتی است. در چنین مواقعی بهتر است بدون آن (UserService) بنویسید و -Impl (UserServiceImpl) را به پیاده سازی آن اضافه کنید. خوب یا به عنوان آخرین چاره، پیشوند C (CUserService) را به پیاده سازی آن اضافه کنید.نام کلاس ها
درست مانند رابط ها، نام ها با حروف بزرگ نوشته می شوند و از سبک شتر (CamelCase) استفاده می کنند. مهم نیست که چه نوع آخرالزمانی اتفاق می افتد، مهم نیست که ضرب الاجل ها چقدر سریع هستند، اما هرگز، به یاد داشته باشید، نام یک کلاس هرگز نباید فعل باشد! نام کلاس ها و شی ها باید اسم ها و ترکیبات آنها باشد (UserController، UserDetails، UserAccount و غیره). شما نباید نام هر کلاس را با مخفف این برنامه وارد کنید، زیرا این کار فقط پیچیدگی غیر ضروری را اضافه می کند (به عنوان مثال، ما یک برنامه انتقال داده های کاربر داریم و به هر کلاس یک UDM اضافه می کنیم - UDMUserDeatils، UDMUserAccount، UDMUserController ).نام روش ها
معمولا نام روش ها با یک حرف کوچک شروع می شود، اما از سبک شتر (CamelCase) نیز استفاده می کنند. در بالا در مورد این واقعیت صحبت کردیم که نام کلاس ها هرگز نباید فعل باشند. در اینجا وضعیت کاملاً مخالف است: نام متدها باید فعل یا ترکیب آنها با افعال باشد: findUserById، findAllUsers، createUser و غیره. هنگام ایجاد یک متد (و همچنین متغیرها و کلاس ها)، برای جلوگیری از سردرگمی، از یک رویکرد نامگذاری استفاده کنید. به عنوان مثال، برای یافتن یک کاربر، روش را می توان به صورت getUserById یا findUserById نوشت. و یک چیز دیگر: از طنز به نام روش استفاده نکنید، زیرا ممکن است شوخی و همچنین آنچه این روش انجام می دهد را متوجه نشوند.نام متغیرها
در اکثر موارد، نام متغیرها با یک حرف کوچک شروع می شود و از Camelcase نیز استفاده می شود، مگر در مواردی که متغیر یک ثابت جهانی است. در چنین مواردی، تمام حروف نام با حروف بزرگ نوشته می شود و کلمات با خط زیر - "_" از هم جدا می شوند. هنگام نامگذاری متغیرها، میتوانید از زمینه معنادار برای راحتی استفاده کنید. به عبارت دیگر، هنگامی که یک متغیر به عنوان بخشی از چیزی بزرگتر وجود دارد - به عنوان مثال، firstName، lastName، وضعیت - در چنین مواردی می توانید یک پیشوند اضافه کنید که نشان می دهد شی که این متغیر بخشی از آن است. به عنوان مثال: userFirstName، userLastName، userStatus. همچنین باید از استفاده از نام های مشابه برای متغیرها در زمانی که معانی کاملاً متفاوتی دارند اجتناب کنید. متضادهای رایج برای متغیرها:- شروع/پایان
- اول آخر
- قفل / باز شده
- حداقل/حداکثر
- بعدی/قبلی
- قدیمی/جدید
- باز / بسته
- قابل مشاهده / نامرئی
- منبع/هدف
- منبع/مقصد
- بالا پایین
نام متغیرهای کوتاه
وقتی متغیرهایی مانند x یا n یا چیزی شبیه آن داریم، بلافاصله قصد شخصی که کد را نوشته است، نمی بینیم. مشخص نیست که روش n چه کاری انجام می دهد: به تفکر متفکرانه تری نیاز دارد (و این زمان، زمان، زمان است). به عنوان مثال، ما یک فیلد داریم - شناسه کاربر مسئول، و به جای نامی مانند x یا just id، این متغیر را answerUserId می نامیم که بلافاصله خوانایی و معنیداری را افزایش میدهد. با این حال، نامهای کوتاه مانند n بهعنوان تغییرات محلی به روشهای کوچک جای خود را دارند، جایی که بلوک کد با آن تغییر تنها چند خط کد است، و نام متد کاملاً توصیف میکند که در آنجا چه اتفاقی میافتد. یک توسعه دهنده با دیدن چنین متغیری، اهمیت ثانویه و دامنه بسیار محدود آن را درک می کند. در نتیجه، مقداری وابستگی به طول نام متغیر وجود دارد: هر چه طولانی تر باشد، متغیر جهانی تر است و بالعکس. به عنوان مثال، روشی برای یافتن آخرین کاربر ذخیره شده بر اساس تاریخ:public User findLastUser() {
return findAllUsers().stream()
.sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
.findFirst()
.orElseThrow(() -> new ResourceNotFoundException("Any user doesn't exist "));
}
در اینجا از نام های کوتاه x و y برای تنظیم مرتب سازی جریان استفاده می کنیم و آنها را فراموش می کنیم.
طول بهینه
موضوع طول نام را ادامه می دهیم. طول نام بهینه جایی بین طول نام حداکثرNumberOfUsersInTheCurrentGroup و n است. یعنی موارد خیلی کوتاه از کمبود معنی رنج میبرند و موارد خیلی طولانی بدون افزودن قابلیت خواندن، برنامه را طولانی میکنند و هر بار برای نوشتن آنها تنبلی میکنند. بدون در نظر گرفتن حالت فوق، برای متغیرهایی با نام کوتاه مانند n، باید طول را تقریباً 8 -16 کاراکتر نگه دارید. این یک قانون سختگیرانه نیست: بیشتر یک دستورالعمل است.تفاوت های کوچک
من نمی توانم تفاوت های ظریف در نام ها را نادیده بگیرم، زیرا این نیز یک روش بد است، زیرا می توانید به سادگی گیج شوید یا زمان زیادی را صرف توجه به تفاوت های جزئی در نام کنید. به عنوان مثال، تشخیص تفاوت بین InvalidDataAccessApiUsageException و InvalidDataAccessResourceUsageException در یک نگاه دشوار است. همچنین، اغلب هنگام استفاده از L و O کوچک ممکن است اطلاعات نادرست ایجاد شود، زیرا به راحتی می توان آنها را با 1 و 0 اشتباه گرفت: در برخی از فونت ها تفاوت آشکارتر است، در برخی دیگر کمتر.بخش معنایی
ما باید قسمت معنایی را در نامها قرار دهیم، اما با مترادفها بیش از حد بازی نکنیم، زیرا، برای مثال، UserData و UserInfo در واقع معنی یکسانی دارند، و باید کمی عمیقتر در کد بگردیم تا بفهمیم به چه شی خاصی نیاز داریم. . از کلمات غیر اطلاعاتی اجتناب کنید، به عنوان مثال، firstNameString: چرا به کلمه string نیاز داریم؟ آیا یک نام می تواند یک شی از نوع تاریخ باشد؟ البته نه: بنابراین، به سادگی - firstName. به عنوان مثال، من می خواهم به متغیرهای بولی، به عنوان مثال، flagDelete اشاره کنم. کلمه پرچم هیچ معنای معنایی ندارد. منطقی تر بود که آن را - isDelete نامید.اطلاعات غلط
در مورد نامگذاری نادرست نیز می خواهم چند کلمه بگویم. فرض کنید نام userActivityList را داریم و شیء به نام از نوع List نیست، بلکه یک ظرف دیگر یا شیء سفارشی برای ذخیره سازی است. این می تواند برنامه نویس معمولی را گیج کند: بهتر است آن را چیزی مانند userActivityGroup یا userActivities بنامیم.جستجو کردن
یکی از معایب نامهای کوتاه و ساده این است که یافتن آنها در حجم زیادی از کدها دشوار است، زیرا یافتن چه چیزی آسانتر است: متغیری به نام name یا NAME_FOR_DEFAULT_USER؟ البته گزینه دوم. لازم است از تکرار کلمات (حروف) در نام ها خودداری کنید، زیرا این کار فقط باعث افزایش تعداد فایل های یافت شده در حین جستجو می شود که خوب نیست. به شما یادآوری می کنیم که برنامه نویسان زمان بیشتری را صرف خواندن کد می کنند تا نوشتن آن، پس حواستان به نام گذاری عناصر برنامه خود باشد. اما اگر نتوانستید آن را با موفقیت نام ببرید چه؟ اگر نام یک روش عملکرد آن را به خوبی توصیف نکند چه می شود؟ اینجاست که وارد عمل می شود، مورد بعدی ما نظرات است.نظرات
هیچ چیز مانند یک نظر مرتبط وجود ندارد، اما هیچ چیزی مانند نظرات بی معنی، قدیمی یا گمراه کننده ماژول را درهم نمی زند. این یک شمشیر دو لبه است، اینطور نیست؟ با این حال، شما نباید نظرات را به عنوان یک خیر بدون ابهام در نظر بگیرید، بلکه به عنوان یک شر کوچکتر. از این گذشته، یک نظر، در اصل خود، جبران یک فکر ناموفق در کد است. به عنوان مثال، ما از آنها برای انتقال ماهیت روش استفاده می کنیم، اگر معلوم شد که خیلی گیج کننده است. در چنین شرایطی، بهتر است به جای نوشتن یادداشت های توصیفی، کد را به درستی بازنویسی کنید. هر چه کامنت قدیمیتر باشد بدتر است، زیرا کد تمایل به رشد و تکامل دارد، اما نظر میتواند ثابت بماند، و هر چه جلوتر میرود، این یادداشتها مشکوکتر میشوند. کامنت های نادرست بسیار بدتر از عدم اظهار نظر هستند، زیرا باعث گیج شدن و فریب دادن و ایجاد انتظارات نادرست می شوند. و حتی اگر کد بسیار مشکلی داشته باشیم، باز هم ارزش آن را دارد که در مورد آن نظر ندهیم، بلکه آن را بازنویسی کنیم.انواع نظرات
-
نظرات حقوقی نظراتی هستند که در ابتدای هر فایل کد منبع به دلایل قانونی مانند:
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-
نظرات آموزنده - نظراتی که توضیحی در مورد کد ارائه می دهند (ارائه اطلاعات اضافی یا هدف یک بخش معین از کد).
به عنوان مثال:
/* * Объединяет пользователя из бд и пришедшего для обновления * Когда в 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() ); }
در این مورد، می توانید بدون نظر انجام دهید، زیرا نام روش و آرگومان های آن، همراه با عملکرد بسیار شفاف، خود را به خوبی توصیف می کند.
-
نظر هشدار - نظری که هدف آن هشدار دادن به سایر توسعه دهندگان در مورد عواقب نامطلوب برخی اقدامات است (به عنوان مثال، چرا یک آزمایش به عنوان @Ignore علامت گذاری شده است):
// Слишком долго отрабатывает // Не запускайте, если не располагаете избытком времени @Ignore @Test public void someIntegrationTest() { …… }
-
TODO - نظراتی که یادداشت هایی برای آینده هستند که باید انجام شوند، اما به دلایلی اکنون نمی توان انجام داد. این یک روش خوب است، اما هنوز هم باید به طور منظم بررسی شوند تا موارد نامربوط حذف شوند تا از شلوغی جلوگیری شود.
Примером послужит:
//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);
Плохие сценарии комментариев
-
бормочущий комментарий — комментарии, которые обычно пишут на скорую руку, смысл которых понятен только разработчику, писавшего их, так 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, и подобный подход излишен.
-
کد کامنت شده کدی است که به دلایلی نظر داده شده است. یکی از بدترین عادتها، زیرا شما آن را نظر دادهاید و فراموش کردهاید، و دیگر توسعهدهندگان به سادگی جرأت حذف آن را ندارند (اگر چیز ارزشمندی باشد چه میشود).
// public void someMethod(SomeObject obj) { // ..... // }
در نتیجه مانند زباله جمع می شود. تحت هیچ شرایطی نباید چنین کدی باقی بماند. اگر واقعاً به آن نیاز دارید، سیستم کنترل نسخه را فراموش نکنید.
-
نظرات غیر آشکار نظراتی هستند که چیزی را به شیوه ای غیر ضروری پیچیده توصیف می کنند.
/* * Начать с массива, размер которого достаточен для хранения * всех byteов данных (плюс byteы фильтра) с запасом, плюс 300 byte * для данных заголовка */ this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];
یک نظر باید کد را توضیح دهد، نه نیاز به توضیح. اینجا چیه؟ "بایت های فیلتر" چیست؟ +1 چه ربطی به این موضوع دارد؟ چرا دقیقا 300؟
- از سبک هایی استفاده کنید که نگهداری آنها آسان است: حفظ سبک هایی که بیش از حد فانتزی و عجیب و غریب هستند می تواند آزاردهنده و وقت گیر باشد.
- از کامنتهایی که به خطوط منفرد اشاره میکنند در انتهای سطرها استفاده نکنید: این باعث ایجاد انبوهی از نظرات میشود و به سختی میتوان برای هر خط یک نظر گویا ارائه داد.
- هنگام ایجاد نظر، سعی کنید به جای «چگونه» به سؤال «چرا» پاسخ دهید.
- از اختصارات خودداری کنید. همانطور که در بالا گفتم، ما نیازی به توضیح برای نظر نداریم: نظر توضیح است.
- می توانید از نظرات برای علامت گذاری واحدهای اندازه گیری و محدوده مقادیر قابل قبول استفاده کنید.
- نظرات را نزدیک به کدی که توصیف می کنند قرار دهید.
GO TO FULL VERSION