Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Для начала небольшой тест, который позволит выяснить стоит ли вам читать эту статью дальше: перед вами задача прочитать информацию из текстового файла, немного преобразовать ее (например, агрегировать по- недельно) и показать результат пользователю. Вы мысленно набросали примерно такой план: читаю файл, преобразую, отображаю? Тогда не задумываясь нажимайте кнопку "Читать далее", поскольку эта статья написана именно для вас.
Предложенная выше реализация соотвествует нашему бытовому решению простых задач: если надо что- то сделать, значит будем это делать последовательно шаг за шагом. Но уже сейчас можно почувстовать ошибку: мы размышляем процедурно, последовательно называя выполняемые действия (прочитать, преобразовать, показать). И даже если мы по всем правилам ООП "упакуем" код в объекты, то в нашей голове мы будем продолжать смотреть на этот код, как на процедурную последовательность.
Также давайте вспомним, что программный код- сложная система, состоящая из взаимовлияющих компонентов. Тогда идея первоочередной реализации низкоуровневых компонент (например, в примере выше- чтение файла), которые содержат минимум информации взаимодействия компонент между собой, становится не такой уж привлекательной.
Я давно заметил, что при программировании одно правильное решение автоматически "подсказывает" другие правильные решения. Правильный код требует "правильности" по всему проекту, поэтому нам придется последовательно пройтись по всем этапам создания кода, нарисовав другой подход программирования. Ниже будут изложены эти шаги, и автор хочет, чтобы вы увидели их взаимное вытекание друг из друга, целостную цепочку верных решений. Раз вы продолжили читать эту статью, то обещаю, что к ее концу ваше понимание программирования будет полностью перевернуто.
Конечно, предложенный подход описывает основную идею создания приложений, при этом всегда есть случаи выбивающиеся из общего правила. Я надеюсь, что вы подойдете к изложенному материалу с некоторой толикой творчества и экспериментаторства, позволяющим вам более гибко применять предложенный ниже подход.
Шаг № 1: Строим Use- саse диаграммы, определяя бизнесс- задачи.
Именно с этого шага должно начинаться создание приложения. Если вы не определили четко основные цели, то можно конечно броситься что- то реализовывать, но вы напишите кучу лишнего кода.
Шаг № 2: Создаем GUI.
Созданные диаграммы автоматически "подсказывают" следующий шаг: свое физическое отражение в пользовательском интерфейсе. Интерфейс нужен не потому что глупым пользователям так удобнее, а потому что вы в том числе с его помощью разделяете проект на независимые компоненты. В простых проектах можно создаеть меню, главными элементами которого являются отдельные исполнители, а пункты второго уровня отражают решаемые ими задачи.
Шаг № 3: Реализуем бизнес- логику.
Созданный интерфейс "смотрит" на нас нерешенными задачами, автоматически подсказывая что туда надо написать код, отражающий выполнение интерфейсных пунктов. Т.е. бизнес- логику приложения. Согласитесь, рука не поднимается в обработке "Выставление предложения покупателю" писать низкоуровневый код (например, обращение к базе данных или создание интернет- соединения), ведь там должно быть именно про логику выставления предложения покупателю (проверка на задолженность, чтобы не продешевить анализ "крупности" покупателя, предсказание интереса, анализ остатков на складах....)
Программируя высокоуровневый код, мы автоматически начинаем ощущать себя Наполеоном на поле боя, который передвигает силы в соответствии с решаемой задачей. Это меняет наше самоощущение: раньше мы в первую очередь хватались за реализацию низкоуровневых частей проекта (в примере выше- чтение файла), ощущая себя на поле боя бегающим со штык- ножом солдатом. Сейчас же мы с холма смотрим на картину свысока, в целом оцинивая ситуацию и ища кому следует поручить то или иное действие. Другими словами, у нас органически появляются объекты.
Шаг № 4: Создаем низкоуровневые объекты.
Теперь, когда определены те действия которые действительно нужно выполнить для решения задачи, мы можем начать реализовывать низкоуровневый код. При этом мы четко знаем весь перечень поставленных задач, поэтому код получается максимально "прямолинейным", очень маленьким и чистым. Казалось бы, реализуем тоже самое, а кода становится в разы меньше. В голове при этом нет каких- то сомнений и небольшой тревоги: а вдруг я пишу немного не то, правильно ли вырулят мои рельсы на "стыковочное место"?
Подведя итого, можно сказать, что реализовывать код необходимо сверху вниз: от бизнес- логики к конкретным реализациям. Такой подход автоматически 1) делит код на уровни, 2) создает легко- заменяемые низкоуровневые компоненты (поскольку они создаются последними и именно они затачиваются под соответствие бизнес- логике). Это азбука правильной архитектуры приложения (и опять же обратите внимание, как одно правильное решение "вытягивает" остальные правильные решения). Более подробно прооптимальную архитектуру можно прочитать в потрясающей книге Роберта Мартина "Чистый код" (она подходит для любого языка программирования).
Заметьте еще одну особенность: низкоуровневый код больше не представлен "глаголами" (прочитать, преобразовать, показать), поскольку эту декомозицию взяла на себя бизнес- логика. Теперь нам нужны существительные, которым высокоуровневый код может поручить выполнить ту или иную задачу. Приведу забавную аналогию: если перед мудрым евреем стоит задача, то он не думает как ее решать, он ищет человека, который лучшим образом с ней справится. Так и в нашем коде: теперь высокоуровневому коду требуется Reader (существительное!), который будет читать файлы по переданному ему адресу и представлять результат в нужном формате.
Итак, общая последовательность действий: создаем Use-cases, на основании них- GUI интерфейс, по кнопке "Выполнить" запускаем код бизнес- логики, который перепоручает дейстия низкоуровневым реализациям. Последовательность "сверху вниз" концентрирует человека на той гениальной идее, которую он хочет воплотить, не позволяя мелким техническим деталям "воровать" его интеллектуальную энергию. Вы становитесь подобно опытному водителю, который во время езды размышляет по какой улице лучше поехать (учтиывая пробки, светофоры, время дня...), автоматически выполняющего действия по управлению автомобилем (на чем всецело концентрируется начинающий водитель).
К сожалению, на большинстве курсов программирования об этом совсем не рассказывают. В книгах об этом также практически не пишут. Хотите литературу про архитектуру?- вот вам книжка про паттерны. И я понимаю выбранный подход: коммерческий продукт (курс или книга) должны максимально быстро дать результат, поэтому считается, что некогда тратить время на какие- то благо- глупости. Например, в курсах ML вы увидите процедурный одноуровневый лапша- код, написанный в Jupyter Notebook, а на курсах С++ будете писать консольные утилитки, где в единственном файле будет процедурно реализована вся программа.
Самое смешное, что именно такое понимание создания приложений отличает джуна от сеньора: первый бросается реализовывать низкоуровневый код, а второй как Наполеон реализует основную идею бизнес- логики, попутно ища библиотеку, которой можно поручить ту или иную второстепенную подзадачу.
Уверен, что эта публикация поможет начинающим программистам сильно продвинуться вперед. С ее помощью можно очень быстро стать сеньором.