Как стать автором
Обновить
30
0.5
Валерий @mvv-rus

Ненастоящий программист

Отправить сообщение

Авито буквально на днях опубликовало статистику:
Цитата:

Рост числа вакансий не влияет на рост зарплат. Это показывает свежая статистика «Авито-Работа» по отрасли маркетплейсов. В сравнении с 2022 годом, в 2023 г. число вакансий для специалистов сегмента маркетплейсов выросло в 2,3 раза, а средние предлагаемые зарплаты увеличились лишь на 2%, до 47.841 руб. С учётом инфляции в 7,5% реальная средняя зарплата даже упала на 5% - и это при таком увеличении спроса на работников. «Топ самых востребованных сотрудников сферы маркетплейсов возглавили маркетологи. Спрос на них год к году вырос в 3,5 раза, а средние зарплатные предложения остались практически неизменными и составили 46.438 руб.».

Ув. Григорий, а вы уверены, что статистика по всяким там "менеджерам маркетплейсов" дает достаточные основания, чтобы судить о состоянии рынка труда разработчиков? Больно уж разные требования предъявляют эти профессии а потому больно уж различаются эти сегменты рынка труда.

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

Английский язык. Документации на что угодно на русском языке и до 2.14 и тем более 2.22 было очень мало для чего-то сложнее do wr, сейчас информации все меньше и меньше

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

План бесшовного релиза

Когда новый код с soft delete на проде, старый уникальный индекс нужно удалить. Иначе он не даст добавить новые записи, аналогичные удаленным с помощью soft delete. C другой стороны, нельзя удалять старый уникальный индекс, пока работает старый код. 

Нам пришла идея: вместе с новым partial индексом создать временный поисковый индекс — аналогичный старому, но без ограничения уникальности.

...

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

Вы не пробовали оценить вероятность появления в таблице по-настоящему дублирующих записей (с deleted_at is null)? А то ведь буде такая появится, то ваш замечательный частичный индекс просто не создастся.

PS Есть еще пара вопросов, чисто технических, но они не в тему IMHO. Потому что тема - она как уронить бой и выжить после этого.

Вы тут описали лабораторные условия, не имеющие никакого отношения к реальному коду в современном C#.

Я описал контрпример к вашему чрезмерно общему утверждению. А к действительности это тоже очень даже может поиметь отношение, если, к примеру, потребуется организовать пересчет значений ячеек в электронной таблице. Но не это главное.

Вообще, я гляжу, вы тут друг сдругом спорите, даже не опрделив, что означает понятие "асинхронный". А так спорить можно долго и бестолку. И я, если что, в такого рода дискуссии участвовать не немерен.

Лично я привык вообще думать не в этих новомодных терминах, а -в понятиях "задача", "поток выполнения(который по-анлийски - flow, а не thread), "многозадачность" - "кооперативная" и "вытесняющая" - "исполнитель" (обычно - "исполнительное устройство", но может быть и человек), "параллельность" работы разных исполнителей и прочим из старых книжек, по которым я учился: проблема неэффективности чисто поледовательного выполнения, если что, была осознана в индустрии еще лет шестьдесят назад, если не больше. Я знаю, как эти понятия определить для себя и, если надо - сформулировать для других, чтобы определиться, о чем речь.

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

Асинхронная операция, например сетевой запрос, будет выполняться в любом случае.

Попробую таки уточнить в вышеуказанных терминах. Асинхронность для операции, как я понял, означает, что для нее есть альтернативный исполнитель, выполняющий ее независимо от основного (под которым подразумевается CPU). Если так, то ничто не мешает в наше время сделать асинхроной и чисто вычислительную операцию. У современных CPU есть несколько независимо работающих ядер, каждое из которых может поддерживать независимый поток выполнения, которому можно поручить выполнение другой задачи.

Более того, современный CPU в реальности состоит из некоторого количества более или менее специализированных исполнительных устройств, работающих более-менее параллельно, так что для более полной их загрузки может иметь смысл спланировать выполнение на них двух квазинезависимых потоков: Intel, к примеру, использует эту технологию, называя ее hyper-threading. А потому в ряде применений вполне может быть осмысленно разделить операции, даже упирающиеся в один CPU, но требующие, в основном, разных исполнительных устройств этого CPU, на две задачи для двух потоков, выполняющихся, пусть и на одном ядре, но в значительной степени параллельно. Например, если программа считает какой-нибудь условный матан и результаты выводит в какой-нибудь условный джейсон - то есть, для этого сравнивает и перемещает байтики, складывает-вычитает чисто целые числа и делает прочие простые операции. то такая программа вполне может почти что параллельно на одном и том же ядре CPU в одном потоке считать матан, а в другом - делать из него джейсон, тем самым более полно загружая все исполнительные устройства ядра.

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

