Современные способы разработки по

Современные подходы к разработке программного обеспечения

May 21 · 13 min read

В октябре прошлого года я выступал на DevFest с докладом на тему, вынесенную в заголовок статьи. Само выступление доступно на Youtube, а ниже будет его текстовая расшифровка.

Разработка зачастую должна напоминать постепенный сбор пазла, но получается обычно как на рисунке справа. Этот доклад был сделан с желанием поделиться тем, как должен быть устроен процесс разработки, чтобы результаты работы команды вас радовали.

Сначала я хотел вам рассказать доклад по плану указанному ниже:

  • Проектирование систем — архитектура
  • Дизайн сервиса — организация кода внутри приложения
  • Хранение и обработка данных сервиса — организация данных
  • Quality Assurance — shift left и пирамида тестов
  • Инфраструктура — IaaC, *aaS
  • Доставка на продакшен — CI/CD pipelines
  • Безопасность
  • Данные для отчетов — подходы Data Lake и Data Mesh

Но потом мне показалось это скучным. В итоге, мы начнем потихоньку и с самого главного … по крайней мере, для начинающего разработчика.

Упрощен н ый процесс разработки выглядит как показано слева. Идеи имеют свойство появляться периодически и мы проходим несколько итераций разработки. В итоге, получается спагетти-код, плохо спроектированная и слабо структурированная программа, которую сложно поддерживать и разбирать. Название идет от миски спагетти, в котором найти концы тоже достаточно сложно:)

Код может превратиться в спагетти от

  • неопытности разработчиков
  • продавливания бизнесом разработчиков по срокам

По-факту, такой код может работать, но развивать его сложно. Для этого надо отдать техдолг и провести рефакторинг системы.

Спагетти-код или системы со спагетти-кодом есть почти везде.
Часто это могут быть legacy системы, которые уже остановились в развитии (зачастую из-за потери контроля над сложностью и невозможности расширить функционал), но все еще находятся в эксплуатации и поддерживаются какой-то командой. Часто такие системы становятся кандидатами на переписывание, если появляется потребность в активном развитии.

Например, в Тинькофф мне досталось несколько таких систем по наследству 4 года назад и мы с моими командами их успешно переписали. Самым ярким примером были 2 системы:

  • Система персонализаций и тестов версии 1.0, которая выросла из прототипа, где ее разработчик не любил лишних вызовов функций (и функции у него были по 500 строк) и не признавал понятие цикломатической сложности и важности ее ограничения
  • Система управления контентом версии 1.0, где несколько фронтендеров писали бекенд систему с API

Теперь подведем итоги разработки в лоб:

  • Всегда ли такой подход плох? — Нет. В прототипах и RnD он может быть хорош.
  • Что делать, если мы пишем не прототип? Или пишем много прототипов? — Нам нужна более умная разработка

Надо добавить как минимум стадию проектирования.

А что же такое проектирование?

По-факту, оно разделяется на две части: что делаем и как делаем. “ Что делаем” относится к требованиям — надо очень внимательно посмотреть на требования, а конкретно на функциональные и нефункциональные требования.

Функциональные требования определяют, что будет делать система или приложение, особенно в контексте внешнего взаимодействия (с пользователем или с другой системой). …
Нефункциональные требования — это любые требования, которые не описывают поведение системы ввода / вывода.

Кстати, нефункциональные требования сейчас часто принято называть атрибутами качества и архитектурными характеристиками системы. Про функциональные требования обычно помнят все, особенно заказчики, а вот про нефункциональные требования забывают. Именно это часто приводит к дальнейшим проблемам.

“ Как делаем” относится больше к паттернам и фреймворкам, которые можно использовать для ускорения и улучшения структуры приложений. Шаблон проектирования или паттерн — это повторяемая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста. Фре́ймворк — каркас, определяющий структуру программной системы и облегчающий разработку и объединение разных компонентов большого программного проекта.

