Понимание чистого кода в Android
6К открытий6К показов
Прежде чем начать писать свой код, нужно понять, как его масштабировать и как им управлять.
Как сказал Дядя Боб в своей книге:
Вы читаете эту статью по двум причинам. Во-первых, вы программист. Во-вторых, вы хотите программировать лучше.Роберт С. Мартин
Представьте, что вы ищете книги в библиотеке. Если книги отсортированы и классифицированы, вы найдёте их гораздо быстрее. Кроме того, благодаря хорошему дизайну интерьера вы будете чувствовать себя комфортно.
Если вы хотите создать что-то стоящее, нужно уметь не только писать, но и аккуратно организовывать свой код. Программист со стороны, получив ваш код, должен увидеть имена переменных, пакетов или классов и сразу всё понять. Он не должен ругаться и начинать проект с нуля.
Что такое «чистый код»?
Нехорошо наспех заканчивать проект, если другие не смогут понять ваш код. Это ваша недоработка и ваша ответственность.
Код можно назвать «чистым», если в нём легко разбирается вся команда. А другой разработчик может прочитать его и улучшить. С понятностью приходит читаемость, изменяемость, расширяемость и лёгкость сопровождения.
Должен ли я заботиться об этом?
Вы должны заботиться о своём коде, потому что именно он будет описывать ваш мыслительный процесс другим. Нужно думать о том, как сделать код более простым и читабельным.
Характеристики чистого кода
- Ваш код элегантен: он должен вызывать у вас улыбку, как от хорошо сделанной музыкальной шкатулки или машины с красивым дизайном.
- О вашем коде позаботились: кто-то нашёл время, чтобы сделать его простым и упорядоченным и уделил внимание деталям.
- Ваш код сфокусирован: каждая функция, каждый класс, каждый модуль выполняют одну конкретную задачу и не перегружены лишними фичами.
- Не содержит дубликатов;
- Работает на всех тестах;
- Имеет минимальное количество объектов, таких как классы, методы, функции и тому подобное.
Одно из различий между умным и профессиональным программистом заключается в том, что профессионал понимает, что чистота — это главное. Профессионалы используют свои способности во благо и пишут код, понятный другим.Роберт С. Мартин
Задавайте уместные имена
Выбор хороших имён требует времени, но экономит больше. Имя переменной, функции или класса должно отвечать на все важные вопросы: зачем нужно, что делает и как используется. Если имя нужно комментировать, то оно не выполняет свою задачу.
Например:
Имена классов
Классы и объекты должны называться существительными или фразами из них, например Customer
, WikiPage
, Account
и AddressParser
. Избегайте таких слов, как Manager
, Processor
, Data
или Info
в названии класса. Имя класса не должно быть глаголом.
Имена методов
Методы должны называться глаголами или фразами из них, например postPayment()
, deletePage()
или save()
. Аксессоры, мутаторы и предикаты должны быть названы по их значению, иметь префикс get
, set
и соответствовать стандарту JavaBean.
Используйте доменные названия для задач
Если не можете подобрать название, используйте доменные названия для задач. По крайней мере, программист, который поддерживает ваш код, может спросить эксперта по домену, что оно значит.
Написание кода с использованием принципов S.O.L.I.D.
Принципы придуманы Робертом К. Мартином (Дядя Боб). SOLID — это термин, описывающий принципы проектирования хорошего кода.
Принцип единой ответственности — SRP
Это означает, что каждый класс должен отвечать за что-то одно. Никогда не должно быть более одной причины для изменения класса. То, что вы можете добавлять в класс всё, что хотите, не означает, что нужно это делать. Разделите большие классы на более мелкие и избегайте классы Бога.
Например:
У нас есть RecyclerView.Adapter
с логикой внутри onBindViewHolder
.
RecyclerView.Adapter
противоречит принципу единой ответственности, потому что он имеет логику внутри onBindViewHolder
.
Принцип Открытости-Закрытости — OCP
Программные объекты должны быть открыты для расширения, но закрыты для модификации. Это означает, что если вы пишете класс A
, а затем ваши товарищи по команде хотят внести изменения в его функцию, они могут легко сделать это, расширив класс A
и не внося изменения.
Простым примером будет класс RecyclerView.Adapter
. Вы можете легко расширить этот класс и создать собственный адаптер с настраиваемым поведением, не изменяя существующий класс RecyclerView.Adapter
.
Принцип подстановки Лисков — LSP
Дочерние классы никогда не должны нарушать определения типов родительского класса.
Это означает, что подкласс должен переопределять методы родительского класса, которые не нарушают функциональность родительского класса. Например, вы создаёте интерфейсный класс с прослушивателем onClick ()
, а затем применяете прослушиватель в MyActivity
и назначаете ему всплывающее действие при вызове onClick ()
.
Принцип разделения интерфейса — ISP
Принцип разделения интерфейса (ISP) гласит, что ни один клиент не должен зависеть от методов, которые он не использует.
Это означает, что если вы хотите создать класс A
и реализовать его в другом классе B
, не нужно переопределять все методы класса A
внутри класса B
. Чтобы стало понятнее, давайте рассмотрим пример:
Внутри кода нужно выполнить SearchView.OnQueryTextListener()
и только метод onQuerySubmit()
.
Как этого добиться? Просто создайте обратный вызов и класс, который распространяется на SearchView.OnQueryTextListener()
.
А вот как это реализовать:
С Kotlin можно использовать функцию-расширение:
И, наконец, вот как это сделать:
Принцип инверсии зависимостей — DIP
Зависит от абстракций. Не зависит от конкрементов.
Принцип обращения зависимостей определяется двумя пунктами:
Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций.
Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Модули высокого уровня со сложной логикой, должны легко использоваться повторно и не подвергаться изменениям в модулях низкого уровня, которые предоставляют служебные функции. Чтобы достичь этого, нужно ввести абстракцию, которая отделяет модули высокого и низкого уровня друг от друга.
Простой пример — шаблон MVP. У вас есть объект интерфейсов, который помогает взаимодействовать с конкретными классами. Это означает, что классам пользовательского интерфейса (Activity
/ Fragment
) не нужно знать фактическую реализацию методов в Presenter
. Если есть какие-либо изменения внутри, классы пользовательского интерфейса не должны знать об изменениях.
Посмотрим на примере кода:
Поэтому мы создаём интерфейс, который абстрагирует реализацию presenter, а наш класс представления сохраняет ссылку на PresenterInterface
.
Заключение
Опытные программисты знают, что все объекты — миф. Иногда действительно нужны простые структуры данных с работающими на них процедурами. С этого момента вы должны начать продумывать, как реализовать проект, чтобы в перспективе его можно было легко обновлять.
Удачного кодинга!
6К открытий6К показов