Рубрики
Без рубрики

Размышления о современной разработке программного обеспечения

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

Вступление

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

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

Случайная и неотъемлемая сложность

Неотъемлемая сложность – это сложность, с которой вам приходится сталкиваться из-за характера бизнеса, для которого вы пишете программное обеспечение. Если вы пишете систему наведения для самолета или разрабатываете сложный алгоритм, который поможет вам синтезировать новое лекарство, то сложность того, как работает система наведения, как самолет ориентируется, как он управляет подъемной силой, сопротивлением, реагирует на команды пилота, или новый препарат считается эффективным или нет…. Все эти факты о вашем домене, в той или иной форме, должны будут в конечном итоге попасть в код. Это неизбежная часть головоломки, от нее никуда не деться.

Искусство написания хорошего программного обеспечения заключается в том, как мы можем встроить эту необходимую сложность в “случайную”: язык и/или технический стек, который мы используем для кодирования этих реальных фактов в код, который может принести реальную пользу бизнесу. Любой согласится, что написание системы наведения для самолета в сборе – ужасная идея: у нас есть инструменты получше. Да, лучшие инструменты, такие как… Питон. За исключением того, что Python – ужасная идея для высокопроизводительной системы реального времени, такой как система наведения. Любой программист, читающий это, может иметь к этому отношение.. Это просто недостаточно быстро, недостаточно эффективно для производительности или памяти, чтобы работать в ограниченных средах. C, C++ или Rust – лучший выбор. Гораздо более быстрые циклы выполнения, сгенерированный машинный код может быть полностью оптимизирован для целевого чипа архитектуры, полный контроль над памятью и т.д.

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

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

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

Я подойду к этому разделу с точки зрения человека, который работает с Java, Spring boot, Git и использует Docker и Kubernetes для управления и предоставления инфраструктуры, но, надеюсь, основополагающие принципы будут достаточно общими, чтобы любой мог извлечь что-то из этого поста.

Команды и процессы

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

Это действительно суть вопроса: соглашение, низкие барьеры при входе, а также управление трениями и конфликтами между командами и отдельными лицами – это самое важное. Это не зависит от какой-либо методологии, которую вы или ваша компания решите принять, но это самый важный аспект, который вам нужно правильно понять, чтобы позволить себе и своим коллегам работать эффективно. Все остальное, будь то методологии, процессы, сертификаты, что угодно, существует только для того, чтобы обеспечить и способствовать прозрачности и ясности требований между членами команды и другими соответствующими заинтересованными сторонами. Помните: никому нет дела до сюжетных очков в билете. Люди вроде как чувствуют, что им это нужно, потому что это то, что вы можете измерить. Но вместо этого сосредоточьтесь на том, что вы НЕ МОЖЕТЕ измерить: ваша выдержка, ваша целеустремленность, ваше желание приносить пользу своим коллегам, продолжать совершенствовать продукт, над которым вы работаете, гордиться хорошо выполненной работой. Если вы сосредоточитесь на этих вещах, вы в конечном итоге увидите свою работу в другом свете, что может эффективно позволить вам работать в ЛЮБОЙ компании, используя ЛЮБУЮ методологию. Потому что в основе всего этого лежат люди. И укрепление хороших отношений между командами и коллегами – это самое важное, когда дело доходит до работы в команде. Остальное естественным образом последует и встанет на свои места. Будьте добры, внимательны, усердно трудитесь, слушайте, высказывайте свою точку зрения, и все выиграют. Команды определяются не их руководящими методологиями, они определяются людьми. Это очень важно.

Оседлай волну DevOps

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

