Pull to refresh
3
0
Евгений Кочуров @evkochurov

Руководитель отдела разработки

Send message

Я больше 20 лет занимаюсь разработкой корпоративных информационных систем, из них почти 10 - в такой суровой отрасли, как медицина. Да, жизнь часто ставит в условия, когда хороший код написать в принципе нельзя, даже если очень хочется. Тут не только ограниченные сроки и бюджет на разработку. Есть внутриорганизационные конфликты интересов, неснимаемые противоречия в требованиях и много чего еще. И если ты стоишь перед выбором, решить задачу хоть как-нибудь или вообще никак (и понимаешь, что тот, кто придет на твое место, встанет перед тем же выбором), то невольно начинаешь искать подходы

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

  1. Порядок колонок в отчете, по-хорошему, должен настраиваться в справочнике номенклатуры. Если по-хорошему нельзя, все равно пишем отчет так, как будто доступ к сортировке справочника номенклатуры у нас есть: пишем функцию (или выделяем блок кода под это прямо в отчете), которая возвращает отсортированный (и если надо - профильтрованный) список номенклатуры для данного отчета. Внутри этой функции/блока, естественно, говнокод: захардкоденный список. Так мы минимизируем телодвижения при изменении справочника номенклатуры. А если небо будет благосклонно, и настройка в справочнике таки появится, или директор откажется от "особого" порядка колонок, то говнокод можно будет удалить достаточно дешево.

  1. Не удалось формулу расчета уложить в одну функцию, хотя, по-хорошему, она должна быть единой? Все равно пишем одну функцию. Просто внутри будет говнокод: if, который по ИД номенклатуры запускает разные вычисления. Если небо будет благосклонно... Ну вы поняли :) Во всяком случае, вся остальная часть отчета будет написана стройно, а не превратится в говнокод из-за того, что нужно разные функции вызывать, в зависимости от данных.

Возможно, эти предложения и не удалось бы в той ситуации применить прямо в таком виде, они просто служат демонстрацией хода мысли.

Инвентаризация - это стандартный способ актуализировать остатки при внедрении новой системы, если мы не очень доверяем остаткам в старой. По сути, как сказал @Fragster, инвентаризация по затрачиваемым усилиям фактически равна переносу остатков.

Нужно лишь подождать пока новый сервис немного поработает

Правильно ли я понимаю, что это "немного" находится в прямой зависимости от времени жизни отдельно взятого остатка на балансе сервиса? Если так, то такой подход не применим для учета долгоживущих остатков. Неликвиды на складе магазина - не редкость, даже у продуктового консервы год-другой могут валяться. Это стоило бы указать в статье.

И Вам спасибо за статью! Мы тоже находимся в процессе миграции, любая информация полезна.
Null его ставит в тупик, так как он определяет его как unknown. Возможно, тут есть какой-то workaround, но сходу мы его не нашли.

мы эту проблему решали явным приведением типов параметров:
select * from some_function(some_param::some_type)
если hibernate отказывается есть ::, можно попробовать CAST
Если я правильно понял теорему о неполноте, мы, находясь внутри данной системы, не сможем ответить на эти фундаментальные вопросы вообще, т.к. эти параметры определяют саму систему и нас в том числе.

Строго говоря, нет.
Во-первых, эта теорема не касается ненаучных методов познания (религия, искусство).
Во-вторых, она утверждает, что всегда найдутся какие-то вопросы, на которые мы не можем ответить, но не утверждает, что все интересующие нас вопросы останутся без ответа.
«Чтобы продать что-нибудь ненужное, нужно сначала купить что-нибудь ненужное» (с) кот Матроскин.

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

За этот подход ребята из внедрения меня иногда поругивали (порой, заслуженно :)) — мало того, что обсуждения и поиск альтернативных решений требовал от них дополнительных усилий, так потом же еще и заказчика за его же деньги приходилось убеждать, что его хотелку мы делать не будем, кушайте то, что есть.

Однако, спустя годы, когда я уже ушел с этого направления, общался с одним из бывших коллег на эту тему. Вот что он мне сказал: «когда ты ушел, наши просьбы что-то добавить стали выполняться легко и непринужденно, но теперь система превратилась в монстра». Это стало реальной проблемой. Дошло до того, что самый монстроидальный модуль переписали заново, вырезав все, что только можно.
Если мы все еще говорим об оргструктуре, то это какая-то немыслимая для меня постановка. Можете привести пример из жизни, где такое может пригодиться?

Если же мы говорим о поиске кратчайшего пути в абстрактном (т.е. до приземления в некоторой предметной области) графе, то да, можно. Рекурсивный запрос — это обычный поиск вширь по графу, а уж что делать с найденными путями (какие характеристики путей собирать, что и в какой момент отбросить, как отсортировать и т.д.), зависит от конкретной задачи.

