Pull to refresh
29
0
Sergei Tovmasian @FranciscoSuarez

Director of Product Growth & Data Insights @Simple

Send message
У меня есть наброски,- где-то 50 условных продуктовых структур. Допустим, я ошибаюсь и будет ещё 50. Так что, скорее всего, уложимся в 100
Расскажите поподробнее пожалуйста как это реализовано? Есть какой-то тип буферной таблицы и как он сбрасывает данные периодически?

Речь идёт о движке Buffer(database, table, num_layers, min_time, max_time, min_rows, max_rows, min_bytes, max_bytes)

Из документации:
Данные сбрасываются из буфера и записываются в таблицу назначения, если выполнены все min-условия или хотя бы одно max-условие. min_time, max_time — условие на время в секундах от момента первой записи в буфер; min_rows, max_rows — условие на количество строк в буфере; min_bytes, max_bytes — условие на количество байт в буфере.

Обычно мы используем с такими параметрами:
Buffer(database, table, 2, 10, 10, 10000000, 10000000, 100000000, 100000000);

Можно еще поподробнее про это, если не затруднит? Вы как то обрабатываете ошибки? Имеется в виду, как вы ошибку записываете в отдельное поле?

У нас буквально в таблице есть has_errors Int8, который служит для быстрого фильтра на предмет наличия ошибок и их количества. Также есть error_log String — строковое поле…

Когда на бэкенде формируется запрос на вставку, то происходит валидация полей на предмет
а) соответствия заданному типу
б) на то, что значение не выходит за размер типа.
В случае, если что-то не выполняется, в error_log пишется сообщение с указанием, что именно пошло не так, само значение заменяется на default значение для типа данных, а получившаяся строка пытается вставиться.
Пример, если я в поле amount Int64 по каким-то причинам буду пытаться с backend вставить строку, то сам ивент вставится, а я получу has_error = 1, error_log = 'amount not numeric', а в поле amount = 0 — дефолтное значение типа.
Сырые данные остаются и хранятся достаточное время — от месяца до бесконечности в зависимости от кол-ва событий. Как правило хватает для решения всех задач.
Всё верно, в агрегате по пользователям для конкретного сервиса: 1 строка на 1 пользователя на 1 дату.
dt, user_id,… cols_about_user ....,… metrics…
1. Возможно, много хочу, но экспериментальные фичи типа LowCardinality (String), чтобы не обрабатывались как or DEFAULT expected, got '('.
Вся консоль красная в итоге, — у меня очень много полей таких.
2. Nested( структуры плохо форматируются…
Наверное, логично было бы сделать вложенность какую-то.
3. Мой основной паттерн работы — это работа на кластере и мне совершенно неважно, какие там машины в кластере — то есть важно, но редко. То есть сейчас у меня 10 машин слева в списке вида ch******. А когда их будет 40? Кластер про шардирование и репликацию, а не про раздельное хранение разных данных.
В связи с этим меняется немного логика работы, — уже было бы приятно вести проект, иметь какой-то Project Explorer — Database Consoles всё же опять про то, что есть много серверов с разными таблицами, а не про 50 тачек в кластере, на которых просто создаются таблицы, альтерятся одновременно и т.д.
4. Говоря про ClickHouse, хотелось бы видеть всякие условные замеры размеров колонок, коэффициентов сжатия, — да и всей таблицы в целом. Да и опять же видеть это всё на кластере… Раз уж я вбил все сервера, то такая сущность как cluster, которая бы объединяла в себе эти сервера была бы удобна очень. До банального «запустить на кластере». Сейчас для того же «SET allow_experimental_low_cardinality_type = 1;» я выбираю галочками все машины (хорошо, что 1 раз).

P.S.
1. Чуток подтормаживает на запросах — потому я использую DataGrip скорее как некоторый «проект» для администрирования, чем как инструмент для работы с данными
2. В связи с этим или LightHouse или консоль — они быстрые, — там я и стараюсь крутить-вертеть данные.
3. Но если резюмировать, я в целом наслаждаюсь работой с DataGrip — это на мой вкус такой промежуточный вариант между какой-то полноценной средой для разработчика и консолью. Пользуюсь, лицензию купили :)
JemmyFX не поддерживается и не развивается, был написан когда JavaFX была ещё куском очередного update-а седьмой JDK
Спасибо за ссылки на проект. Согласен — TestFX — это просто отправная точка. Трэшем я бы её не называл, потому что она решает все задачи, которые я пока могу себе представить, но, безусловно требует доработки. Потому я и оговорился по поводу версии 4.0.1 — там много, очень много интересного.
Gson замечательная библиотека по приведению json к объектной модели, но она, увы, не даёт рандомизации и, в Вашем случае, приходится создавать ручками json-ы с фиксированными значениям в дереве. Если приходится писать ассерты на каждую пару классов в маппинге, то попробуйте через Generic-и — мне думается, что можно написать один ассерт. Ну или я не понял Вашей задачи.
Он разбирает объект используя reflection, рекурсивно опускается до примитивов и коллекций. Аннотации — договорились — лучше не использовать. Если так уже надо работать с базой, можно это сделать на уровне своей абстракции.

