Обновить
162
0.9
Кирилл Мокевнин@toxicmt

Программист & Предприниматель

Отправить сообщение

Почему нужно использовать DTO

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

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

  • Модель => DTO => json/protobuf/sql...

  • json/protobuf/sql... => DTO => Модель

Нафига? Почему не сразу преобразовывать из, допустим, json в нашу модель или наоборот? Тем более во всех экосистемах есть механизмы, которые позволяют упаковывать любые объекты, задавая правила преобразования через метаданные, аннотации или еще как-то. Пример из Java:

@Entity
public class User {
    @Id
    private Long id;
    @JsonIgnore              // приходится скрывать
    private String passwordHash;
    @JsonProperty("created_at")
    private LocalDateTime createdAt;

    // getters/setters ...
}

var json = new ObjectMapper().writeValueAsString(dto);

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

Одна и та же сущность для внешнего мира редко представляется одним способом. В зависимости от задачи, это может быть один набор полей или другой. Как это разрулить? Дальше, здесь плохо контролируется процесс, легко может быть такое, что новое поле автоматически попало наружу, хотя вы этого не планировали, но забыли его исключить. А если нужны вычисляемые поля или другое представление (всегда в датах)? В такой ситуации модель будет наполняться доп свойствами и методами, которые готовят доп данные для преобразования, что ведет к сильному загрязнению кода. Что из этого относится к бизнес-части, а что к представлению? Проблема.

DTO позволяют отделить представление от модели в коде, создавая по сути промежуточный слой. Имея его, вы можете независимо развивать свою модель и API для взаимодействия с ним. И да, это один из аспектов MVC, конкретно Model-View.

Готовые DTO гораздо легче чем модели конвертировать в типы на TS если у вас есть такая потребность. Например мы наши DTO (используем Alba), превращаем в типы TS с помощью готового инструмента (Typelizer). С моделями так легко не получится.

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

Но это только базовая история. Если мы еще подключаем инструменты генерации из sql (как в go) или openapi как везде, то те самые DTO создаются вообще автоматически на основе описаний.

INSERT INTO links (original_url, short_name)
VALUES (sqlc.arg(original_url), sqlc.arg(short_name))
RETURNING *;

DTO:

type CreateLinkParams struct {
	OriginalUrl string `json:"original_url"`
	ShortName   string `json:"short_name"`
}

Причем для update будет создана своя структура:

type UpdateLinkParams struct {
	OriginalUrl string `json:"original_url"`
	ShortName   string `json:"short_name"`
	ID          int64  `json:"id"`
}

Здесь отличается только id, но в реальных кейсах, отличий в создании или обновлении одной сущности обычно значительно больше, поэтому количество DTO тут становится еще больше.

DTO, кстати, должны быть имутабельны, иначе туда потечет логика

Больше про разработку в моем телеграм-канале Организованное программирование

Теги:
+6
Комментарии1

А всё таки, когда моки зло, а когда нет?

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

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

Последний случай, описывает процесс мокирования. То есть мок, это когда мы проверяем то, как код что-то делает, а не что он делает. Иногда говорят, что мы тестируем методом white-box, потому что мы знаем как конкретно написан тест и завязываемся на это, а не на результат работы этого кода, как в black-box тестировании.

Когда мы проверяем как код работает, мы связываем тест с внутренней реализацией. Любое изменение внутри функции (например, вызов другого метода или смена порядка действий) может поломать тест, даже если внешнее поведение программы остаётся тем же. В итоге тест перестает быть защитой от ошибок и превращается в тормоз для рефакторинга. В подкасте про спринг я услышал классный термин: "бетонирование кода", вот это оно и есть.

Когда же моки все таки нужны? Допустим мы пишем систему с поддержкой хуков, например фреймворк для тестирования. В тестах такого фреймворка вполне допустимо проверить что хуки setup, teardown, beforeSetup, afterSetup и так далее, вызываются в нужном порядке и с нужными аргументами.

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

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

Например:

  • База данных, которая хранит данные в памяти.

  • Фейковые сервисы какого-нибудь облака, например AWS

  • Поддельный HTTP клиент, который возвращает заранее заготовленные ответы.  

  • Заглушка почтового сервиса, которая записывает письма в список, а не отправляет их.

Все эти решения делают тесты быстрыми, предсказуемыми и независимыми от инфраструктуры, при этом вы все еще проверяете поведение системы снаружи, не нарушая принцип black-box.

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

Итого

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

Больше про разработку в моем телеграм-канале Организованное программирование

Теги:
0
Комментарии0

Управление сложностью

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

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

Ниже 5 рекомендаций, по тому, как определить, что выстрелит, а что можно отложить на потом и не сильно париться с кодом.

Грамотное управление состоянием

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

Изолированная сложность

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