И хотя можно, не думаю, что стоит. Если вы хотите решать графовые задачи непременно в РСУБД общего назначения, то это значит, что у вас какая-то очень специфическая задача. Ну вот, например, в оргструктурах не бывает циклов, а это значит, не надо заморачиваться обнаружением этих самых циклов. А если соблюдается принцип единоначалия, то еще и путь между любой парой вершин единственен, а к его поиску можно применить существенные оптимизации.
Из текста осталось неясно:
1. Для чего нарезали ребра графа на половинки?
2. Чем не подошло типичное для такого сорта задач решение на рекурсивных CTE?

Я бы эту задачу решал как-то так: www.db-fiddle.com/f/urNknBbgKFJ6x8B5aJJC7p/4
Вроде проще получается.
GCD — greatest common divisor, наибольший общий делитель (НОД, а не НОК). Простите, но дальше этого момента читать не смог.
Что касается содержания статьи. Вы в первом же совете предлагаете типичные грабли: структурирование файлов по техническим ролям, а не по компонентам. Почему это плохо? Читайте ссылку выше. Но и здравого смысла должно быть достаточно, чтобы увидеть: если вы захотите разобраться, как работают Users, то будете метаться минимум по трем папкам (controllers, models, routes). И так, разумеется, будет с любой компонентой.

По моему опыту, единственный период жизни проект, когда такая структура дает хоть какой-то профит — это когда устаканивается инфраструктура и частно нужно «проходить рубанком» по всем компонентам скопом, внося однотипные правки. Но тут надо понимать, что этот период устаканивания временный (и он тем короче, чем больше опыта), а вот компоненты будут правиться всегда, пока проект жив.
Не могу не оставить это здесь: Node.js Лучшие практики
Вы точно на дату смотрели, прежде чем комментировать?
Спасибо. А то я уже начал переживать, каким образом MSSQL придумал выполнить второй запрос эффективнее первого на таких исходных данных.

То, что планы получились одинаковыми — так в идеале и должно быть, поскольку запросы семантически эквивалентные. Но в жизни это происходит, к сожалению, не всегда, особенно с запросами похитрее. Огорчает и то, что третий вариант не всегда доступен, например, когда платформа, под которую пишется запрос, берет на себя сортировку и пагинацию, а программисту дает только базовый запрос написать. Мы с этим наелись в Oracle Application Express в свое время.
DDL и тексты запросов покажете? Хочу планы запросов посмотреть, для общего развития.
Да на каждом шагу. Самое типичное — join десятка таблиц + order by.
www.db-fiddle.com/f/uSjTZ1u5zFZKqBjwLesi6c/1
Запрос #1 в пять раз быстрее #2. Если посмотреть в планы запросов, то понятно, что это еще не предел, с ростом данных и числа join-ов разрыв будет расти.

Понято, что конкретно в данном случае запрос #2 можно переписать в запрос #3. Но, во-первых, на практике вы не всегда будете иметь возможность протащить (order by + limit) вглубь запроса. А во-вторых, план запроса #3 ничем не лучше плана #1. Вот конкретно в данном случае выполняется за сопоставимое время, но все же чуть дольше, чем #1.

Можно пенять, что, мол, планировщик глуповат у PG. Не принимается :) У Оракла та же история. Про современный MS SQL ничего не могу сказать, т.к. не работал с ним уже лет 10.
Это смотря какой запрос. Если аналитический, для отчета на мильён строк — да, не надо. А если тащим десяток записей для веб-странички с пагианцией — уже не так однозначно, какой вариант будет эффективней работать.
Обновить файл в кэше из кода Service Worker'а элементарно. Единственное, Service Worker должен как-то понять, что обновление необходимо.
Если делать это, как выше предложено (менять адрес файла), то можно даже старую версию файла из кэша удалить, чтобы место зря на устройстве не занимать.
В общем, для всяких хитрых случаев, когда стандартного кэширования не хватает, вполне можно этот процесс под свой контроль взять.
Все остальные их действия просто кричат о том насколько мало там профессионалов.

Мне кажется, Вы здесь совершаете логическую ошибку. Если Вы обладаете информацией о провалах спецслужб, то вполне можете оценить, насколько много там непрофессионалов. Но сколько там профессионалов (тех, кто не прокалывается) — по общедоступной информации не можете никак.
Да, это быстро, но на физическом уровне создается новая версия строки а не перезаписывается существующая, т.е. мы получаем полную копию всего jsonb (с заменой одного поля), в то время, как в EAV — только копию строки, содержащей измененное значение. Как интенсивные обновления больших jsonb повлияют на размер WAL и TOAST-таблиц, на поведение VACUUM — вопрос, который я бы игнорировать поостерегся.

Хотя с основным посылом я согласен — jsonb во многих случаях выглядит предпочтительнее, чем EAV. Указываю только на то, что в общем случае нагрузка на БД не сводится к одним только select-ам.

Information

Rating
Does not participate
Location
Россия
Registered
Activity