Если мы воспользуемся этим подходом, то мы вместо спагетти-кода придем к архитектуре. Обычно это слоеная архитектура, например

  • UI-слой
  • слой бизнес-логики
  • слой хранения данных

Но, со временем, часто бывает так, что слои переплетаются и опять возникают проблемы. Поэтому важно на берегу договориться о том, а сколько слоев и как они связаны.

Есть разные варианты организации архитектуры слоеной системы, но мне персонально нравится подход Uncle Bob, который он назвал чистой архитектурой. У него вообще пунктик на слове “Clean”, что подтверждают книги ««Clean Code», «Clean Architecture», «Clean Agile». Но если возвращаться к Чистой Архитектуре, то в основе лежит Правило Зависимостей

Читайте также:  Антипар для рыбок способ применения

Концентрические круги на диаграмме представляют собой различные слои программного обеспечения. В общем случае, чем дальше вы идете, тем более общим становится уровень. Внешние круги — механика. Внутренние круги — политика.

Главным правилом, делающим эту архитектуру работающей является Правило Зависимостей. Это правило гласит, что зависимости в исходном коде могут указывать только во внутрь. Ничто из внутреннего круга не может знать что-либо о внешнем круге, ничто из внутреннего круга не может указывать на внешний круг. Это касается функций, классов, переменных и т.д.

Более того, структуры данных, используемых во внешнем круге не должны быть использованы во внутреннем круге, особенно если эти структуры генерируются фреймворком во внешнем круге.
Мы не используем ничего из внешнего круга, чтобы могло повлиять на внутренний.

Данные

Эволюция подходов изображена на рисунке ниже.

Все начиналось с файловых систем, которые использовались для хранения данных и императивного выбора данных. Но при работе с файловыми системами была пара неудобств:

  • совместный доступ к данным
  • сложные выборки данных, когда паттерн выборки меняется

Эти моменты решаются при использовании реляционных баз данных, которые предложил доктор Эдгар Кодд в 1970, когда он работал в IBM. Для работы с реляционными БД применяют реляционные системы управления базами данных (для краткости просто базами данных). Кодд предложил 12 правил, которым должна удовлетворять база данных, чтобы считаться реляционной. Интересно, что большинство реляционных баз данных не соблюдают часть этих правил:)

Реляционные базы данных поддерживают SQL — декларативный язык программирования, применяемый для создания, модификации и управления данными в реляционной базе данных, управляемой соответствующей системой управления базами данных.

Также обычно реляционные базы данных дают гарантии ACID

  • Atomicity — Атомарность
  • Consistency — Согласованность
  • Isolation — Изолированность
  • Durability — Стойкость

Реляционные базы данных подходили не ко всем нагрузкам. Их хорошо было использовать для OLTP нагрузок (Online Transaction Processing). А вот для OLAP нагрузок (Online Analytical Processing) нужны отдельные решения. Саму концепцию предложил тоже Кодд в 1993 году. Основная причина использования OLAP для обработки запросов — скорость. В OLAP решении важна подготовка суммарной (агрегированной) информации на основе больших массивов данных, структурированных по многомерному принципу. OLAP-структура, созданная из рабочих данных, называется OLAP-куб.

Дальнейшим развитием файловых систем стало появление объектных хранилищ, первым популярным среди которых стало Amazon S3 (Simple Storage Service), предоставляющая возможность для хранения и получения любого объёма данных, в любое время из любой точки сети, так называемый файловый хостинг. Впервые появилась в марте 2006 года в США и в ноябре 2007 года в Европе.

В начале 2000-х годов объем информации, которую нужно было обрабатывать перестал помещаться в одно хранилище и потребовалась возможность параллельной обработки на группе машин. Google представил модель распределенных вычислений MapReduce, который использовался для параллельных вычислений над очень большими, вплоть до нескольких петабайт, наборами данных в компьютерных кластерах. Apache Hadoop — это open source проект, который был разработан на основе идеи MapReduce для распределенных вычислений. Он нашел своих последователей и стал крайне популярным в своем классе решений для обработки BigData. Кстати, проект был назван в честь игрушечного слонёнка ребёнка основателя проекта.