public abstract class MyAbstractDataProviderStrategy implements DataProviderStrategy

Можно базу, прочие поставщики, связи и зависимости отыграть интерфейсами. Сделать абстрактных наследников, реализующих собственно генерацию. И реальных наследников, дающих инстансы. Видится реализуемым. Вообще всё зависит от потребностей и конкретных задач. Обычно, на периферии, там где живут интерфейсы и стыки модулей, объектные модели не бывают сложными, так как стараются не накручивать логику раньше времени. Если входить оттуда и использовать Podam для генерации, будет удобно. Вот реальный
пример полей объекта результата банковской авторизации
	private Long amount = null;
	private String currencyCode = null;
	private Date date = null;
	private String authCode = null;
	private Long refNumber = null;
	private Long hostTransId = null;
	private Long cashTransId = null;
	private BankCard card = null;
	private Long operationCode = null;
	private String terminalId = null;
	private String merchantId = null;
	private String responseCode = null;
	private Long resultCode = null;
	private boolean status = false;
	private String message = null;
	private List<List<String>> slips = null;
	private boolean isPrintNegativeSlip = false;
	private boolean isTransactionCancelled = false;
	private String bankid = null;

Блин. Кто же говорит про одну стратегию для всех — это же просто пример использования. Просто инструмент — ООП в руки желающим, — выводите уровень абстракции стратегии на тот, который нужен. Наследуйте стратегии…
Или, например, в объект Country надо добавить только те City, которые проходят какое-то условие, это тоже решается через if-else?

Создаём фабрики — не вижу проблемы связать фабрики друг с другом. Да, универсального способа разруливать сложную логику связей не существует, — но для каждой конкретной задачи, если подумать, существует элегантное решение.
Так же, по всей видимости, забыты enumeration'ы, которые живут в дб, их тоже руками в strategy добавлять?

Если речь идёт о справочниках, сделайте стратегию для отдельного атрибута, — в ней реализуйте обращение к базе, получение того, что нужно и возвращения генератору.

Это не библиотtка-пилюля-от-всех-проблем. Это альтернатива тому, чтобы сетить фикс значения в объекты и, по-возможности, организовать их генерацию.
Рад, что понравилось :)
Вам не за что просить прощения — конструктивная критика всегда приветствуется.

По проблемам:
1. Я за вычисление. Независимое вычисление. Которое проверит ожидаемый результат исходя из этих вычислений
2. Вероятностные тесты не могут пропустить регрессию. Они делают ровно то же, что и обычные тесты. К примеру, обычный тест нажимает на калькуляторе 2, +, 2, = и проверяет, что результат 4. Рандомизированный тест нажимает a, +, b, = (a+b). Да он берёт на себя логику по проверке суммирования. Но зато, в случае, если существуют значения, на которых сумма по каким-то неведомым причинам не сходится, то это причина для «посмотреть код». Фишка в том, что тесты гонять нужно ровно столько же сколько и раньше, просто в них появляется фактор нестабильности, напрямую отвечающий за отлавливание багов на данных, на которых ни один тестировщик не подумает их искать. Утрируя, 99 случаев из 100 обычный тест и рандомизированный будут вести себя одинаково — цель добиться, чтобы это было в 100 случаях из 100. Не нужно запускать рандомизированные тесты по 100 раз — гоняйте как и раньше, но внимательно следите за теми, которые «иногда» не проходят — поймите причины — найдите проблему.

Говоря о 109.11, я имел ввиду не точку на пространстве возможных значений, а точку из класса значений, с которыми округление ведёт себя неверно. Таких точек может быть много… Это же метафора…