Docker и Kubernetes были выпущены, соответственно, 7 и 6 лет назад. Разработчик, который начал профессионально работать в 2012 году, УВИДЕЛ, как изменилась воспроизводимость сборки. Он или она увидели, как это может повлиять на то, как целые команды работают и управляют своим кодом. Это была революция. Однако технология сложна, и от разработчиков требуются усилия, чтобы изучить ее и использовать наилучшим образом. Мне нравится думать о DevOps как о “разработчиках, берущих на себя ответственность за операции”. Это очень важно, и это одна из лучших инвестиций, которые вы можете сделать сегодня, которая будет продолжать окупаться в будущем. Изучите основы Docker и Kubernetes и используйте их, чтобы быть эффективными, а также помогать вашей команде быть эффективной. Существует множество аспектов, с помощью которых вы можете приблизиться к волне DevOps для себя и для своей компании:

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

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

  • Создавайте “шаблонные” файлы docker compose, в которые вы можете добавлять определенные сервисы, например, из разных филиалов или, например, из разных баз данных, таких как управляемые реплики, созданные вашей командой DevOps, или кластеры из облачной платформы Google, называйте как хотите. Docker предоставляет вам гибкость, безопасность и изоляцию, необходимые вашим разработчикам для максимально возможной производительности на местном уровне. Примите это так сильно, как только сможете.

  • Дать толчок использованию Kubernetes в вашей компании? Изучите развертывание филиалов. Kubernetes можно использовать как отличный инструмент, позволяющий разработчикам создавать полноценную “отраслевую среду”, которая ведет себя как настоящая производственная среда, но содержит ваши хирургические изменения, внесенные в вашу ветку. Это бесценно”. Будет ли это достаточно производительным?”, “Влияет ли изменение этой конечной точки на интерфейс?” Ответ на эти вопросы, позволив развернуть полную среду с помощью git push, является реальным стимулом. Это трудно сделать правильно и требует усилий, но это отличный способ быть в авангарде современных методов разработки и очень полезный для разработчиков. Gitlab предлагает интеграцию с Kubernetes, а Amazon Web Services предоставляет доступные кластеры kubernetes и поддерживает такие инструменты, как cdk8s, для реализации декларативного подхода, при котором мы можем использовать Java и шаблон Builder для программного создания файлов yaml, которые могут быть развернуты в работающем кластере k8s. Возможности безграничны.

Docker и Kubernetes тесно связаны с DevOps в том смысле, что они позволяют разработчикам управлять ресурсами и средами и предоставлять их таким образом, который несколько лет назад обычно предоставлялся “ребятам из DevOps”.

Написание хорошего кода

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

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

  • Состояние и распространение состояния являются источником многочисленных ошибок. Если происходят события, которые вы не контролируете, изолируйте эти события заранее и убедитесь, что состояние не просачивается дальше, чем необходимо. Обработка данных, как и чтение из базы данных, всегда является действием с отслеживанием состояния, и мы не всегда можем делать предположения, которые всегда верны в отношении наших данных и их структуры: “это поле никогда не будет пустым?”, “Может ли этот список быть пустым здесь?” и т.д. То, что я считаю очень подходящим подходом, который косвенно ориентирует вас на такие фреймворки, как Spring boot, – это использовать концепцию “луковой архитектуры”. Заимствованная из функционального программирования, эта архитектура, как следует из названия, состоит из слоев, где внешние слои являются уровнями с отслеживанием состояния и где информация течет от внешних к внутренним слоям. Изолируйте выборку и обработку данных на определенном уровне (например, для абстракции хранилища Spring над используемой вами базой данных) и убедитесь, что никакая информация не может передаваться с этого уровня на уровни, которые непосредственно отвечают за логику вашего бизнес-домена, например, отправка ответов клиенту.

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

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

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

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

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

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

  • Напишите свой код таким образом, и вы увидите, что он хорошо поддается тестированию. Пишите модульные тесты И интеграционные тесты. Оба типа важны, и они могут тестировать различные уровни вашей архитектуры. Чем ближе вы приближаетесь к “внешней оболочке” onion, где все может стать более отслеживающим состояние (например, вызов конечной точки или взаимодействие с базой данных), тем сложнее тестировать, вам могут понадобиться тестовые данные, mocks, обычно вам также нужен целый “контекст тестового приложения”. Это происходит потому, что при работе с состоянием количество движущихся частей увеличивается, и эта сложность также отражается на тестах.

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

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

Вывод

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

Оригинал: “https://dev.to/brunooliveira/aspects-of-good-code-and-design-hc8”