В 2009 году появился термин NoSQL, который был придуман Эриком Эвансом, когда Джоан Оскарсон из Last.fm хотел организовать мероприятие для обсуждения распределенных баз данных с открытым исходным кодом. Сейчас он применяется к системам, в которых делается попытка решить проблемы масштабируемости и доступности за счёт полного или частичного отказа от требований атомарности и согласованности данных. В итоге, NoSQL базы уже не дают гарантии ACID, вместо этого они говорят о гарантиях BASE

Эти гарантии связаны с CAP-теоремой, которая является эвристическим утверждение о том, что в любой реализации распределённых вычислений возможно обеспечить не более двух из трёх следующих свойств:

  • согласованность данных (англ. consistency) — во всех вычислительных узлах в один момент времени данные не противоречат друг другу
  • доступность (англ. availability) — любой запрос к распределённой системе завершается корректным откликом, однако без гарантии, что ответы всех узлов системы совпадают
  • устойчивость к разделению (англ. partition tolerance) — расщепление распределённой системы на несколько изолированных секций не приводит к некорректности отклика от каждой из секций

Мы обсудили подходы к хранению данных, а теперь пришло время обсудить архитектуру систем, а точнее распределенных систем.

Архитектура

Эволюция архитектуры решений представлена на рисунке ниже. Все зачастую начинается с монолитного решения — оно проще, дешевле для старта и при правильном модульном подходе позволяет получить неплохое приложение.

Читайте также:  Эргоферон для взрослых способ применения

Источник

10 важнейших принципов разработки программного обеспечения

Принципы разработки программного обеспечения необходимо знать каждому инженеру, который хочет писать чистый код. Следование этим принципам позволяет вам и другим разработчикам понять проект.

Кроме того, обслуживание или изменение проекта в будущем станет легким. Таким образом, вы в конечном итоге сэкономите деньги, время и ресурсы. Если вы хотите, чтобы проект развивался более плавно, то рекомендуется жить по этим законам.

Мы хотим помочь вам внедрить чистый код. Давайте рассмотрим наиболее распространенные принципы разработки программного обеспечения.

1. Будь проще, Саймон (Keep It Simple Simon, KISS)

При написании следующего большого проекта убедитесь, что ваш код прост и понятен. Код не должен вызывать затруднений у людей при модификации или изменении.

Ваши методы должны быть небольшими, не превышающими 40-50 строк.

Каждый метод должен решать только одну проблему.

У вас в проекте много условий? Убедитесь, что вы разбили их на более мелкие блоки кода.

Always Keep It Simple, Stupid (KISS) позволяет вам и другим программистам быстро выявлять ошибки. Он также помогает вносить дальнейшие изменения в код. Это один из наиболее распространенных принципов бережливого производства в гибкой разработке программного обеспечения.

2. Вам это не понадобится (You Aren’t Gonna Need It, YAGNI)

Большинство программистов с самого начала попадают в ловушку, пытаясь реализовать все функции сразу. В конце концов, часть или большинство из этих функций становятся бесполезными.

Как развивающийся разработчик программного обеспечения, всегда начинайте с добавления всего нескольких методов в класс. Когда ваш проект начнет обретать форму и возникнут новые требования, вы можете добавить больше функций. Таким образом, вы будете придерживаться принципов бережливой разработки программного обеспечения.

Этот принцип экономит время, усилия и расходы, которые тратятся впустую на попытки понять или отладить код.

3. Дважды отмерь и один раз отрежь (Measure Twice and Cut Once)

Некачественно выполненный этап написания требований обычно приводит к более чем 50% проблем в разработке. Поэтому подготовьтесь, разработав системный подход к процессу программирования.

Дважды проверьте все требования проекта, чтобы убедиться, что вы ничего не упускаете и не добавляете лишнего в свой код. После этого сделайте наброски, которые будут направлять весь процесс для получения высококачественного кода. Всегда тестируйте свой проект с самых основ, чтобы убедиться, что все в порядке.

