26 августа 2013 года я получил самое сложное задание в своей жизни — написать «Hello World» на C. Большинство моих одноклассников справились с этим за 10 минут. Код был на доске. Через час не смог. Я чувствовал себя так плохо. Затем спросил моего инструктора, где двойная кавычка на клавиатуре. Она помогла. Вернувшись домой, я пожалел, что выбрал специальность «Разработка программного обеспечения». Но у меня не хватило смелости сменить специальность.

Я делюсь здесь лучшими практиками кодирования, которые я изучил за 10 лет.

Абстракция

Абстракция — наиболее важная концепция для написания крупномасштабных корпоративных приложений. В начале проекта старшие инженеры-программисты проектируют приложение и создают его анатомию, используя абстрактные классы и/или интерфейсы. Разработчики младшего и среднего уровня следуют структуре и реализуют конкретные классы. Мне потребовались годы, чтобы понять, почему мы наносим друг на друга такие приложения, как Service и ServiceImpl, которые можно объединить в один слой. Ответ:

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

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

interface FileStorage {
  storeFile(file: File): void
}

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

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

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

Базовая реализация или конкретный класс могут быть AwsFileStorageкоторые хранят файлы в AWS.

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

Допустим, некоторые клиенты хотят хранить свои файлы в своих локальных системах, а не у поставщика общедоступного облака. В этом случае вы можете добавить еще один конкретный класс OnPremiseFileStorage, реализующий класс FileStorage. С помощью абстракции все клиентские коды, вызывающие storeFile(), остаются неизменными. Потому что в интерфейсе ничего не менялось, только добавлялась новая реализация.

class Handler {
  saveFile(file: File, client: String): HttpResponse {
    FileStorage fs = (client == 'handpro') 
         ? new OnPremiseFileStorage()
         : new AwsFileStorage();
    fs.storeFile(file);
  }
}

Обратите внимание: если мы хотим добавить третью реализацию хранилища файлов, такую ​​как SftpFileStorage, то в обработчике мы должны добавить третью ветвь if/else. Наличие большого количества ветвей if/else не является хорошей практикой. Вместо этого вы можете использовать фабричные шаблоны вместе с полиморфизмом. Фабричный класс создает правильный экземпляр FileStorage на основе клиента во время выполнения. В то время как полиморфизм просто означает, что один класс или интерфейс может иметь несколько реализаций. И правильный класс реализации выбирается во время выполнения на основе контекста запроса. Возможность делать что-то во время выполнения — это хорошо, и это делает ваш код более гибким и динамичным.

class Handler {
  saveFile(file: File, client: String): HttpResponse {
    // No more if/else statements.
    FileStorage fs = new FileStorageFactory('handpro');
    fs.storeFile(file);
  }
}

Есть еще одна вещь, которую мы могли бы оптимизировать в приведенном выше коде. Когда у нас будет новый запрос, он снова и снова будет создавать новый конкретный класс FileStorage. Это нехорошо, поскольку у нас могут быть тысячи запросов одновременно. Почему мы не можем создать экземпляр этого класса один раз и использовать его снова и снова? Это известно как внедрение зависимостей. Внедрение зависимостей — это не что иное, как экземпляр класса, созданный только один раз фреймворком, таким как Spring Boot. Затем можно повторно использовать во всем приложении. Некоторая задержка и объем памяти сохраняются, поскольку мы не создаем экземпляр много раз. Вы можете называть эти внедренные классы Beans в Spring. Кроме того, Groovy может повторно использовать эти компоненты во время выполнения. Так что, если что-то нужно изменить, вы можете сделать это во время выполнения без внесения каких-либо изменений в код и повторного развертывания приложения в рабочей среде.

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

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

Лучшей практикой в ​​программировании и архитектуре программного обеспечения является поощрение слабой связи. Так что изменения не сломают другие компоненты.

Для повторного использования кода вы также можете использовать композицию, которая просто создает экземпляр другого класса в текущем классе и использует методы этого другого класса.

Принципы

  • Держите это супер Sпростым (KISS)
  • Слабо связанные, атомарные и независимые компоненты. Если класс не помещается на одном экране и вам приходится прокручивать его, не бойтесь разбивать его на части, пока он не станет достаточно маленьким и атомарным.
  • Не повторяйте себя (DRY) — используйте преимущества наследования и композиции. Но не создавайте utils-классы. Вместо этого вы можете записать код класса util в отдельный модуль.
  • Drawable и именование — раньше я тщательно и комплексно думал, прежде чем писать код. Затем каким-то образом код со временем становится спагетти. Нарисовав каждый модуль на draw.io, я смог точно указать, где он запутался. Если вы правильно назвали свои компоненты, вы сможете увидеть архитектурную диаграмму в своем коде. Не торопитесь правильно называть переменные, правильно называть классы и правильно называть микросервисы.
  • Примите A синхронность. Асинхронность — это отдельная тема. Я могу написать об этом книгу. На данный момент асинхронность делает ваш код быстрее, надежнее и естественнее. В вашей функции, если вы вызываете несколько других функций, некоторые из них могут вызываться асинхронно на основе бизнес-логики. Воспользуйтесь преимуществами очередей, потоков и ядер ЦП.

Я бы сказал, что SOLID устарел. Он делал свою работу с 2000-х по 2010-е годы. В 2023 году технологии слишком сильно продвинулись. Инженеры-программисты используют облачные технологии и адаптируют архитектуры, например, управляемые событиями. Когда дело доходит до написания современных приложений, мои новые принципы SCRDA работают лучше.

Структура папок

Серверные приложения:

  • Handler (Контроллер) — здесь в первую очередь обрабатываются запросы. Только запросы, прошедшие проверку, перейдут на следующий уровень бизнес-кода, Сервис.
  • Сервис (бизнес-код) — абстракции и интерфейсы, которые скрывают детали реализации.
  • ServiceImpl — фактическая реализация службы.
  • Репозиторий — слой, который взаимодействует с базой данных и постоянно сохраняет данные.

Интерфейсные приложения аналогичны.

  • Просмотр (презентация) — взаимодействие конечных пользователей
  • Уровень бизнес-кода
  • Внутренний уровень вызывающего абонента

Исключение составляют интерфейсные приложения. В зависимости от библиотеки управления состоянием вам, возможно, придется следовать структуре библиотек управления состоянием, такой как Redux в React и Bloc во Flutter.

Контрольный список

  • Типы использования — 1-минутное прерывание может привести к тому, что бизнес потеряет тысячи долларов. Вы можете зафиксировать эту ошибку во время разработки, если используете типы. По этой причине теперь TypeScript является стандартным в JavaScript.
  • Напишите модульные тесты — вы должны написать модульные тесты для каждой строки кода бизнес-уровня. Не просто пишите тестовые примеры, чтобы увеличить тестовое покрытие. Напишите тесты и для его контекста.
  • Обработать ошибки — Обработать ошибки в каждом слое. Разработка фичи занимает день. Это только 30% задачи. Написание модульных тестов и обработка пограничных случаев — это остальные 70%.
  • Журналы — понимайте слои журналов и будьте внимательны при ведении журналов. Например, не регистрируйте PII.
  • Стандартизируйте стили кодирования и применяйте их с помощью таких инструментов, как linting.
  • Переменные среды. Ничто не может быть жестко закодировано в кодовой базе. Он должен динамически изменять некоторые значения во время сборки в CICD. Кстати, никогда не отправляйте токены в Git, из-за чего некоторые из моих студентов потеряли сотни долларов.
  • Без комментариев — Ваш код должен объясняться сам.
  • Не вкладывать

Разнообразный

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

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

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

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