А как такие системы делают резервные копии БД? Просто переиспользуют инструменты, предоставляемые разработчиками БД? Или у них свой подход? Если свой, то как обстоят дела с консистентностью и целостностью данных в резервных копиях?
Это полный булщита пресс-релиз, а не статья для технического ресурса. Шутка в тему:
Разница между машинным обучением и искусственным интеллектом:
— Если это написано на Python — это скорее всего машинное обучение,
— Если это написано в PowerPoint — это скорее всего искусственный интеллект.
В долгосрочной перспективе с таким подходом ничего хорошего не получится. В случае если у нас есть десятки типов, которые надо как-то регистрировать или сериализовать, то метод, принимающий на вход много разных типов получится похожим на что-то вроде:
function register($input) {
if ($input instanceof Type1) { /* do smth with Type1 */}
elseif ($input instanceof Type2) { /* do smth with Type2 */}
// ...
elseif ($input instanceof Type999) { /* do smth with Type999 */}
}
В случае с интерфейсом Registerable код будет предельно простым:
function register(Registerable $input) {
$input.register();
}
В случае если мы не контролируем тип, который надо зарегистрировать, то просто делаем для него обертку:
class RegisterableInt implements Registerable {
function register(int $input) {
// do smth with int
}
}
Нет. В таком случае метод на вход должен принимать тип Registerable или Serializable (названия из головы), а соответствующие классы их должны имплементить.
Это понятно. Но на стороне клиентского кода все равно будет неочевидно, что конкретно будет возвращено методом: число или строка, отсюда мой вывод о том, что это не может считаться строгой типизацией.
Кроме того смешивание чисел и строк это явный пример плохого дизайна, как в моем примере выше. И если в случае «Animal|Vehicle» ошибка дизайна очевидна, то чем в таком случае отличается пример с «int|string».
Почитал про юнион типы в PHP 8, в этом посте в качестве примера приводится тип «int|float». Такой тип в сравнении с «int|string» имеет хоть какой-то смысл.
С точки зрения разработчиков PHP это действительно отдельный тип, но с точки зрения здравого смысла это выглядит очень странно. Эту идею можно развить до примерно следующей (псевдокод):
interface Animal
class Cat implements Animal
class Dog implements Animal
interface Vehicle
class Car implements Vehicle
class Moto implements Vehicle
function process(Animal|Vehicle $item)
Очевидно, что метод с такой сигнатурой спроектирован некорректно, не может один метод что-то делать и с животными, и с транспортом. Точно также и «int|string» говорит о некорректном дизайне метода, даже если с точки зрения разработчиков языка это валидная конструкция.
По одной из классификаций, языки программирования неформально делятся на сильно и слабо типизированные.
…
В русскоязычной литературе часто используется термин «строгая типизация»; общепринятый вариант «сильная типизация» используется лишь при противопоставлении «слабой типизации».
Стати́ческая типиза́ция — приём, широко используемый в языках программирования, при котором переменная, параметр подпрограммы, возвращаемое значение функции связывается с типом в момент объявления и тип не может быть изменён позже (переменная или параметр будут принимать, а функция — возвращать значения только этого типа)
Определение «int|string» это не тип, это указание на то, что в этом месте будет или тип int, или тип string, что противоречит определению из цитаты выше.
Тут нет возможности выполнить с аргументами, отличными от string или int
То что в качестве аргумента можно передать или int, или string это уже не строгая типизация. При строгой типизации метод или принимает только int, или принимает только string.
Это уже не примитивный, как не крути. Список примитивных типов фиксирован, а тут комплексный тип.
Здесь int примитивный тип. Тип «или int, или строка» не алгебраический, из-за использования инта.
Кому должен? Откуда такие требования?
Вы можете посмотреть как алгебраические типы данных реализованы в других языках или почитать статью на википедии, вот цитата:
Конструктор представляет собой функцию, которая строит значение своего типа на основе входных значений. Для последующего извлечения этих значений из алгебраического типа используется сопоставление с образцом.
Ключевая фраза здесь: "используется сопоставление с образцом" (другими словами это паттерн матчинг). Если вам заранее неизвестны все классы, то и написать всеобъемлющий паттерн матчинг вы не сможете.
Вот это: string|int не алгебраический тип данных, а кривой костыль, использование которого говорит о том, что метод, использующий такой тип, спроектирован некорректно.
Во-первых, примитивный тип не может быть алгебраическим.
Во-вторых, для алгебраического типа данных должен определяться интерфейс и несколько классов имплементящих этот интерфейс. При этом очень желательно, чтобы заранее были известны все типы имплементящие этот интерфейс. Это может быть достигнуто, например, фичей языка, которая разрешает создавать классы реализующих этот интерфейс только том же файле, где определен интерфейс.
Некорректно сравнивать консольную утилиту с языком программирования. А вот сравнить две консольных утилиты (clickhouse-client и logscli) можно.
Моё приложение требует только того, чтобы в таблице присутствовали колонки со временем и
Все равно это ограничение, которого нет в clickhouse-client и поэтому мне непонятно зачем нужно использовать программу с такой урезанной функциональностью.
Он заточен под ровно одну задачу — быстро и удобно показать текстовые логи и позволяет их легко и быстро фильтровать.
Можно вот так:
clickhouse-client -q "SELECT * FROM table WHERE column LIKE '%some-search-string%'"
Вроде тоже быстро и удобно. И гораздо гибче.
Он также умеет то, что достаточно сложно сделать одним запросом в ClickHouse, например он умеет показывать контекст вокруг совпадений.
Судя по описанию программа ведь просто достает несколько строк вокруг текущей. Это решение приносит мало пользы. Если в лог пишет много потоков, то вокруг строки с ошибкой могут оказаться записи совершенно несвязанные с текущей строкой. В таком случае лучше писать во все логи параметр типа trace_id, затем найти сначала строку с ошибкой, а потом все записи с тем же trace_id.
Вы смешиваете два разных сценария
Нет.
При этом, для той задачи, которую я описываю в статье (например, как я уже говорил, показ контекста вокруг сообщения, или просто фильтрация по фиксированной строке или по регулярному выражению), использовать clickhouse-client напрямую не слишком удобно
Тоже нет. Я уже написал выше, что контекст в таком виде не добавит полезной информации.
Я согласен, что пока логи спокойно помещаются на одну машину и можно использовать обычный tail/grep/less для их просмотра, ничего больше и не требуется, и это справедливо примерно для 90-95% компаний.
Ты невнимательно прочитал комментарий, в нем речь не о хранилище логов, а о просмотрщике.
Если логи лежат в Кликхаусе, то чем твое решение лучше чем стандартный cli-клиент Кликхауса? У последнего как минимум следующие преимущества:
1. нулевая цена разработки и поддержки,
2. поддержка любых схем, а не только той, что захардкожена в твоем приложении,
3. поддержка любых типов запросов, а не только тех, что предусмотрены твоим прложением.
Хочешь сгруппировать логи веб-сервера по коду ответа? Пожалуйста. Хочешь сгруппировать ошибки по типу и посмотреть какие новые ошибки появились с момента последнего релиза? Не вопрос. Хочешь еще каким-то хитрым способом повертеть данными? Все это доступно через стандартный клиент Кликхауса и этого нет logscli.
Если рассматривать это приложение как хеллоу ворлд, написанный, чтобы поизучать го и Кликхаус, то это ок, но это точно не решение для продакшена.
Все-таки я считаю <...> термин «машина» уместнее, я думаю.
Вы можете считать и думать как вам больше нравится, это ваше дело, но у термина finite-state machine есть вполне конкретный однозначный перевод (1, 2, 3). И если вы хотите, чтобы ваш перевод был понятен другим людям, то нужно использовать общеупотребительную терминологию, а не выдумывать свою.
Это же просто ваш домысел основанный на вашем опыте. Я на своем опыте часто сталкивался с ошибочным мнением, что внутри Докера используется lxc, поэтому с тем же успехом могу домыслить, что автор имел ввиду именно то, что написал:
в линуксе их аналог – LXC, который и используется в containerd
Если отбросить домыслы и посмотреть на эту фразу логически, то чему она эквивалентна:
— фразе «внутри containerd используется lxc»
— или фразе «containerd и lxc внутри себя используют одни и те же инструменты предоставляемые ядром»?
А как такие системы делают резервные копии БД? Просто переиспользуют инструменты, предоставляемые разработчиками БД? Или у них свой подход? Если свой, то как обстоят дела с консистентностью и целостностью данных в резервных копиях?
Ошибка в заголовке, правильно: «Хау ту байпассить reCaptcha V3 уиз Selenium Python?»
В случае с интерфейсом Registerable код будет предельно простым:
В случае если мы не контролируем тип, который надо зарегистрировать, то просто делаем для него обертку:
Кроме того смешивание чисел и строк это явный пример плохого дизайна, как в моем примере выше. И если в случае «Animal|Vehicle» ошибка дизайна очевидна, то чем в таком случае отличается пример с «int|string».
С точки зрения разработчиков PHP это действительно отдельный тип, но с точки зрения здравого смысла это выглядит очень странно. Эту идею можно развить до примерно следующей (псевдокод):
Очевидно, что метод с такой сигнатурой спроектирован некорректно, не может один метод что-то делать и с животными, и с транспортом. Точно также и «int|string» говорит о некорректном дизайне метода, даже если с точки зрения разработчиков языка это валидная конструкция.
В моем комментарии выше есть определение алгебраического типа данных и структура «int|string» в него не укладывается.
Нет. Давайте начнем отсюда:
Теперь посмотрим сюда:
Определение «int|string» это не тип, это указание на то, что в этом месте будет или тип int, или тип string, что противоречит определению из цитаты выше.
То что в качестве аргумента можно передать или int, или string это уже не строгая типизация. При строгой типизации метод или принимает только int, или принимает только string.
Здесь int примитивный тип. Тип «или int, или строка» не алгебраический, из-за использования инта.
Вы можете посмотреть как алгебраические типы данных реализованы в других языках или почитать статью на википедии, вот цитата:
Ключевая фраза здесь: "используется сопоставление с образцом" (другими словами это паттерн матчинг). Если вам заранее неизвестны все классы, то и написать всеобъемлющий паттерн матчинг вы не сможете.
Именно это и следует. Если нет, что что тогда такое для вас строгая типизация?
string|int
не алгебраический тип данных, а кривой костыль, использование которого говорит о том, что метод, использующий такой тип, спроектирован некорректно.Во-первых, примитивный тип не может быть алгебраическим.
Во-вторых, для алгебраического типа данных должен определяться интерфейс и несколько классов имплементящих этот интерфейс. При этом очень желательно, чтобы заранее были известны все типы имплементящие этот интерфейс. Это может быть достигнуто, например, фичей языка, которая разрешает создавать классы реализующих этот интерфейс только том же файле, где определен интерфейс.
Некорректно сравнивать консольную утилиту с языком программирования. А вот сравнить две консольных утилиты (clickhouse-client и logscli) можно.
Все равно это ограничение, которого нет в clickhouse-client и поэтому мне непонятно зачем нужно использовать программу с такой урезанной функциональностью.
Можно вот так:
Вроде тоже быстро и удобно. И гораздо гибче.
Судя по описанию программа ведь просто достает несколько строк вокруг текущей. Это решение приносит мало пользы. Если в лог пишет много потоков, то вокруг строки с ошибкой могут оказаться записи совершенно несвязанные с текущей строкой. В таком случае лучше писать во все логи параметр типа trace_id, затем найти сначала строку с ошибкой, а потом все записи с тем же trace_id.
Нет.
Тоже нет. Я уже написал выше, что контекст в таком виде не добавит полезной информации.
Ты невнимательно прочитал комментарий, в нем речь не о хранилище логов, а о просмотрщике.
Если логи лежат в Кликхаусе, то чем твое решение лучше чем стандартный cli-клиент Кликхауса? У последнего как минимум следующие преимущества:
1. нулевая цена разработки и поддержки,
2. поддержка любых схем, а не только той, что захардкожена в твоем приложении,
3. поддержка любых типов запросов, а не только тех, что предусмотрены твоим прложением.
Хочешь сгруппировать логи веб-сервера по коду ответа? Пожалуйста. Хочешь сгруппировать ошибки по типу и посмотреть какие новые ошибки появились с момента последнего релиза? Не вопрос. Хочешь еще каким-то хитрым способом повертеть данными? Все это доступно через стандартный клиент Кликхауса и этого нет logscli.
Если рассматривать это приложение как хеллоу ворлд, написанный, чтобы поизучать го и Кликхаус, то это ок, но это точно не решение для продакшена.
Вы можете считать и думать как вам больше нравится, это ваше дело, но у термина finite-state machine есть вполне конкретный однозначный перевод (1, 2, 3). И если вы хотите, чтобы ваш перевод был понятен другим людям, то нужно использовать общеупотребительную терминологию, а не выдумывать свою.
"конечного состояния машины" в оригинале наверное было finite state machine, по-русски это "конечный автомат".
Это же просто ваш домысел основанный на вашем опыте. Я на своем опыте часто сталкивался с ошибочным мнением, что внутри Докера используется lxc, поэтому с тем же успехом могу домыслить, что автор имел ввиду именно то, что написал:
Если отбросить домыслы и посмотреть на эту фразу логически, то чему она эквивалентна:
— фразе «внутри containerd используется lxc»
— или фразе «containerd и lxc внутри себя используют одни и те же инструменты предоставляемые ядром»?
С версии 0.9, выпущенной в 2014 году, Докер не зависит от LXC: https://blog.docker.com/2014/03/docker-0-9-introducing-execution-drivers-and-libcontainer/