Этот принцип дает гораздо более предсказуемые результаты, особенно если стоимость проекта уже высока. Вы избавите себя от головной боли, связанной с удалением или добавлением строк кода в соответствии с требованиями.

4. Не повторяйся (Don’t Repeat Yourself, DRY)

При написании кода не повторяйтесь. То есть избегайте копирования кода в разные места. В противном случае дальнейшее обслуживание будет трудным. Причина в том, что вам придется изменять код в разных местах.

Эти изменения затронут и тесты, которые нужно будет починить. Для этого потребуется больше времени, усилий и денег.

Чтобы избежать этой ловушки, вы можете извлечь общую логику.

Кроме того автоматизируйте всё, что можно автоматизировать. Тогда ваш код останется бережливым.

Описанные выше шаги помогут повторно использовать код без необходимости копировать его.

5. Бритва Оккама

Создатель этого принципа — Уильям Оккам, философ 14 века. Принцип гласит, что в группе гипотез всегда выбирайте ту, которая имеет наименьшее количество предположений.

Следуя принципу бережливой разработки программного обеспечения, всегда начинайте с максимально простого кода. Затем осторожно увеличивайте сложность по мере необходимости.

Простой код позволяет легко представить, разработать, протестировать и исправить продукт на каждом этапе. Он также значительно сокращает количество ошибок, что позволяет программе работать быстрее.

6. Сначала большое проектирование (Big Design Up Front, BDUF)

Этот принцип разработки программного обеспечения утверждает, что разработчик должен сначала завершить проектирование. После этого проект можно реализовать.

Сторонники утверждают, что такой подход помогает обнаруживать проблемы на стадии требований и быстро их решать.

Однако изменения в требованиях к программному обеспечению могут произойти в течение жизненного цикла проекта. Такие изменения могут вызвать трудности или даже сделать дизайн проекта устаревшим.

Один из способов решить эту проблему — сначала создать общую архитектуру. Затем необходимо разделить требования на несколько этапов в соответствии с приоритетами. В процессе разработки начните с этапа с самым высоким приоритетом, постепенно опускаясь до самого низкого. На каждом этапе используйте этот принцип перед началом разработки.

7. Избегайте преждевременной оптимизации

Дональд Кнут утверждал, что корень всего зла в программировании — преждевременная оптимизация.

Мы все согласны с тем, что оптимизация ускоряет процесс разработки и снижает потребление ресурсов. Однако она приведёт к неприятным последствиям, если вы займётесь ей слишком рано.

Читайте также:  Туберкулез почки способы лечения

Причина в том, что приоритизация кода занимает много времени и значительно усложняется, если делать её не вовремя. Кроме того, в процессе реализации наиболее оптимального решения требования могут измениться. Если это произойдет, ваша программа окажется в мусорной корзине или ее будет сложно изменить.

Поэтому начните с самого простого подхода, даже если он не самый оптимальный. Затем в дальнейшем оцените выбранный метод с точки зрения затрат ресурсов и времени. Основываясь на оценке, вы можете выбрать более быстрый алгоритм, который позволит потреблять меньше ресурсов или усилий.

8. Наименьшее удивление

Принцип наименьшего удивления гласит, что желательно разработать функцию, которая не имеет высокого коэффициента удивления.

Компоненты системы должны вести себя так, как того ожидают конечные пользователи. Поэтому результаты вашего проекта будут прибыльными только в том случае, если они очевидны, предсказуемы и последовательны.В противном случае пользователи будут уклоняться от использования функций или структур, которые удивляют или сбивают их с толку.

Вы создаёте программные продукты для людей. Таким образом, вы сильно выиграете от разработки удобных для пользователя функций. Стремитесь соответствовать ментальным моделям, опыту и ожиданиям людей.

Помните, что вы должны привлечь внимание пользователя как можно быстрее. Насколько нам известно, объем внимания современных пользователей резко упал.

