Search
Write a publication
Pull to refresh
21
0
Кирилл Лукашёв @sicikh

User

Send message

Ну и не Алекс, а Алексей)

Вся шутка в том, что это был Rust, а обработка ошибок в Go мне самому не нравится :) и try catch в Rust нет, вообще никакого

Обработать весь массив пользователей, а затем вернуть массив невалидных пользователей:

pub fn process_users(users: Vec<User>) -> Result<(), Vec<ProcessError>> {
  let mut errors: Vec<ProcessError> = Vec::new();

  for user in users.iter() {
    if let Err(invalid_user) = process_user(user) {
      errors.push(invalid_user);
    }
  }

  if errors.is_empty() {
    Ok(())
  } else {
    Err(errors)
  }
}

Обработать массив пользователей и прервать обработку при первом невалидном пользователе:

pub fn process_users(users: Vec<User>) -> Result<(), ProcessError> {
  for user in users.iter() {
    process_user(user)? // или более многословные конструкции
  }

  Ok(())
}

А если ошибка непредусмотренная, то получается, что и восстановиться соответствующе мы от неё не сможем — здесь либо unexpected_error.map_err(|source| MyError::Unexpected { source })? , который завернёт ошибку в какой-то наш тип ошибки, от которого мы восстанавливаемся «в общем порядке», либо повесить поток через panic!("Unexpected error"), чтобы не распространять неопределённое поведение дальше по программе.

Для прототипирования алгоритма в Rust, например, придумали макросы todo!() и unimplemented!(), которые говорят компилятору, чтобы он не задирался на неудовлетворённые типы.

А обрабатывать ошибки придётся в любом случае, сейчас или потом :)

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

fn return_result(res: Result<(), YamlError>) -> Result<(), MyError> {
  res.map_err(|source| MyError::IO { source })
}

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

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

Куча вопросов и слов «вроде». Как раз из-за того, что слышим только одну сторону. Но если рассматривать «абстрактного коня в вакууме» и проблему падения в рантайме из-за отсутствия соединения с Redis, то решение спокойно гуглится за 5 минут и приводится в жизнь. Если же источник проблемы не в этом, то надо дальше смотреть. А как иначе? Бросать всё и говорить «не могу, так как фреймворк плохой»? Ну пусть тогда возьмёт другой, где опыта побольше, если уж изначально хотел поэкспериментировать, что тоже бывает и что, на самом деле, полезно (если простор возможностей такой дали).

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

Предыдущий проект был как раз тем MVP — «давайте не будем запихивать все функции сразу, а сделаем хоть что-то в короткие сроки». Лично меня в конкретной ситуации разработки СУБД такой подход не удовлетворил — банально не хватило теоретической базы, чтобы предварительно учесть будущие требования к продукту.

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

Я всё-таки рассчитываю на то, что, получив опыт создания исследовательских проектов через «сначала в теории, затем всё на практике», получится более разумно подходить к бизнес-разработке. Собственно, что и получается — MySQL не очень-то и нужны были эти транзакции с самого начала, жить можно было и без них :)

Честно говоря, такого взгляда на статью я ещё не видел :)

Всегда радует, что твои собственные потуги воодушевляют кого-то продолжить бороться уже со своей сложностью. Удачной декомпозиции с вашим детищем!

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

Простой взгляд на сложные проблемы встретишь не часто...

Я мельком думал насчёт того, как поведёт данная система в случае, когда операционная система отдаст концы. В общем, должны сохраняться те транзакции, которые были заверены — а заверяются они тогда, когда происходит fsync() в упреждающий журнал. Тогда данные сохранятся в журнале даже при перебое питания (насколько я это понимаю). Если же сбой произошёл при переносе страниц из журнала в основной файл — то данные удаляются из журнала только в самом конце операции. В любом случае эту операцию начнёт сначала первое открытое соединение СУБД, когда оно заметит переполнение журнала, так что заверенные данные останутся в сохранности. По логике...

Очень приятно, спасибо! Ваш недавний пост тоже было приятно перечитывать, занял своё почётное место в закладках :)

Немного подумав, как обычно хорошая мысля приходит опосля, я пришёл к тому, структуру статьи можно было выстроить иначе, более понятно. Но что получилось, то получилось :)

