To'g'ri nomlash
To'g'ri nomlar kodning o'qilishini yaxshilaydi, shunga mos ravishda tanishish vaqtini tejaydi, chunki nom uning funksionalligini taxminan tavsiflaganda usuldan foydalanish ancha oson bo'ladi. Koddagi hamma narsa nomlardan (o'zgaruvchilar, usullar, sinflar, fayl ob'ektlari va boshqalar) iborat bo'lganligi sababli, bu nuqta to'g'ri, toza kod yaratishda juda muhim bo'ladi. Yuqoridagilardan kelib chiqqan holda, ism, masalan, o'zgaruvchining nima uchun mavjudligini, nima qilishini va qanday ishlatilishini anglatishi kerak. O'zgaruvchini tavsiflash uchun eng yaxshi izoh uning to'g'ri nomi ekanligini qayta-qayta ta'kidlayman.Interfeyslarni nomlash
Interfeyslar odatda bosh harf bilan boshlanadigan va tuya harfida (CamelCase) yozilgan nomlardan foydalanadi. Ilgari interfeys yozishda uni interfeys (masalan, IUserService) sifatida belgilash uchun I bilan prefiks qo'yish yaxshi amaliyot edi, lekin bu juda xunuk va chalg'ituvchi. Bunday hollarda, unsiz (UserService) yozish va uni amalga oshirish uchun -Impl (UserServiceImpl) qo'shish yaxshiroqdir. Xo'sh, yoki oxirgi chora sifatida uni amalga oshirish uchun C (CUserService) prefiksini qo'shing.Sinf nomlari
Interfeyslar singari, nomlar ham bosh harf bilan yoziladi va tuya uslubidan (CamelCase) foydalanadi. Qanday apokalipsis sodir bo'lishidan qat'i nazar, muddatlar qanchalik tez bo'lmasin, lekin hech qachon, unutmang, sinf nomi hech qachon fe'l bo'lmasligi kerak! Sinf va ob'ekt nomlari otlar va ularning birikmalari bo'lishi kerak (UserController, UserDetails, UserAccount va boshqalar). Har bir sinf nomini ushbu ilovaning qisqartmasi bilan koʻrsatmasligingiz kerak, chunki bu faqat keraksiz murakkablikni keltirib chiqaradi (masalan, bizda “Foydalanuvchi maʼlumotlarini koʻchirish” ilovasi mavjud va har bir sinfga UDM qoʻshamiz – UDMUserDeatils, UDMUserAccount, UDMUserController ).Usul nomlari
Odatda usullarning nomlari kichik harf bilan boshlanadi, lekin ular tuya uslubidan ham foydalanadilar (CamelCase). Yuqorida sinf nomlari hech qachon fe'l bo'lmasligi kerakligi haqida gapirdik. Bu erda vaziyat diametrik ravishda qarama-qarshidir: usullarning nomlari fe'llar yoki ularning fe'llar bilan birikmalari bo'lishi kerak: findUserById, findAllUsers, createUser va boshqalar. Usulni (shuningdek, o'zgaruvchilar va sinflarni) yaratishda chalkashmaslik uchun bitta nomlash usulidan foydalaning. Masalan, foydalanuvchini topish uchun usul getUserById yoki findUserById sifatida yozilishi mumkin. Va yana bir narsa: usullarning nomlarida hazildan foydalanmang, chunki ular hazilni tushunmasliklari mumkin, shuningdek, bu usul nima qilishini.O'zgaruvchilar nomlari
Ko'pgina hollarda o'zgaruvchilar nomlari kichik harf bilan boshlanadi va shuningdek, o'zgaruvchi global konstanta bo'lgan hollar bundan mustasno, Camelcase dan foydalanadi. Bunday hollarda ismning barcha harflari bosh harf bilan yoziladi va so'zlar pastki chiziq bilan ajratiladi - "_". O'zgaruvchilarni nomlashda siz qulaylik uchun mazmunli kontekstdan foydalanishingiz mumkin. Boshqacha qilib aytganda, kattaroq narsaning bir qismi sifatida o'zgaruvchi mavjud bo'lganda - masalan, firstName, familiya, status - bunday hollarda siz ushbu o'zgaruvchi qismi bo'lgan ob'ektni ko'rsatadigan prefiks qo'shishingiz mumkin. Masalan: userFirstName, userLastName, userStatus. Bundan tashqari, o'zgaruvchilar uchun mutlaqo boshqa ma'noga ega bo'lsa, o'xshash nomlardan qochish kerak. O'zgaruvchilar uchun umumiy antonimlar:- boshlash/tugatish
- birinchi / oxirgi
- qulflangan/ochilgan
- min/maks
- keyingi/oldingi
- eski / yangi
- ochildi/yopildi
- ko'rinadigan/ko'rinmas
- manba/maqsad
- manba/maqsad
- yuqoriga/pastga
Qisqa o'zgaruvchilar nomlari
Agar bizda x yoki n yoki shunga o'xshash o'zgaruvchilar bo'lsa, biz kodni yozgan odamning niyatini darhol ko'ra olmaymiz. n usulining nima qilishi aniq emas: bu ko'proq o'ylangan fikrlashni talab qiladi (va bu vaqt, vaqt, vaqt). Misol uchun, bizda maydon bor - mas'ul foydalanuvchining identifikatori va x yoki oddiy id kabi ba'zi nomlar o'rniga biz bu o'zgaruvchini javobgarUserId deb ataymiz, bu darhol o'qilishi va mazmunliligini oshiradi. Biroq, n kabi qisqa nomlar kichik usullarga mahalliy o'zgarishlar sifatida o'z o'rniga ega bo'lib, bu o'zgarish bilan kod bloki atigi bir necha qator kodlardan iborat va usul nomi u erda nima sodir bo'lishini juda yaxshi tasvirlaydi. Ishlab chiquvchi bunday o'zgaruvchini ko'rib, uning ikkinchi darajali ahamiyatini va juda cheklangan doirasini tushunadi. Natijada, o'zgaruvchining nomi uzunligiga ma'lum darajada bog'liqlik mavjud: u qanchalik uzun bo'lsa, o'zgaruvchi shunchalik global bo'ladi va aksincha. Misol tariqasida, oxirgi saqlangan foydalanuvchini sana bo'yicha topish usuli:public User findLastUser() {
return findAllUsers().stream()
.sorted((x, y) -> -x.getCreatedDate().compareTo(y.getCreatedDate()))
.findFirst()
.orElseThrow(() -> new ResourceNotFoundException("Any user doesn't exist "));
}
Bu erda biz oqimlarni saralashni o'rnatish uchun x va y qisqa nomlaridan foydalanamiz va ular haqida unutamiz.
Optimal uzunlik
Ism uzunligi mavzusini davom ettiramiz. Optimal nom uzunligi maksimalNumberOfUsersInTheCurrentGroup nomi uzunligi va n oralig'ida bo'ladi. Ya'ni, juda qisqa bo'lganlar ma'no etishmasligidan aziyat chekishadi va juda uzunlar dasturni o'qish qobiliyatini qo'shmasdan uzaytiradilar va ularni har safar yozishga juda dangasa. Yuqoridagi holatni hisobga olmagan holda, n kabi qisqa nomli o'zgaruvchilar uchun uzunlikni taxminan 8 -16 belgigacha saqlashingiz kerak. Bu qat'iy qoida emas: ko'proq ko'rsatma.Kichik farqlar
Men ismlardagi nozik farqlarni e'tiborsiz qoldirolmayman, chunki bu ham yomon amaliyot, chunki siz shunchaki chalkashishingiz yoki ismlardagi kichik farqlarni ko'rish uchun ko'p vaqt sarflashingiz mumkin. Misol uchun, InvalidDataAccessApiUsageException va InvalidDataAccessResourceUsageException o'rtasidagi farqni bir qarashda aniqlash qiyin. Bundan tashqari, kichik L va O dan foydalanganda noto'g'ri ma'lumotlar ko'pincha paydo bo'lishi mumkin, chunki ularni 1 va 0 bilan osongina chalkashtirib yuborish mumkin: ba'zi shriftlarda farq aniqroq, boshqalarida esa kamroq.Semantik qism
Biz semantik qismni nomlarga qo'yishimiz kerak, lekin sinonimlar bilan ortiqcha o'ynamaslik kerak, chunki, masalan, UserData va UserInfo aslida bir xil ma'noga ega va bizga qanday aniq ob'ekt kerakligini tushunish uchun kodni biroz chuqurroq qazishimiz kerak bo'ladi. . Noma'lum so'zlardan saqlaning, masalan, firstNameString: nima uchun bizga string so'zi kerak? Ism sana turi ob'ekti bo'lishi mumkinmi? Albatta yo'q: shuning uchun, oddiygina - firstName. Misol tariqasida, mantiqiy o'zgaruvchilarni eslatib o'tmoqchiman, masalan, flagDelete. Bayroq so'zi hech qanday semantik ma'noga ega emas. Buni isDelete deb atash yanada oqilona bo'lardi.Dezinformatsiya
Noto'g'ri nomlash haqida ham bir necha so'z aytmoqchiman. Aytaylik, bizda userActivityList nomi bor va shunday nomlangan ob'ekt List tipidagi emas, balki saqlash uchun boshqa konteyner yoki maxsus ob'ekt. Bu oddiy dasturchini chalkashtirib yuborishi mumkin: uni userActivityGroup yoki userActivities kabi bir narsa deb atash yaxshi bo'lardi.Qidirmoq
Qisqa va oddiy nomlarning kamchiliklaridan biri shundaki, ularni katta hajmdagi kodda topish qiyin, chunki nimani topish osonroq bo'ladi: name yoki NAME_FOR_DEFAULT_USER deb nomlangan o'zgaruvchi? Albatta, ikkinchi variant. Ismlarda tez-tez uchraydigan so'zlardan (harflardan) qochish kerak, chunki bu faqat qidiruv paytida topilgan fayllar sonini oshiradi, bu yaxshi emas. Sizga shuni eslatib o'tmoqchimizki, dasturchilar uni yozishdan ko'ra kodni o'qishga ko'proq vaqt sarflashadi, shuning uchun ilovangiz elementlarini nomlashga e'tibor bering. Ammo agar siz uni muvaffaqiyatli nomlay olmasangiz nima bo'ladi? Agar usulning nomi uning funksionalligini yaxshi tasvirlamasa-chi? Bu erda u o'ynaydi, bizning keyingi elementimiz - sharhlar.Izohlar
Tegishli sharh kabi hech narsa yo'q, lekin hech narsa ma'nosiz, eskirgan yoki chalg'ituvchi sharhlar kabi modulni bezovta qilmaydi. Bu ikki qirrali qilich, shunday emasmi? Shunday bo'lsa-da, siz sharhlarga aniq yaxshilik sifatida qaramasligingiz kerak: aksincha, kamroq yomonlik. Axir, sharh, o'z mohiyatiga ko'ra, kodda muvaffaqiyatsiz ifodalangan fikr uchun kompensatsiyadir. Masalan, agar u juda chalkash bo'lib chiqsa, biz ulardan qandaydir tarzda usulning mohiyatini etkazish uchun foydalanamiz. Bunday vaziyatda tavsiflovchi eslatmalarni yozishdan ko'ra kodni to'g'ri qayta ishlash yaxshiroqdir. Izoh qanchalik eski bo'lsa, shunchalik yomon, chunki kod o'sish va rivojlanish tendentsiyasiga ega, ammo sharh o'zgarishsiz qolishi mumkin va u qanchalik uzoqqa borsa, bu eslatmalar shunchalik shubhali bo'ladi. Noto'g'ri sharhlar hech qanday izohdan ko'ra yomonroqdir, chunki ular chalkashtirib yuboradi va yolg'on umidlar beradi. Va agar bizda juda qiyin kod bo'lsa ham, bu haqda izoh bermaslik, balki uni qayta yozishga arziydi.Sharhlar turlari
-
huquqiy izohlar har bir manba kod faylining boshida yuridik sabablarga ko'ra qoldirilgan izohlardir, masalan:
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-
ma'lumot beruvchi sharhlar - kodni tushuntirishni ta'minlaydigan sharhlar (qo'shimcha ma'lumot yoki kodning ma'lum bir qismining maqsadini taqdim etish).
Misol tariqasida:
/* * Объединяет пользователя из бд и пришедшего для обновления * Когда в 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() ); }
Bunday holda, siz sharhlarsiz qilishingiz mumkin, chunki usulning nomi va uning argumentlari juda shaffof funksionallik bilan birgalikda o'zlarini juda yaxshi tasvirlaydi.
-
ogohlantirish sharhi - maqsadi boshqa ishlab chiquvchilarni biron bir harakatning nomaqbul oqibatlari haqida ogohlantirish bo'lgan sharh (masalan, nima uchun test @Ignore deb belgilangan):
// Слишком долго отрабатывает // Не запускайте, если не располагаете избытком времени @Ignore @Test public void someIntegrationTest() { …… }
-
TODO - bajarilishi kerak bo'lgan kelajak uchun eslatmalar, lekin ba'zi sabablarga ko'ra hozir qilish mumkin emas. Bu yaxshi amaliyot, ammo tartibsizliklarga yo'l qo'ymaslik uchun ahamiyatsizlarini olib tashlash uchun ular hali ham muntazam ravishda ko'rib chiqilishi kerak.
Примером послужит:
//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, и подобный подход излишен.
-
sharhlangan kod - bu yoki boshqa sabablarga ko'ra sharhlangan kod. Eng yomon odatlardan biri, chunki siz uni sharhlab, unutgansiz va boshqa ishlab chiquvchilar uni o'chirishga jasoratga ega emaslar (agar bu qimmatli narsa bo'lsa).
// public void someMethod(SomeObject obj) { // ..... // }
Natijada, u axlat kabi to'planadi. Hech qanday holatda bunday kod qoldirilmasligi kerak. Agar sizga haqiqatan ham kerak bo'lsa, versiyani boshqarish tizimi haqida unutmang.
-
noaniq izohlar - biror narsani keraksiz murakkab tarzda tasvirlaydigan izohlar.
/* * Начать с массива, размер которого достаточен для хранения * всех byteов данных (плюс byteы фильтра) с запасом, плюс 300 byte * для данных заголовка */ this.dataBytes = new byte[(this.size * (this.deep + 1) * 2)+300];
Sharh kodni tushuntirishi kerak, tushuntirishga muhtoj emas. Bu yerda nima bor? “Filtr baytlari” nima? +1 ning bunga nima aloqasi bor? Nega aynan 300?
- Xizmat qilish oson bo'lgan uslublardan foydalaning: juda chiroyli va ekzotik uslublarni saqlash zerikarli va vaqt talab qilishi mumkin.
- Yagona satrlarga ishora qiluvchi satrlar oxiridagi izohlardan foydalanmang: bu ko'plab sharhlar to'plamini yaratadi va har bir satr uchun ifodali sharhni topish qiyin.
- Sharh yaratishda “qanday qilib” emas, “nima uchun” degan savolga javob berishga harakat qiling.
- Qisqartmalardan saqlaning. Yuqorida aytganimdek, izoh uchun tushuntirish kerak emas: izoh tushuntirishdir.
- O'lchov birliklari va qabul qilinadigan qiymatlar oralig'ini belgilash uchun sharhlardan foydalanishingiz mumkin.
- Izohlarni ular tavsiflagan kodga yaqin joylashtiring.
GO TO FULL VERSION