9. Закон Деметры

Закон Деметры пытается разделить обязанности между классами и уменьшить связанность между ними.

Настоятельно рекомендуется:

Обеспечить независимость программных объектов друг от друга.

Уменьшить общение или связь между разными классами.

Поместить связанные классы в один и тот же пакет, модуль или каталог для достижения согласованности.

Следование этой идее позволит вашему приложению быть более удобным в обслуживании, понятным и гибким.

10. S.O.L.I.D

Эта аббревиатура обозначает пять принципов объектно-ориентированного программирования и дизайна.

S — Single Responsibility Principle (SRP) — Принцип единой ответственности.

O — Open/Closed Principle (OCP) — Принцип открытия / закрытия.

L — Liskov Substitution Principle — Принцип замещения Лисков.

I — Interface Segregation Principle — Принцип разделения интерфейса.

D — Dependency Inversion Principle — Принцип инверсии зависимостей.

Давайте кратко рассмотрим каждый из этих принципов

Принцип единой ответственности (SRP)

Это принцип разработки программного обеспечения, который гласит, что класс должен иметь только одну причину для изменения. Другими словами, у него должна быть только одна ответственность.

Здесь мы говорим о связанности. Все элементы в структурах или модулях данного класса должны иметь функциональное родство друг с другом. Чётко определив ответственность своего класса, вы повысите его связанность.

Принцип открытости / закрытости (OCP)

Принцип гласит, что вы должны иметь возможность изменять поведение класса, не изменяя сам класс.

Следовательно, вы можете расширить поведение класса за счет композиции, интерфейса и наследования. Однако вы не можете открыть класс для незначительных изменений.

Принцип замещения Лисков (LSP)

В своей исследовательской работе 1988 года Барбара Лисков заявила, что производные классы должны быть спроектированы так, чтобы их при необходимости можно было заменить своими базовыми классами без потери обратной совместимости. Таким образом, вам нужно проявлять осторожность при использовании наследования в проекте.

Хотя наследование выгодно, рекомендуется использовать его в контексте и умеренно. Принцип направлен на предотвращение случаев, когда классы расширяются только за счет общих вещей.

Перед выполнением наследования необходимо учитывать предварительные условия класса.

Принцип разделения интерфейса (ISP)

ISP предпочитает много конкретных интерфейсов одному общему. Цель состоит в том, чтобы иметь гранулярные и специфичные для клиента интерфейсы.

Вам необходимо повысить связанность в интерфейсах и разработать бережливые модули — с минимально возможным поведением.

Интерфейсы с множеством поведений сложно поддерживать и развивать. Так что вам следует избегать их.

Принцип инверсии зависимостей (DIP)

Принцип утверждает, что программисты должны полагаться на абстракции, а не на конкретные классы. Мы можем разбить это на две части:

Модули высокого уровня должны быть независимыми от модулей низкого уровня. И те, и другие должны зависеть от абстракций

Абстракции не должны зависеть от деталей реализации. Детали должны зависеть от абстракций.

Итак, в чем причина этого принципа? Ответ состоит в том, что абстракции мало меняются. Следовательно, вы можете легко изменить поведение вашего приватного или публичного кода. Таким образом, вы ускорите его дальнейшую эволюцию.

Заключение

У каждого профессионала должны быть руководящие принципы. Подобные принципы способствуют единству среди профессионалов в обслуживании своих клиентов. Как благородная область деятельности, разработка программного обеспечения не должна оставаться в стороне.

Инженеры-программисты сделают себе одолжение, придерживаясь вышеуказанных принципов разработки и проектирования программного обеспечения. Таким образом вы сможете более эффективно обслуживать своих клиентов и сотрудничать с другими инженерами.

Для вас подготовил перевод Никита Ульшин, Team Lead & JS-разработчик, веду блог ulshin.me и ТГ-канал @ulshinblog.

Комментарии, пожелания и конструктивная критика приветствуются 🙂

Источник

Оцените статью
Разные способы