Статья вышла как набор заметок «по поводу», и, собственно, она таким образом и создавалась (см. Zettelkasten). Постараюсь не допустить такой оплошности в будущем — комментарии с критикой на Хабре это очень ценный ресурс для развития. Благодарю за неё!

P. S. Ниже в комментариях один из читателей уже вдохновился продолжить какой-то свой собственный проект. Статья свою задачу выполнила — а остальное лишь послужит почвой для будущих статей. Проба пера — она такая :)

Да, с кодом, соответствующим текущим виденьем архитектуры, не очень густо :)

Прототип, который не знал ни о блокировках, ни о транзакциях, ни об индексах, меня настолько не удовлетворил, что я сознательно начал всё сначала. Это стало похоже на эксперимент — возможно ли по тексту статьи восстановить то, что имел в виду её автор :)

А о вашем проекте наслышан — то ли сезон своих СУБД начался, то ли ретроградный Меркурий. Благодарю, вам тоже желаю удачи!

Благодарю за ответ, минус не мой.

И я согласен с тем, что это самое настоящее галопом по Европам. Но плохо ли это? Может, кому-то и требуется краткий (или не очень) экскурс в происходящее?

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

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

По поводу стилистики текста — кому-то такой стиль очень понравился. Кому-то нет. Разве не так всё устроено в нашем мире? А диагнозы я бы, честно говоря, придержал при себе. Но развиваться есть куда — и я понимаю это как сейчас, так и тогда, в самом начале создания статьи.

По поводу постраничной организации — данный формат организации данных задаёт логику организации БД — какие-то страницы у нас рассказывают о таблицах, другие — о страницах в таблице, третьи же — о самих записях. Это позволяет нам строить индексы на основе деревьев, упрощает логику упреждающего журнала и так далее, и так далее...

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

P. S. Я бы больше задумался о необходимости «виртуальной машины» и кодогенератора. Так ли он нужен при наличии реляционной алгебры — возможно стоит несколько усложнить хранение операций и отсечь необходимость кодогенератора, позволив движку работать непосредственно с ней.

Полная блокировка (предоставление процессу соединения с БД блокировки записи основного файла посредством системного вызова) осуществляется только в момент очистки упреждающего журнала, то есть, когда нам такое поведение и нужно.

В момент чтения из файла БД и чтения/записи упреждающего журнала процессам СУБД предоставляется блокировка чтения/записи только определённой части файла, и зачастую эта часть файла равняется размеру страницы.

Случайности не случайны, не зря в тегах статьи стоит SQLite, а в источниках — её архитектура :)

Для меня она стала путеводной звездой, образом простоты и функциональности — и это позволило мне взглянуть на неё с другой стороны. Если бы многие вещи в SQLite были доступны без дополнительных танцев с бубном через pragma, то, я думаю, у этой СУБД было бы больше поклонников и меньше тех, кто рассматривает её только как СУБД для тестов (что на самом деле является не очень практичным подходом).

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

Благодарю за ответ!

Про строки и NULL — очень интересное наблюдение, обязательно надо ознакомиться с обоснованием для такого решения.

А про версионность записей — я с вами согласен, что СУБД, которые реализуют изоляцию транзакций на основе блокировок отдельных записей, добиваются большей параллельности.

На самом деле, первый прототип, который больше не увидит свет, SicQL пытался в блокировки строк — по крайней мере, в начале пути этого хотелось. Но, столкнувшись с неведомой сложностью сего дела, я быстро идею отбросил. Достаточно наивным было считать, что получится за два месяца теоретически охватить PostgreSQL/..., а затем воплотить в жизнь хоть малейший его клон. После такого провала, хе-хе, взгляд был обращён на SQLite, чья заслуга заключается в том, что изоляция транзакций и многоверсионность относительно других проектов реализованы относительно просто, да так, что для работы с базой данных достаточно одного процесса, который можно запускать непосредственно из приложения.

Но, в итоге, всё получилось как в этой цитате: «Всё не так просто, как кажется на первый взгляд, но и не так легко, как кажется на второй».

Рекомендую читателям ознакомиться ещё с тем, как изоляции транзакций поддерживаются в PostgreSQL.

Я надеюсь, что во второй части статьи получится затронуть теоретическую основу блокировок не просто страниц, а записей в ней.

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

Information

Rating
Does not participate
Location
Томск, Томская обл., Россия
Date of birth
Registered
Activity

Specialization

Backend Developer