По поводу сравнения со StringBuilder. Какие именно сценарии интересуют? В

В общем-то - любые манипуляции со строками. Но это так, чисто пожелания, чисто посмотреть, чтобы знать на будущее. В отличие от гражданина, страдающего тут по UTF-8, с практической стороны у меня сейчас никаких нужд пока нет.

Ну и пусть он ждет синхронно. Но для того, кто вызывает GetModel(), асинхронность будет - он в это время может сделать что-то полезное? Или я как-то неправильно понимаю слово "асинхронность"? Ну, тогда ладно: это - всего лишь слово.

Но глаавное "не то" написано не здесь, а вот тут

Потоки освобождаться не будут. Наоборот, текущий поток должен дождаться выполнения Task, которая обращается к БД.

Вот это - уже не всего лишь слово, а неправильное описание того, что происходит: текущий поток вполне себе продолжает выполняться дальше: возвращается в код, вызвавший метод GetModel() и может там сделать что-то ещё, пока где-нибудь не понадобится узнать результат этого синхроннно ожидающего выполнения обращения к EF. А если и там, где надо узнать, тоже await, и тоже - первый сработавший, то поток вернется ещё на один уровень вложенности выше и т.д. - пока не упрется в Wait или не вернется, к примеру (допустим, что никакого контекста синхронизации у нас нет), в пул, выполнив всю доступную на данный момент работу.

Но эта операция не будет ассинхронной, она будет параллельной.

Ну, почему-же? Если это будет чисто вычислительный метод, но - помеченный как async и не забывающий время от времени делать await Task.Yield(), то он вполне может работать и в однопоточном контексте синхронизации - по очереди с основным методом, получая от него управление когда он, в свою очередь, делает await. То есть, выполнение получается квази-параллельным. Лучше всего оно описывается старым, (но ныне ставшим популярным у плюсовиков, потому что недавно в стандарт C++ наконец-то завезли их поддержку) словом "сопрограмма".

Собственно в системах с коооперативной многозадачностью - Win3.x, к примеру - мы так и жили тогда: там был ровно один поток управления. Только тогда не было такого замечательного компилятора, который был способен развернуть async/await в машину состояний, и приходилось отдачу управления делать по-другому: например, через вторичный цикл сообщений. Или - явно разбивать выполнение на куски и запускать их по очереди через PostMessage.

Не буду говорить за все остальное, но async/await блок провальный.

Он вообще содержит не только неточности, но и явную ошибку:

async Task<Model> GetModel(Func<Model, bool> condition)
{
   var model = await Task.Run(dbContext.Models.FirstOrDefault(condition);)
   return model;
}    

Этот код выше будет работать, но асинхронности здесь не будет. Потоки освобождаться не будут. Наоборот, текущий поток должен дождаться выполнения Task, которая обращается к БД. В момент когда выполнение доходит до await выполнение прерывается и текущий поток освобождается. Но код внутри Task не является асинхронным, и он заморозит поток, пока не получит ответ от БД.

В цитате - чушь. В реальности await Task.Run тут же (если созданная задача не завершилась сразу) вернет управление в метод вызвавший GetModel() и тот может выполнить что-то ещё, пока ему не потребуется результат от GetModel(). А до того текущий поток отнюдь не прерывается, а продолжает выполнять код вызывающего метода.

Что там дальше в статье - не читал: этого мне достаточно, чтобы сделать вывод.

PS А еще - по синглетону: автору, похоже, невдомек, что сервис-Singleton - это типичный обитатель DI-контейнера, без которого, например, приложение на ASP.NET Core просто не может обойтись.

Как я полагаю, чисто в задаче извлечения подстроки Span (AsSpan+ToString) вряд ли будет существенно быстрее, чем стандартный метод: все равно память потребуется выделять один раз, под результат и копировать результат туда. Я прав?

Но вот если потребуется обработка, которую одним стандартным методом не сделаешь, то там разница может быть существенной. Если будете писать статью про Span - мне был бы интересен именно этот аспект. И - сравнение с использованием не String, а StringBuilder как альтернативы.

Был бы рад прочитать.

Они могут быть "весьма квалифицированы", но они будут хуже тех кто с другой стороны.

Как показывает практика, на совершенно разные с моральной точки зрения стороны могут работать люди высокой квалификации вполне сопоставимых уровней. Пример - атомные проекты СССР и США в плане ключевых для термоядерного оружия решений: схема Теллера-Улама была воспроизведена в СССР совершенно независимо и достаточно быстро, а использование дейтрида лития-6 для боезаряда было предложено в СССР AFAIK даже раньше, чем в США.

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

Так что ваш оптимизм практикой не подтверждается.

Ссылка на Microsoft Virtualization team's blog  из статьи Managing CPU Groups  ведет в никуда, вместо блога

Ссылка исправлена: прямо в цитате выше теперь правильная.

PS На поиск правильной ссылки мне потребовалось минут пять, максимум. Так что можно было бы и не начинать сразу ныть, а таки исправить ещё при написании статьи (IMHO).
Если хотите, поправьте в своей статье сейчас. Но на Хабре обычно комментарии читают до статьи ;-) , так что этого уже, наверное, не требуется (тоже IMHO).

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

И при желании, нет абсолютно никаких проблем выжрать хоть тыщу ядер на винде, было бы желание.

Тут кроме желания нужно ещё и умение. В системном API Windows поддержка более 64 ядер реализована через процессорные группы. Старые API (Get/SetProcessAffinity и Get/SetThread Affinity) ограничены 64 ядрами чисто из-за формата параметров. Соответственно, приложение, чтобы использовать >64 ядер, должно уметь с этими процессорными группами работать. По крайней мере так было, судя по документации, до Windows Server 2022: про него было объявлено что по умолчанию потоки приложения создаются на процессорах во всех группах, а раньше, вроде бы, все потоки по умолчанию создавались в рамках одной группы. К лучшему или к худшему это изменение - не скажу: через процессорные группы реализована ещё и поддержка NUMA (а в наше время каждый физический процессор - это минимум один отдельный узел NUMA), а поток, попавший не на тот узел, будет обращаться к своей памяти в разы медленнее.

PS Если вам захочется подискутировать насчет суперкомпьютеров, то прочитайте комментарий от того же автора, которому вы только что ответили: этот комментарий даст вам ответ (на самом деле - давно известный) на вопрос почему нет Windows на суперкомпьютерах.

PPS Я в здешней священной войне, как я написал выше, решил в этот раз не участвовать, так что по существу этой войны мне отвечать не надо.
Но если нужны ссылки на документацию по упомянутым API (вдруг сами найти не можете) - поделюсь. Заодно попутно могу поделиться кое-чем из документации уже на .NET на указанную тему (там тоже все не просто, кстати - вплоть до того, что некоторые параметры конфигурации в Linux и Windows имеют разный формат - и там для .NET 8 заявлено аналогичное изменение).

@moderator, а это точно новость? Как по мне, так нет. Может, стоило бы перенести ее куда следует?

Из-за страха в собственном рабочем коллективе не распознать и выбрать в управление профсоюзом "крысу", которая вас кинет - вы решаете не объединятся вообще?

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

Вы ведь, судя по комментариям, такой профсоюз имели в виду, да? Так вот, про авторов статьи, что имено имеют в виду под словом "объединяйтесь" они, я такое сказать не могу - недостаточно данных. Именно об этом (и только об этом) я и написал.

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

Так что, теоретически вы, вроде бы, правы, "но есть нюанс"(с). И проявлений этого нюанса в истории профсоюзного движения хватает.

Отвлекаясь от Windows и Linux: статья прекрасно демонстрирует использование приема "вброс", которым тут нередко добывают себе дополнительные просмотры авторы корпоративных блогов.

Суть приема - опубликовать какое-нибудь (лучше - как можно более радикальное) мнение на тему, которая интересна многим и по которой распространены несовместимые точки зрения. И темы древних священных войн - типа Linux vs Windows, как в этой статье - они очень даже подходят для вброса.

Опубликованный вброс как правило привлекает внимание большого количества сторонников обеих точек зрения, сначала - горячих, потом - и всех остальных: одни кидаются опровергать радикальную позицию из вброса, другие - защищать. Короче, возникает то, что лучше назвать иностранным словом flame (есть и русские аналоги, но не хочу подводить Хабр под РКН) - большой поток комментариев, который уже начинает привлекать просто любопытных сам по себе. И, таким образом - обеспечивает статье много-много просмотров, лайков и прочих ништяков авторам корпоративных блогов. При том, что самой компании от того, какая сторона права, а какая - нет, обычно и не жарко, и не холодно. Такая вот получается манипуляция массовым вниманием.

Кстати, для вброса лучше всего использовать что-нибудь переводное, с самой компанией и говорящими от ее лица авторами не связанное. Так компании проще избежать неприязни (обычно нежелательной) одной из сторон начашейся, так скажем, дискуссии. А результат дискуссии, напоминаю, компании, в общем-то вряд ли интересен. И именно такой выбор материала вброса мы видим здесь.

Как к этому относиться - личное дело. Но я рекомендую все же сначала распознать факт испоьзования манипулятивного приема, а уж потом принимать решение, что делать (лично делать вам, естественно).
Я вот свое решение принял: в этой дискуссии не участвовать. Но про использованный прием таки решил написать: конечно этим я отбиваю работу у капитана Очевидного, но вдруг кто не знает?

Как любой догматизм ущербен по своей сути эта формула выхолащивает всё человеческое из поведения бизнесменов.

Вообще-то это не догматизм, а абстракция. То есть - метод приближенного описания действительности. В данном случае, оглашенная в статье абстракция - это самый первый и самый грубый уровень описания действительности в рамках концепции материализма: описание через объективные материальные интересы. Оно опираюется на, то, что я люблю называть "гипотезой Маркса-Энгельса": "общественное бытие определяет общественное сознание". Т .е. этой самой гипотезой такое описание полагается базовым - ну, а дальше это описание можно уточнять и развивать на основе знаний о практике, используя методологию работы с абстракциями, обычно именуюемую диалектикой. Но это - не для Хабра тема: вряд ли тут найдется сколь-нибудь заметное число хоть как-то разбирающихся в этих отвлеченных концепциях. Лично я их когда изучил (в СССР, по необходимости), сдал (на "отлично", если это имеет какое-то значение), но и только.

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

PS Ну, а про Шиндлера уже написали.

Работа проделана хорошая и интересная. Но я так и не понял, надо было ли ее делать вообще. Или задачу можно было бы решить по-другому? Загрузить историческую информацию в другие экземпляры(шарды) БД и организовать к ней доступ только по чтению. То есть - сделать своего рода архив. Вы ведь все равно были вынуждены были ради сокращения времени простоя дорабатывать в программе объекты слоя работы с хранилищем, что логика этого слоя работала с двумя копиями БД. Можно ведь было дорабтоать ее так, чтобы чтение данных производилось из двух экземпляров - рабочего и архивного, и результаты бы собирались в одну логическую сущность, с которой уже работает вышележащий слой. Ну а запись при этом всегда бы шла в рабочий экземпляр.

В такой схеме можно было бы сэкономить, например, на дисках: рабочий экземпляр размещен на чем-то быстром, а архивный - на медленном, типа типа HDD на 7200 об/мин. И на резервном копировании тоже экономить можно. Лично я с такими схемами работал с MS Exchange (там сообщения хранятся тоже в БД, пусть и не реляционной), и было вполне работоспособно.

Интересно узнать, если можно - рассматривали ли вы такой вариант, и если да - почему от него отказались.

Ну, раз вы хотите истории - получите.

Многоверсионники с хранением версий внутри основного хранилища проиграли в OLTP ещё лет двадцать назад, когда Borland отчаялась сделать деньги на купленном когда-то ей Interbase и отдала его исходники в общее пользование. А заодно - отказалась от своего ПО промежуточного уровня под названием BDE. BDE работал с SQL-серверами как с файловыми БД, а потому держал курсор открытым на протяжении всей работы с выборкой в GUI (например - во время редактирования записи на форме Delphi). Такая логика работы действительно требовала для хоть сколь-нибудь эффективной многопользовательской работы многоверсионника. Но времена изменились, и уже в Delphi 5 работа с MS SQL была сделана через ADO и по-нормальному, в духе CQS: данные быстро выбирались на клиент, там как надо правились через GUI, а потом изменения отправлялись командами на сервер. И, насколько я понимаю, в то время PostgreSQL в этой битве ещё не участвовал.

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

Информация

В рейтинге
1 553-й
Зарегистрирован
Активность