Приоритеты слоев

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

модели + структура базы => обработчики (контроллеры, сервисная история) => вывод (сюда же переводы и работа со строками)

Публичные контракты (API)

Все что выставляется наружу, будет иметь серьезные последствия в будущем. Хрен что поменяешь и поправишь. Поэтому на проектирование API нужно уделять внимание. А для этого нужно немного прокачаться, например, в том как делать REST API, знать про открытые и закрытые схемы, про принципы формирования ответов, обработки ошибок и всего такого (а они там есть). Это не хухры мухры, когда речь идет про проектирование каких-то сложных действий, авторизаций и других механизмов.

Отложенные решения

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

- Все, что можно поменять без боли - оставляем простым.- Все, что будет трудно поменять (API, модели, схемы БД, протоколы взаимодействия) - продумываем особенно тщательно.

Больше про разработку в моем телеграм-канале Организованное программирование

Теги:
Всего голосов 6: ↑4 и ↓2+2
Комментарии2

Какая должна быть длина у функций?

Щас скажу кое-что неочевидное. На эту проблему нельзя смотреть в статитке. Вот правильно 4 строки, 10, 100, поэтому разбиваем как-только доходим до предела. Я смотрю на это в динамике.

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

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

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

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

p.s. Смог тут загуглить исследование сотен миллионов строк на гитхабе: https://arxiv.org/pdf/1806.04556 (на скрине выдержка)

Больше про разработку в моем телеграм-канале Организованное программирование

Теги:
Всего голосов 5: ↑4 и ↓1+4
Комментарии3

Как научиться программировать лучше

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

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

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

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

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

Мой личный топ того, что учит писать грамотный код на высокоуровневых языках, где мы фокусируемся на создании правильных абстракций это SICP/HTDP + попрактиковаться в написании кода на одном из популярных функциональных языков.

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

И это не только мое наблюдение, почти все ребята с кем мы тогда активно тусили в разных комьюнити, пересекались на конфах и дружили, в целом отмечали как фп (в частности clojure, haskell, ocaml, erlang) значительно сдвигали понимание программирования.

Почему это так? А потому что в остатке мы упираемся в побочные эффекты, барьеры абстракции (тут сикп) и грамотное управление состоянием. Вот такие пироги

Больше про разработку в моем телеграм-канале Организованное программирование

Теги:
Всего голосов 10: ↑8 и ↓2+7
Комментарии2

Полиморфизм и наследование

Каждый раз, когда я слышу от кого-то описание или определение полиморфизма, там присутствует слово "наследование".

> Объясните что такое полиморфизм? Ну это когда базовый класс и наследники...

Давайте по порядку. Полиморфизмов вообще существует больше чем один. Но, все таки, когда речь идет про массовое программирование (простите функциональщики), по умолчанию говорят о полиморфизме подтипов (subtyping). Упрощенно, в этом полиморфизме мы заменяем иф на общий метод для разных типов объекта. Таким образом сам объект (его тип) определяет реальное поведение, а вызывающий код про это не знает, он просто дергает метод (или методы):

function doSomething(logger) {
  // Где-то снаружи выбирается конкретный логгер
  // Разные логгеры могут работать сильно по разному
  logger.info('hey');
}

Что мы тут получили? Возможность менять поведение конфигурированием приложения (меняем тип объекта во время настройки), а не тем, что ходим по ифам где выбирается конкретная реализация и меняем там код.

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

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

Больше про разработку в моем телеграм-канале Организованное программирование

Теги:
Всего голосов 6: ↑3 и ↓30
Комментарии2

Как правильно откатывать миграции? Если коротко, то никак.

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

Ролбек, в идеале, это просто переключение с одной версии кода на другую. Но ведь тогда возможны ошибки связанные с изменениями в базе? Если делать через жопу, то возможны. При правильном подходе, база всегда обратно совместима как минимум на одну версию. Только в этом случае мы можем обеспечить и бесшовный деплой (zero downtime deploy) и практически моментальный откат.

А это значит, что нельзя менять тип у колонок (если тип сужается), нельзя менять именования таблиц и полей. Если это все таки нужно, то существует немало техник, позволяющих сделать переход через создание новых сущностей и синхронизацией либо через код либо через саму базу (например с помощью триггеров). По этой теме даже написали целую книгу "Refactoring Databases: Evolutionary Database Design".

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

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

Больше про разработку в моем телеграм-канале организованное программирование

Теги:
Всего голосов 8: ↑6 и ↓2+5
Комментарии2

Глубокий спец vs Фулстек. Я наверное никогда не устану говорить об этой теме, потому что для меня фулстек это нормальное состояние разработчика, в смысле легко достижимое, а не история про то что это обязательно плохой спец во всем. Более того, для меня норма, когда разработчик:

- Может в бек в несколько языков
- Может во фронт
- Умеет и настраивает пайпланый от Docker Compose до Github Actions
- Может сетапить и настраивать облака

(дисклеймер: речь не о том, что таким должен быть каждый, а что это не рокет сайнс все это уметь на хорошем уровне, достаточным чтобы классно делать проекты)

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

Знает ли досконально все? Вообще не факт, а скорее всего нет. От того что человек занимается только чем-то одним, не означает что он сидит и как не в себя копает во внутрь по этой теме. Как правило я вижу другую картину, если делать долго и упорно одно и тоже, то в какой-то момент это все делается на автомате, а дальше человек просто останавливается в развитии (соседний фреймворк не считается) ну либо становится тем, о ком я пишу выше.

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

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

На практике все чуть сложнее. Главный фактор, который вижу я, помимо “я не буду этого делать” - компания и команда в которой работает человек. Где-то это норма, где-то нет и в зависимости от этого и идет рост.

p.s. Больше про разработку я пишу в своем канале Организованное Программирование

Теги:
Всего голосов 7: ↑5 и ↓2+3
Комментарии10

Знаете как часто это бывает, когда разработчики говорят что мой код, который я написал полгода назад сейчас выглядит отвратительно. Знакомо? Через это проходят все, кто так или иначе начинает заниматься разработкой и нарабатывает опыт в свои первые годы. Но сколько это может продолжаться?

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

Смотря назад, я понимаю что поворотным моментом в моей карьере стал период, когда я увлекся функциональными языками и курсом СИКП, по которому потом во многом строилось обучение на Хекслете. Произошло это так, я видел что вокруг меня, многие профессионалы, говорят и используют функциональные языки и какие-то связанные с этим подходы. В тот момент речь шла про erlang, scheme/racket (для сикпа), clojure и haskell, которые я в разной степени начал изучать. На эрланге даже получилось сделать проект codebattle.hexlet.io, который потом, спустя много лет переписали на elixir (это опенсорс).

Изучение этих языков многое перевернуло в моей голове и дело даже не в том что они функциональные, а в том, что в среде программистов на этих языках поднимались вопросы, с которыми я раньше не сталкивался. Я понял что смотрел на разработку не на том уровне. Весь мой предыдущий опыт был скорее в стиле вот чистый код, вот мартин, вот фаулер, вот ООП, вот паттерны. Как оказалось, несмотря на здравые мысли в этой части, все же это была оболочка, а не фундамент. А фундамент лежал в таких областях как управление состоянием, изоляция побочных эффектов, конечные автоматы, statefull/stateless части системы и тому подобное.

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

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

p.s. Делюсь опытом программирования в своем телеграм-канале организованное программирование

Теги:
Всего голосов 5: ↑4 и ↓1+3
Комментарии1

Функциональное ядро, императивная оболочка

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


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

const linter = new Linter(/* сюда передаем набор правил */);
const result = linter.lint('список файлов');

Такой код вполне допустим, но он смешивает побочные эффекты с логикой работы. Почему это проблема?

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

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

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

Всего этого можно было бы избежать, если бы побочные эффекты были вынесены за пределы ядра:

const linter = new Linter(/* сюда передаем набор правил */);
const filesData = readFiles(); // С учетом исключений и добавлением метаданных
const result = filesData.map((data) => linter.lint(data));

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

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

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

p.s. Делюсь опытом программирования в своем телеграм-канале организованное программирование

Теги:
Всего голосов 6: ↑6 и ↓0+8
Комментарии1

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

На самом деле, большинство пунктов так же применимо и к другим языкам. Большая их часть универсальна, так же проста (js, php или ruby не сильно отличаются на этом уровне) и в целом универсально подходит для всего (php конечно тут выпадает). Реальная же причина популярности кроется в неожиданном аспекте. Питон уже давно основной язык изучения Computer Science в университетах по всему миру. Я не скажу сколько точно это добавляет пунктов, но если посмотреть использование питона в разрезе конкретных направлений, то видно что разрыв резко уменьшается. Та же django, внезапно, проигрывает rails в веб разработке. А это довольно серьезная часть проектов на Python. И даже лидерство в аналитике достигается скорее за счет числа людей, которые с питоном соприкасаются, но надо понимать, что реального программирования там мало и объемы кода в аналитике не идут ни в какое сравнение с веб-разработкой.

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

p.s. Делюсь опытом программирования и предпринимательства в своем телеграм-канале организованное программирование

Теги:
Всего голосов 2: ↑1 и ↓1+2
Комментарии6

Информация

В рейтинге
1 824-й
Откуда
Miami Beach, Florida, США
Дата рождения
Зарегистрирован
Активность

Специализация

Фулстек разработчик, Технический директор
Ведущий