1. «а полностью выкинуть первое и оставить только второй» — вы неправильно меня поняли. Я предлагаю выкинуть модульное там, где оно может быть покрыто рандомизированным функциональным, да и то не везде. Если проверяется хитрый алгоритм реализованный в недрах нескольких классов, то лучше, конечно, модульным. Если же речь идёт о том, что при нажатии на кнопку у контроллера спрашиваются данные, а потом передаются на вход хранимой процедуре, то есть два подхода — модульно вызовем метод со значениями какими-нибудь, а потом проверим, что в базе. Или же функционально нажмём кнопку и проверим, что в базе. При таком выборе я за второе, потому что в функциональное поведение первично. К примеру, — в реально работающей программе в контроллере нашем оказались пустыми какие-то значения и какие -то значения придут пустыми или некорректными. Хранимая процедура отработает, запишет всё в базу и модульный тест будет зелёный. Функциональный тест при этом упадёт. Как альтернатива этому одному функциональному — декартово произведение всех возможных входных параметров для модульного теста :) Но это будет дороговато и утомительно. В этом была моя мысль

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

3. Модульный тесты до тех пор проще, пока автоматические не становятся проще модульных :) Ещё надо создать «кривой» тариф, nullевой тариф, tariff, который меняется из другого потока — такое же тоже может вдруг случиться… Фуyкциональные тесты (рандомизированные) это выловят — если такое когда-нибудь произойдёт. Модульные вы так писать не станете. Модульные проверяют утверждение «эта отвёртка умеет откручивать эти винты», хотя в реальной работе системы могут оказаться другие винты. Да — эта отвёртка в большинстве случаев справится и с ними. Но если появится винт, с которым она не справляется, функциональный тест упадёт, пояснив, что при таком винте и при использовании этой отвёртки винт почему-то в конце не у нас в руках, а по-прежнему закручен в доску. Модульный тест будет по-прежнему зелёным потому что работает с тем винтом, с которым у него всё хорошо.

4. Да — это отдельный пункт. И самая главная критика автоматических тестов. Но, если не пользоваться sleep-ами, автоматические тесты начинают летать — habrahabr.ru/company/crystal_service/blog/251339/ — в конце этого моего поста есть ссылка на ютюб. Можете посмотреть видео.

Я на самом деле пытаюсь толкнуть теорию тестирования вперёд и мне очень интересны подобные споры. Я сам в целом разработчик, которого прёт от создания тестовых фрэймворков. Мне не нравятся классические идеи тестирования, потому что они рождались, когда мы жили в мире описанных хорошо или плохо, но всё-таки тех-заданий. Сейчас современное программирование и IT-бизнес, стараются идти от пользователя, развиваются и активно внедряются идеологии Agile. И меня можно было бы поругать, что я вот тут что-то придумываю и предлагаю голословно — но вот уже два проекта внедрены более чем успешно именно на этих идеях. Возможно, они не везде подходят — хочется об этом узнать, конечно. Но проблем с регрессией нет, вылавливаются баги, которые никогда бы не были выявлены никем кроме как пользователями продукта, все счастливы.
Я стараюсь правильно использовать термины. По-прежнему не понимаю, что сказал не так. Если, говоря качество, имел ввиду ту часть качества, которая обеспечивается тестированием, а вам не нравится, что обеспечение качества — это не тестирование лишь, а совокупность мер… Ну ок… Это само собой и не противоречит тому, что написано в пункте 2. Если же я оскорбил чьи-то чувства… Ваши или Роберта Гласса или Стива Макконнелла, то прошу прощения. Не хотел… Просто привык говорить по существу, а не вязнуть в вопросах безукоризненной точности определений
Есть модули, которые непременно нуждаются в unit-тестировании. Но везде, где только возможно покрыть модуль сквозным процессом пользователя, лучше покрыть именно процессом, чем со всех сторон юнит-тестами. Быстрее по времени и эффективнее.
Конечно, если налажен полноценный TDD, то что тут мне спорить)) У всех разные задачи и разные реализации. Я просто делюсь своим опытом.
Повторяемость — безусловно важная черта тестов. Безусловно, реализация рандомизации должна отличаться «от простой замены констант на рандом». Конечно, тут нужно и логирование красивое и понятное — это, безусловно искусство. Основная идея, которую я уже не раз реализовывал, — это взять распределение наиболее вероятных значений (провести исследования, например), создать стратегию генерации случайных входных данных с разбросом в пределах нескольких сигма от матожидания. В результате мы получаем максимальную эмуляцию пользователя, — тест начинает быть не given-then, а given(спектр)-then(спектр). Да, ожидаемый результат будет варьироваться. Если тест раньше набивал один конкретный товар в корзину интернет-магазина и проверял конкретную цифру, которую заранее сгенерил и залил в базу, то теперь он будет добавлять случайные товары, которые надо будет верифицировать в конце суммами, наименованиями и прочими разностями. Конечно, цены в диапазоне, количество товаров в корзине в среднем, например, 4 +-.

