Как выглядит код приложения
// для инициализации Direct3D 3D-устройства, обязательно! окно должно иметь не нулевые размеры
// в нашем случае размеры дочернего окна сделаем равными клиентской области фрейма
CRect rc_initchildview;
GetClientRect(&rc_initchildview);
if (!m_wndView.Create(NULL, NULL, WS_CHILD|WS_VISIBLE,
rc_initchildview, this, AFX_IDW_PANE_FIRST, NULL))
<
TRACE0("Failed to create view window\n");
return -1;
>
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
<
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
>
// CMainFrame message handlers
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
<
// forward focus to the view window
m_wndView.SetFocus();
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
// let the view have first crack at the command
if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// otherwise, do default handling
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
>
void CMainFrame::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
<
CFrameWnd::OnActivate(nState, pWndOther, bMinimized);
// будем информировать функции 3D среды
// об сотоянии активности и неактивности фрейма приложения,
// именно фрейма, а не приложения, посколько вызов
// дочернего диалогового окна не приводит к неактивности приложения
if(nState == WA_INACTIVE)
<
m_wndView.m_IsActive = false;
>
else
<
// После активации возбуждаем событие OnPaint(),
// для вызова самогенерации событий перерисовки окна вида.
m_wndView.Invalidate();
if(nState == WA_ACTIVE || nState == WA_CLICKACTIVE)
m_wndView.m_IsActive = true;
// после активации приложения (после нажатия клавиш Alt+Tab)
// восстановим устройство 3D
m_wndView.ResetScene();
>
>
void CMainFrame::DataToRegistry(void)
<
HKEY hKey;
if(ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, REGKEY,
0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, NULL))
<
WINDOWPLACEMENT wp;
GetWindowPlacement(&wp);
GlobalBinaryToRegKey(hKey, "WindowPlacement", (BYTE*)&wp, sizeof(WINDOWPLACEMENT));
Дядя Боб говорил в своей книге: «Вы читаете эту статью по двум причинам. Во-первых, вы разработчик. Во-вторых, вы хотите стать лучше как разработчик».
Представьте, что вы в библиотеке и ищете книгу. Если издания рассортированы и каталогизированы, вы быстро найдёте нужное. А если у библиотеки приятный интерьер и архитектура, во время поиска вам будет особенно комфортно.
Так же и с кодом. Если вы хотите создать что-то хорошее, нужно уметь писать понятный код и организовывать его в проекте. Когда коллегам понадобится найти что-то в коде, будет достаточно посмотреть названия методов, классов и пекеджей, чтобы разобраться. И не придётся переписывать всё с нуля, махнув на вашу работу рукой.
Что такое чистый код
Как вы понимаете, недостаточно просто побыстрее написать приложение. Если другим разработчикам будет тяжело в нём разобраться, это просто увеличит технический долг.
Код можно назвать чистым, если его с ходу понимают другие разработчики. Тогда его можно читать и изменять, расширять и поддерживать.
Почему это важно
Код отражает ваш мыслительный процесс. Поэтому нужно стараться сделать код более простым и читаемым.
Основные характеристики чистого кода
- Изящный — он должен заставлять вас улыбаться, как когда любуетесь хорошо спроектированным домом или пробуете вкусную еду.
- О нём позаботились — вы потратили много времени, чтобы структурировать и упростить код. Уделили время деталям.
- Сфокусированный — каждый метод, класс и модуль преследуют одну понятную цель и не перегружены деталями.
- В нём нет повторяемых функций, функциональность не дублируется.
- Проходит все тесты.
- Количество сущностей — методов, классов и абстракций — сведено к необходимому минимуму.
Разница между умным разработчиком и профессиональным в том, что второй ставит читаемость во главу угла. Профессионалы используют весь свой опыт, чтобы писать код, который поймут остальные.
Создавайте говорящие названия
Выбор хорошего говорящего названия отнимает время, но в итоге экономит ещё больше. Название переменной, метода или класса должно отвечать на все основные вопросы. То есть объяснять, для чего этот класс (метод, переменная), что он делает и как его использовать. Если приходится пояснять что-то в комментариях — значит, название недостаточно говорящее. Посмотрим на пример:
Имена классов
Названия классов и объектов должны быть существительными типа Customer, WikiPage, Account, AddressParser. Избегайте в именах слов Manager, Processor, Data или Info, потому что они мало говорят о функциональности объекта. Не используйте глаголы.
Имена методов
В названиях методов как раз нужны глаголы типа postPayment, deletePage, save.
Используйте названия из предметной области
Если общепринятого термина нет, используйте название из предметной области. Тогда разработчик, который поддерживает ваш код, сможет спросить о его значении эксперта.
Комментарий автора статьи
Например, вы пишете софт для телекоммуникационного оборудования. Ваши области задачи (экспертизы, решения) — это текстовое и голосовое общение, видеосвязь. Неважно, на каком языке, как и на какой платформе вы пишете, — предметная область от этого не меняется. Если вы разрабатываете приложение для создания и продажи фотоконтента, то предметная область включает фотографию и e-commerce. Любой человек, который видит ваш код в первый раз, должен сразу понимать, чем занимается каждый класс, модуль или пекедж в вашем приложении. Думайте об этом, когда добавляете в название что-то из предметной области этого класса.
Пишем код, используя принципы SOLID
Эти принципы были введены в практику ООП Робертом Мартином, а SOLID — мнемоническая аббревиатура для них. Они описывают подход к проектированию простых, читаемых и надёжных программных решений не только в Android-разработке, но и в целом в объектно-ориентированном программировании.
Принцип единой ответственности (Single Responsibility Principle — SRP)
У класса должна быть одна задача. Изменить состояние класса можно только для того, чтобы выполнить конкретную задачу. Не добавляйте в класс функциональность просто потому, что можете. Если класс выполняет разные задачи — разбейте его на два или вынесите часть задач в другие классы. Избегайте божественных классов. Посмотрим на пример:
В классе RecyclerView.Adapter есть метод onBindViewHolder, который занимается посторонними задачами. Adapter должен только создавать ViewHolder и передавать в него данные. Он не должен обрабатывать эти данные в методе onBindViewHolder. Даже само название метода говорит нам об этом.
Принцип открытости-закрытости (Open-Closed Principle — OCP)
Классы должны быть открыты для расширения, но закрыты для изменения. Иными словами, если кто-то захочет внести коррективы в ваш класс А, то его можно расширить (отнаследоваться от него), но никак не менять напрямую.
Простой пример — тот же RecyclerView.Adapter. Вы можете отнаследоваться от него, чтобы создать свою имплементацию с необходимыми вам свойствами и поведением. Но вы не можете внести эти изменения непосредственно в RecyclerView.Adapter.
Принцип подстановки Барбары Лисков (Liskov Substitution Principle — LSP)
Класс-потомок никогда не изменяет поведение класса-родителя. То есть подкласс может переопределять методы родительского класса, только если это не меняет его функциональность.
Например, вы создаёте интерфейс, у которого есть метод onClick(). Затем вы имплементируете интерфейс в MyActivity, и когда onClick() вызовется — отобразите в нём Toast. Не прописывайте эту функциональность в интерфейсе. Дополняйте onClick(), только переопределяя его в классе-потомке.
Принцип разделения интерфейсов (Interface Segregation Principle — ISP)
Ни один наследник не должен имплементировать методы, которые он не использует. Если у вас есть класс или интерфейс А и вы имплементируете его в классе B, то не нужно переопределять все методы А в B.
Для примера рассмотрим имплементацию в вашей Activity SearchView.OnQueryTextListener(). Вам нужен оттуда только один метод, но там их два:
Как сделать так, чтобы вы не имплементировали ненужную функциональность? Отнаследуйтесь от SearchView.OnQueryTextListener(), создайте свой колбэк и передавайте дальше только то, что вам нужно:
Как это будет выглядеть в нашей Activity:
Или можно написать функцию-расширение, как это принято в Kotlin:
Как это будет выглядеть в Activity:
Принцип инверсии зависимостей (Dependency Inversion Principle — DIP)
Зависимости должны быть от абстракций, а не от конкретных имплементаций. Роберт Мартин приводит два аргумента:
- Верхнеуровневые модули не должны зависеть от низкоуровневых. И те и другие должны зависеть от абстракций.
- Абстракции не должны зависеть от деталей, детали должны зависеть от абстракций.
Высокоуровневые модули, в которых прописана сложная бизнес-логика, должны легко переиспользоваться и не зависеть от изменений в низкоуровневых модулях. Чтобы это работало, вам нужно определить абстракции, которые отделяют высокоуровневые модули от низкоуровневых.
Простой пример — паттерн MVP, где вы определяете интерфейсы, которые помогают передавать данные из одного конкретного класса в другой. Это значит, что UI-часть (Activity/Fragment) не должна ничего знать о том, как именно работают методы Presenter. И если вы измените что-то в Presenter, Activity этого даже не заметит. Посмотрим на примере. Presenter имплементирует интерфейс:
То же самое в Activity:
Мы создали интерфейс, отделяющий имплементацию Presenter от Activity, которая содержит ссылку на интерфейс, а не на Presenter.
Если вы уже разрабатывали приложение, в котором были бессмысленные названия, божественные классы, спагетти-код — поверьте, я тоже такое делал. Поэтому и делюсь знаниями от Дяди Боба о чистом коде. Надеюсь, они вам помогут.
В предыдущей части мы затронули азы программирования, где рассказали о машинном языке, преобразователях, языках программирования и работе с CLI. Двигаемся дальше.
Исходным кодом называется основной файл вроде Microsoft (.doc), но немного другой. Это текстовый файл, написанный с помощью простых редакторов, таких как Windows Блокнот. В предыдущем разделе мы перечислили, что нужно, чтобы интерпретаторы или компиляторы конвертировали исходный код в двоичный. Первый должен быть сохранен в файле, что передается для ввода в переводчик (преобразователь).
В зависимости от выбранного языка, есть назначенные расширения для сохранения файла: Python – .py. Java – .java. PHP – .php, PERL – .pl и т. д.
Когда вы закончите писать код, запустите его через переводчик. Рассмотрим в качестве примера запуск кода на языке Python с использованием команды python.
Начало работы: ваша первая программа
- Следуйте приведенным здесь инструкциям, чтобы настроить Python в вашей компьютерной системе.
- Установите простой редактор, чтобы ввести исходный код. Для начала можете использовать этот текстовый редактор.
3. Откройте в нем новый файл и введите следующее:
- Не забудьте сохранить файл как main.py.
- Найдите путь к файлу через CLI и введите следующую команду:
Результат должен выглядеть так:
Анатомия типичного кода
Теперь мы рассмотрим содержимое типичного файла исходного кода. Ниже приведены регулярные компоненты.
Ключевые слова
Короткие человекочитаемые слова, обычно называемые ключевыми. Они свойственны изучаемому вами языку и они особенны. Их просто нужно знать. Вот небольшой набор ключевых слов, часто используемых в Python.
Идентификаторы
Слова, изобретенные вами. Да, не удивляйтесь! Вы, программист. Эти слова обычно называются идентификаторами. Они могут быть созданы вами или другими программистами. Они упакованы в плагины, более известные как библиотеки.
Примером является библиотека Math. Она позволяет получить доступ к функциям, таким как квадратный корень (Math.sqrt), используемый в JavaScript.
Многие языки программирования поставляются со множеством библиотек. Они обычно называются SDK (комплекты разработки программного обеспечения). Загружаются вместе с компилятором для дальнейшего создания технологий, приложений и проектов. Также существуют фреймворки, созданные, чтобы облегчить разработку проекта и объединить его различные составляющие.
Некоторые идентификаторы в комплекте с выбранным языком не могут использоваться в качестве идентификатора пользователя. Примером является слово string в Java. Такие идентификаторы вместе с ключевыми словами называются Зарезервированными Словами. Они также являются особыми.
Все ключевые слова являются зарезервированными. Также слова, которые вы выбираете, должны иметь смысл для тех, кто впервые их видит.
Основные типы данных
Исходный код – сосредоточение разных типов даннх: числа (3, 5.7, -100, 3.142) и символы (M, A). В некоторых языках программирования числа разбиваются на подтипы, такие как integers (целые числа).
Целые числа могут быть знаковыми и беззнаковыми, большими и малыми. Последние фактически зависят от объема памяти, зарезервированного для таких чисел. Есть числа с десятичными частями, обычно называемые double и float, в зависимости от языка, который вы изучаете.
Также существуют логические типы данных boolean, которые имеют значение true или false.
Сложные типы данных
Указанные выше типы известны как элементарные, первичные или базовые. Мы можем создавать более сложные типы данных из приведенных базовых.
Массив (Array) – это простейшая форма сложного типа. Строка (String) – это массив символов. Мы не можем обойтись без этих данных и часто используем их при написании кода.
Комбинация символов – это строка. Чтобы использовать аналогию, строка для компьютера означает, что слово принадлежит человеку. Слово «термометр» состоит из 9 символов – мы просто называем это строкой символов. Обработка строк – это обширная тема, которая должна изучаться каждым начинающим программистом.
Сложные типы данных поставляются с большинством языков программирования, которые используются. Есть и другие, такие как системы классов. Это явление также известно как объектно-ориентированное программирование (ООП).
Переменные
Переменные – это просто имена областей памяти. Иногда нужно сохранить данные в исходном коде в месте, откуда их можно вызвать, чтобы использовать. Обычно это место памяти, которое резервирует компилятор/интерпретатор. Нам нужно дать имя этим ячейкам памяти, чтобы потом их вспомнить. Рассмотрим фрагмент кода Python ниже:
pet_name – пример переменной, и тип данных, хранящихся в pet_name, является строкой, что делает переменную строковой. Существуют также числовые. Таким образом, переменные классифицируются по типам данных.
Константы
Константы – это значения, которые не изменяются на протяжении всего жизненного цикла программы. Чаще всего в их именах используются заглавные буквы. Некоторые языки поддерживают создание постоянных значений, а некоторые – нет.
Существуют строго типизированные языки программирования, в которых каждая переменная должна быть определенного типа. Выбрав тип один раз, вы больше не сможете его изменить. Java – хороший пример такого ЯП.
Другие же не предоставляют эти функции. Они являются свободно типизированными или динамическими языками программирования. Пример – Python.
Вот как объявить постоянное значение в JavaScript:
Литералы
В каждом исходном коде существуют типы данных, которые используются повсюду и изменяются только в том случае, если их отредактировали. Это литералы, которые не следует путать с переменными или константами. Ни один исходный код не обходится без них. Литералы могут быть строками, числами, десятичными знаками или любыми другими типами данных.
В приведенном выше фрагменте слово «Hippo» является строковым литералом. Это всегда будет «Hippo», пока вы не отредактируете исходный код. Когда вы научитесь кодить, узнаете, как управлять литералами таким образом, чтобы оставлять неизменной большую часть кода.
Пунктуация/Символы
В большинстве написанных программ вы найдете различные знаки препинания в зависимости от выбранного языка программирования. Например, в Java используется больше знаков препинания, чем в Python.
Основные знаки включают в себя запятую (,), точку с запятой (;), двоеточие (:), фигурные скобки (<>), обычные круглые скобки (()), квадратные скобки ([]), кавычки ("" или ''), вертикальную черту (|), слэш (\), точку (.), знак вопроса (?), карет (^) и процент (%).
Операторы
Шансы, что вы будете писать исходный код для выполнения какой-нибудь операции, крайне высоки. Любые языки программирования, которые мы используем, включают в себя множество операторов. Среди применяемых выделяют сложение (+), деление (/) умножение (*), вычитание (-) и знак больше (>).
Операторы обычно классифицируются следующим образом:
- Операторы присваивания. Они иногда истолковываются как equals, что неправильно. Равенство используется для сравнения двух значений. А вот оператор присваивания присваивает значение переменной, например pet_name = 'Hippo'
- Арифметические операторы. Состоят из операторов для выполнения арифметических задач, таких как сложение и вычитание. Некоторые языки программирования предоставляют арифметические операторы, когда другие могут их не иметь в своем арсенале. Например, оператор модуля/остатка (%) возвращает остаточное значение в операциях деления.
- Реляционные операторы. Используются для сравнения значений. Они включают в себя больше, меньше, равно, не равно. Их представление также зависит от того, какой язык программирования вы изучаете. Для некоторых ЯП не равно – это <>, для других же – != или !==.
- Логические операторы. Применяются для произведения логических операций. Обычно используемыми логическими операторами являются и, или, нет. Некоторые языки представляют эти операторы в виде специальных символов. Например, && для представления логического и, || – для или, и ! – для нет. Логические значения принято оценивать с помощью булевых значений true или false.
Комментарии
Документация будет важным аспектом деятельности в сфере программирования. Это то, как вы объясняете свой код другим программистам. Подобное делается с помощью комментариев, которые добавляются к различным частям кода. С помощью комментариев вы можете направлять других программистов через написанную программу.
Компилятор игнорирует строки кода, которые являются комментариями.
Вот пример комментария в Python:
Пробелы и вкладки
Это пробелы, созданные между кодом, который вы пишете. Они ставятся при нажатии пробела или клавиши табуляции на клавиатуре.
Двигаемся дальше
Вы познакомились с исходным кодом и изучили его содержимое. Скомпилированный или преобразованный код может не запускаться по ряду причин. Эти причины обычно связаны с ошибками. Действие поиска и удаления ошибок называется отладкой и является навыком, который вы должны изучить. Ошибки мы рассмотрим в следующей части.
Убедитесь, что вы правильно настроили Python в своей компьютерной системе, и запустите свою первую программу.
Викторина
Определите элементы, которые мы изучили, в приведенном ниже фрагменте кода Java:
Программы делятся на открытые и закрытые. В первом случае для всех пользователей интернета доступно скачивание ее исходного кода с официального сайта и других ресурсов, во втором – код системы закрыт и его просмотр нарушает правила пользования программным обеспечением.
- Как посмотреть код программы
- Как открыть исходный код страницы
- Как получить исходный код
Просмотрите исходный код программы при помощи ее исходника. Исходный файл содержит в себе код, написанный программистом при создании программного обеспечения, после этого он компилируется при помощи специальных иснструментов и превращается в файл установки.
Если вами был утерян файл исходного кода, или он недоступен вам по другим причинам, воспользуйтесь специальными программами-декомпиляторами. Также имеются программы-дизассемблеры. Обратите внимание, что просмотр исходного кода зачастую может стать невозможным в случаях, когда вам не известно, какой язык программирования использовался при его разработке.
Если вы хотите найти код свободной программы, выполните поиск в интернете с соответствующим запросом. Также попробуйте скачать данную программу и в ее меню найти пункт «Просмотр исходного кода». Обычно это доступно для бесплатно распространяемых программ.
Будьте осторожны при их использовании, в частности это относится к программам, скачанных не с сайта разработчика, поскольку в исходник может быть заложен вредоносный код, который при установке на ваш компьютер также инсталлирует трояны, клавиатурные шпионы и так далее.
Будьте внимательны при использовании программ-декомпиляторов, поскольку многие разработчики программного обеспечения пользуются специальными программами, которые затрудняют процесс воссоздания исходного кода. Если программа была написана на ассемблере, также принимаются специальные программы.
Средств обратной программной разработки достаточно немало, не используйте их в мошеннических целях или для внесения изменений в программы с закрытым кодом, поскольку зачастую за данные действия предусмотрена определенная ответственность в соответствии с законодательством.
Читайте также: