А как быть, если класс реализует 2 интерфейса, и его нужно зарегистрировать как синглтон таким образом, чтобы при резолве любого из интерфейсов возвращался один и тот же экземпляр?
А потом в реальной жизни внезапно потребуется, помимо числовых значений, в JSON положить текстовые, потом там встретится кавычка, которую забыли экранировать, и привет...
JSON в РСУБД - это плохо. EAV, как принцип хранения всех основных данных в РСУБД - тоже плохо.
Такая аргументация нормальна при общении с трехлеткой. Для людей постарше желательно давать какое-то обоснование.
Как по мне, так наоборот, разветвленные сущности с переменным составом полей, которые обычно извлекаются целиком, намного удобнее и эффективнее хранить в JSON-е, чем делать 20 left join-ов при сильно нормализованной форме или танцевать с таблицами атрибутов, пытаясь хоть как-то выжать из них перформанс. Ваш опыт может отличаться от моего, но на доводах "это плохо, потому что плохо" дискуссию не построить.
В защиту кандидатов, указывающих опыт вне IT в своем резюме - в этом может определенная польза, если кандидат работал в том же бизнес-домене, куда ищется специалист. Зная кухню изнутри, он гораздо быстрее и качественнее вольётся в работу при прочих равных. Но это относится, в первую очередь, к аналитикам и QA, а к разработчикам - пожалуй, в малой степени.
Так я и не призываю все гвозди забивать одним молотком. Ваше решение хорошее и подходит для многих сценариев, но одновременно есть сценарии, где другие решения (например, те же enum-ы или record struct, как в SmartEnum) кажутся более уместными. Пользователю библиотеки знание о том, что какой-то тип занимаем 7 бит, мало что даёт, для него это чаще всего малосущественная деталь реализации. А вот гарантия на уровне типов, что переменная с номером канала не будет записана в поле, ожидающее ноту - это полезно, это удобно.
Что касается возможности получения невалидного значения в enum-е при совершении арифметических операций - так это для любого способа представления так. Контроль выхода за границы необходимо делать независимо от формата. И я не знаю, может быть пользователи библиотеки и правда активно складывают и умножают ноты, но более рациональным видится дать возможность прибавить вычесть интервал (терция, квинта, октава...) или найти разницу между двумя нотами в виде интервала. Такой сценарий опять же удобнее реализовывать через отдельные типы (можно провести аналогию с DateTime + TimeSpan), а не через единый универсальный SevenBitNumber.
Для 127 значений можно подумать в направлении enum-ов. Они дают практически все те же преимущества, но сверх того помогают не перепутать порядок, в котором аргументы передаются в метод (note, velocity или velocity, note), а также позволяют задать человекочитаемую семантику:
enum Pitch : byte
{
C0 = 0, /*Значения наобум, я понятия не имею, какое соответствие нот кодам*/
Csharp0 = 1,
D0 = 2,
...
}
Для Velocity польза сомнительна, конечно, но для нот - вполне удобно, мне кажется.
Главный мой поинт в том, что не бывает одного "как надо". Вовремя заданный PO вопрос (вместо восприятия задачи как математически точной) может привести к ответу: эх, точно, а про это-то мы и не подумали, у нас верстка на дашборде ожидает строго одну фамилию, надо с дизайнером обсудить... А может не привести.
Запросы надо писать с нуля под задачу, а не костылить старые под "похожую" задачу.
Это довольно категоричное утверждение, как будто в реальности существует единственное "как надо" (что особенно иронично в контексте обсуждения статьи, где "начальник уверен, что запрос надо писать только одним единственно правильным образом"). На мой взгляд, реальность немного сложнее и в разных ситуациях может требоваться разное. Например, уточнить, а что делать с ситуацией, когда самую большую зарплату получают несколько сотрудников в отделе. Если надо вывести всех - то варианты с MAX, RANK и LEFT JOIN равно подходят. А если окажется, что вернуть надо строго одного сотрудника (иначе дальше где-то что-то сломается) - то стоит уточнить "по какому критерию выбирать топового сотрудника?" и использовать DENSE_RANK.
Помимо производительности запроса бывают и другие нефункциональные требования, которые тоже имеют значение. И когда нам нужна производительность любой ценой - ну да, тогда наверное оправдано под каждое изменение требований переписывать запрос целиком, чтобы выдать максимум. А если важны поддерживаемость и готовность к изменениям требований, при этом объемы данных не такие, чтобы доставлять проблемы - то лучше бы иметь понятный, легко читаемый запрос, который легко адаптируется от "топ 1" к "топ N" и к "все с наибольшей зп".
В защиту варианта с rank() отмечу, что с его помощью легче всего адаптировать запрос под внезапное изменение требований вида "а теперь выведи топ-3 сотрудников по зп в каждом отделе".
И в копилку вариантов добавлю ещё один без агрегатных и оконных функций
SELECT e.name AS employee, e.salary
FROM employees e
LEFT JOIN employees e_higher
ON e.department_id = e_higher.department_id
AND e.salary > e_higher.salary
WHERE e_higher.id IS NULL
Надо смотреть планы, но зачастую запросы в такой форме оказываются весьма эффективными.
Так своя разработка заведомо будет содержать несколько процентов от требуемой привычной функциональности, и ее долго-долго нужно будет развивать. И всё это время в ее сторону будут плеваться, называя никчёмной поделкой и обучая разработчиков жизни: "не могли что ли зрелое решение за основу взять?" Посмотрите тон обсуждений статей вида "мы пишем свою СУБД с нуля" - там то же самое.
Какие интересные комментарии. Представляю, если бы Сбер написал полностью своё решение, была бы тонна комментов в духе: "нахрена было столько ресурсов тратить на разработку с нуля, не могли VSCode форкнуть? Кто к этому будет плагины писать?" Форкнули бы VSCode, была бы тонна комментов "Нахрена было VSCode форкать, он и так бесплатен. Не могли что ли IDEA форкнуть?" И все лучше всех знают, как надо, ЧСХ.
Вот конкретно проблему поиска и замены в сотнях файлов XLSX как раз можно было решить за секунды плюс несколько минут на написание PowerShell скрипта, если воспользоваться тем фактом, что XLSX - это zip-архив с XML-ками. Макросы я бы оставил для каких-нибудь более сложных манипуляций.
По-моему, тема сообщений об ошибках неполна без рассказа об их локализации. В теории, там всё легко, локаль настраивается в одном месте, но в деталях вылезают всякие неприятные мелочи, вроде того, что текст сообщения выводится по-русски, а даты в плейсхолдерах форматируется в US-формате.
Всех подробностей не помню, но где-то что-то приходилось подпиливать напильником. И это у нас ещё не было потребности отдавать разным пользователям ответ на разном языке, там бы наверняка ещё что-то вылезло.
Если вы используете стороннюю библиотеку, в которой такие структуры не определены, а вам хочется свой код сделать более лаконичным и наглядным - то использование алиасов позволит это сделать без введения доп. типов, конвертации, нагрузки на GC и т.п. Понятно, что этот вариант использования является довольно узким, и без него вполне можно же жить, ну так это вообще ко всем алиасам относится (тот же `using static ...` всего лишь позволяет чуточку меньше символов писать. Мелкая, иногда приятная, но точно не необходимая "плюшка")
Джуниоры и Миддлы могут предложить новое решение с их прежнего места работы/учёбы,
Тут у меня большие сомнения. Так-то и джуниор, и сеньор могут сказать "у нас на прошлом проекте использовался X для Y", но навыков Джуна или Мидла (если только это не "сильный мидл, почти сеньор) вряд ли хватит на то, чтобы сопоставить требования, которые были "там" и есть "тут", оценить подводные камни и издержки по внедрению того решения и принять взвешенное решение о целесообразности этого. А у сеньора и опыта прошлых проектов побольше обычно. Так что этот пункт вообще мимо.
А как быть, если класс реализует 2 интерфейса, и его нужно зарегистрировать как синглтон таким образом, чтобы при резолве любого из интерфейсов возвращался один и тот же экземпляр?
А потом в реальной жизни внезапно потребуется, помимо числовых значений, в JSON положить текстовые, потом там встретится кавычка, которую забыли экранировать, и привет...
Мне ещё с операторами понравилось - довольно изящно получилось.
Такая аргументация нормальна при общении с трехлеткой. Для людей постарше желательно давать какое-то обоснование.
Как по мне, так наоборот, разветвленные сущности с переменным составом полей, которые обычно извлекаются целиком, намного удобнее и эффективнее хранить в JSON-е, чем делать 20 left join-ов при сильно нормализованной форме или танцевать с таблицами атрибутов, пытаясь хоть как-то выжать из них перформанс. Ваш опыт может отличаться от моего, но на доводах "это плохо, потому что плохо" дискуссию не построить.
Там был NULL, насколько я помню.
Кузов типа самосвал сильно проще.
Медиана так не работает. Чтобы получить медиану в 500К, надо чтобы половина выборки получала более 500К.
В защиту кандидатов, указывающих опыт вне IT в своем резюме - в этом может определенная польза, если кандидат работал в том же бизнес-домене, куда ищется специалист. Зная кухню изнутри, он гораздо быстрее и качественнее вольётся в работу при прочих равных. Но это относится, в первую очередь, к аналитикам и QA, а к разработчикам - пожалуй, в малой степени.
Так я и не призываю все гвозди забивать одним молотком. Ваше решение хорошее и подходит для многих сценариев, но одновременно есть сценарии, где другие решения (например, те же enum-ы или record struct, как в SmartEnum) кажутся более уместными. Пользователю библиотеки знание о том, что какой-то тип занимаем 7 бит, мало что даёт, для него это чаще всего малосущественная деталь реализации. А вот гарантия на уровне типов, что переменная с номером канала не будет записана в поле, ожидающее ноту - это полезно, это удобно.
Что касается возможности получения невалидного значения в enum-е при совершении арифметических операций - так это для любого способа представления так. Контроль выхода за границы необходимо делать независимо от формата. И я не знаю, может быть пользователи библиотеки и правда активно складывают и умножают ноты, но более рациональным видится дать возможность прибавить вычесть интервал (терция, квинта, октава...) или найти разницу между двумя нотами в виде интервала. Такой сценарий опять же удобнее реализовывать через отдельные типы (можно провести аналогию с DateTime + TimeSpan), а не через единый универсальный SevenBitNumber.
Для 127 значений можно подумать в направлении enum-ов. Они дают практически все те же преимущества, но сверх того помогают не перепутать порядок, в котором аргументы передаются в метод (note, velocity или velocity, note), а также позволяют задать человекочитаемую семантику:
Для Velocity польза сомнительна, конечно, но для нот - вполне удобно, мне кажется.
Главный мой поинт в том, что не бывает одного "как надо". Вовремя заданный PO вопрос (вместо восприятия задачи как математически точной) может привести к ответу: эх, точно, а про это-то мы и не подумали, у нас верстка на дашборде ожидает строго одну фамилию, надо с дизайнером обсудить... А может не привести.
Это довольно категоричное утверждение, как будто в реальности существует единственное "как надо" (что особенно иронично в контексте обсуждения статьи, где "начальник уверен, что запрос надо писать только одним единственно правильным образом"). На мой взгляд, реальность немного сложнее и в разных ситуациях может требоваться разное. Например, уточнить, а что делать с ситуацией, когда самую большую зарплату получают несколько сотрудников в отделе. Если надо вывести всех - то варианты с MAX, RANK и LEFT JOIN равно подходят. А если окажется, что вернуть надо строго одного сотрудника (иначе дальше где-то что-то сломается) - то стоит уточнить "по какому критерию выбирать топового сотрудника?" и использовать DENSE_RANK.
Помимо производительности запроса бывают и другие нефункциональные требования, которые тоже имеют значение. И когда нам нужна производительность любой ценой - ну да, тогда наверное оправдано под каждое изменение требований переписывать запрос целиком, чтобы выдать максимум. А если важны поддерживаемость и готовность к изменениям требований, при этом объемы данных не такие, чтобы доставлять проблемы - то лучше бы иметь понятный, легко читаемый запрос, который легко адаптируется от "топ 1" к "топ N" и к "все с наибольшей зп".
В защиту варианта с rank() отмечу, что с его помощью легче всего адаптировать запрос под внезапное изменение требований вида "а теперь выведи топ-3 сотрудников по зп в каждом отделе".
И в копилку вариантов добавлю ещё один без агрегатных и оконных функций
Надо смотреть планы, но зачастую запросы в такой форме оказываются весьма эффективными.
Так своя разработка заведомо будет содержать несколько процентов от
требуемойпривычной функциональности, и ее долго-долго нужно будет развивать. И всё это время в ее сторону будут плеваться, называя никчёмной поделкой и обучая разработчиков жизни: "не могли что ли зрелое решение за основу взять?" Посмотрите тон обсуждений статей вида "мы пишем свою СУБД с нуля" - там то же самое.Какие интересные комментарии. Представляю, если бы Сбер написал полностью своё решение, была бы тонна комментов в духе: "нахрена было столько ресурсов тратить на разработку с нуля, не могли VSCode форкнуть? Кто к этому будет плагины писать?" Форкнули бы VSCode, была бы тонна комментов "Нахрена было VSCode форкать, он и так бесплатен. Не могли что ли IDEA форкнуть?" И все лучше всех знают, как надо, ЧСХ.
Вот конкретно проблему поиска и замены в сотнях файлов XLSX как раз можно было решить за секунды плюс несколько минут на написание PowerShell скрипта, если воспользоваться тем фактом, что XLSX - это zip-архив с XML-ками. Макросы я бы оставил для каких-нибудь более сложных манипуляций.
Абсолютно неадекватные цифры для 2024 г. Даже затрудняюсь сказать, на сколько лет они отстали от рынка.
По-моему, тема сообщений об ошибках неполна без рассказа об их локализации. В теории, там всё легко, локаль настраивается в одном месте, но в деталях вылезают всякие неприятные мелочи, вроде того, что текст сообщения выводится по-русски, а даты в плейсхолдерах форматируется в US-формате.
Всех подробностей не помню, но где-то что-то приходилось подпиливать напильником. И это у нас ещё не было потребности отдавать разным пользователям ответ на разном языке, там бы наверняка ещё что-то вылезло.
Если вы используете стороннюю библиотеку, в которой такие структуры не определены, а вам хочется свой код сделать более лаконичным и наглядным - то использование алиасов позволит это сделать без введения доп. типов, конвертации, нагрузки на GC и т.п. Понятно, что этот вариант использования является довольно узким, и без него вполне можно же жить, ну так это вообще ко всем алиасам относится (тот же `using static ...` всего лишь позволяет чуточку меньше символов писать. Мелкая, иногда приятная, но точно не необходимая "плюшка")
Тут у меня большие сомнения. Так-то и джуниор, и сеньор могут сказать "у нас на прошлом проекте использовался X для Y", но навыков Джуна или Мидла (если только это не "сильный мидл, почти сеньор) вряд ли хватит на то, чтобы сопоставить требования, которые были "там" и есть "тут", оценить подводные камни и издержки по внедрению того решения и принять взвешенное решение о целесообразности этого. А у сеньора и опыта прошлых проектов побольше обычно. Так что этот пункт вообще мимо.