Мя тут немного почитал, немного посмотрел и немного поговнокодил, и что-то не складывается каменный цветок. Выглядит оно это ваше TDD как учебная методика, форсирующая приобретение навыков создания тестируемого дизайна и на своём примере показывающая, насколько больно поддерживать хрупкие тесты, но не как реальный способ разрабатывать сложный функционал.
В целом, вопросные тезисы и тезисные вопросы таковы:
С чего начинать? Как выбрать фичу, к написанию теста на которую приступить в первую очередь? Как не попасть в ситуацию «написал приёмочный тест вместо красивого чёткого TDD, ну ты лох», о которой многие упоминают, но не рассказывают, как правильно? Практически все мануалы показывают написание теста сразу для фичи верхнего уровня, что, КМК, приёмочным/дымовым тестом и является.
Написание теста для функционала, решение которого нетривиально, вынуждает писать тонны заглушек просто чтобы «скомпилируйся наконец уже пожалуйста». Количество заглушек умножается на количество «baby steps» при рефакторинге и добавлении новых тестов, генерируя адский объём механической работы. Определённо, значительная часть таких затыков порождена моей дизайнерской криворукостью, но мя не вижу способа полностью избежать этого рака.
Как TDD предлагает «пробивать» инкапсуляцию, когда функционал под тестом оказывается нетривиальным и требует вынесения части функционала в новую сущность? Многие статьи демонстрируют погрузку болта на внутреннюю сложность реализации, тестируя только контракт, что выглядит очевидно неправильным. Имеет ли концептуально реализация право порождать новый тест? Нужно ли, когда в ходе рефакторинга или позеленевания тестов требуется создать что-то новое, откладывать текущую работу над реализацией и идти писать новый тест для свежеобозначившейся проблемы? Что делать, когда поймёшь, что погряз в огромном объёме некомпилируемого кода и незапускающихся тестов?
Некоторые авторы предлагают следующий рекурсивненький жизненный цикл: ставим задачу верхнего уровня, решаем её. Если не удаётся за вменяемое время написать тест/реализацию, дропаем текущие наработки, собираем митап и распиливаем её на подзадачи, далее работаем с ними. Это выглядит минимально-рабочим, но вызывает вопросы: как планировать время на реализацию фичи, как рефакторить функционал более верхнего уровня, если он окажется концептуально неправильным, как избежать лавинообразного рефакторинга с проблемой кучи некомпилируемого кода, чем безумно дорогая по времени перековка какашки в конфетку лучше, классического предварительного планирования с UML и быстрого написания прототипов отдельных штуковин.
TLDR: «под капотом» TDD очень сильно напоминает наивное «не надо ничего планировать, щас что-нибудь в процессе выдумаю», прикрытое сверху идеологией тестирования и горстью баззвордов. При попытке использовать его на не-совсем-тривиальном-проекте, который уже нельзя полностью держать в памяти, количество забытых нереализованных фунций и количество неожиданно всплывающей работы по рефакторингу и реимплементации превышают все мыслимые пределы. Это выглядит полезным для обучения, но не для реальной разработки.
Change my mind, как говорится, если есть желание. Мя ещё не зафиксировал какого-то конечного мнения о сабже, но первые впечатления смешанные.
Проблема вроде бы и простая, но не могу придумать нормальное решение.
Есть одна клиент-серверная программа. Есть несколько типов («B», «C», «D»), унаследованных от интерфейса («A»). Объектами этих типов перекидываются между собой всякие классы типа БД-воркера, TCP-сервера, менеджера устройств, etc. Чтобы не загромождать последние кучей сигналов-слотов на каждый тип, в сигналах-слотах передаются смарт-поинтеры на объект типа A, после чего в слоте проверяется, что там за тип вызовом метода а-ля get_type(), указатель приводится к действительному типу и соответствующе обрабатывается. В итоге код загромождается этими switch'ами, что ведёт к понятным проблемам, если понадобится добавить ещё один тип — придётся бегать и править все эти портянки.
Вроде как, можно применить другой способ — перегрузку сигналов/слотов, но тогда для каждого перегруженного сигнала/слота, как я понимаю, надо будет прописывать свой connect, что тоже смотрится не очень. UPD: может нафигачить глобально доступный макрос, который будет вставлять эту кучу коннектов на каждый существующий тип? Тогда достаточно будет модифицировать макрос при введении ещё одного типа.
Хочется, чтобы при добавлении нового типа-наследника «A», места для допиливания были строго локализованы и легко определяемы.
Наверняка есть какое-то решение, до которого я не могу допетрить, может кто подсказать? Или дать ссылку на проэхт, где можно подсмотреть, как делать по красоте?
Привет. Ребят подскажите пожалуйста какой-нить брокер с гарантированной доставкой POST запросов.
Пример такой: Прилетает на nginx/haproxy(балансер) -> кладётся в очередь -> из очереди пушиться (причём нужна именно гарантированная доставка) в nginx -> php.app.
AMPQ не подходит т,к нет возможности вносить изменения в webhook сторонних разработчиков, а хочется как-то сбалансировать траф + при падении бека оставить в живых очередь.
Так как не все ЛОРовцы внимательно следят за событиями и пропустив разрозненные факты не могут увидеть их взаимные связи то я для того чтобы они их увидели буду сюда постить ссылки на посты указывающие на те или иные возможности вендорлока в Linux.
Допустим, есть микросервис1(мк1) и микросервис2(мк2), есть сервер сообщений rabbitmq(mq). Мк1 предоставляет апи, которое пишет в бд мк1 данные. После записи мк1 один должен отправить сообщение мк2. И тут вопросы:
как быть, если мк2 лежит?
как быть, если mq лежит?
Предполагаю, что мк1 должен при не отвечающем mq записать сообщение куда-то в базу, а потом какой-то воркер должен чекнуть то, что mq поднялся и отправить сообщение и удалить его из списка локальных сообщений. Но просто вот по этой логике(если mq лежит, то записываем сообщение локально, если не лежит - тогда отправляем) делать нельзя. Потому как тут появится такое событие:
запрос1 выполнен: пытаемся отправить сообщение1
mq лежит? Да!
записываем сообщение1 в базу мк1(самого себя), чтобы отправить позже
запрос2 выполнен: пытаемся отправить сообщение2
mq лежит? Нет!
отправляем сообщение2
периодик воркер срабатывает и отправляет сообщение1
В итоге мы получаем, что сообщение2 отправлено быстрей, чем сообщение1. Это не правильно
А как вообще правильно выстраивать систему отправки сообщений, чтобы это всё правильно работало?
В каждом мессенджере используется какой-то свой алгоритм, но почему-бы не сделать несколько, чтоб безопасность возросла? По принципу луковицы, в несколько слоев разными алгоритмами, збс же будет?
Само собой, все придется познавать методом экспериментов, НО...
1. Есть база данных. Таблица простая, но огромная, состоящая из двух полей, ID (int), TEXT (text) с максимальным размером в несколько килобайт. Записей может быть 10-20 миллионов, т.е. не мало.
2. Есть задача поиска по содержимому этого текстового поля.
Как думаете, что сработает быстрее: родной мускульный SELECT FROM where TEXT like '%что ищем%', или быстрее будет PHP-шным скриптом читать все 10 миллионов записей последовательно, на ходу парся какой-нибудь PHP-шной функцией навроде substr_count ?