Да, порой случается, что рандомизированные входные данные приводят к нестабильности теста при повторениях — это и есть тот прекрасный результат… Когда мы видим, что на значении суммы покупок в 109.11 вдруг округление сработало неведомым образом. Эти баги потом прилетают с боя и их намного сложнее воспроизвести, потому что неясные входные данные. Уж лучше тест сто раз прогонится с разными значениями и 1 раз упадёт и мы это пофиксим, чем сотый клиент, произведя операцию, получит неожидаемый результат или положит систему (такое, как ни странно, тоже бывает)…
Можно со мной не соглашаться, но именно эти мелкие трудновоспроизводимые, порой критичные баги, больше всего выводят разработчиков, — ещё больше выводят бизнес, потому что их фиксы занимают много времени…

По поводу разделения unit/функциональные. Если у нас есть модуль А, который вызывает модуль B, тот химичит, отдаёт модулю C. Если мы можем написать функциональный тест с рандомизированными(это я подчёркиваю) входными данными, который войдёт в процессе выполнения в точку А и выйдет из точки C с правильной верификацией, то в 99.9% случаев можно считать, что модуль B покрыт и будет работать правильно без каких-либо unit-тестов. Я никак не отвергаю идею unit-тестирования, просто стараюсь сузить область её применения. Наоборот — я тащусь от Mockito, закрываю моками всё, что можно и стараюсь генерить рандомные значения со стороны заглушек и смотреть, а как вот мой этот функциональный тест, поведёт себя в разрезе работы вот с этими модулями, этими методами…

Надеюсь, смог сформулировать свою мысль. Если есть вопросы, буду рад ответить
Ну так же можно считать самообманом, что IDE повышает скорость и качество разработки и что лучше всё писать в блокноте. Давайте отойдём от споров на тему глобальных определений и будем считать качеством соответствие продукта прямым требованиям и косвенным. Фактически автоматизация тестирования является инструментом для поддержания этой идеи.
«Понятность: Назначение ПО должно быть понятным, из самой программы и документации.»
Вы уж простите, но автоматические тесты для этого не предназначены.

К тому же, в Вашей ссылке на Вики:
«Фактор качества ПО — это нефункциональное требование к программе...»

Автоматические тесты в первую очередь предназначены для обеспечения гарантии качества именно функциональных требований (описанных в договоре и не описанных, но являющихся критичными для бизнес-процессов продукта и пользователей). Причём не просто гарантии, а гарантии во времени -, чтобы при появлении новых фич, аффекты по уже имеющимся были бы выявлены автоматически и быстро, без рутинных проверок руками.
Я, если честно, не понимаю Ваш вопрос. Сформулируйте, пожалуйста, точнее… Автоматические тесты — это инструмент для достижения какой-то цели — , например, понижения в среднесрочной перспективе стоимости регрессионного тестирования.
Быть может и о разном. Быть может и нет :)
*эритроциты))) очепятка
Ой… тут в голову пример пришёл.
Вот вопрос — сколько надо сделать заборов крови, что провести анализ? :)

У меня в последний раз делали 3 забора:
1. Всякие стандартные элитроциты, лейкоциты, тромбоциты и т.д. штук 25
2. Всякие нехорошие — ВИЧ, гепатит и т.д.
3. Сахар…

4*… Ещё делали время свёртываемости крови из пальца…

Окей… я вижу 4 сценария…
Ну или как предлагается Вами за 30 даже — если на секунду забыть о том, что человек умрёт от такого большого количества заборов. Кстати — если перевести на язык тестирования, то сценарии экономят время на инициализации. Потому что она проводится реже. 4 против 30 небольшая экономия. Но 100 против 2000 — огого… Особенно, если инициализация тяжёлая…

Окей. Вернёмся к нашей крови… Давайте поанализируем результаты. Я на терапевта не учился… Но рискну предположить, что часто «картиной» является не отдельный анализ, а некоторая совокупность. То есть терапевт, увидев, повышенные тромбоциты заостряет своё внимание на каких-то определённых показателях из общего списка анализов, отвергая в голове версии, или подтверждая их. Получив некоторую наибольшую вероятность, он/она принимает решение о том, к кому направить…

Согласитесь, добавив в мои 4 сецнария немного макс-правдоподобия и гипотетическую таблицу направлений в зависимости от того, на что похожа «картина», я получу неплохой движок, отвечающий с точки зрения тестирования(анализа) крови на бОльшее количество вопросов, чем изолированные проверки каждого из показателей.
1

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity