#46 Нужно ли писать юнит-тесты? Дебаты о TDD, моках и бережливом тестировании | Илья Ильиных
друзья привет это подкаст Организованное программирование сегодня со мной Илья и тема сегодняшнего подкаста - это ТД на самом деле фактически это не совсем подкаст потому что сегодня мы продолжаем традицию дебатов которую я начал с СРМ когда-то и это так хорошо зашло что я решил в общем-то регулярно их делать честно говоря не так легко это получается как я хотел бы просто по одной причине довольно легко най ой легко наоборот сложно найти людей которые такие готовы бежать со мной и обсуждать любую тему но слава богу немножко получается и сегодня с Ильёй мы обсудим э тд мы обсудим а пирамиду тестирования ну и вообще всё вокруг этого илья расскажи пару слов о себе да всем привет меня как уже сказали зовут Илья я автор канала "Куда войти" там можете все апдейты если что найти познакомиться с моим мнением поподробнее если вам оно покажется близким или нет и да я очень люблю тдд я последние года три пишу практически на 100% по тд то есть любой продакшн-код из-под меня выходит в хорошем смысле по тд это как моя вторая любимая фраза это вторая любимая фраза - это хорошо когда всё в коде знаешь когда ты делаешь вот одну точку входа в приложение и когда всё можно сделать через одно место вот это тоже хорошая фраза такая но это тоже звучит интересно так про раскажи про стеки да про стеки стеки в основном я был jaва разработчиком до начала 2024 года там я пришёл на го меня перекрестили в Гофера сказали: "Погнали к нам перекрестим" и вроде бы неплохо получилось и я сразу начал писать тоже по тд я благо есть ресурсы я за 2 недели подготовился learning Go with Tests называется вот этот ресурс и я понял как почти всё что угодно можно тестировать поэтому я пришёл со спокойной душой и понял что я не попаду в какие-то проблемы из-за того что не могу протестировать угу а я уточню твой опыт - это написание веб-сервисов да то есть это там какой-нибуд Спринбуд какие-то ну роутинка кажется эти пишки лучше не скажешь спрингбд кавка манга пасгрес соответственно сейчас Гошка гошка там много внутреннего ну тоже пазгря и так далее ну стандартный вебстек в больших компаниях скажем это так а Гошка это какой-то конкретный фреймворк или там как положит бог на душу там как товарищ майор скажет на то мы будем писать ну я почему спрашиваю потому что да потому что это имеет значение в контексте тестирования в том числе потому что у тебя в Springwood всё-таки а очень классно реализован с точки зрения тестов там интегрированы классные инструменты за тебя там решается много всяких вопросов в том числе с откатами транзакций стартом приложений и так далее а в GO если ты не используешь готовый фреймворк где-то есть но это может быть проблемой да ведь мт проблемой и есть проблема потому что первое что я написал когда пришёл - это обвязку для всех внепроцессорных зависимостей которые у нас есть на проекте чтобы они ну и в принципе даже на Спрингбуте не всегда люди хотят или могут поднимать ээ полноценные базы данных для интеграционных тестов то использовать то что SpringБot позволяет да ты вообще всё супер правильно сказал мне очень нравится что в Спрингбте повесил Спрингб тест и более или менее прозрачно он что-то тебе поднял это классно но не всегда этим пользуются вот у меня был один проект где не получилось это использовать потому что у ребят не так просто это было сделать так как миграции были в отдельном репозитории вообще там была одна база на несколько сервисов миграции были в отдельном репозитории надо было поднять БД на неё накатить миграции и никто не хотел взять и написать утилиту которая поднимет этот бедный тестконтейнер и на этот бедный тестконтейнер через бедный Quви BASйс накат миграции вот я тем человеком был и я это сделал вот но это всё равно никто не использовал но я использую по Это правда это правда это кстати вот при всей э ну скажем так продуманности и проработанности Спрингбта и наличию большого количества разных приблуд к нему да из коробки и спринга а вот эта часть меня конечно всегда выбешивала потому что когда ты приходишь из фреймворков где у тебя всё это из коробки там Jungle Raavel Rails любые вокруг них фреймворки где у тебя миграция - это часть экосистемы ты просто об этом не думаешь они просто работают и ты каждый раз когда в спринге такой: "Так сейчас мне нужно сделать миграции" и погнал с этим ликвид бейзом который там ещё по дисконфигурии чтобы он заработал честно тебе скажу у меня каждый раз вот каждый раз в новом проекте я не то чтобы всё время писал на Джаве но каждый раз когда я писал всё я делал 1 2три заработало все пакеты подключил 3 дня сижу с ликвидбейзом я не понимаю почему у меня так всегда получалось ну у меня не то что прямо какие-то проблемы с ним были ээ и с Ликвибейзом и с Флайвеем у меня особо проблем не было наверное я согласен что во многих фреймворках лучше это сделано и в частности вот ты привёл Rails я знаю что ты на Руби писал до этого так как я смотрел твой подкаст и как сказал мне очень нравится формат так вот что я хотел сказать что на самом деле и тд оно очень близко к Rails вот и многие крутые фичи они вот близки к Rйлс у меня почему-то такое сложилось впечатление потому что все ре все интересные практики все интересные рассказы в интернете которые я вижу это от ребят которые когда-то тамлs пользовались это прям что-то значит я думаю ну это исторически да так сложилось просто как раз это год когда ну там примерно одновременно появились всякие разные фреймворки но Ril действительно оказал гигантское влияние то есть вот именно миграции очень многие инструменты которые сейчас есть везде все используют они не то чтобы были придуманы Rails естественно миграции не они там придумали но вот имплементация такая что типа у тебя из коробки всё работает само это было там собрано и поэтому так это разошлось и очень многие вещи пошли конечно же в том числе оттуда и ты до сих пор кстати это довольно забавно я очень часто вижу уши торчащие ещё из старых Rails то есть например Rils велемиграции я так просто как пример скажу первая имплементация была такая они добавляли в начало номер прямо порядковый номер а как ты а не таймстмп как сейчас принято и когда ты добавляешь номер ну все очевидно кто вот с этим работал они знают что у тебя появляются проблемы при параллельной работе потому что это нормально работает когда ты один а когда вас несколько вот он миграцию делает а там какой номер будет и поэтому они очень быстро это поняли и перешли на таймстемпы но за это время очень многие экосистемы успели это скопировать к себе и так получилось что когда там уже перешли на таймстемпы у тебя многие продолжили работать на номерах и по-моему Base работает на номерах или работал до недавнего времени нет по-моему можно настроить вот ну я знаю точно что он на XML конфигах у нас был но это ну там про тот проект про который я говорю но вроде бы можно настроить угу да можно настроить ну о'кей ну это так просто такое историческое интересное что-то ну я согласен с тем что это неправильно я даже в каком-то чате это один из тех немногих кейсов когда мне помогли нейронные сети это вот будет полезно видео чтобы было охваты больше нейронные сети заколдовываю видео на популярны словами нейронные сети так вот один из немногих кейсов когда нейронные сети мне помогли это было какой-то чувак в чате зашёл и сказал: "Ребята вот у меня мигрилка и она делает миграции с циферками по очереди дайте мне линтер чтобы оно он это проверял и не давал мержиться если заметил такую проблему это простая задача и вот её неронки сделали вообще без проблем они я им сказал: "Сделай такой линтер скинул снипет чуваку он такой: "Спасибо большое пошёл себе там это в продакшн затаскивать" а я а я что-то подумал что ты ему сказал что правильно таймстемпы и спросил почему у чат GPT показал ему ответ нене не по поводу таймстмпов там ему уже до меня написали то есть я просто решил помочь человеку а не рассказать что он не прав вот я как добрый самаритянин такой встретил его да я тебе помогу хорош хватает таких да любите каждый может написать что надо таймстмп использовать и что он вообще не прав это да мне было просто интересно нейронки попробовать я им сказал сделать они сделали и получилось неплохо супер ну что я прямо чувствую что нам с тобой очень много интересного можем обсудить воспоминать всякие истории мы это сегодня сделаем а я должен наверное пару слов тоже сказать несмотря на то что многие ребята которые меня смотрят они это делают не первый день и знают гораздо больше чем я сейчас наверное скажу но понятное дело то что сюда приходит и новая аудитория поэтому просто пару слов я в каком-то смысле уже чёрт знает сколько в разработке там в 2007 зашёл и у меня конечно количество языков и стем на которых я писал оно довольно большое и при этом с тестами слава богу мне так повезло что в 2008 году я по-моему рассказывал Дима Котеров очень известный человек который мой круг сделал а вообще многие системы то есть он такой один из мастадонтов вот того времени а и мне повезло с ним поработать он книжку просто PHP в подлиннике написал чтобы ты понимал все тогда учились по его книге его знают все денвер если ты знаешь вот такая штука может быть слышал короче этот человек создатель всего этого добра вот видишь ушло ушла эпоха как говорится а у него был самый популярный форум вообще по разработке так вот а мне с ним повезло поработать именно он привил ко мне любовь к тестированию и научил очень многим практикам и вещам и у меня был период знаешь таких вот когда бросает тебя фанат тестирования а потом ты поровал хаски или по-другому на это посмотрел потом с типами без типами динамика значит с базой моки шмоки рспеки там другие разные подходы а тут у тебя кукумбер а тут бд а я действительно за всю свою жизнь очень много этим увлекался много про это писал и более того у меня есть такая история что на некоторые работы брали только по этой причине то есть знаешь как я когда проходил собеседование у меня люди такие: "О слушай чувак да ты в тестах сечёшь давай тебя возьмём потому что нам как раз надо выстроить систему" я так перешёл когда-то на Rub потому что когда я их спросил: "А что вы меня взяли-то я же как бы PHP разработчик да там конкуренция" они говорят: "Слушай ну мы хотели чтобы ты нам помог с вот выстраиванием сийки там пайплайнов и всего остального" поэтому я эту тему обожаю готов про неё тоже бесконечно говорить и вот прекрасный у нас с тобой момент это всё пообсуждать но есть всё-таки нюанс я хочу сказать потому что поскольку опять же много на эту тему дискутировал всё-таки есть разница э где ты эти тесты пишешь потому что например ну просто чтобы знаешь мы границы описали потому что сейчас к нам прибегут ребята скажут: "А вот у меня там виртуализация или я там под микроконтроллеры что-нибудь пишу" то есть мы с Ильёй фактически как ни крути так или иначе веб-девелперы в каком-то смысле то есть крудошлёп я крудошлёп так и говори да мы Jon перекладчики дададакладчики не пишем игры мы не пишем софт под микроконтроллеры мы в общем-то мы даже мобилки-то не пишем несмотря на то что там какой-то опыт тоже есть но это типа не считается для текущего дня поэтому и даже мы когда про фронтенд будем говорить я в этом плане как бы тоже его пишу там тестирую но наверное может не очень твоя тема да хотя мы пару сложим очень моя тема о'кей поэтому короче наш фокус - это классические бэкэнды клиентсерверные немножко фронт-энд но остальное там уж как пойдёт если что-то вспомним а это сразу такая некое вот ограничение того о чём мы говорим но поскольку этого много и таких людей наверное больше всего то как будто бы мы попадаем в аудиторию хорошо давай прямо начинаем с вообще пирамиды тестирования а которую просто вот человек который куда попадает да ему её показывают а-а ну все помнят если что напомню в двух словах да что у нас как она вот так да изображается у тебя там внизу юнит-тесты там более высокие высокие ну так вот в двух словах до end to тестирования а что ты скажешь по этой пирамиде актуально не актуально согласен не согласен ну я с тем как я пишу тесты я пишу как наверное понятно потдд я даже более скажу я по лондонской школе пишу поэтому может с тобой сильно будем не согласны я не знаю как ты к этому лондонская школа ну ну расскажи да это интересно ну я потом расскажу если это ну чтобы и для зрителей было понятно в общем потом расскажу подробнее что это такое так вот да у меня больше получается юнитов да есть такие места где больше интеграционных тестов и скорее правильно писать больше интеграционных тестов но я когда пишу тесты об этом наверное тоже поговорю поподробнее стараюсь отходить от мест от которых я не знаю то есть я начинаю писать тесты с мест которые я не знаю как реализовывать например если я мне пришёл бизнес сказал что мне надо сделать новую апишку я вначале там с фронтом утвердил API и я не знаю какая у меня ещё будет реализация какая схема база данных и я иду к этому месту точнее я иду к этим местам которые я не знаю я например взял и реализовал JRPC ручку начинаю её реализовывать понимаю какой у меня должен быть сервисный слой чтобы получилось то что получилось на уровне RPC потом я это всё с помощью моков и так далее углубляюсь углубляюсь у меня в конце получается очень много юнит-тестов прямо очень много получается часть я бы сказал это интеграционные тесты но не всей системы а интеграционные - это просто поднимаю репозиторий для доступа к базе данных с базой данных то есть чтобы проверить полноценно что там XQL реально работает а не это какой-то мок коннекшна то есть чтобы всё более-менее было хорошо и потом не словить какие-то проблемы там надо S3 поднимаю S3 надо ещё что-то поднимаю ещё что-то и тестирую с этим но только изолированной репозиторий и бывает что иногда пишу вот на го реже это получается в Спрингбте это было намного проще на го получается реже пишу тесты когда всё приложение поднимается и прямо сквозные пару позитивных сценариев пару негативных и смотрю что всё работает вот так у меня выходит тестирование и получается примерно да пирамидка тестирования угу а ну вообще то есть в целом глобально а если отвечать на вопрос про пирамиду ты считаешь что это концепт классный у тебя получается в него укладываться причём не потому что ты специально в него укладываешься а потому что у тебя такой стиль и на выходе получается пирамида правильно я понимаю ну в моём случае да пирамида подходит но я понимаю что она не всегда может подходить потому что если бы вот как я сейчас пишу небольшую для себя утилиту и там надо тестировать lsp короче я пишу реализацию lang сервер протокола вот для себя хочу написать и там больше уже будет интеграционных тестов потому что я вообще пока не знаю что я хочу в смысле бизнес-логики то есть я даже не знаю какая у меня должна быть структура я ни разу не писал LSP и там на самом деле там GSON RPC но там есть своя специфика потому что он через STD и на STDO работает там нету нормальных фреймворков на GO по крайней мере поэтому приходится что-то костылить и из-за этого там больше интеграционных тестов там буквально несколько юнит всё остальное интеграции сделано это кстати об этом тоже поговорим потому что а всегда когда у тебя контекст приложений контекст библиотека - это два разных контекста да потому что когда ты пишешь приложение у тебя в голове сразу: "О у меня сервис о у меня модели у меня" то есть у тебя слои в принципе как архитектура в голове есть а когда ты пишешь библиотеку ты такой за неё берёшься особенно если опыта мало и ты понимаешь что тут вообще никаких правил нет у тебя структура будет абсолютно вот уникальная и хрен его знает какая если ты сейчас напишешь тебе потом просто всё придётся переписывать к чертям потому что хрен его знает как оно выльется потому что в голове картинки просто пустой лист ну ты хорошо подсветил у меня с библиотеками такой проблемы уже не очень много потом не очень актуально потому что у меня был опыт я работал в команде которая разрабатывала библиотеки для остальных команд поэтому я добил руку по крайней мере в Спрингбуте у меня ну в Спрингбуте очень просто писать интеграционные тесты там даже иногда юнит-тесты оформляются как интеграционные это такой довольно специфичный сценарий но там есть свои подковырочки которые могут сделать тесты очень медленными но это я думаю без деталей потому что это неинтересно никому мы копнём копнём всё равно это интересно потому что как бы много есть интересного сквозь все фреймворки что стоит не использовать что не стоит как они подходят потому что там ну например банально транзакции ну вообще когда у тебя очистка данных в тестах вроде такая простая понятная вещь я целые видосы про это снимал а потом людям говоришь они такие: "Вау ни фига себе" особенно если у тебя экосистемы нет готовой да вот пришёл человек в Го он такой: "Понял тесты хочу писать" а тест пишет: "У тебя раз в базе что-нибуд появилось" он такой: "Ой надо очищать" начинает очищать ты имеешь в виду очищать транзакциями ставить transaction над тестом и что оно потом откатывается ты об этом ну как пример да то есть вообще как инженерное такое понимание что есть некоторые стратегии работы там с состоянием да например классическая дефолтная стратегия в большинстве фреймворках - это откат транзакции у тебя старт откат а люди которые этого не знают и допустим у них в экосистеме этого нет ты же понимаешь к чему это приводит они начинают такие то есть дойти до транзакции сложно честно тебе скажу вот я сколько с людьми общался кто в такие ситуации попадал если они не встречали это в других фреймворках ну потому что опыта какого-то нет они до этого как правило сами не доходят и я часто сталкивался с тем что они там начинают ну пытаются короче после этого всё что создали удалить ну и ты понимаешь сколько у тебя инфраструктурного кода появляется чтобы это делать а там же проблема-то ещё в том что а вдруг у тебя эксепtion ну это без фреймворка не сделать потому что он должен всё пронизывать он должен понимать и БД и когда транзакции открывать и тут ещё проблема в том что если у тебя там под капотом ещё транзакции создаются а неed транзакции - это в принципе ну не знаю баз данных которые их поддерживают многоэтапные транзакции там есть конечно save pointты у сн у этого у пагри но я ни разу не использовал не знаю как они будут работать в тестах поэтому не всегда применимо но это очень просто но я такой спойлер закину потому что скорее всего не знаю когда это будем обсуждать но я считаю что это не очень хорошая практика делать именно через транзакции откат данных вот это тоже поговорим да я сейчас скорее пока выступаю не со стороны за против хотя я честно говоря за в данном случае а со стороны дефолтного поведения большинства фреймворков то есть это просто считается дефолтной практикой я тебе могу так сказать что в пасгре сейпоинты работают просто прекрасно то есть вложные транзакции то есть ноль вообще проблем при этом обычно знаешь как они реализованы в MySQL адаптере там сделано так что у тебя грубо говоря выложенные транзакции тупо игнорятся то есть у тебя в режиме тестирования адаптер работает так чтобы у тебя не было проблем то есть для тебя это прозрачно у тебя всё равно в начале начала ну старт в конце откат и всё ну это должен быть фреймворк именно полноценный а не у всех языков такой есть ну это вопрос именно да развития экосистемы и как раз да собственно я с этого и начал что сколько людей я видел это PHP касается это Го касается то есть это там где вот в основном любят ну PHP по историческим причинам раньше просто сам понимаешь каждый сам что-то писал в Го ну тоже по историческим причинам все такие: "Нам фреймворки не нужны мы сами с усами" они берут конечно же часто очень базовые экосистемы где этого нет ну и ты либо этого не делаешь вообще либо делаешь это через жопу либо тебе приходится реализовывать нормальный фреймворк да потому что а как иначе вот ну я к тому что короче не надо ручками чистить при любом раскладе это просто плохая практика вы просто задолбайтесь с ошибками там эксеепшн всё у тебя всё в базе осталось вот соответственно это будет проблемой ну я могу говорю что потом как я это в год делаю но я не пользуюсь транзакциями я по-другому делаю ну я скажу какая-то дефолтная стратегия то есть есть транзак стратегии вот например в рельсе был прямо отдельный гем он тебе там около пяти разных т стратегий предлагал там от трункейтов и транзакций до там ещё что-то ну то есть зави в основном транкейты запускают и всё и не парятся ну тут поит наверное в том что это не то что к языку относится это вопрос твоих инструментов вот что они используют да абсолютно да хорошо значит про пирамиду знаешь ли ты вдоль ночных дорог мне запечь за слабосиком дайamмонд даймонд это пирамида или как это он называется трофи он называется а Трофи да что я читал какой-то блок у DH да он критиковал пирамиду по-моему а ну в целом про Трофи ты знаешь да да я по-моему слышал там как раз о том что Nend короче должно быть примерно столько же сколько юнитов там какая-то такая пропорция но суть в том что смещается акцент с юнитов больше на высокоуровневые тесты чтобы аля проще было рефакторить не совсем то есть это в целом как бы концептуально у тебя действительно проще рефакторить но это мы тоже вот это вот как раз когда мы про ДД будем обсуждать я скорее просто сейчас чутьчуть расскажу а у меня просто есть ещё доклад наверное ты его не видел я выступал на тех в 2021 году это последний раз когда я в Россию ещё ездил и у меня был там открывающий доклад где я вот просто в целом знаешь про всякие штуки в разработке рассказывал одна из них - это была как раз а ну такой докладнаброс то есть я говорил что вот все люди говорят про это а вот смотрите что сейчас уже как бы куда мы ушли там я и на solid накинул на всё на свете и вот там как раз я показывал трофи это ребят по парафте НТ код по-моему его зовут это чувак который library сделал для м этого фронтенд тестирования которое мы активно используем на Джес доме он там завязан вот там просто идея как бы даже не то что рефакторинг проще а то что смотрите ребят современный мир - это мир микросервисов не согласен но о'кей допустим ну и вообще в целом интеграции это это уже правда потому что у вас даже сервисы не сервисы это не имеет значения любой современный проект - это ещё 500 млрд как бы систем которые с вами взаимодействуют даже если это не вы написали внешние какие-то да вот поэтому получается что как бы то что там внутри не так важно и вообще в целом с точки зрения системы вы начинаете вот этими блоками оперировать это я сейчас не свои мысли это я как бы некую концепцию передаю и поэтому типа вот то что там тесты все дела это как бы не то что этого нет это прерогатива конкретного разработчика ну типа с точки зрения важности того как вот мы на всю систему смотрим важно что у нас эти блоки друг с другом могут нормально взаимодействовать а поскольку они стали такие маленькие что они помещаются в голову одного человека то как бы нахрена нам вот это всё да то есть это слишком как бы всё это было рассчитано на то что у вас супер сложная система в одном месте и вам надо понимать как она там работает вот юнитесты тра-та-та вот прямо такая логика а в этом всём добре и смотри когда ты говоришь вот там и юнитов мало ой в смысле одинаково там речь не про не только про то что их одинаковы их слишком их очень мало то есть там трофи он же вот так выглядит типа у тебя расходится и так сходится поэтому получается сверху мало снизу мало и вот у тебя интеграционный это такой прямо жирный жирный блок посерединке я почему-то думал что это даймонд ну может я перепутал подебатели такие вдвоём молчим сидим ну тут что добавить ты выдержку привёл я согласен я подтверждаю всё всё хорошо я согласен такой спора не получилось ну тут как бы не то что спорить давай так я всегда топил за подход вот мы тут уже давай к тд приближаться тут смотри кстати надо ещё учитывать дело в том что есть тд а есть в принципе как бы написание тестов да это ведь не одно и то же потому что у меня например был когда-то пост когда я писал что я пишу тесты до кода но я не работаю по ДД у меня есть такой даже пост где я это объяснял и вот сейчас мы с тобой про это поговорим поэтому ребят смотрите когда мы сейчас всё это обсуждаем а тут очень важно это не путать то есть отсутствие наличия ТД не равно отсутствию наличию тестов и то когда эти тесты пишутся ТД- это очень конкретная штука которая прямо некая практика того как надо делать вот Илья это объяснял мы это ещё чуть-чуть коснёмся так вот э переходя плавно в сторону вообще тестов я смотри всегда считал что интеграционных тестов должно быть больше всего почему потому что во-первых вот мы уже с тобой обсуждали а когда мы работаем в классических MVC именно клиент-серверном MVC не фронтендовом у тебя есть запрос у тебя есть соответственно а какой-то там контроллер как обычно да ну что-то в этом духе обработчик он соответственно что-то готовит и в конечном итоге у тебя всё сводится к тому что есть урл запрос и ответ а дальше там сквозной цепочкой может идти любая логика есть несколько вещей которые обычно говорят любители юнитов и тд значит типа если вы пишете такие тесты то значит у вас непонятно где там ошибка произошла типа слишком много слоёв я с этим не согласен потому что как правило слоёв довольно мало то есть у вас там ну максимум типа контроллер максимум сервис ну как правило там часто даже сервиса нет внутри немножко логика с модельками и сохранил базу то есть э я скажу так в ситуации когда там такие цепочки что там капец ничего не найдёшь это почти не встречается во-вторых это не отрицает того что на какие-то сложные куски особенно там где много состояний у меня такое отношение вообще вот к в этом плане к тестам что там где много состояний там надо конечно тестировать уже низкоуровневыми тестами потому что ты сверху просто задолбаешься восстанавливать ситуации чтобы ну проверить все эти кейсы но мой как бы подход в том что я пишу именно интеграционные тесты которые работают на уровне фреймворка это очень важно не уровень end to end to end - это слишком высокий уровень потому что когда ты идёшь снаружи в приложении у тебя появляется а очень много нестабильных тестов у тебя очень сложно их писать а как правило вообще это чужи другие люди пишут да это отдельные тестировщики пишут и завязка там и на вёрстку есть даже если ты тест ID используешь атрибуты какие-то специальные короче это всё слишком дорогие тесты которые мы пишем например только на суперкритические участки ну например банальная регистрация или оплата там типа четыре кейса на весь проект а и то в очень простом варианте так вот собственно вот я стараюсь писать в основном такие тесты потому что какая разница что там внутри у тебя внутри вот отличие от библиотек то что я вчера всегда привожу в пример там нету как бы юнитов-то не на что писать у тебя типичная модель которая в динамических языках вообще там ноль кода у тебя просто всё автоматом выводится из базы ты понимаешь да там у тебя динамически генерится ну ладно в какой-нибудь спринг ты просто пошёл и там гетеров сетеров э написал добавив там валидации сверху в аннотациях вот и по большому счёту всё дальше у тебя сервис там какой-нибудь метод аля там не знаю вход через то вход через сё и через это а если например он там часто используется много где я бы отдельно его тестировал если у тебя по сути точка одна и как правило она там какой-то крут ну допустим в простейшем случае регистрация пользователя да ты понимаешь что это одно место ну по дефолту я так пишу и получается что каждый такой тест он супердешёвый то есть там сколько ну не знаю строк пять ну типа данный обычно это кстати причём делается не ручками а у тебя есть например кстати вот я могу сказать в том же а Спрингбуте буквально недавно там классный инструмент появился я забыл его название он как в фабрике в рельсе работает он ты ему описываешь говоришь: "Вот эта моделька" и он тебе по модельке генерирует данные сразу ну это был фейкер и я делал такое у нас на работе ты грубо говоря определяешь параметр в в методе который помеченное тест Gюнитовского там подхватывает это всё специфический так называемый exнtion Gюнитовский и сам напихивает в него данные и поэтому тесту у тебя получается аля фазинг такой в тестах у тебя просто все зависимости которые могут быть случайными которые не принципиальны их значения они как параметры висят и забиваются какими-то рандомными значениями да да то есть тут отличие в том что фейкер всё-таки - это более низкоуровневая штука он тебе просто говорит что ему там email да а тут речь идёт именно о том что ты прямо эту штуку натравливаешь на любой свой класс и говоришь: "Мне нужен класс с рандомными данными" при этом ты можешь дополнительно описать по какому принципу даже с учётом связи это создавать поэтому получается что у тебя да у тебя создание ну там одна строчка в простейшем случае понятно иногда сложнее сетап бывает сложный это правда а-а запрос проверка респонса и как правило проверка в базе то есть именно прямо в базе что он стейт поменялся что что-то сущность была создана и у тебя фреймворк вот этот уровень абстракции даёт полностью автоматический то есть у тебя транзакция накатилась откатилась эти тесты как правило покрывают вот если пишешь их на все точки то есть я пишу их на все входы-выходы они покрывают 80% а ну потому что там ещё эксепшн бывает то есть я не всегда покрываю все негативные сценарии примерно 80% они крайне лёгкие в рефакторинге как ты понимаешь и более того знаешь вот часто есть такой кейс говорят: "Ребята ну как же так у вас типа а если я стартап пишу у меня всё каждый день меняется" я каждый раз говорю: "Ну давай разберёмся типа как часто у тебя меняется регистрация или там создание товара?" Ну то есть она Ну такой вот странный вообще вот тема про ТД почему-то решил поговорить это она почему-то сейчас на слуху и вот буквально только вчера вышел у праймаджина видеоролик где они по-моему 40 минут в четвером обсуждают что они не понимают тд вот ну я не знаю кто не знает что такое prim кто знает кто не знает загуглите primary там The Good The Bad The Trash The Stand Up там TDD они в общем там вчетвером поливают на чём свет стоит что-то ДД это не работает так вот продолжая то что ты говоришь на самом деле вот аргумент когда у меня стартап у меня всё меняется вот те тесты которые ты сказал это вообще джентльменский минимум который должны делать вот по-моему все вот их просто делать я согласен особенно если в фреймворках поддерживать прямо в сердечко прямо да потому что они настолько дешёвые они настолько глубоко затрагивают всё что я не понимаю просто почему их можно не писать и поэтому когда я слышу кто-то говорит: "Мне не дают время у меня стартап а у меня ещё что-то" а мне повезло в своей жизни всё-таки не просто слушать это в интернете а поскольку я и консалтингом занимался и с людьми много лично работал и как бы внутри компаний разных работал как бы на разных должностях не в смысле просто работая где-то а вот именно знаешь как такой ментор скажем так а могу сказать по моему опыту большинство людей которые это говорит они тесты просто писать не умеют потому что м знаешь с тестами какую я штуку заметил да ещё простите ребят что мы сейчас про это говорим я сейчас знаеш что понял перед тем как говорить про ТД вот прямо именно различия надо всё-таки вот про такое тестирование поговорить потому что иначе мы ну слишком много предположений будет что мы имеем в виду с тобой под тестами да когда мы в это ныряем так вот поэтому давай ска мифами мы какими-то разбираемся короче я не знаю это на твоём опыте так или нет вот на моём опыте так если человек не сидел с кем-то кто умеет писать тесты и ктому это показал вот самостоятельная попытка писать тесты она почему-то всегда проваливается то есть слишком много моков слишком много а не того уровня тестов неправильное понимание что надо тестировать или нет почему-то и плюс ка психологически сложно почему-то у людей возникает ощущение что это сложно то есть я говорю что ребят я с тестом вот в тех условиях которые мы обсудили пишу код быстрее чем без тестов и поэтому просто людей хочется спросить: "Вот ты не пишешь тесты и ты что каждый раз проверяешь руками типа или неужели это быстрее?" Я никогда не поверю что это быстрее скорее всего ты если проверяешь руками ты может быть даже не то проверяешь руками не говоря о том что часто вот буквально там в подкасте было у меня тут заметочки есть я готовился между прочим так заметочки короче там говорили что зачем писать тесты если код всё равно надо будет менять и вот к таким тестам ты не придрёшься то есть ты не поменяешь код но тесты останутся и даже более того если тебе код придётся менять то зачем мы пишем тесты чтобы спокойно менять код и почему-то не протестировать код который мы знаем что бизнес придёт через 5 минут и поменяет требования к фиче которую мы уже реализовыем она ещё буквально в процессе почему сразу не начать с тестов и вот это вот как раз предверие тдд почему любую фичутн не покрывает тестами то есть кто-то называет это бандлтестами как спор с дяде бобом там говорили что правильно бандл-тесты делать кто-то придерживаться TDD как я но я не вижу причины не писать тесты потому что зачем писать тесты если код надо будет менять потому что для этого я их и пишу код меняется я спокоен что он работает так же как я планировал вот это вот важная вещь которую многие почему-то может быть как ты правильно сказал кто-то не умеет писать тесты и просто ищет какие-то отговорки и вообще много когда мы что-то обсуждаем например когда человек говорит: "Здесь тд не работает" часто когда человек говорит что-то о чём-то он говорит что-то о себе это так знаешь неявно получается когда человек говорит что-то о какой-то вещи он скорее говорит о себе то есть вот как ты сказал что люди говорят что нету времени писать тесты а потом оказывается что просто у них какого-то опыта не хватало они не знали какие-то хорошие практики и вот в этом вот дело дело не в том что не хватает времени а что-то о себе можно было сказать что у меня не хватало времени разобраться с тестами вот можно с этой стороны посмотреть поэтому я стараюсь это во многих вещах делать если вы например считаете что тд не работает а к вам приходит человек и вы видите что он там по ТД пишет и прямо хорошо и никто на него не жалуется то может быть проблема не в практике может быть проблема в то может быть она вам не подходит но говорить что практика плохая она не работает это не очень правильно угу мы можем это свести к чему какие вот точно вещи на тему того писать тест или не писать то есть это ещё не ТД вообще в целом писать или не писать вот эти тезисы сейчас я попробую просуммировать первое а эти тесты вот интеграционные которые я назвал а вот именно в том виде в котором я про них рассказал мы кстати ссылки прикрепим у меня очень много осорсов можно прямо посмотреть как действительно на практике это происходит а они на фичи слабо влияют то есть если вы например делаете каталог продуктов вряд ли у вас он исчезнет у вас скорее поменяется там его внешний вид у вас поменяются фичи внутри него но например добавление товара оно как бы и есть и будет другой вопрос типа а что там ещё происходит параллельно с этим поэтому какой бы вы стартап не делали я не представляю какого уровня должны происходить изменения ну типа сегодня крипту продаём а завтра для кошек корм вот тогда я согласен тогда тесты вам не понадобятся но если вы ту же самую крипту продаёте но у вас там кошельки были такие стали такие вот эти тесты они просто будут скорее всего чуть-чуть допиливаться то есть они такого уровня когда они очень дешёвые они очень надёжные в отличие отту тестов а дешёвый потому что вам не нужно вёрской заниматься тогда вы просто тупо шлёте правильную структуру в правильную урл да ну там просто запрос делаете с правильными данными и проверка очень тупая то есть вы смотрите внешние проявления но опять же с точки зрения базы ничего там в браузере появилось а например что у вас там не знаю сделка перешла в состояние заказ отправлен да и всё вот и в таком случае это а не влияет второе а как я уже говорил эта история про да скорость мы разобрали изменяемость мы разобрали и третье есть поинт вот этот что типа Кирилл ну это же прямо не юниты смотри там будет ошибки а и ты не разберёшься блин ну это не так но я не знаю какого размера должно быть приложение сколько там должно кода запускаться чтобы вы не могли найти концов что происходит то есть как правило дебаг там тоже довольно короткий в плане того что так упало посмотрели откуда пришло понятно что там надо дебагинг нормальное логирование настраивать потому что не всегда это просто можно так пройти знаешь как по циклу что там у тебя плюс с минусом ты перепутал у тебя бывает всё-таки действительно система которая требует понимания там действий которые друг за другом идут и так далее вот это просто чтобы вот эту тему зафиксировать а при этом видишь я опускаюсь на уровень юнитов и вот тут разница у нас начинается а только в том случае если я понимаю что есть какая-то у меня есть прямо критерий он называется количество состояний то есть если у тебя даже сложная логика но состояние там одно ну просто что-то добавили да и так далее у тебя выходов нет ну знаешь такие количественные изменения а если это косвенно покрывается таким тестом я не буду писать отдельный тест но если я понимаю что у тебя я покрываю один кейс а там ещё например внутри комбинаторика которая на десяток других кейсов раскладывается и при этом у тебя реально может там знаешь в одном случае создалось в другом случае переиспользовалось в третьем случае если у тебя там нету денег там ещё как-то себя повело то я на этот блок иду обычно он как-то выделяется иду пишу тест то есть это вот моё как бы кредо по написанию а тестов вот в подобных приложениях ты при этом действуешь не так я единственное знаешь что хочу сказать давай то есть сейчас мы ещё не про типа TDD а вообще про вот сами тесты расскажи как ты пишешь вот в таких же ситуациях давай ситуацию классическую просто мы вокруг одного кейса с тобой разбирали у нас допустим есть уже пользователи у нас есть регистрация у нас есть каталог продуктов и а мы добавляем ну допустим это Amazon и ты создаёшь мерчанта то есть ты типа магазин создаёшь внутри сайта и вот ты на это пишешь тесты ра вот понятно что я сделаю то есть вот есть Крут есть создание а этого мерчанта я просто тупо иду и пишу соответственно постзапрос параметры тра-та-та там значит фреймворк мне это даёт транзакции откатили всё хорошо коротенький тест о'кей вот что ты будешь делать в этой ситуации смотри я хочу в начале дополнить ты говорил например что мерчанта как ты проверишь что Мирчант создался вот это вот важный момент как ты в своём тесте бы это проверил ты говорил что ты в базу сходишь и проверишь это именно тут как бы и совпадение есть и того что я делаю и того как эти тесты в принципе пишутся именно вот интеграционные во фреймворках где они встроены то есть у тебя типовая история сделал запрос и посмотрел э состояние в базе да то есть они именно на это завязаны у тебя и транзакционности всё на свете всё вместе я просто ещё скажу что мы сейчас не про джейсончики говорим это не IPIка ipiка понятно там у тебя ещё скорее всего Open AP и у тебя там валидация вообще структуры есть даже автоматическая то есть во многих фреймворках тебе не нужно проверять ручками потому что у тебя есть а формат который JSON да схема которая связана просто с выводом и он у тебя даже на уровне фреймворка может упасть то есть тебе даже как бы в тесте не надо это запускать он просто грохнется скажет: "Слушай ты тут что-то отдал" это очень спорно утверждение потому что я буквально на одном проекте там Springбot Shоop как это называется был и в этом Спрингбшопе я знал что я зайду на любой полреквест и найду багу в расставлении аннотации валидации в Спринбути вот прям половина фреймворка сколько ты не Я писал статьи мой блок начался из того что я написал статью про то как растволять аннотации в Springbot Validation API и я его всем кидал не помогало вот люди просто им надо было вот ну в спрингбуте если ты писал я думаю ты знаешь там очень просто сделать тест который ходит прямо в MVCшной ручке то есть через MOК MVC там есть специальный класс который ты говоришь: "Я хочу вызвать такую-то HTTP ручку с таким-то телом" ну мы по сути про это и говорим сейчас да да про этим интерационно да да и я на самом деле вот если бы я писал на Спрингбте я бы начал свою фичу именно с таких тестов т только скорее всего я бы вначале начал писать эти тесты не полностью интеграционные а скорее всего я сделал в Спрингбуте есть изолированный слой контроллеров я бы сделал смоками грубо говоря я бы сделал у меня был бы слой контроллеров в котором я бы проверял что у меня там валидация откидывается я бы всю валидацию настроил которая мне нужна это опять же так как я пишу ПТД я не смог бы сразу написать тест и быстро итерироваться работая с валидацией не написа без моков я просто не смог бы это физически сделать мне надо было ещё базу бы сделать и потому что у меня ещё нету полноценной реализации вот регистрации мерчента у меня этого сервиса ещё нет в сервисном слое я бы просто объявил интерфейс и вокруг него бы вначале накидал валидацию как я её представляю потом я бы скорее всего пошёл бы делать сервисный слой и у меня уже есть API для сервисного слоя потому что я его сформулировал своими тестами которые были бы на API это можно сказать такие интеграционные тесты но они поднимают не в том смысле в котором ты говоришь я бы называл это спрингбутовые тесты контроллеров вот я протестировал свои API ручки потом бы я спустился на уровень сервисов сделал бы сервисную логику этой фичи и она бы тестировалась через юниты потому что я пишу ПТД я бы вначале писал какой-то самый простой кейс что например ээ создать мерчента и там какая-то белиберда возвращается что у мерчанта там создан айдишник такой-то сделал бы такой тест потом я бы сделал что мерчента нет и прогнал бы все сценарии которые мне в голову приходят про мерчента обычно я их выписываю себе в тудушник либо в ту-ду в коде либо в редшке в проекте чтобы в какое-то место где складируются задачки я делал бы так дальше бы я отдельно тест на репозитории сделал репозиторий бы довольно хорошо протестировал а потом в самом конце когда у меня уже всё плюс-минус складывается я бы проверил складывается оно всё вместе или нет на самом деле и написал тест который ты говоришь например дёргнуть мерчанта получить адишник и там бы поднимался полностью весь контекст со всеми зависимости со всей БД наверное в случае с крудом это overkill но у меня есть такое например мнение что лучше написать простые юнит-тесты заранее вот не пренебречиями просто потому что человек который будет потом приходить он будет лениться даже начать писать юнит-тесты и взял например добавил одну строчку и у него div покрыт тестами там на сколько-то процентов и потом получается одна куча кода которая не покрыта тестами потому что всегда был чуть-чуть не покрыт и получилось так что какой-то код стал в принципе очень сильно непокрыт там очень много логики появилось которая была просто не покрыта потому что юниты не писали вот юниты они позволяют быстро так проверить места у которых есть логика а логика она иногда появляется со временем вот и как ты правильно сказал да интеграционный тест у меня был бы и я бы его правда написал в последнюю очередь он бы поднимал всё потому что опять же когда например ещё это только проект стартует это например новый API и я не работал например ещё мне сказали с Кассандрой работать я ещё с ней не работал и я не знаю как её тестировать поэтому я это бы решение как работать с Кассандрой я бы отложил на потом как её в тестах поднять я бы отложил на потом когда у мне уже я буду отдельно репозиторий писать хотя вот в этом случае я бы скорее всего в начале пописал репозиторий и написал бы тулинг вокруг Касандры но это уже отдельная тема и важный ещё момент если бы у меня фича была не только из создать мерчента но например и из удалить мерчанта я бы обязательно удалить мерчента я не буду повторяться процесс точно такой же иду сверху вниз и реализую постепенно покрываю это всё тестами я бы поступил немножко иначе вот как ты вот в самом начале ещё говорил ты в этих интеграционных тестах например что-то вызвал а потом проверяешь что в базу данных сохранилось вот я пользуюсь когда пишу тесты на репозиторий и тесты интеграционные со всем приложением я такое правило для себя сформулировал принцип э-э одного уровня абстракций что это значит это значит что когда я пишу тесты на м mv ручки вот как мы сказали с Прин позволяет дёрнуть MVC ручку вашего приложения просто в рамках вашего фреймворка и если у меня есть ручка создать пользователя мерчанта как ты сказал э и я хочу проверить что он действительно создался во-первых я проверю возвращаемый код моей ручки а во-вторых я сделаю getзапрос я не буду ходить в базу данных потому что когда я хожу в базу данных это я уже проваливаюсь и понимаю как это будет реализовано какой репозиторий надо использовать чтобы эти данные получить я бы скорее всего всё равно думал в терминах если уже end to end позволяет писать мне фреймворк то я бы скорее всего поступил вот так и преимущества вижу такие что это и читать было бы проще потому что я не должен понимать что там вот этот вот репозиторий что это действительно тот метод что у меня нигде там под капотом нету каких-то допущений то есть это полный полноценный такой насколько его можно назвать туэнным сценарий в рамках одного вашего сервиса монолита чего угодно я бы скорее всего поступал вот так и продлевая вот этот вот один уровень абстракций в репозиториях я стараюсь чтобы в тестах не было сQэля то есть если я пишу вот это второй пример где я это используют принцип если я пишу какой-нибудь тест на репозиторий у меня не будет метода у меня не будет например SQLэля с инсертом в базу данных в тесте я буду вставлять столько через репозиторий который тестирую вставлять удалять только через этот репозиторий вот такая вот штука ну кстати для меня вот как для человека который на фрейворках в основном пишет вообще идея что будет какой-то ручной скель она какая-то противоестественная то есть ты реально с этим сталкиваешься что люди пишут SQL на s я реально сталкиваюсь и иногда буквально вот я очень сильно с этого пригорел у меня было недавно к нам пришли наши товарищи майоры и сказали что у нас новая версия драйвера для базы данных сейчас ребята все обновляйтесь не обновитесь запретим вам работать короче я конечно очень расстроился что мне запретят работать но пошёл обновляться пошёл обновляться и что я заметил что тесты которые я писал по принципу вот это вот одного уровня абстракций в них вообще не было СQэля в тестах и я просто взял изменил репозиторий и он вещь в себе то есть он нигде не говорит что я говорю по SQэлю и у меня тесты легко они буквально не потребовали изменений а там где ребята писали тесты и вставляли например нцерты писали либо делиты либо транкейты писали в базе данных например почистить базу данных в базе при этом есть я просто не понимаю зачем это го а не ну это же вопрос наверное не го я уверен что если мы сейчас загулим мы найдём горм и я уверен я знаю что с таким названием есть у РМКА это это вопрос всё-таки больше уровня развития культуры но но не проблема го то есть типа люди которые хотят у них это есть они это сделают да но я тебя понимаю о чём речь да это это чисто гошный прикол потому что понятное дело что какой нахер тронкейт или инсерт руками у тебя это просто стандартная операция в любом ну в любой Рэмке и она не страдает от производительности то есть обычно же говорят: "Вот производительность" у тебя на инсерте объекты не создаются он просто генерит запрос и сам его выполняет поэтому конечно тут это уже вопрос квалификации то есть я понимаю что когда у тебя ты выбираешь из базы 10.000 объектов и они создаются там тебе уже надо думать плю эти N + О но когда ты вставку делаешь у тебя уремка ты делаешь это ручками это конечно так себе а этих ребят я понимаю да это те самые которые вот говорят что нагонь не нужны библиотеки я очень люблю ну я я это избегаю тем что обычно я делаю репозитории замкнутыми то есть они позволяют полностью себя протестировать без вот например как я себе представляю репозиторий вот например мерчента если я делаю я делаю всегда парные методы это по-моему есть ещё у Стива Маконелав совершенный код я перечитывал какое-то время назад чтобы короче мне хотелось чек-листы оттуда актуализировать в общем я и под себя и суть в том что я перечитывал книгу и заметил там что он как раз тоже эту идею говорит что объекты должны быть парные методы то есть если через объект можно вставить что-то то должна быть возможность удалить и вот по придерживаясь этого что у объекта должны быть парные методы легко можно реализовать тесты на репозитории которые не требуют написания сQля вообще никакого ну именно о мы считаем что да это здесь наверное мы и не обсуждаем это то есть у нас наверное про Икели мы и не говорим я знаешь сейчас что понял пока ты говорил у нас разное восприятие уровня тестов про которые ты говоришь понятно принцип э одного уровня абстракции с точки зрения теста но это интересно я раньше так это не формулировал то есть получается что когда ты пишешь этот тест ты его скорее воспринимаешь как end тест несмотря на то что это не уровень всё-таки это не через браузер мы запрос делаем да или там какой-то внешний мы всё-таки внутри находимся да я считаю что я тестирую юнит и никак не должен знать что у него внутри то есть если я тестирую класс я не должен знать что у него там внутри какая-то мешанина происходит если я тестирую репозиторий я не должен знать SQL он либо касандровский либо родисовый я ничего из этого не должен знать это должно быть за тулингом спрятано ну это понятно тулинг поднимает БД и это максимум который я могу знать то есть как-то там БД это поднимается как-то репозиторий на какой-то коннекшн натравливается на какое-то соединение но что там под капотом я не должен знать в тесте у меня отношение к другое я воспринимаю это не как мы делаем nend а запрос да то есть что типа мы вот такую высокоуровневую штуку и поэтому высокоуровневого мы смотрим на результат то есть если бы я писал на плейрайте каком-нибудь или селениуме я бы так и писал тесты я воспринимаю наоборот что как бы знаешь такая есть история ребята типа мы делаем очень много абстракций и мы очень часто забываем что всё что мы делаем - это какие-то даём туда данные и просто меняем структуру в базе данных прослойка у тебя может быть всё что угодно то есть ты мы могли это написать на Rub на Джаве ещё на чём-то ты можешь создать 500.000 слоёв ты тоже сразу говоришь: "Сервис" я например сервисы по дефолту не пишу то есть мы сервисы используем только тогда когда надо потому что в большинстве случаев э мы можем прямо в контроллере есть моделька создали у тебя там три строчки кода то есть сервис - это всё-таки когда у тебя взаимодействие появляется и так далее то есть у меня подход такой: добавляем только в тот момент если оно нужно вот а поэтому в этом смысле у меня отношение другое к этому то есть это ручка чтобы послать куда-то данные но я на это смотрю как в конечном итоге мы работаем с базой объясню ещё кроме того что это в принципе вот легко делать и не вызывает особых проблем есть ещё очень важный момент вот ты говоришь создание мерчанта да создание мерчанта или мерчанта мерчанта у тебя приводит к тому что ну допустим в базе создалась запись но вообще-то параллельно с этим у тебя может сработать событие которое приведёт к тому что у тебя отработает ещё довольно много всего ну например вот из последнего что я сейчас делаю на проекте COD Basics у нас то есть после того как ты регистрируешься там срабатывает событийная система там есть доменные события а что ты зарегистрировался и отрабатывает специальный хендлер который проверяет в базе наличия service то есть опросов которые тебе нужно запустить по событию ну по-любому и там есть триггер например регистрации он соответственно запускается по регистрации и не на этот запрос вот не здесь а в другом месте потом ты как бы ну кликаешь куда-нибудь тебя автоматически редиректт на этот опрос и э понятное дело что этот сам механизм можно проверить отдельно но фактически я знаю что конкретно здесь вот эта штука должна запуститься и поэтому если я просто сделаю запрос на создание там пользователя ну или в данном случае как мерчанта тебе никаким образом система через внешнюю ручку не расскажет о том что там ещё и запланировался соответствующий опрос да ну ты правильно есть некоторые кейсы которые так ну не проверить да да и для меня это не то что какой-то экстра кейс для меня это как раз и есть стандартный кейс потому что как правило там на событиях очень много внутри всего происходит поэтому я всегда смотрю на эту систему как просто для меня чёрный ящик каким образом это попадает в базу но база с точки зрения э меня не является чёрным ящиком база - это это как бы вообще центр э того что мы делаем поэтому я воспринимаю всю систему так есть методы воздействия на неё есть внутри большая история которая начинается с ручки э хендлера ну обработчики его просто по-разному называют экшн контроллер там тра-та-та внутри у тебя сервисы шмерсы у нас там есть ещё мутаторы там вот если папочки посмотреть в Спрингбте или там в Хексле там их 100.000 папок у тебя там стерилизаторы ресурсы дтошки шмошки там что только нет вот это всё для меня как бы вот типа месиво которое мы не должны знать но на выходе у тебя есть база вот я вот отношусь к этому так ну если я даже скажу я могу с этим согласиться в одном кейсе я просто почему я так вот говорю про этот принцип одного уровня абстракции потому что я травмированный человек у меня травма по моему лицу видно я не знаю у меня травма детская вот мои первые говоря про Сейчас немножко про Спрингбд поговорим я травмирован спринг тестами на Спрингбуте и у меня многие друзья которые тестируют они и долгие но отдельно тема почему они долгие сейчас я это расскажу у меня друзья которые перекрестились в ТД и которые просто любят тесты они все травмированы с тестами в Спрингбуте по одной причине потому что все любят там именно интеграционные тесты как ты говоришь но с одной проблемой нету опыта написания хороших интеграционных тестов поэтому там получается аля поднимается весь сервис и мокается каких-то три сервиса и в них делаются какие-то там три стаба потому что они там вызовутся где-то там ещё и вот когда всё полноценно как ты рассказываешь что ты дёргаешь ручку потом просто проверил через репозиторию в базе данных я бы увидел это на ревью сказал: "Красота красиво прямо так можем запускать я бы ничего против не имел" но вот спримбте травмирован тем что ребята берут и делают такой интеграционный тест и добавляют в него ещё моки подмешивают и вот тут вот начинается прикол какой-то репозиторий замокан какой-то нет какие-то проверяются результаты что моки отработали или нет я вообще считаю что если ты застабил что-то то это должно сработать если это не срабатывает это должен тест падать но не всегда так люди делают в общем происходит какая-то вот мешанина из подходов и вот когда нету структуры в тестах вот это вот очень большая проблема когда люди кучу разных подходов смешивают в одном тесте: и юнит-тест и интеграционный тест не говоря уже о том что в Спрингбте есть такая специфика что когда ты подмешиваешь моки так называемый могбин это очень сильно замедляет тест у тебя на каждый тест если ты работал со спрингбтом ты наверное знаешь про это что каждый тест будет заново поднимать всё приложение и даже более того Springбot умеет хорошо работать с разными конфигурациями для тестов он может закшировать все эти контексты очень хорошо с этим работает но вот единственный кейс когда вы реально делаете всякие могбины которые у меня на проектах любили делать и за них тест работали долго и были вообще непонятными вот это вот я этим травмирован и очень поэтому вот я топлю за этот принцип одного уровня абстракций но он мне помогает не только в том чтобы не писать такие тесты но и в том чтобы вот как я говорил рефакторить базу с одного драйвера на другой ну и в целом я отношусь к любому юниту System andдатеest как это в книгах говорится как чёрному ящику и не только на уровне репозитория но и как когда я пишу тесты интеграционные на контроллеры слушай а знаешь я сейчас что понял а мы сейчас даже тупить не будем я прямо эти тесты поскольку у меня всё на гитхабе лежит мы сейчас откроем даже обсудим потому что я думаю людям будет гораздо приятнее видеть что происходит но ты очень важную штуку затронул которую действительно стоит сказать спрингбд реально травмирует людей и я это встречал очень много заголовок видоса стримб когда я начал писать на стримбуте на спрингбуте после фреймворков не хочу всё время релс говорить а то скажу: "Кирилл задрал с этими рел" ребят у меня опыта много на разных фреймворках в том плане что я и на джанге много писал и на PHP я очень много писал причём наверное не меньше в этом смысле а там просто не существует такой проблемы ну то есть ты короче не понимаешь что вообще люди с этим сталкиваются пока ты в SpringБД не приходишь и вот ты правильно сказал есть э-э короче фича которая превратилась в проблему у тебя грубо говоря контекст а поскольку у тебя всё через контейнер да он может быть меняться индивидуально и как только он индивидуально меняется тебе приходится пересобирать весь контейнер это приводит к адовому замедлению и когда я сначала пришёл я думаю что какая-то вообще искусственная проблема потому что в моей голове вот у нас вообще такого не бывает то есть мы грубо говоря когда приложение поднимаем у нас есть чётко: база не может мокаться мы работаем с базой это очень важно потому что я потом расскажу кстати кейсы ээ смоками как удаляли 40.000 этих тестов кода а потому что не смогли работать с ним но при этом есть например внешние вызовы ну внешний вызов обязан быть за давай так не замокан застабан тут небольшой я сейчас это отступление чтобы люди понимали разницу между моками и стабами технически это одно и то же поэтому везде очень часто используется слово мог и люди употребляют слово мог а хотя раньше во фреймворках прямо было разделение стап и мог но семантически разница большая стап - это вот например ты делаешь ну допустим у тебя есть система которая ку логи шлёт во внешнюю штуку систему и она не нужна ну то есть она просто тупо мешает вы её не собираетесь тестировать она вот просто если вы запустите тест она пойдёт в какую-то внешнюю систему ну во-первых она закрыта на сийке 100% это правильно да во-вторых она просто тупо мешает может у вас вообще интернета локально нет и он там завис поэтому это называется стабом вы делаете подмену в которой ничего не происходит ну или что-то происходит но то что вам не мешает ну например логи можно класть ну не знаю в файл или вed out всё вопрос решён мог - это другое мог - это когда вы делаете подмену но ваша цель - проверить что например какая-то [ __ ] была реально вызвана то есть вы как бы сразу составом у вас код продолжает быть классным вы это не тестируете у вас чёрный ящик мог тут же делает как правило код прозрачным то есть это называется transparent да боx или whiteбокс когда вы фактически знаете что происходит внутри я скажу потом поспорим я тебя спойлерю потом поспорим потому что я пишу по лондонской школе у меня довольно много моков вот поэтому мы потом поспорим ну не я не про то что я говорю скорее сейчас я про определение не про то сколько их много или мало это другой немножко разговор я скорее про то что если ты как бы что-то подменил и твоя задача именно это проверить то есть ты прямо проверяешь эта штука была вызвана тогда это мог если ты подменил чтобы эта штука не мешала тебе тестировать то что ты хочешь протестировать ну чтобы внешние запросы не делались а тестируешь ты в принципе свой свой код это стап и поэтому отношение к томукому что если у тебя всё в моках вот моё отношение и оно довольно распространённое что плохо у тебя другое это ради этого мы сегодня и собрались ну это так я немножко отвлёкся а давай так по стеку назад вернёмся я же говорил про а собственно про скорость про скорость про скорость да производство короче получается что в Спрингбуте почему-то так получилось что принято люди начинают слишком оптимизироваться под каждый тест и они говорят: "Ой вот в этом тесте я подменю а в этом тесте я не подменю" так вот в в моей практике так мы никогда не делали и у нас даже мысли такой не возникало потому что нет такой фичи то есть ты понимаешь чётко что база у тебя работает тупо всегда у тебя ну как я могу здесь её выключить она работает всегда но например внешний запрос не работает никогда поэтому у тебя не существует кейсов при которых ты говоришь: "Так это я сейчас замокаю это сейчас не замокаю" у тебя есть общий контейнер который ну или не обязательно контейнер потому что не везде есть контейнеры смысл в том что у тебя конфигурация единая на в принципе запуск тестов и она делается ровно один раз поэтому действительно а SpringБ один из немногих вот в моей практике просто фреймворков который очень сильно влияет на стиль тестирования только потому как он устроен вот такую мысль я Да я согласен ну я такие тесты видел не только со Спрингбутом поэтому ногой я тоже такое видел когда там часть смоками часть без смоков часть в БД часть ты имеешь динамически меняется прямо в процессе запуска тестов ну например основная проблема один тест да он поднимает БД второй тест поднимает БД и добавляет туда ещё мок третий уже без мока и в целом когда в тестах мешаются и МОКи и база данных это вот это сложно уже отслеживать тут уже надо в голове держать тут идёт сохранение в базу данных а здесь мок база данных или не база данных короче начинаются вопросы я уточню всё-таки чтобы люди нас поняли речь идёт не о том что Моки используется ты сейчас говоришь именно про то что у тебя это происходит динамически от теста к тесту то есть у тебя бегут все тесты но в этом тесте так а в этом так и соответственно я об этом говорю что видимо это делают люди которые со Спрингбута пришли потому что если бы ты пришёл с динамического фреймворка у тебя бы даже мысль такая не возникла ты бы делал контейнер один общий на весь запуск ну там тнетчик был какой-то я по-бму ну вот так это это те же самые ребята да в этом плане когда я говорю Java я имею в виду cotlin.net и все вот эти языки потому что они как бы у них очень похожи фреймворки и система да угу да они тоже туда же эти ребята о'кей сейчас а мы ещё не дотдд мы ещё не тд нет смотри мы как бы в любом случае ты рассказал про уровень одного одной абстракции как ты вот множественно тестируешь и ты тестируешь там в том числе много вот по юнитам и знаешь вот кстати даже классно что мы ТД про это не говорим потому что это же вообще неважно да в данном случае использование этого слова то есть грубо говоря если бы мы слово это не использовали и не знали это же сильно не изменило наш подход ты правильно всё с Ты на самом деле очень правильную вещь в самом начале сказал по поводу того что ТД - это меньше это не скорее не про есть тестирование а есть ТД вот ТД хоть кажется что тут тестирование первое слово наверное это важно тdд - это development test driven development это в первую очередь девелопмент вы не получите идеального сюта вот поэтому как ты говоришь что ты такие тесты любишь писать вот интеграционные я такие тесты люблю тоже писать но это такие тесты я люблю писать как тесты а не как ТД то есть тdд я люблю практиковать именно через юнит-тесты а потому что так просто проще а вот если мы говорим про тесты которые позволят мне сказать спать спокойно скажем так то это в какой-то степени юниты ну не часто я такую логику пишу чтобы юниты давали мне спать спокойно какие-то тонкие места проверяли в основном это интеграция как ты сказал проверить целиком приложение что там всё проходит поэтому ты очень правильно сказал что разделил две эти вещи потому что это разные и вот у меня всему моему программированию как я рассказывал куча юнит-тестов она проходит через него и интеграционных для репозитория только потому что мне так удобнее писать это связано именно с девелопментом а не с тестированием я не пытаюсь всё идеально протестировать я пытаюсь написать код когда пишу эти тесты они получаются просто как сайд-эффект самого процесса тд вот так да-да да это вот интересно насколько с этой стороны в целом люди на это так смотрят мне кажется тут много что есть пообсуждать ребят напишите по этому поводу тоже в комментариях потому что это реально интересно я уверен у каждого есть своё какое-то прямо очень чёткое мнение по этой теме тема вообще довольно холиварная да и как бы вот мы сейчас говорим и понятно то что скорее различие оно не такое фундаментальное в этом смысле то есть есть особенности связанные с экосистемами и с тем какая инфраструктура и подходами непосредственно к девелопменту но на выходе как бы результаты часто очень похожи но там есть нюансики конечно слушай знаешь вот я прямо открыл сейчас я хочу давай попробуем презентацию сделать потому что в прошлый раз тоже говорили было бы круто увидеть но давай попробуем посмотреть я приведу пример ну и сам соответственно скажешь что ты об этом думаешь то есть это вот тесты код бесикса это всё на гитхабе можно посмотреть открыт я специально зашёл в админку потому что всё-таки не в админки мало крудов там там просто выборки как правило да кстати поэтому тесты очень тупые и вот мы сейчас просто заходи заходи в давай ранжирование поднимать видеоролик заходи в модули VI тоже зайдём я там там кассеты используются ты знаешь такое кассеты нет я не знаю а это наверное что-то связано со сNпшот-тестами нет а увидишь сейчас я кассеты покажу ну давай оп о прикинь не написал ха нашёл тест в котором ничего нет надо покритить ну вот давайте вот рею прошло ревью прошло а я сам себе ревью ну тогда понятно да да вот давай посмотрим собственно здесь всё видно прекрасно кстати есть линтеры хорошие на не знаю для Rubuби там вот ваш рабокоп есть у него это правило no assertions per test есть такой линтер в Джаве PMD по-моему такую проверку имеет да есть конечно э ну тут вопрос в том ну короче есть да если надо вот смотрите пример а тест на индекс что такое индекс это как правило список да то есть вот мы делаем запрос на урл обрати внимание кстати тоже вот в спринге этого нет здесь урлы э они не строчками то есть получается что у тебя как бы есть ещё если ты не то указываешь он у тебя упадёт с ошибкой что такого маршрута не существует и всё что здесь проверяется response success а тест три строчки то есть почти все списки тестируются так почему а потому что там на самом деле поднимаются фикстуры то есть у тебя база по дефолту заполнена и там гарантированно есть данные получается что у тебя фактически отрабатывает то есть надо понимать что там прямо вьюха да то есть она отрабатывает и тут ничего не надо делать вот к вопросу о том мм ну как бы про изменения про инфраструктуру по количеству кода по времени написа что у меня нет времени написания на тестов а тут и нет никакого времени написания на тестов потому что это просто копипаста да то же самое new вот create уже чуть поинтереснее тут видно что мы передаём параметры пост запрос эти параметры смотрим что был редирект если очень хочется можно проверить куда был конкретно редирект я честно этого не делаю потому что я считаю что это ну как бы бессмысленно а такие вещи ну ладно это не это не принципиально можно было бы ставить я обычно не ставлю считаю что это не настолько критично а просто тупо лень писать конкретные урлы и смотри видишь идёт проверка что просто в базе он есть не это всё это классные тесты то есть я бы если такие увидел я бы поставил лайк и я бы на таком проекте остался то есть я здесь вот это хороший интеграционный тест 90% тестов такие вот как бы это то как я пишу тесты в своём коде там конечно если мне скажет: "Кирилл ну где-то же есть подвох" я бы конечно сказал что подвох конечно же есть потому что например ну это кстати неважно как вы пишете тесты подготовить некоторые кейсы крайне сложно бывает да ну где-то есть проверки ну дай я просто покажу а где-то есть проверки 100% более такие хитрые но сам понимаешь это ещё на А ну вот вот смотри то самое о чём я тебе говорил Update Review а я проверяю что он был опубликован заметь до запроса делаю запрос говорю что мы его архивируем и проверяю после того что он был архивирован это вот тот самый кейс про который мы с тобой говорили с проверкой в базе не ну это я не вижу вообще никакие здесь тесты понятны и хорошо что вот сам фреймворк позволяет такие тесты писать потому что если бы не было фреймворка это пришлось бы руками придумывать этот фреймворк это был бы и 90% разработчикам им лень и вот на самом деле большая проблема с которой вот я борюсь это что те кто пишет фреймворки иногда сами не тестируют свои фреймворки и должны быть э те кто делают какой-то инструмент фреймворк так это назовём они должны предоставить инструменты для тестирования вот я часто захожу вот Rails вижу инструменты есть хорошие что писать я знаю в Спрингбуте есть хорошие инструменты я пользуюсь линтерами там вот Go Lind я недавно приводил его как в пример в одном месте так вот там офигенная просто штука для тестирования ты прямо берёшь и у тебя билдер теста вот на эту папочку запустили вот тот в нём проверь вот тут вот у тебя такие должны быть нарушения в этом файле вот такие правила на нём запусти с таким конфигом всё вообще идеально и вот когда люди делают инструменты и делают инструменты для тестирования этих инструментов я считаю это как маркер такого знаешь класса программиста то есть ребята которые думают о том как их системы будут тестировать как их инструмент будут тестировать это вот хороший показатель я им по умолчанию скорее всего доверяю потому что их инструментом даже если вот я заводил баг как раз в гонке и я понял что я в баге не прав мне сказали что типа ты не прав там не так всё работает и я понял это благодаря тестам я просто взял и свои свои гипотезы в тестах воспроизвёл с помощью их инструментарии это прямо офигенно было я себя почувствовал что ребята сделали офигенный инструмент которым можно пользоваться и пользоваться легко я никакой там гайд не читал я просто автодополнение в Вимасее посмотрел там понял что вот это вот метод надо вызвать и всё заработало офигенно это правда это правда а но у меня есть к этому какие вещи которые я тебе чуть позже скажу вот я тебе давай тебе покажу просто тест а и ты скажешь что-то об это ну вообще насколько он для тебя понятно здесь используется концепция кассет кассеты по-моему тоже придуманы в рельсе ну тут могу ошибаться но понятно что мы их используем там миллиард лет назад подобные штуки появлялись и где-то есть в других фреймворках но в целом разработчики про кассеты не очень много знают глянь что ты об этом думаешь а я тебе потом скажу что на самом деле здесь происходит как видишь кода снова полтора вот полторы строчки мне пока сложно сказать что делает вот это вот VCR кассет если честно сразу так ну ну при этом одна строчка обрати внимание да то есть использовать какую-то кассету ты вообще-то был близок когда сказал про сNпшоты и можно сказать что ты прав был только единственное - это снапшоты для пи-вызовов как эта штука работает а мы например в Stйpe её суперактивно используем с Open с OpenI потому что там ответы вот километровые просто чтобы всё это сделать то есть это о апишка специальная отдельная которая в реальности входит в Openi альтернативой то есть как смотри мне не надо чтобы ходил в Open в тесте и альтернатива - это как раз для клиента который в Open ходит потому что понятно что там через клиент делается сделать его стаб-версию подмену делать в тестах и он бы там возвращал что-то там да допустим и куда-то складывал и опять же это была бы единая конфигурация под э ну всё то есть я бы не делал это только в этом тесте то есть просто повторюсь опять же это универсальная конфигурация поэтому всё быстро работает один раз а всё поднялось в ба в смысле в память и одинаковое всегда на протяжении всех тестов но есть другой подход например когда я начал это делать я такой подумал: "Блин мне придётся реализовывать довольно ну навороченный интерфейс там много методов вот этого всего ещё куда-то это сохранять там что-то внутри надо стейт какой-то придумывать очистку может быть подумать." Я такой думаю: "Ладно что-то мне лениво" я использую кассеты кассе - это что это [ __ ] когда ты запуска запускаешь тест первый раз он реально идёт туда складывает это всё в файлике локально и на повторный запрос вот видишь вот это название это по сути название файлика там в его в папочках это кстати их можно посмотреть они чтобы ты понимал прямо комитится в репозиторий он просто этот ответ возвращает и поэтому тебе не надо а мокать или стабать в зависимости от что ты хочешь эту херню оно просто будет выполнять как будто бы запрос но он там он сни короче он делает патч там на очень низком уровне я понял это как снапшоты только с другой стороны снапшоты они сверху и они результатами оперируют а кассета - это именно снапшоты снизу то есть это то что мы хотим грубо говоря записанные взаимодействие воспроизвести была интересная штука такая вот на одном из наших проектов мы делали штуку похожую но мы не использовали её для стабов мы как делали мы брали и записывали какие у нас тоже были вот интеграционные тесты которые поднимают всё приложение дёргают ручки и у нас были ребята которые пишут документацию и они должны были брать и например говорить что это ручка вызывает там такие-то опишки вот примеры таких-то вызовов и кучу вот такой вот бюрократической ерунды делать на рукопашке там да было да и был были сделаны такие инструменты вот один из них я там дорабатывал и улучшал можно наверное это так сказать это ко всем внешним взаимодействиям добавляются интерсепторы которые записывают во время тестов что мы там сделали с какими запросами мы пошли какие ответы получили и это работало на базе вармока вот в Джаве есть такой инструмент ты можешь там сказать что типа возьми на такой-то запрос такие-то ответы отдавай именно STB для HTTP вызовов и оно всё это записывало и оформляло там в документацию это можно в Маркдаун оформить можно оформить там не знаю чем вы пользуетесь все наверное сейчас Маркдауном там Аскидоком или какой-нибудь PL yam сразу сделать просто sequнс диаграмму это всё вот в эту документацию оформлялось и у нас был тест и рядом к тесту это называлось сгенерённые такие вот документационные снипеты которые аналитики могли использовать для того чтобы сформулировать документацию с точными примерами запросов как они делаются вот такая штука была похожа но не для тестов ага а я кстати сейчас загуглил есть попытка скопипастить Веса рубевские на Java но ну не популярная но кто-то попытался это сделать да а вот я кстати открыл собственно штуку которую он складывает а теперь просто посмотри сколько здесь да то есть у тебя ну так много что ты просто обалдеешь вот а что тут с авторизацией тут нет смотри смотри обрати внимание смотри а да всё это в конфигурации настраивается ты прямо в конфиге указываешь какие ну по сути он регкспамет по-моему заменяет то есть ты указываешь что надо спрятать и он прячет хотя на самом деле можно было легко тупануть и туда это добавить особенно если это публичный репозиторий у меня но я так сразу подумал думаю хм надо глянуть я все токи да опыт так сказать не пропьёшь слава богу не вайп-кодер спасибо маме что не вако спасибо маме да пошёл как бы сразу это сделал хотя у меня были приколы когда я помню стримил м значит как я разрабатываю по-моему то ли Хексли то ли что я значит запускаю радостно плой а тогда ещё у нас это делал как Камал сейчас делает вот похожую штуку он делал там ну там достаточно легко было написан этот скрипт на ямле и а у меня дебак режим был включён и он меня как начал все инвайменты вываливать то есть я буквально ребятам на лайве показал вообще все ключи которые были на Хекслите вот всё паттерны все вот ко всему показал все ключи и я прямо вот пока типа я лайв продолжал но в это время я быстренько написал своему разработчику говорю: "Чувак у тебя есть 20 минут поменять все абсолютно доступы которые секреты ратировать" да да но он менял да вот такая вот смешная ситуация была но правда у нас правда там ещё видишь всё-таки многие из этих сервисов не публичные то есть даже зная ключи ты бы не смог ничего с этим сделать так что мы не то чтобы совсем уж лохи но ситуация была смешная вот такие вот кассеты я впол ребят если никогда про это не видели не слышали скажите насколько вам это понравилось и будете ли вы использовать это у себя в коде это тоже интересно а слушай я ещё знаешь что тогда хотел сказать раз уж мы смотрим просто про фикстуры давай про немножко поговорим про а вот твоё отношение к тестам в плане наката отката транзакции то есть я по дефолту всегда выбирают подход бывают редкой ситуации так называемый автокоммит то есть когда например у тебя письма уходят или ещё что-то они прямо вот на комит должны срабатывать и у тебя система событий под это рассчитана но мм мы а как бы вложенные транзакции постгреса обычно эту проблему решают потому что у тебя всё равно есть некий внутренний ещё внутренняя транзакция и тестах просто адаптеры правильно настраиваются а но я хотел просто тебе сказать откуда данные берутся как они работают потому что вот с таким ты возможно не сталкивался обычный подход в большинстве фреймворков - это тебе вообще самому что-то надо делать кто-то из SQL херачит у кого-то вот какая-то есть попытка там динамически создавать данные проблема в том что динамическое создание данных в базу во-первых требует постоянного ну понимаешь это очень много запросов и обычно это тяжёлая операция которая очень быстро убивает твои тесты в рельсе в этом плане я вот честно тебе клянусь я бы хотел сказать что где-то ещё это реализовано но я нигде этого не увидел есть фикстуры это данные которые загружаются перед стартом тестов в базу и она у тебя по сути сразу наполняется
снб так можно аннотацию SQL ставить и там это сильно другое вот прям чтобы ты понимал под DX Developer Experience это типа вообще нельзя сравнить смотри что такое фикстуры смотри что такое фикстуры вот у тебя просто есть сущность там юзеры смотри он сам вставляет структуру это не я сделал и ты просто вот описываешь обрати внимание что здесь есть связи то есть например вот я пишу блокпост вот смотри блокпост у тебя Нет ладно давай тебе я покажу где есть связи вот буквест например вот видишь user full знаешь что такое full full - это вот у меня название просто ключа вот он угу и знаешь ещё что очень важно у тебя фактически вот этот ключ формирует идентификатор то есть у тебя полностью предсказуемая структура идентификаторов в плане того что поэтому у тебя работает завязка в тестах помнишь как там было когда ты хочешь взять из базы пользователя тебе не надо знать его email тебе не надо знать его там какой-то параметр который ты в текстурах описал ты просто говоришь взять юзераф и несмотря на то что этого словаф в базе нет он у тебя однозначным образом конвертируется в идентификатор ну да потому что фреймворк понимает он умный потому что ф да это за это во фреймворк заложено и вот такого я не видел вообще нигде больше и поэтому каждый раз когда я куда-то возвращаюсь там обычно фабрики то есть сейчас бы кто меня слушает они уже наверное в голове такие думают: "Кирилл Кирилл как же так к фабрике а в рельсе тоже фабрики есть более того они тут во многом и появились factory Bot или Factory Girl когда в начале это было это стал прототипом для Factory Boy в джанге там много где эту штуку начали копировать но проблема этой фигни в том что она в динамике генерит слишком много сущностей и у тебя системы которые используют в конечном итоге приходит к тому что на каждый тест э прогружается вот этот контекст который может занимать там десятки таблиц сотни строк и скорость общая тестов падает там типа в 10 раз в 20 раз в 30 раз особенно когда сеты большие становятся ну смотри я такого не видел опять же это видимо какая-то да штука с потому что вы моки используете она не рельсовая она Давай так если ты не мокаешь базу то по дефолту у тебя люди все делают так: база наполняется не в начале она наполняется в процессе и поэтому допустим ты тестируешь биллинг скажем у тебя архивный план и тебе надо протестировать что человек может к на него подписаться или отписаться ты же понимаешь сколько надо сущности в базе создать то есть у тебя скорее всего там типа надо за 2 года списываний там добавить и так далее то есть в сложных кейсах это очень большой объём данных вот в текстурах ты можешь этот как бы описать это дерево и оно у тебя загрузится один раз а потом ты можешь его использовать хоть 500 раз для разных кейсов при классическом подходе тебе придётся добавлять это в каждом тесте и это занимает прямо до секунд вот настолько тяжело а третий вариант который опять же это скорее всего вот твоя история - это моканье просто и поэтому получается что у вас в большинстве случаев вообще ничего не отрабатывает но зато вы всё перемокали там ну смотри если говорить про Я никогда ну мне сейчас сложно сказать конкретно про какой мы кейс говорим но вот если бы мне надо было данные для БД подготовить кучу я честно скажу у меня обычно в БД может быть это специфика потому что всё-таки это сервисная архитектура и это не огромная система вот как ты говоришь кучу сущностей подготавливать не надо там несколько там штуки три максимум четыре каких-нибудь подготовят для теста и я не пишу обычно тесты на 10 сущности у меня я использую тесты без сущностей тесты с одной сущностью и тесты там с несколькими с двумя с тремя и из них только одна ключевая и я в каждом тесте вначале добавляю её через репозиторий как я говорил в конце я её удаляю ну в го это через хуки на конец теста и примерно так я с этим поступаю то есть в Спрингбуте принципиально ничего не было точно так же я тестировал старался много сущностей не создавать для теста потому что я почему-то не видел в этом в этом смысла и просто создаю одну сущность с ней как-то оперирую удаляю там модифицирую её зависимости создаю и это всё делалось бы через factory методы какие-то ну я говорю у тебя подход вот именно который Factory то есть когда у тебя генерация в процессе тут просто есть несколько недостатков сразу тебе скажу а есть много кейсов когда у тебя нету ну типа ты такой говоришь две-три сущности у меня вот кейс типа из серии нужен какой-то архивный план а для того чтобы был архивный план у человека должна быть какая-то целая история на которую там завязаны сложные проверки например подписка на разные планы доступы что я там до этого сделал там вплоть до того что может быть какой-то хак стоять на конкретную дату после которой какая-то фича не работала и для того чтобы тебе просто этот кейс восстановить тебе нужно понаписать ну прямо конкретно много сущностей в базе а ещё это надо в разных местах а потом у тебя есть какой-нибудь список в котором что-то выводится то есть получается что здесь мне как бы с одной стороны объём больше но я как бы понимаешь один раз это описал и ты это используешь мало того что везде ты ещё и видел как выглядят списки на на тесты на списки они просто пустые почему так потому что у тебя там всё заполнено знаешь просто как часто бывает особенно когда у тебя именно не апишка а когда у тебя hмлька у тебя ж блоков всяких есть сюда блок туда блок и он зависит от количества данных и если ты создаёшь вот этот маленький кусочек тебе всё время надо смотреть на покрытие а не забыл ли ты данные под какой-то блок ну потому что иначе он тупо не выведется у тебя ифчик не сработал и всё и поэтому когда у тебя есть вот эта большая фикстурная история заготовленная то во-первых кстати чтобы ты понимал мы это переиспользуем на 100% в девелопменте то есть это единый датасет для девелопмента и единый датасет для тестов а то есть грубо говоря когда я что-то делаю в девелопменте у меня все эти текстуры загружены и например я хочу увидеть как конкретный там архивный план а что там пишет я захожу под это я захожу видишь вот список пользователей файлики в текстуры захожу туда и я вижу и дальше в тесте ровно то же самое повторяю в твоём случае если ты в девелопменте разрабатываешь что ты делаешь там обычно вообще свои данные какие-то довольно богом забытые иногда они очень актуальные поэтому да есть этим откуда они берутся откуда они берутся ну от проекта к проекту зависит на текущем проекте мы накатываем раз со времени опусцированные данные опустицированные тоже ну у нас есть процессы свои в компании там всё это более-менее организовано там за это команды ребята отвечают целые дада не это кстати я тоже согласен то есть на определённом объёме тут тоже важно понимать что даже то что я говорю мне бы сейчас накидали в панамку а она у меня есть типа Кирилл как же так а есть у тебя реально большой проект то есть у нас как бы ну знаешь размер проекта я тоже всегда об этом говорю определяется во многом количеством сущностей и связями между ними потому что по сути ну и автоматами то есть процессы в которых они участвуют потому что у тебя по сути переходы надо программировать ну у нас там типа порядка не знаю 300-400 моделек в проекте ну типа не самые маленькие но например с каким-нибудь с шопифаем не сравнится где у тебя де там сколько десятки тысяч моделей ну да вот но в целом подход классный и вот про кассеты интересная штука я говорю я такого нигде не видел и про именно такие я бы назвал это именованные данные именованные датасеты не знаю как это правильно назвать но выглядят удобно но вот пока что я не могу представить такого в моей текущем опыте мне кажется в моих текущих реалиях такого я просто не встречу потому что для этого нужен вот такой вот всепронизывающий фреймворк для спрингбта либо rails да ну кстати если ты посмотришь для Спрингбута тоже были попытки фикстуры написать и для многих других но часто действительно фабриками обходится хорошо смотри блин я знаешь что понимаю вот у нас с тобой полчаса осталось а мы ещё по сути глубоко про Да да да и я такое понимаю что ещё хочется сказать столько классных вещей на самом деле там происходит давай вот попробуем поспорить по такой вещи вот ты говоришь ты пишешь по слоям у тебя там изолировано там контроллер тра-та-та-тра-та-тат и ты даже оговорился что это может быть оверкилом то есть правильно я понимаю что мне не надо сейчас спрашивать вопрос типа это дольше по времени то есть вот тот тест который я тебе показал то что ты пишешь у тебя занимает реально больше времени м сейчас смотря что ты име что я подразумевал под оверкилом кому-то они дублируют ту проверку которую может проверять один интеграционный тест вот это вот я называю оверкилом считаю ли я их зря потраченным временем я не скажу я не замерял но никто мне никогда не говорил что я делаю ээ я ни разу в своих проектах вот отвечаю там предупреждаю один вопрос ни разу я не работал с коллегами которые пишут ПТД у меня не было ни одного такого коллеги были ребята которые там спрашивали и говорили: "Да-да да интересно классно прикольно у меня вот я не смогу у нас на проекте код так писать но я дальше разговоров особо не было." Но суть в том что ээ я вижу такую проблему что да эти тесты могут дублировать функциональность одного интеграционного теста но я не скажу что они у меня требуют время то есть я буквально пишу тест и потом я грубо говоря генерию код то есть у меня очень маленькие тесты и я не вижу особой разницы писать без тд или по ТД я потом на всяких мелочах там разбора с индексами тем более в год там очень довольно вербозный язык поэтому вот на всяких мелочах на отладке этих мелочей всё равно съедается время и проще это сделать когда у тебя уже есть тест и ты точно знаешь что твой код работает так как ты хочешь именно юнит-тестами поэтому я именно в этом смысле назвал оверкилом что чисто как требование например к покрытию которое я считаю покрытие переоценено но как требование к покрытию вполне закрывает интеграционный тест и для э большин вот требований к качеству часто достаточно интеграционного теста в такой опишке в которой мало бизнес-логики вот но юниты они воз нам воздастся когда мы начнём дорабатывать систему и поймём что она уже стала сложной и на неё не надо будет начинать писать юниты она уже будет более-менее уже будет какая-то обвязочка какие-то поднятия какие-то там подготовленные данные просто бери и добавляй тесты и вот такой вот с самого начала создавания такой ступеньки на которую легко будет ступить и дальше подниматься усложняя систему я считаю это очень полезным но кто-то может быть со мной не согласен ну ТД эту штуку даёт но для меня эти тесты в основном служат именно как дизайн дисиisженом я когда их пишу я формулирую что я хочу в реализации сделать вот вместо того чтобы сидеть и думать я эти думания заменяю написанием теста вот так бы я это сформулировал а сколько ну вот давай допустим вот я взял сейчас пример э ну мы смотрели с тобой да там блокпост по-моему что-то типа такого создаётся или ну какая-то фигня там один тест ну сколько там не знаю строчка пять если вот мы берём только существенные строчки да там данные запрос ответ и пару проверок там стейта что-нибудь такое ну там 5-10 строк допустим сколько у тебя будет я не потому что у тебя плохо это хорошо просто хочется понять соотношение то есть сколько строк скорее всего у тебя будет вот если ты так посчитаешь ну мне сложно сказать учитывая вот эти слои то есть юниты потом контроллер отдельно сложно сказать но я же не знаю сколько у тебя этот тест проверяет тут опять же вот почему мне сложно это сказать ответить на твой вопрос потому что я не знаю сколько там конкретно логики под этими вот всеми тестами сидят то есть тест выглядит просто и я понимаю что он хочет сказать но я не понимаю как много тебе надо было доработать кода чтобы его реализовать чтобы этот тест а ноль ноль смотри если нету внешних вызовов как ты понимаешь база она ну работает это часть инфраструктуры а всё остальное ну как бы какая сколько тебе надо было написать кода чтобы вот ты написал этот интеграционный тест вот сколько тебе надо было изменить строчек кода чтобы у тебя система начала его реализовывать чтобы он стал зелёным грубо говоря ты его написал этот тест вот я думаю как ты в самом начале подкаста говорил ты бы мог писать такие тесты а потом их реализовывать это не тд как ты правильно заметил но это что-то похоже тестф разработка сделать вот тако да я вот так часто делаю я сначала на контроллер пишу тест он у меня падает типа такого он падает кстати с такого маршрута нет и дальше я пойду его например добавляешь маршрут смотришь ошибка теперь другая потом начинаешь реализовывать что-то другое и вот так вот запускаешь этот тест проверяешь близок ты к цели или нет и вот понимаешь вот я предполагаю как ты можешь работать с этим ну не на самом деле маршрут кстати даже скорее всего в начале потому что у тебя по дизайну у тебя даже вот этот метод не появится чтобы я его вызвал да то есть сначала я иду в маршрут потом пишу это кстати не всегда так часто одновременно иногда мне лениво это быстрее но в конечном итоге у меня всегда ну как бы вот тест готов и контроллер и сколько писать кода ну кода там тоже мало ну давай круто возьмём ну что там кода у тебя взял сущность из базы достал вызвал апдейт сейв и ну скорее всего вот у меня бы тогда был бы если говорим про го у меня были бы тесты на именно ручку например юниттесты вот на endpint там HTTP handler и вторые были бы у меня тесты на репозитории потому что я в гоне вижу проблему вызвать сразу репозитории потому что в GO да и в Джаве потому что всё равно всё за интерфейсом откуда мы знаем что там под этим интерфейсом репозитория вообще или сервис ээ поэтому мы просто берём и на репозитории тоже бы написал тесты ну да было бы наверное в два раза больше кода вот по моему если судить из того что ты говоришь я бы скорее всего выдал в два раза больше кода и у меня были бы тесты ещё на репозитории в дополнение к тому что у тебя есть вот я не очень понимаю кстати вот по поводу теста на репозитории смотри а давай я тебе даже продемонстрирую потому что мне просто интересно как будто может быть я что-то упускаю у тебя репозиторий с урмкой да да то есть я не очень понимаю что такое тест на репозитории когда это просто стандартный метод вот смотри давай мы открываем app я же на го пишу мне надо SQL писать руками а ну я просто хочу показать всё равно и чтобы ребята тоже показали чтобы
было Ну вот давай вот
ну вот типа такого ну ладно давай апдейт ладно о'кей апдейт вот чтобы было понятно что вот метод это здесь не репозиторий здесь actтив recкоord как ты понимаешь то есть там часто у тебя это просто actтив recкоord это просто стандартный апдейт то есть это вообще не твой метод не ты его написал не я понимаю и я говорю что это просто специфика вот я тебе говорю у меня на проекте не используется шаблоны то есть там репозитория - это просто интерфейс за которым работа с датасннекшеном вот и всё а хорошо а как бы ты это делал то есть я я правильно понимаю что поэтому тут речь скорее идёт не о том чтобы ты бы писал просто знаешь в начале это звучало так чтобы ты как бы на ручку и писал сразу тест под репозиторий речь просто идёт о том что если у тебя в репозитории в принципе нет апдейта то ты бы в целом написал бы апдейт на ну в смысле тест на апдейт правильно я понимаю ты на Да да если бы уже апдейт был написан в репозитории я бы просто написал тест один на ручку и потом бы вызвал из него существующий метод и потом бы скорее всего написал если бы у меня была возможность и были инструменты я бы обязательно написал интеграционный тест который ты с самого начала показывал то есть я бы его просто написал в конце вот и всё я понял а у меня тогда вопрос возникает вот если бы ты допустим сейчас сам выбирал и на го решил с нуля писать э ты бы инструментарий поменял или нет то есть вот мне интересно давай если возьмём репозитории там Урмка неважно уровень абстракции может быть разный у тебя главное что либо есть прямо сырой SQL который ты херачишь в прямо вот в свой коннектор либо у тебя что-то более высокоуровневое то есть какой ты бы выбрал подход
я ну я честно мне не принципиально вообще я думаю что у меня бы предпочтений не было в этом смысле я тут вот знаешь в чём проблема что мы сейчас утыкаемся мы сейчас вообще обсуждаем производительность фреймвор производительность девелопера на фреймворке каком-то и вот в Го с фреймворками проблема ээ если сравнивать с Rub или со Спрингбутом в Спрингбуте всё генерится в Джаве всё на рефлексии там в рантайме генерится тоже много чего за тебя сделано репозиторий писать руками не надо всё это буквально методы уже существующего репозитория поэтому да я согласен с тем что надо было делать меньше работы если бы писал на го но это вот сугубок к го относится в го вот так вот принято все пользуются сQэлем напрямую ом практически не используют и кстати мне когда вот про это рассказывают я всегда говорю: "Ребята а как тогда получается?" Вот мне говорят: "Типaм почти ну давай так даже нем фреймворким почти не пользуюсь" я говорю: "А как так получается что вот я с ходу гуглю а пять-шесть фреймворков у многих из которых по 50.000 старов?" Ну то есть типа 50.000 - это охереть цифра и вот я сейчас тебе честно скажу вот я загуглил вот этот ГОРМ наверное я подозреваю что я правильно читаю ну я не знаю как люди могут говорить что этим никто не пользуется если там почти 40.000 таров и 4.000 форков это да смотри я я тебе говорил что я работал в большой компании у нас есть свой фреймворк нене я даже не прол я просто в целом про скорее вот что наверное утверждение о том что никто не пользуется оно очень такое суперсубъективное потому что вот я по активности этим всем вещам вижу что очень много пользуются конечно я согласен с тобой то есть по признакам да но вот у нас на проектах я в соседних командах нигде не видел да в моём окружении ни у кого такого нету и я думаю что это даже специфика компаний во многих больших компаниях вот в гошопах скажем это так в них много чего понаписано своего то есть я уверен что где-то используется УРМ там есть для него свои когда тебе надо быстро начать то есть это намного удобнее использовать УРМ но тут ещё иногда удобнее и с Qэлем написать запрос то есть я если у вас есть вот УРМ он раскрывается и вот решает на самом деле проблемы когда он связан со всем вот как в рейссе как в Спринбуте с миграциями когда он со схемой связан когда он умеет её накатить когда он умеет откатить когда он умеет там транзакцию на тест повесить чтобы её откатить когда вот всё это есть подсказать типа подсказать когда вот у тебя есть куча разных штучек и они все вместе вот соединяются тогда появляется катарсис и вот ты такой довольный сидишь ты этим пользуешься вот как ты мне сейчас показываешь я сижу как гофер такой: "Круто вы там в рейлсмете" единственное что я могу ответить начать там про то что живой ли там Руби или нет но я не люблю такие разговоры вот но сразу уничтожил ну вот тут я просто считаю что это не очень правильно кстати я смотрел твой выпуск про Руби это офтоп но и там была прикольная тема что делаются легковесные потоки и вот там говорилось что нигде не делается как в Руби в Джаве сделали же тоже виртуальные потоки и они как вот то что вы обсуждали на подкасте с лёгкими потоками в Руби которые будут сами переключать контекст будут как в Гобе Засинка в Джаве же это реализовано уже и вот я не знаю там твой гость он видел или нет но он может в Джаву посмотреть подсмотреть как там это сделано там есть куча документов как это реализовано может ему будет интересно короче фреймворки - это круто и они позволяют удобно писать тесты вот это что можно вывести из часа сорока на шестого сейчас обсуждение что фреймворки помогают писать тесты хорошо и по тдт и не по тд на самом деле как угодно но единственное я бы хотел чтобы всё-таки не этот опять не складывался это впечатление что Кирилл тут заруби то опт и про рельсы говорит а я это делаю просто по одной по одной простой причине потому что действительно это вот как ты правильно говоришь интегрированный фреймворк где всё из коробки потому что во всех во многих других местах это скорее типа я могу говорить про отдельные элементы потому что если мне прямо спросить какой типа твой вот ОR который бы ты сейчас выбрал использовал всё такое я бы сказал дризл потому что дризл в а джесе ну в тайпскрипте это просто как бы следующий уровень и я знаю люди там приходят говорят: "Кирилл ты этот entity фреймворк не видел?" Прекрасно видел знаю говорит: "Нет он сильно отстаёт по удобству по простоте по уровню типа выводимости потому что система типов в Джейсе в Тейсе она фантастическая" так что посмотрите делают ребята большие молодцы считаю что это Number one штука вообще в мире сейчас в этом отношении но она естественно там много с чем не интегрирована хотя миграции там классные внутри есть ну ладно мы сегодня не про это хотя честно говоря вы тоже нас не обессудьте про это невозможно не говорить по одной простой причине когда мы говорим про тесты не библиотек вы просто не можете от этого уйти более того это будут ваши самые главные сложности потому что вы допустим никогда их не писали ваша экосистема не готова первое с чем вы столкнётесь - это с экосистемой а как вообще писать тесты и вот э state в базе - это одна из самых больших проблем внешний state - это вторая большая проблема ну типа опишные вызовы но есть ещё третье кстати я ещё пример скажу а например люди которые на ноде часто пишут и не пишут на Фify допустим да пишут до сих пор на Экспрессе не знаю насколько ты знаком с этими системами я тебе просто могу сказать что с Экспрессом знаком но с первой которой ты говорил нет да ну так вот прикол в том что Экспресс невозможно нормально тестировать у тебя во фреймворке этого нет там есть специальная отдельная библиотека которая патчит HTTP стек потому что там экспресс он не оторван от HTTP и ты поэтому не можешь как бы вот то что мы сейчас показывали в тестах во фреймворке и людям кажется что мы прямо HTTP запрос внутрь делаем вообще-то нет это на самом деле как бы минуя типистек он прокидывает внутрь потому что многие не знают кто не разрабатывал фреймворки что любой фреймворк в конечном итоге превращается как правило в объект и вот э между ним и в этим господи а веб-сервером на том же языке то есть это application сервер есть некий интерфейс который как бы берёт envirймен и пробрасывает его внутрь но при этом там уже это не отрабатывает и тесты по сути позволяют обращаться к этому напрямую и вот если этого нет и нужно поднимать реальный сервер HTTP вот это прямо проблема вот те же самые Спринбуд это позволяет настраивать ты им прямо можешь сказать: "Подними" они сразу у тебя резко дольше идут у тебя сервак поднимается но вроде как бы может зато отработать ещё какие-то дополнительные да вещи которые у тебя там а вот например в том же Экспрессе нет возможности работать без него и поэтому там геморрой СТИF уже есть всё сразу тесты легче писать а в большинстве этих фреймворков динамических языках там в отличие от спринга нет такого выбора там просто говорят: "Либо уж совсем end to пиши либо вот напрямую" это правильно кстати иногда выбор не нужен вот в этом плане я думаю что он лишний правильнее спринг реально кстати да он в этом плане гипермощный то есть если ты его знаешь но он вот с теми же Мками создаёт проблему которую вообще могло не существовать я понимаю что кто-то может сказать: "Не Кирилл есть кейсы расскажите про них" уверен что есть но и при этом уверен что они суперредкие потому что ну за свою вот карьеру я не сказал бы что я пишу Facebook там или Google да но всё-таки не сказал бы что я видел много кейсов когда вот тут вот прямо надо замокать а вот тут надо по-настоящему вы назовите эти кейсы а потом найдите подойдите к десяти разработчикам на Java и спросите любят ли они тесты смоками и вы увидите кучу травмированных глаз и вы поймёте что насадили люди убегают в закат вашим кейсом стоило бы пренебречь ради всех этих разрушенных судеб которые теперь не вернуть а теперь я вот вот unнит-тест - это наверное большая часть давай так я с тобой не согласен по поводу э То есть я согласен по поводу репозитория только по той причине потому которой ты сейчас объяснил что фактически у вас просто ни хрена нет и вам нужно просто с нуля делать и типы там не особо помогают потому что всё-таки на таком уровне там видимо проверки нет как в тайпскрипте может проверять либо это слишком сложно реализовать плюс просто реально это везде используется надо тестировать отдельно вопросов нет а при этом когда ты говоришь про контроллер тут у меня просто мнение другое я считаю что это ненужное смысла в этом нет это просто потеря времени у тебя вешь другое мнение но я не считаю что это та часть которую надо типа спорить как правильно неправильно не видел гошный контроллер я тебе так скажу там надо Ну конечно да там хочется сказать что что там тестировать в этом контролле в джаве тоже там P varable стоит там пару реквест quрам там ещё что-то каких-то аннотаций request body что тестировать или ты что с ума сошёл этот дед который любит тесты хватит брезжать но ты просто не видел гошныит это там может быть на 100 строк просто разбора вот этого вот штуки валидации нету из фреймворка поэтому валидацию надо руками всю накидать и самая проблема получается что да казалось бы эта логика она не критична да она вот неважна мы даже фреймворках не тестируем потому что она не важна но в ней очень легко ошибиться потому что это огромный метод там на кучу строк и его уже надо абстрагировать то есть там его надо бить потому что он уже сложный то есть это просто вот какой-то гошный шейминг сегодня получается мне очень понравилась статья одна прямо шикарная которая называется Rails is not your application ну это по сути как бы к сервисам к тому что типа ребят рельса это конечно классно но вам надо понимать что интерфейс может быть comлай у вас может быть мобилка и ваша логика не должна быть там то есть то что ты рассказываешь разбор это разве не решается какими-то не знаю автоматическими парсерами трансляторами описаниями описательными языками да не то что там ручками надо есть там тоже у нас протобув используется то есть в протобафе можно валидацию сделать ээ через генерация есть ну в протобафе можно использовать ээ валидацию например через теги да это можно сделать но это опять же можно сделать но это не очень сильно распространено и там не такой богатый выбор настроек туда нельзя инверсию зависимости сделать а добавлять свой генератор это в C сложно сделать потому что короче есть специфика проекта вот в C сложно добавить свой генератор который и я думаю что поддерживать это тоже будет сложно вот тут хороший момент что например в Спрингбте легко добавить свой валидатор который берёт и кастомно обрабатывает аннотацию и то многие не любят когда так делают потому что говорят: "Это слишком сложно" то есть новички там войдут проект не поймут но это холиварный вопрос но это намного проще чем делать там свой плагин про табуфу это намного проще чем это слушай не могу не поделиться мы вот как-то рассказывали в этом вебинаре прост есть такая штука Typees за неё сейчас топлю такой немножко стал этот адвокат этой штуки это Microsoft сделал некий язык очень похоже кстати на ТС но такой декларативный то есть это неполноценный язык программирования для описания в том числе протабуфа и э он может генерить репики эта штука генерит а и к ней там много всего она генерит open API можно было конечно сказать: "А что сразу Open API спеку не писать её сложно писать" кто её не писал должен понимать кто писал должен ну знает что это кошмар вообще должен какой-то другой быть язык который позволяет её описывать так вот я просто что хотел сказать то есть грубо говоря эта штука не просто эту генерит Open API она ещё и схемы все генерирует потому что там валидации как вот ты говоришь примерно через аннотации делаются всё вот так вот слушай дай я прямо покажу потому что это такая шикарная вещь которую а ну нельзя не показать настолько она классная я думаю тебе понравится если ты никогда её не видел во смотри зацени я не знаю понравится тебе или нет ну слушай выглядит понятно выглядит очень похоже на самом деле на протобаф не знаю насколько это расширяется то есть своими валидациями своими проверками посмотри посмотри а типа ошибок какие там ошибки смотри модель юзера всё вообще некоторые люди когда видят они такие: "Хм это типа может быть это вообще Typeesрипt?" Нет это не Typeesрипт это свой ну это очень похоже и то как в спрингбуте делается по валидации и то как ну на самом деле очень похоже прямо как будто спрингбутовая пишка но я так понимаю и в похоже есть и фреймворки для тайпскрипта поэтому тут объясню в чём разница и как бы это немножко поменяло мой подход ээ я кстати такой небольшая рекламная вставка у меня есть курс по RESTPI который пока только на ноде ну на Фестива как раз я его планирую потом на все языки перенести то есть вот этот вот подход когда там вешают валидации почему я вообще про это хотел сказать я собственно с этого-то и хотел начать ты такой рассказываешь вот там парсит тра-та-та валидации все дела а я просто уже перешёл немножко в другой режим потому что когда много тайпскрипта и вот такого дизайн first API а мне нравится идея и я уже её затестил вот на Фастифае когда ты генерируешь вот через эту штуку у тебя генерится API спека дальше ты из этой спеки через там есть там специальные штуки которые создают типы по сути под Typeesриpt вообще-то эта штука тоже может напрямую типы под typesриpt создавать и дальше знаешь что происходит опять же это конечно удобство одного единого языка и вот этой полной интеграции я думаю что в других языках что-то подобное есть но это должно быть ещё интеграция с фреймворком быть фtifй конкретно позволяет тебе задать валидацию всего входящего вот прямо полностью от и до на базе того что ты прямо над каждым маршрутом говоришь типа проверять вот эту штуку и также ты там описываешь респонс а что я туплю я собственно в этом же репозитории тебе и могу это показать прямо вот в этом потому что собственно в нём это и делать видишь это как раз называется JZ Fify вот дризл тут все мои любимые штуки а так сейчас я тебе открою маршруты просто покажу как пример как это работает во вот тебе прямо пример посмотри и я тебе сейчас прямо а в двух словах скажу что здесь происходит и что это даёт угу ну выглядит по крайней мере ну я бы сказал на спринг будет типа поприятнее это выглядит это вопрос того что здесь по сути рукопашка да то есть это не грубо говоря почему потому что штука которая генерит типа под typesрипt понимаешь она с Фастифаем никак не связана поэтому я тут ручками указываю поэтому это вопрос это вопрос как бы адаптера там миграции но на Спрингбуте нет это именно вот этой концепции сейчас я тебе объясню то есть в Спринбуте всё-таки ты просто делаешь типа проверки у тебя там нал не нал какие-то параметры и так далее здесь ты по сути передаёшь полную схему как на входящие данные так и на выходящие данные и у тебя получается речь идёт о том что например твой вот ты видишь код 2011 там сент и курс если у тебя дтошка транслирует не в то у тебя прямо в фреймворк упадёт с ошибкой даже если ты без тестов просто запустил в браузере и скажет что у тебя структура не соответствует выходу всё я понял да и вот такого я вообще нигде не видел я верю что это есть но вот чтобы массово это использовали знаешь что самое красивое самое классное в этом это не Runтайм это всё проверяется в статике м Это получается какой-то этот плагин компилятору тайпскрипта да какой-то или как нет это просто Typeesрипt это обычный Typeesрипt просто механика именно проверки а типа респонса и реквеста она встроена в fastify видишь за счёт вот этой вот параметры который можно передать ну а дальше внутри у тебя там тайп так написано типа тайпскрипта что как только я туда это передаю у меня автоматически попытка вернуть респонс который не соответствует типу определённому здесь приведёт к тому что ничего не скомпилируется ну слушай выглядит интересно сложненько но интересно ну тут сложного нет в том плане что вот это всё автогенерация чтобы ты понимал то есть всё что тебе нужно - это Open API спека грубо говоря ну так если в двух словах а а дальше автоматические трансляторы это превращают типы и всё что тебе надо здесь добавить конечно вот эту вот штучку ещё можно было бы убрать но я просто не заморочился самая главная концепция понятна так кстати к слову что я такой думаю после этого: "Блин мне и тестов-то реально надо меньше писать" то есть вот история когда ты в тесте: "А давайте респонс посмотрим и проверим что он ещё мало того что какие там данные так ещё и структуру да соответствие у тебя эта проблема она как класс исчезает в такой системе?" Да ну с этим я согласен да вот ну это как раз тем что вот есть часто я когда хожу в бар там обсуждают всякие вещи и аля одна из этих вещей - это кодрев нужно оно или нет и вот эта вот вещь когда у тебя дизайнрев согласование спеки формулирование спеки её refinement он позволяет избавиться не только от какого-то дизайна но ещё от тестирования то есть у тебя уже в спеке самой заключено понятно что надо вообще перепроверить что вот эта вот спека подходит требованиям что вы действительно хотите вот это вот поле такими что вы хотите то есть как-то это надо будет перепроверить но как будто это уже решается не на уровне приложения а наверное на общем фасаде всего приложения и может реализоваться по Ну у тебя как минимум фронтендеры есть которые Да у тебя же бэкэндеры фронтендеры какие-то внешние чуваки они генрят из этого свои сдкашки они сразу видят что несоответствие то есть тут как правило уже кросспровер кросспроверк достаточно потому что ты тесте можешь херню написать и у тебя будет фигня слушай а чему я всё это рассказывал я же не просто там типа смотрите как классно бывает я изначально хотел спросить то есть сначала чтобы ты понял а теперь спросить вот те гошные штуки про которые ты мне рассказываешь да оно порешает или не порешает вот проблему которую ты мне сейчас описывал что у тебя там 100 строчек вот этого разбора не пойми что в гошной штуке вот 100 строчек разбора можно порешать и я говорю плагинами для этого для протобуфа и там не сложно есть goго плагины для валидации которые там но они к ним сложно плагины писать вот например добавить свою например какую-то проверку сложнее чем что-то там больше или размера в массиве больше или массив не должен быть там пустым сложнее чего-то такого это надо уже приседать и я не помню что у нас где-то были у нас да автогенерация вот такие вот проверки я знаю много где они генерятся так но что-то сложнее вот нету инверсии контроля у фреймворка чтобы добавить вот возможность это сделать например протобаф он расширяем но сложный там порог входа побольше чем просто добавить валидатор вот не знаю там в какой-либо из фреймворков который мы обсуждали там себе время легко добавить не говоря уже о спрингбуте там один класс добавить ну там нету там нет инверсии зависимостей а в том плане что там просто всё глобальное так что там хватает своих проблем поэтому например контейнер мы сами подключали у А хорошо давай тогда вот всё-таки теперь про ТД и про тесты я начну с истории а ты потом скажешь у меня есть один наверное самых больших консёрнов но опять же это блин не к ТД это скорее к про ТД- это ближе наверное к библиотекам а вот если мы с тобой говорим про а вот такие системы о которых мы сейчас вот рассуждали всё это время у меня был кейс значит я устроился в компанию кто знает аф она называется как раз на Rруби перешёл с PHPA и меня в общем-то попросили там потестно помочь разобраться ребята значит если там спект такой есть ты помнишь тут как такой синтаксис вот этих вот шууд там должно быть у это вот это вот полому это да но это в Груна вообще появилось то есть это появилося в Гру потом его взяли в спекрубишный и оно очень сильно потом после этого разошлось везде это прямо такой типа мы БД делаем хотя на самом деле слово просто да по факту-то глобально ничего не поменялось там матчеров миллиарды вот вот это всё да вот и значит они начитались в книже как это надо писать там было написано что всё надо мокать база не должна работать а вообще в принципе да и при том что в рельсе это работало то есть они ещё против фрейворка как бы пошли они написали огромную тонну кода для руби это много 40.000 строк кода понимаешь если ты сконвертишь это в голи в Джаву там явно будет больше причём сильно больше потому что здесь уровень абстракции он конечно космический и синтактического сахара так вот когда я пришёл по сути эти 40.000 строк кода были полностью выброшены ты я думаю знаешь почему потому что началось серьёзное рефакторинг приложения и когда ты делаешь любое изменение а у тебя падает там допустим 100 тестов из-за этих моков люди просто не выдержали и в конце концов к херам собачьим всё это стёрли не буду никак комментировать вот мой так знаешь этот панч в твою сторону ну это на самом деле это не такой чтобы панч это ты же в самом начале сказал что ребята позвали тебя помочь им с тестами и ну у ребят был просто негативный опыт вот много тестов ну это это кстати хорошо что они этот опыт получили теперь они будут использовать я думаю сейчас используют ты наверное лучше знаешь они используют теперь я думаю комбинацию какую-то потому что иногда моки применимы иногда моки неже нет а наверное используют но в других местах ну ладно я я добавлю тогда хорошо тогда чтобы было понятно а мой поинт всегда когда говорят как мы видим с тобой знаешь как русскому хорошо немцу смерть вот есть такое выражение оно прямо про нас сейчас с тобой кстати заметь я у меня белый фон у тебя чёрный фон прямо так классно сошлось у тебя значит поинт какой тесты нужны потому что они помогают тра-та-та я сейчас про юнит-тесты у меня понт другой юнит-тесты как раз и есть причина почему очень сложно делать рефакторинг ну смотря что считать рефакторингом вот а рефакторинг как правило то есть допустим это особенно в библиотеках проявляется то есть вот прямо когда мы просто говорим про приложение того уровня которые мы сейчас обсуждали там вообще-то ну опять же слоёв мало у тебя там ну ну переименуется метод ну у тебя глобально там вот очень всё понятно и просто но то есть там нет такого что вот прямо юниты вот прямо у тебя много мелких тестов много мелких классов много мелких объектов да у тебя есть конкретно вот ДТОшко транслировали вот у тебя есть объект сущность модель вот у тебя сервис как бы ну и плюс-минус всё ну очень утрировано если ты берёшь библиотечку да то у тебя там может 500 классов и они вот в такой структуре в такой структуре а тут адаптеры а тут шмаптеры там ну как это как фреймворк тестировать по сути да там же очень по-разному можно делать угу и мой поинт в чём люди которые пишут очень много очень низкоуровневых тестов особенно вот если ещё и по ДД во время разработки да некоторые говорят что ТДД - это тесты надо выкидывать если ты их написал они тебе не нужны там есть уже такое разветление да но если ты в принципе пишешь много юнитов это приводит к чему в какой-то момент ты вдруг допустим осознаёшь что твоя структура вообще неправильная речь идёт не о том что ты метод неправильно назвал а у тебя вообще в принципе вся структура неправильная и у тебя надо её просто по-другому реализовывать мой поинт что большинство этих юнитов тебе не то что не помогут а тебе придётся их просто выкинуть потому что у тебя ну допустим если это классовый язык Java да у тебя просто сама структура классов просто будет другая если и не вся то хотя бы в той части в которой вот ты которую рефакторишь ну я понимаю что такие кейсы могут быть я в самом начале приводил мы когда раз общались я говорил что я когда вот начал писать lsp я больше пишу интеграционных тестов у меня там ни одного мока нету ещё и я думаю что у меня и не будет моков у меня будут теest doubles но у меня не будет моков потому что на го проще без моков и иногда да вот в библиотеках я буквально сегодня писал библиотечку нашу Reфакторил и там у меня тоже не было я не писал ни одного юнит-теста но у меня все тесты были ну можно сказать интеграционными да там библиотека для запуска Chromejob можно так сказать вот видишь чем че приходится самому писать вот потому что там надо скрестить ежа с ужом была и пришлось библиотеку для запуска своих джобок сделать и получилось так что да мне пришлось бы переписать если бы у меня было много юнит-тестов но там логики немного там интеграция поэтому я писал сразу интеграционные тесты тут скорее нужен опыт чтобы понимать когда тебе нужны будут интеграционные тесты а когда тебе нужны будут тесты на моках апдже я вижу например что вот у меня есть ээ из моих фич недавних у меня есть логика когда там надо сделать какой-то отчёт для отчёта надо собрать данные в отчёте надо данные как-то сагрегировать отфильтровать потом ещё надо кроме того чтобы это сделать добавить их там срендерить по ним отчёт и его потом куда-то загрузить там данные об этом ещё куда-то откидать и вот тут вот сама вся логика вот эта вот я буквально расскажу как я это писал я буквально вот по тд сел и там моки вот вовсю во весь рост раскрылись потому что и многие кто пишут такие системы они знают что есть вещи которые часто будут меняться я знаю что часто будет меняться логика агрегации потому что у меня будут меняться источники данных скорее всего к ним надо будет по-разному делать запросы они будут меняться их надо будет отдельно менять я сразу закрыл их за отдельным интерфейсом его замокал и вот часть агрегации я о ней даже не думал я объявил данные которые мне нужны будут для отчёта которые я понимаю а как их получать я пока не знаю и вот я сделал намоках сформулировал свои предположения что мне надо будет в таких вот входных данных вот такие вот данные и такие-то ошибки должны быть в таких-то комбинациях они могут быть и всё это я понял с помощью Мока мок мне помог это понять то есть я когда писал юнит-тест на вот эту вот генерилку отчёта я сформулировал свои требования к тому что я дальше буду реализовывать с помощью МОКА потом дальше что я сделал дальше я пошёл реализовывать этот агрегатор и у меня есть куча систем из которых он собирает данные и я тоже не хотел сразу писать там адаптеры к этим системам они по-разному работают и я просто закрыл их за интерфейсами потом всю эту агрегилку сделал там лишние данные от них подрезал лишнее убрал что-то отфильтровал и у меня получилась вот такая вот первый слой генерации отчёта он работает на моках потом я его реализовал и моками сформулировал требования к нижним к его зависимостям потом я взял и начал его зависимости реализовывать если эти зависимости ещё не конечные аля это не репозиторий либо не интеграция с какой-то там HTTP GRPC там GFQL ручкой я её тоже делаю через Моки а вот потом когда я дохожу до этого места которое уже должно быть само интеграции вот сам транспортный слой который транслирует мои бизнес-объекты в какую-то там стороннюю ерунду вот в этом случае я уже поднимаю интеграционный тест в БД-то поднимаю БД и с ней тестирую там уже моков никаких не будет и даже более того скажу я потом пошёл дальше часть вещей которые всё ещё относились к бизнес-логике например но они относились к интеграции например генерацию отчёта надо было делать эксельные отчёты но я решил сделать иначе я вместо того чтобы делать моки вот это вот абстрактного отчёта я сделал иначе я взял и создал csвишный отчёт и у меня в тестах работают csвишные отчёты я могу брать и проверять какой у меня отчёт сгенерился у меня есть несколько генераторов отчётов есть xcсельные есть csвишны в тесты использую csвишные с ними проще работать и это всё я сделал с помощью моков то есть я с помощью моков составил требования и вот часть с моками которая связана с отчётом изначально у меня отчёт - это был тоже мог но потом когда я понял как он должен выглядеть какой у него должен быть интерфейс я взял и реализовал csвишный мок и просто взял буквально в самом начале теста место где я создаю мок вместо него создал CSV там отчёт и он заработал и всё тест работает но теперь с настоящим рендерером который генерит реальные данные и вот тут такая вот пазл сложился и вот так вот я использую Моки то есть да не везде они применимы но когда мы ещё не знаем как у нас будут работать какие данные как мы хотим сагрегировать чтобы сконцентрироваться на одной задаче можно использовать Моки понятно что если я сяду и пойму что агрегации у меня теперь не должно быть теперь у меня агрегация это отдельный сервис её предоставляет мне не надо самому там ничего париться ну да я просто выпилю все эти юнит-тесты которые я писал на агрегатор и реализация агрегатора у меня просто подменится на ту которая будет ходить уже напрямую в этот сервис и она станет интеграционным тестом будет уже в рамках него делаться но так можно говорить что ну я же писал этот код и иногда код надо удалять ну да иногда код надо удалять и всё то есть к этому надо нормально относиться у меня здесь есть два момента которые хочется обсудить первое ну я в том плане что ты ответил на два разных вопроса просто наличие отсутствия моков - это не вообще параллельная вещь потому что ты можешь писать библиотеку в которой у тебя мок ну моки не нужны у меня например очень много библиотек работающих тупо с файлами и как бы ну вот просто ты файл положил и всё и там очень много хитрой логики может быть ну банально я там ассистентов очень много пишу например у меня очень много сборок всяких ямол тра-та-та-та-тта чтобы собрать файлики которые я враг потом в Open API там например загружаю ну как бы там моки не нужны я к тому что Моки - это вообще параллельная немножко тема и когда ты говорил я сразу хотел сказать в принципе зачем если можно было создать у тебя же всё равно интерфейс да но делаешь имплементацию которая в памяти просто держит там набор данных и возвращает и складывает да ну у меня же ещё даже так я же даже не знаю что я хочу чтобы как этот репозиторий inмеemory работал вот в чём проблема мок мне позволяет это требование для этой имплементации сформулировать то есть я например сохраняю в базу эти данные а хочу ли я чтобы они там в outбок сообщения сложили хочу чтобы они там ещё что-нибудь сделали какое-нибудь состояние поменяли вот что я хочу я ещё не знаю и вот моки позволяют мне не знать вот я просто абстрагировался что у меня есть какая-то сохранялка и я думаю какие должны быть входные у неё данные какие у неё должны быть выходы чтобы я это выражало то что я хочу вот об этом Моки моки - это о дизайне скорее даже вот наверное у меня другое тут отношение я бы делал то есть для меня мог - это всё-таки когда у тебя Давай во-первых не моки а стабы начнём с этого да потому что моки ещё раз это всё-таки другое мок - это ты конкретно хочешь проверить что у тебя вот прямо тест пишешь конкретно на то что там внутри вызвалась какая-то [ __ ] например репозиторий и конкретный метод сейв в данном случае речь идёт о том что у тебя нет готовой имплементации тебе просто надо чтобы оно вот так работало но ты не то что там дёргаешь в тесте эту проверку угу это просто очень это сильно влияет на то о чём мы вообще говорим и э я в таком случае как бы в любом случае бы ну сразу начал то есть опять же это не про ДД это вообще в целом отдельная штука с какой-то простейшей имплементацией в памяти или как ты говоришь цсвэшкой потому что интерфейс-то ты написал у тебя всё равно в интерфейсе есть сейф реально какая разница там внутри но как бы имплементацию я имею в виду что когда ты пишешь МОК ты по сути делаешь ровно то же самое просто в одном случае ты как бы динамически это определяешь в своём сетапе в другом месте можно просто тупо класс создать и его использовать я согласен ну ну глобальнох разницы не будет я я согласен с тем что это вот буквально то как ты сказал мог это ты динамически описываешь то что ты хочешь увидеть от сущности без того чтобы реализовать эту логику сущности но тут знаешь сразу появляются вопросы: а кто вообще про скажет что эта сущность вот in memory правильно работает понятно что какую-то тупую можно легко реализовать но например кто тебе может гарантировать что вот эта вот сущность которая ты короче у этих сущностей invemory что я хочу сказать я бы назвал их вот таких вот тест doubles которые мы пишем руками это именно теestст doubles не в том смысле как моки потому что это тоже тест douбles но тест douбles как самописная реализация упрощённая ну это стабы я вот как в начале говорил что это стабы обычно называется да о'кей ну суть в том что их проблема что они тоже могут быть вести себя не так как антеest настоящий как настоящий репозиторий который потом появятся и их на самом деле тоже можно будет выкинуть когда ты поймёшь что вот у них причина выкидывания будет точно такая же потому что они принципиально не меняют вот противоречие-то оно что в чём что когда мы моки выкидываем почему потому что мы понимаем что моки перестали расходиться с тем какое поведение у системы которую они подменяют мы их настраиваем одним способом а система ведёт себя другим вот это вот противоречие которое есть и тогда моки просто удаляют потому что с ними невозможно работать ну ты получаешь ровно ту проблему о которой мы говорили то есть знаешь как инструмент определяет мышление это ровно то что мы обсуждали когда ты вот так вот мыслишь ты начинаешь делать в спринге ровно то на что вы натыкаетесь когда мы говорим про вот то что я сказал у тебя получается единый сетап то есть ты не в конкретном месте сделал мог и в свою систему интеграции воткнул ты просто сконфигурировал своё приложение одним образом заранее и у тебя все тесты гарантированно идут одинаково понимаешь я знаешь из чего исхожу а я исхожу всегда не из того что знаешь вот есть такой: "Мы исходим из того что люди тупые или там мы исходим из того что должно быть гибко или мы исходим тра-та-та" для меня хорошая архитектура архитектура знаешь принципно меньше удивления и там где не надо думать проблема твоего подхода и ты сам про это сказал в начале то есть он круто работает у меня вообще вопросов нет потому что ну по большому счёту то на то то есть ты как бы мог написал я например класс написал но ты же в Моке всё равно имплементацию какую-то написал тебе что-то надо вернуть ты конкретно что-то вернул то есть они грубо говоря с точки зрения поведения будут идентичные на 100% вот прямо на 100% да поэтому в этом смысле разницы нет но разница ментальная в чём когда ты делаешь так у тебя как раз у человека появляется вот много вот этих нюансиков так вот тут мне нужен мог там по такой-то причине это всё требует тонкой душевной настройки это требует высокой квалификации и это как раз требует того чтобы человек такой: "Так вот я в спрингбуте вот тут вот мне нужен мог херак у тебя для этого теста свой собственный контейнер" а он даже об этом не подумал потому что это как бы Спрингбт - это отдельная тема вот у меня в Спрингбуте такой проблемы не было потому что я об этом знал я принципиален в этом моменте требует квалификации это вот именно в этом мой поинт это требует квалификации то есть ты фактически у тебя человек на каждом этапе работы с кодом должен понимать весь этот контекст и понимать все последствия а знаешь у меня есть такой доклад называется ментальное программирование он кстати когда-то очень стрельнул его просто везде смотрели я с ним как это знаешь как циркач ездил колесил по стране выступая с этим да у меня даже второй потом третий был вот и у меня там был как раз прикольный кейс что знания в компании распространяются не через понимание и умение что-то делать а через копи-пасту поэтому у меня это база это прямо базовая база прямо очень да и у меня там такой поинт был что типа первое решение должно быть идеальным и всё такие: "Кирилл как же так?" Я говорю: "Ну естественно речь не идёт о том что вы там идеально фичу запилили просто например если вы пишете первый тест в компании то есть речь идёт о такие утилитарные штучки да то естественно все остальные тесты будут писаться по аналогии и поэтому если вы туда закладываете систему которая требует от вас то есть типа я так написал это прикольно но вы ещё при этом должны 500 штук в голове учитывать чтобы ну не напортачить а ты понимаешь что происходит дальше никто этого не учитывает новые люди старые люди нет времени забил хер вообще не понял о чём речь скопипастил бам поменял мог и да можно сказать: "Ну Кирилл ну это же только в спринбутите" а я говорю: "Да если так писать то мы создаём архитектуру которая не является знаешь есть такое понятие защитная архитектура то есть которая заставляет тебя делать что-то определённым образом безопасно по дефолту" да она тебя может ограничивать все дела но вот это такое моё кредо я сторонник таких архитектур поэтому если бы например опять же я видишь нисколько не умоляю твой подход я говорю просто про то что он требует очень высокой квалификации и вот этого вот понимания в каждом элементе а я люблю тупые решения которые можно скопипастить и у тебя получается правильно и тебе не надо об этом думать вот ну мне тут сложно что-то сказать потому что ну как я говорю я травмирован спрингбутом поэтому я вижу что правильные решения их там можно сколько угодно на самом деле писать но неправильно они всё равно тоже будут рождаться то есть мне тут сложно как-то сказать потому что да действительно моки могут привести к каким-то плачевным ситуациям но вообще как и любой инструмент то есть в принципе вот например не знаю как у тебя но по моему опыту люди вообще часто не стесняются брать например и в Го это не знаю как в Rils там но в Го - это до сих пор спорный вопрос стоит ли тестировать только публичные API ну вот это забавно потому что знаешь это как вот история повторяется у нас вот там были года например 2012 когда мы там всё это обсуждали и так далее потом проходит я вот заметил восьмилетние циклы есть такие когда возвращается видимо в каждой системе немножко по-разному но оно возвращается и видимо люди повторяются ты знаешь что есть такой антипаттер называется Павлик Морозов ну я я не знаю но я примерно наверное понимаю чём это паблик Морозов - это такой антипаттерн который в Джаве придумали для того чтобы тестировать скрытые методы это знаешь как ты делаешь ты наследуешься и прикол в том что протекто методы базового класса можно объявить пабликом можно пабликом объявить наследники делают наследника специально в тестовом окружении подменяют и имеют доступ к ним дадада я это я знаю про эту штуку и на самом деле ты сколько угодно можешь рассказывать что так делать неправильно что это просто ты не можешь потом ожидать от объекта того что он объявляет своим интерфейсом то есть ты уже под него залез то есть человек который его проектировал уже тебе никакие гарантии дать не может что вот он ты ему не сможешь завести бак и сказать что вот работает неправильно он скажет: "Это ты его неправильно используешь" и это очень большая проблема и вот до сих пор есть дискуссии правильно это делать или нет потому что ты не знаю в гоферский чат зайдёшь и там тебя спросят вот в Го есть два вида тестов есть тесты которые ээ с именем пакета а есть тест с именем пакета префикс тест и вот из теста в который префикс пакета тест из них невозможно вызвать приватные функции пакета и я по умолчанию только такие тесты пишу и ну для меня это даже не вопрос почему так надо делать потому что во-первых пользователи будут пользоваться только публичным API моей библиотеки никто не будет пользовать непубличные функции этого просто нельзя сделать э пользователи будут читать видеть при автодополнении просто везде будет мой публичный API то есть я его в конце концов в пользователям даю и когда я захочу что-нибудь рефакторить как раз мой код уже будет хрупким потому что я изменю внутреннюю реализацию а вдруг окажется так что там тесты были рассчитывая что именно вот эта функция будет использоваться в реализации и тесты были на неё а не на общий API и это проблема которая сразу же вылезет и что до сих пор это приходится объяснять это на самом деле проблема и вот сколько на самом деле не старайся делать тупые инструменты чтобы было бы просто пользоваться всегда найдутся какие-то моменты которые используют не так как нам хочется вот это то что я понял поэтому я просто знаешь вот не удивляюсь вот как говоришь как мы там в гостраиваем без Орма там сложно всё я просто этому уже не удивляюсь то есть я пишу в принципе да наверное на каком-нибудь рейлсе там с с хорошими репозиториями это было бы намного быстрее но есть какие-то свои преимущества у того что в Go это всё прозрачно потому что у нас нету репозитория у нас мы видим буквально по-любому GO to definition можем дойти до самого вот не наесть SQэля и прямо его посмотреть без запуска какого-то динамического просто вот как код и везде провалиться есть на этом можно считать плюсом но опять же я за это не адвокатирую но суть в том что просто не напишешь такой тупой код что его все будут правильно использовать вот это наверное то что я хотел сказать тут очень важно да путать то что ты просто говоришь Го на самом деле не GO а конкретно то как пишутся определённые люди потому что в Го мы видим с тобой есть она популярна и пользуется по поводу кстати провалиться в SQL не могу не сказать что тот же самый дризл который я рекламирую у тебя там такая фишка что там такой уровень типизации то что ты по сути это и так видишь и более того ты банально сджойнить не сможешь неправильно если у тебя по типам не сойдётся то есть он там на таком уровне проверяет и это не какой-то специальный язык типа HQL как в этом в кибернейте был там а как он проверяет что этот типы совпадают с тем что реально в БД у тебя схема вся описана вот в его языке у тебя знаешь этот у тебя с данными есть два подхода датафст и есть кодф вот здесь кодфёст у тебя грубо говоря ты меняешь код и соответственно меняются миграции генератся автоматом но в отличие от многих кстати которые генеряют довольно тупо миграции например банально если ты переименовываешь поле он знаешь как работает он работает как тероформ который тебе показывает и говорит: "О тут вот так вот так вот так" и ты понимаешь ты когда запускаешь миграцию он прямо грубо говоря перед тем как сгенерить миграцию он такой смотрит: "Так тип совпа ну там хитрая проверка" он такой смотрит и говорит: "Слушай вот это вот поле это ты старой удалил новое добавил или ты его переименовал?" И такой переименовал он такой всё правильно делает круто да не ну это прикольно да да и поэтому и там язык как бы максимально скельный то есть у них смысл был в этом поэтому там как бы даже при Джойне у тебя там такие так дженерики все устроены что он просто скажет тебе: "У тебя ты не можешь джойнить эти две таблички у тебя нет общего ключа" прикинь то есть просто фантастика я такого нигде не видел ну ладно а смотри у меня было два дополнения в эту сторону пока я не забыл попробую их добавить я вспомнил ещё один промок один важный момент то есть вот по поводу во-первых я сказал в целом из того что ты делаешь моки индивидуальные у тебя получается много индивидуальных моков то есть это слишком получается разнородная система и её слишком сложно контролировать потому что люки люди будут добавлять а второе что мне в этой системе не нравится она тебя толкает к тому чтобы люди моки использовали как моки знаешь что происходит обычно это вот мой прямо опыт это не то что я там теоретические рассуждения как только человек видит какую-то фичу он её тут же думает: "Ну как же без этого жить надо её использовать" так вот когда ты в создаёшь Мок у тебя что в любой доке по мокам написано вот тебе 200 матчеров или ассертов на то чтобы проверить сколько раз он был вызван с какими параметрами он был вызван что делает человек который понима ну вот знаешь такой просто: "О у меня мог такой: "Ну раз у меня мог значит я должен проверять" и у тебя тесты начинают заполняться там три раза был вызван туда передали это туда передали это это создаёт то есть я могу точно сказать где это нужно вот если например я для своего фреймворка реализую систему плагинов какую-нибудь да или хуков я там обязан это использовать просто потому что ты иначе ну не узнаешь как она работает там реально надо так делать но если я пишу просто нормальный прикладной код то какая нахер разница как я вот тебе говорил мы же проверяем там что по базе например да какой стейт в конечном итоге каким штукам это привело тоже проблема на самом деле тулинга потому что вот современный Да я я понял о чём ты куча вот этих вот метод was колд там в конце тестода вот вот вот именно из-за того что ты моки начинаешь использовать я тебе клянусь дело не только в тулинге а в том что они такие видят: "О у меня мог о смотри тут в доке написано я её открыл" ну как бы логично и человек начинает это многие так делают например про в GЮюниity с Мокери почему проблема потому что на самом деле Мокери там с последних версий у него есть такая фича что он сам проверит вот если ты сделал стаб на какой-то метод через Мокере вот определение возвращаясь к нему если ты заставил какой-то вызов метода он проверит вызвался он или нет ему не надо ничего дополнительно писать если ты сделал стап который никогда не работает он тебе об этом скажет и ты можешь явно ему сказать: "Тип этот стап можешь не проверять типа ты можешь ему это сказать" и это убирает ту проблему про которую ты подсвечиваешь в Го есть то же самое то есть там если ты создал Моки ты можешь сделать так чтобы ты взял описал через них стабы и все стабы обязательно проверились и не надо в конце проверять сколько они там вызвались сколько раз с какими аргументами ты просто сказал: "На такие-то аргументы возвращаю вот такие вот значения" всё вот эта штука она если не вызовется тебе упадёт тест ну если тебе не надо чтобы она не вызывалась ну тогда напиши что можно не вызывать типа и всё это на самом деле многие инструменты эту уже проблему решают но я согласен что тут есть такая штука что как во многи да есть злоупотребление и во многих вещах вот как я на самом деле вот с опытом это приходит и я это наверное несколько лет назад ощутил потому что у меня опыта немного с восемнадцатого года даже по сравнению с твоим не говоря там каких-нибудь ещё ребята которые там очень давно пишут но суть в том что с опытом приходит то что надо разобраться в том что ты используешь и вот человек когда он видит например Мокери или Макита или там Powerмо MOК любой фреймворк для макирования он что делает у него нету идеи взять там прошерстить документацию как им пользоваться то есть всего его по он берёт вот как ты сказал по принципу коэпасты как там кто-то делал и вставляет в лучшем случае загуглил в интернете примеры вставляет всё то есть он не пытается разобраться и вот я с опытом себе убрал вот это вот стараюсь убирать эту привычку и я если вижу какую-то новую библиотеку я ей очень аккуратно пользуюсь и у меня обязательно там я в течение недели беру и штудирую всю документацию чтобы идейно пропитаться как этой штукой надо пользоваться потому что вот будут такие вот детские ошибки что ты знал не знал что фреймворк вот так вот умеет или что его лучше так не использовать и это просто надо приучить себя изучать инструменты которыми ты пользуешься и тогда жизнь станет проще вот если изучить Rails то можно понять там кучу вещей которые в нем есть как спрингбте и понять как там на самом деле я уверен немногие скажут как поднимается Спрингб тест когда ты на нём вот эту вот аннотацию ставишь там есть куча правил которые по-разному в разных ситуациях по-разному работают и это надо изучать за этим надо следить это важно во всех фреймворках есть крутые штуки единственное только тут надо добавить ты очень правильно говоришь с точки зрения тебя как профессионала а есть ещё взгляд как бы на систему то есть вот я скорее как бы как профессионал действую очень похоже на тебя то есть то что ты говоришь изучаю смотрю понимаю критично оцениваю и так далее но когда я говорю про себя как человека создаёт систему которой пользуются другие а я по дефолту исхожу что люди так делать не будут и я не воспринимаю это как зло я воспринимаю это как данность и поэтому всё что я делаю стараюсь делать так что а ну максимально тупо вот тупее не придумаешь э знаешь классический пример - это вот сервисы и вот вокруг сервисов знаешь же сколько существует разных этих срачей концепций тут у тебя анимичная модель тут у тебя такая тут тра-та-та-та-та и я каждый раз вот был момент когда я этим тоже жил и прямо вот тд контексты то есть я это всё хорошо понимаю люблю понимаю где как надо и так далее но каждый раз когда я понимаю что проект сваливается в то что мы начинаем ну не мы в смысле а я вижу как разработчики сидят и начинают обсуждать соответствует ли это вот этим определениями или нет я понимаю что мы в тупике ну в том плане что архитек вот уже перешли эту границу сложности потому что помнишь как люди это как-то обсуждали что типа нельзя писать господи как же эта фраза звучала что нельзя писать код на границе своего возможного потому что типа тесты будешь писать ещё сложнее ещё сложнее к такому коду и типа это будет уже выходить за преимущество ТД потому что ты когда пишешь тесты ты уже понимаешь что ты даже тест не выкупаешь не можешь придумать то тогда стоит остановиться да какая-то я знаю что меня поправят но там вот как раз с этим было связано а вот вторая часть которую я тебе хотел сказать по поводу собственно юнитов вот ты мне объяснил да что они выкидываются это как раз вот история про ТД написали маленькую штуку что-то вернули тра-т тт-т в процессе поняли что надо отрефакторить выкинули все тесты и как бы хорошо и наверное я согласен что в каких-то местах плюс-минус похожим образом я действую когда но это касается очень тонких вещей там мне парсер я буду писать какой-нибудь наверное там будет что-то похожее но недалеко не во всех библиотеках так вот я ещё заметил одну вещь про которую не могу не сказать уверен что со мной кто-нибудь согласится проблема в тестах то что нельзя на них логически смотреть просто с точки зрения вот мы с тобой говорим вот есть ситуация такая делай раз вот ситуация такая делай два а ещё тут у тебя опыт наложил получилось три люди не любят выкидывать свой код если ты нахерачил тесты разработчик не будет рефакторить потом понимая что сейчас ему надо всё либо переписывать выкиидывать я говорю про усреднённого разработчика понятно что ты будешь и я буду и многие будут но многие не будут почему потому что они такие: "Ну как же я же я же не зря писал все эти тесты так жалко я с этим встречался очень много раз для этого надо вот почитать книгу но это не про программирование просто смириться смириться с тем что код написан про стоицизм надо просто код написан всему своё время вот пришло время кода ну просто с ним не знаю в последний танец не знаю что что вы любите там Линтер на нём погоняйте в последний раз и удаляйте и всё ну люди влюбляются в тесты ты не замечаешь этого вот прямо таким: "А я лучше рефакторить не буду" и геморрой и и блин писали же не зря всё ну честно я я замечаю такое что иногда люди вот у меня была такая вот на работе вот буквально ситуация чувак взял написал тесты на Питоне без линтеров я вижу что он не питанист то есть они вообще знаешь там какие-то зака куча вот просто по качеству вот ниши не знаю он наверное не смотрит но в общем если ты смотришь это очень плохой Python код типа очень плохой Python код был и суть в чём была в том что я просто взял и сказал: "Типаa: "Ребята вот давайте если у нас есть код в репозитории он должен соответствовать качеству вот какому-то то он на нём должны быть линтеры то есть все должны иметь его подде он должен запускаться через cake то есть а не так что там запусти вот это поставь ту-то версию питона вот эти зависимости без requirements txt пойми что там установить короче без вот этих вот танцев с бубном я просто взял и по-дружески переписал их на го я просто взял и переписал на го и он такой: "В следующий раз когда будешь переписывать мои тесты с питона на го ты этот это у меня спрашивай" типа и не надо было их переписывать я их использую я такой: "Ну теперь же можно одной командой там go make integraation теest запустить и у тебя всё это прогоняется и на гошке интер работает вообще всё классные там инфраструктура переиспользуется" он такой он их написал вот и мне пришлось ревертить комиты я ревертил комит я удалял свои тесты возвращал на Питоне да ну тут конечно скажем что это действительно как с какой бый целью не делалось [музыка] это можно некоторые бы и по лицу захотели дать вот такой ситуации но но я тебя понимаю как бы концептуально а ну да в общем действительно есть такая штука особенно когда знаешь много времени всё это пишется и в какой-то момент нужен рефакторинг а там например много действительно мелких тестов понаписано там не знаю на валидацию на какие-то методы всякие мелкие и вдруг это всё вот самый главный момент это нельзя переиспользовать то есть у тебя грубо говоря эти тесты не помогают регрессу то есть если ты в какой-то момент понял что вот мне быстро ну не знаю у меня вот два класса так соединены а мне надо вот вот так вот сделать и соответственно ты полностью перекидал всё получается весь скоуп именно вот тестов прямо конкретно под них он просто он вообще никак тебе не помогает тебе просто с нуля их надо писать потому что ну просто у тебя логика разъехалась по-другому у тебя не просто метод переехал с одного класса в другой у тебя должны быть интеграционные тесты которые плюс-минус это тестируют и ты ну я бы просто как сделал я бы параллельно начал такую же реализацию писать по ТД и у меня были какие-то интеграционные тесты я может быть бы их натравливал на одно на другое то есть да понятно что скорее всего если прямо полный рихал то есть там полная переделка или оно было неправильно сделано логику вообще надо менять даже дело не в структуре просто бизнес-логика меняется ну да надо выкинуть но я бы написал такие же крутые тесты рядом надо смотреть на это как на возможность написать тесты ещё круче вот мы написали эти тесты мы научились теперь делаем тесты ещё круче это можешь видео назвать тд и стоицизм то есть как смириться с тем чтобы ударять тест здесь не могу не сказать вот твою фразу в начале я единственный поэтому пишу и больше никто так не делает и особо не хочет фактически я к этому наверное вёл что людей которые вот так готовы как-то писать это требует очень высокой а квалификации б очень такого мотивации понимания того что ты делаешь да у тебя есть не то что мотивация это просто ты так чувствуешь мир ты так живёшь и ээ м такого нет у большинства поэтому как бы я когда про это думаю я пытаюсь максимально прагматичный подход то есть с одной стороны тесты с другой стороны максимально дёшево и даже кстати знаешь вот не могу не добавить вот люди любят спорить юниты шмуниты и так далее я всегда на эту тему говорю очень простую вещь я говорю: "Смотрите вот в чистом виде да мы же с тобой даже вот ты говоришь: "Вот я моку я пишу юнит не юнит" если мы сейчас начнём говорить это ещё на 2 часа потому что кто-то юнит считает только маленький кусочек кода а если у меня маленький кусочек кода в три строчки но зато который два раза в базу сходил и HTTP запрос сделал а если у тебя например [ __ ] там классов шмасов и так далее а на выходе у тебя чистая функция типа на вход передал данные ну типа парсер какой-нибудь да но зато у тебя кода там полно а а если между серви Ну и понимаешь да у тебя получается что нету чёткого юнита нет чёткого интеграционного теста это шкала и у тебя как бы по этой шкале ты в ту сторону двигаешься и поэтому когда мы обсуждаем тесты я не просто так вот про мы очертили вот этот фреймворк потому что я скорее говорю так: "Ребята смотрите а вот вы когда берёте фреймворк готовый" у вас там даже понятиями такими особо честно говоря не оперирует у вас конечно может называться PHP unit XIT Junit там ещё что-нибудь но во Фреймворке конкретно тесты контроллеров конкретно тесты эндпоинтов конкретно тесты моделей а модель может там вообще чудеса творить сам понимаешь да там что только не пишут люди вот и вот я считаю что это гораздо лучше аэ так к этому подходить потому что ты чётко понимаешь если ты находишься в этом фреймворке и пишешь эти тесты то там типа они принято их там писать так например вот а споритьют они или нет ну бессмысленно вообще это ни к чему не приведёт или ты приходишь в сприн и говоришь: "Сейчас я тут напишу" ну блин если ты пишешь контроллер на хенднр но это контроллер на хендлер какая разница что ты там мокаешь или не мокаешь ну да-да ну я с этим полностью согласен что если у вас есть уже язык какой-то устоявшийся то есть вот как в Спрингбуте есть SpringБot тест есть WebMVC тест есть там дата JPA тест есть все эти слои не надо придумывать новые нейминги то есть говори я написал дата JPA тест это значит одно то есть просто если вы начнёте от них отказываться говорить считается это юнитом или нет просто скатитесь в кучу бесполезных эливаров и всё то есть просто пишите тесты которые позволяют фреймворк и называйте там если вы написали тест без спринга ну так скажите это тест без спринга это просто классик создаётся там проверяй он сложный типа его надо проверить типа так и скажи если у тебя тест который там куча он без спринга смокере так скажи тест смокери то есть когда есть я не вижу смысла вводить второй язык когда уже есть устоявшийся в какой-то инфраструктуре я думаю в РUБЕ там свои есть устоявшиеся там названия там для тестов тесты моделей тесты контроллеров тесты вью да то есть тесты роутинга даже пожалуйста когда у вас есть более конкретные вещи говорите конкретными словами не надо говорить абстракциями когда у вас есть конкретные слова вот наверное то что ну то что вы те же самые юниты просто к этому не прицепите никак потому что тут же найдётся человек который скажет что вот не знаю есть люди которые из модели письма отправляют или с очередью работают а юнит - это или не юнит кто-то скажет юнит кто-то скажет: "Нет не юнит" а другой говорит: "А я замокал" из чего вдруг это сразу юнитом стало да и вот вот эта вот шляпа она конечно не имеет никакого формального определения а но я например банально раз уж мы про это заговорили не согласен с людьми которые берут какую-нибуд высокоуровневую штуку всё к херам собачьему окут и говорят что у меня юниттест я не согласен то есть типа ну и что что ты замокл у тебя капец там вся система работает вот а ты може смотри сложный юнит-тест ну сложный юнит-тест да это ещё одно опи этот э не конкретное слово в определении я что хотел сказать вообще как я к ТД пришёл потому что это может быть я думаю кому-то интересно в ТД я вообще пришёл книга которую я начал читать которая мне Я пришёл на проект очень страшный там была огромная система куча хранимых вот просто ужас полный то есть там большая система отчёта там финансовой организации там жесть и что надо было делать и надо было изменять её и я просто понял что я я просто очкую мне просто страшно я что-то меняю и я понимаю что выстрелит там вообще где-то в других местах непонятных и есть книга Майкла Федерса Working Effectively with Legacy Code там работа с унаследованным кодом как-то так называется я её прочитал и я тогда ещё не понял про ТД я понял что мне понравилась идея там эксплуреation-тестинга я не помню я ещё что-то читал я тогда много учитался в тестировании потому что мне было страшно я подумал что проверять руками - это сложно то есть вот я начал бороться с этим страхом и вот я понял что есть такой expiration тестингing и я начал понимать что вот я прежде чем сделать какой-то фикс я меняю тесты и смотрю как система себя поведёт там благо можно было поднять это всё интеграционно там через курлом написать тесты и всё это воспроизводить так вот я начал такие штуки писать и потом я понял что я же могу сразу написать тесты которые будут брать и говорить что я хочу увидеть и так делать я начал так постепенно делать и потом я понял что об этом же Майкл Федс писал что это есть Test Driven Development я начал в эту тему погружаться и в конце понял что мне действительно так комфортно работать и это вообще опять же не о тестирование и шло это именно от страха то есть мне было страшно дорабатывать системы вот как там Кентбек пишет я когда начал читать его книгу вот тут вот стоит вот тут вот она у меня всегда вот тут вот рядом видишь экстремальное программирование разработка через тестирование вот она у меня тут настольная когда я начал её читать я понял что это как раз то о чём он говорит что мне страшно менять код я просто хочу быть уверенным что я всегда понимаю что я написал и ТД позволяет это сделать и опять же тесты тут просто сайд-эффект это не мы не хотим если ты хочешь протестировать своё приложение ТД тебе не поможет то есть тд - это про дизайн и про то что я вот сегодня закончил работу и я уверен что вот на том этапе на котором я додумался как это будет работать всё работает правильно то есть я там дальше буду детали доуточнять что-то может измениться но я пока понимаю свою систему и она работает так как я хочу от этого и у меня часто вот после того как я начал писать по ТД получается так что я релизу релизную фичу и она просто работает ну вот получается так что я всё протестировал и всё это из коробки даже в каких-то маленьких деталях просто вот так вот получается я стал спокойне спать но потом другие проблемы появились из-за которых перестал спокойно спать но это другая история в налоговую плоскость перешли а хотел пару замечаний по Кенту Беку дать потому что я в том же докладе на Тимлет Конфе про это рассказывал как раз показывал собственно как пример у него знаешь как часто бывает когда ну кто-то что-то такое сделает известное все такие: "О побежали" а потом он там отказывается от своих слов что-то меняет вообще жизнь утекает он говорит: "Что за херня?" Вот как Мартин например говорил по поводу Джайла да говорит: "Манифест придумали там его взяли превратили в целый индустрию зарабатывают там на этом бабке" хотя вообще конечно в начале никто ничего подобного не имел и в виду и вообще всё там уже совершенно по-другому то же самое с тестами есть два прикольных момента это только то что я знаю понимаешь больше первое Кенбек сказал: "А если бы я познакомился с Хаскелем до того как написал эту книгу то возможно она была бы сильно другой" то есть он в Фейсбуке по-моему писал пост на тему или кто-то постил его на тему того что когда он поработал с системами с очень навороченными системами типа а он конечно понял что значение во многом тестов ну короче может быть их меньше то есть пошь логику тебе никто если ты плюс с минусом перепутал тебе никто тут не поможет да но в целом у всё равно там чуть проще с этим а и действительно в том же Тайпскрипте вот по поводу говоришь работает там я обожаю просто ТС я сейчас вот мы там рельсы рельсы на самом деле я фанат Теса стал и в Тайпскрипте конечно чудеса вообще творятся в плане того что ты можешь осо всяких хний и всего остального и уровень тестирования который тебе нужен он конечно сильно снижается то есть только на логику а так-то там всё отрабатывает а второе что я тебе хотел сказать тоже по нему уже Кен сказал следующую вещь его то ли на Редите то ли где-то спросили типа вот тесты и он очень классную прямо такую длинную фразу написал это был 2015 год он говорит: "Ребята вы меня короче все задрали я на работе работаю не для того чтобы тесты писать я не имел" то есть он говорит фактически он говорит очень похожую вещь на которую я сегодня рассказывал да и в принципе ты с ней согласился я пишу как можно меньше тестов короче он свёл по сути грубо говоря к тем же самым интеграционным тестам он прямо так сказал в основном интеграционно немножко чтобы просто вот убедиться что всё работает типа но мне платят на работе не за то чтобы я писал тесты короче его задрали все вот короче его идея была в том что перестаньте придумывать всеобщую теорию тестов её не существует я её не придумывал и я не собирался рассказывать всем что вот существует вот так вот перпендикулярно параллельно по тестированию вся фигня вот так тд оно как раз вот об этом что ты пишешь красный тест на том уровне на котором ты понимаешь систему потом делаешь его зелёным рефакторишь всё типа хочешь ты написать интеграционный тест если у тебя в голове эта предметная область настолько проста что тебе не сложно написать интеграционный тест потом его быстренько реализовать и пойти дальше следующий тест написать ну напиши интеграционный то есть никто тебе не запретит тд - это в этом его и прелесть и минус как любой практики которая не проверяется линтером не проверяется при сборке не проверяется типами это просто практика и каждый её применяет индивидуально для себя это просто дизайн и в плане дизайна я с чем соглашусь и более того сам всегда я про это топлю как надо чётко разделять если мы пишем какие-то библиотеки фреймворки и так далее вы дизайните там без остановки и там реально это сложно во многом кстати уровень программиста для меня этим проверяется то есть как только он выходит за рамки фреймворка насколько он вообще может написать такую вещь и часто люди там плыть начинают потому что они как бы немножко путают они вка фреймворка привыкли работать но концептуальное понимание вещей у них нет это то же самое из Реакта если людей забрать например они сразу перестанут такие вещи писать и кстати о вот я про реакт сказал нельзя не добавить а тд во фронтде полным-полно но это как бы опять же это библиотеки то есть если вам нужно какую-то либу запилить но если вы думаете а некоторые думают и пытаются применять начитавшихся этих ник что они могут делать тд на по сути нату ну знаешь когда у тебя страничка Дада да это безумие ну то есть типа у вас нет вёрстки вы там пытаетесь на что-то завязываться ничего хорошего из этого не получается а есть люди которые даже утверждают что у них это как-то работает но тут я легко наверное скажу про это что многие всё-таки со мной согласны то что это как бы хрень но это очень сложно в комментариях и на подкасте расскажете как у вас это работает вот да если у кого-то работает давайте об этом поговорим потому что фронтENд в этом плане тон-тесты они требуют всё-таки перед глазами что-то увидеть без вёрстки вы там охренеете это ну самое главное никакого смысла то что никакого дизайна нет то есть вы просто то есть в этом как бы поинт получается что дизайна нет вы ничего не дизайните вот слушай ну классно получилось я спасибо тебе большое Илья что пришёл рассказал мне кажется количество пользы на единицу времени было сумасшедшее хотя возможно сейчас сороше не в комментах всегда напишут это нормально ничего страшного илья тебе спасибо за то что ты пришёл ребят я очень надеюсь что вы дослушали до конца потому что мы очень долго сегодня разговаривали близко к рекорду кстати который у меня был тут недавно а напишите в комментариях что вы обо всём этом думаете какой вы предпочитаете стиль программирования и не забывайте подписываться на мой канал Организованное программирование и на канал Илии который называется Куда Войти вот он вот так не потеряйте да смотри мы такие с тобой подготовленные ребята да брендированные ребята всем спасибо
Creators and Guests

