Как стать автором
Обновить
40
0.3
Valentin Nechayev @netch80

Программист (backend/сети)

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

ни на одном языке вообще нельзя сравнивать дробные числа на равенство!

Можно и нужно - но, понимая, что именно делаешь и почему. И имея в виду возможные проблемы от реализации. А вот если не понимать... вот тут целое собачье кладбище зарыто.

В обсуждаемом случае сравнение int и float - это не сравнение двух float. Это отдельный вариант (хоть внутри и получается конверсия к float (double), но она замаскирована видом констант). И последствия от него примерно такие же, как в JS ситуация типа "ваш номер карточки 4.1492103e+15". Это больше проблема типизации, чем собственно сравнение floatʼов.

Сравнение floatʼов на равенство вредно тогда, когда мы говорим о результатах вычислений с заведомо приближёнными значениями (типично для прикладной математики всех видов выше, чем 4 арифметические операции). Вот там появляется правило про корректный выбор относительной погрешности (каковой выбор ещё надо осилить, не всегда сразу получается адекватная погрешность).

А вот если значения по каким-то причинам точные (или гарантированно точные, или результат однозначно определённых операций типа i*0.01), тогда и точное сравнение возможно. Также есть случаи сравнения с нулём, как признак полной потери значения (даже не денормализованные). Но очень часто само по себе такое сравнение подсказывает, что выбрана неверная модель представления числа.

В финансовых расчётах точное сравнение возможно и нужно. Но тут вопрос, с какого момента может начаться недопустимое округление. Всякие Decimal из С# маскируют проблему до предела, давая аж до 28 знаков точности... обычно хватает. Но с фиксированной точкой таки честнее (и проблема, если что, выскочит явно).

Но попросту, конечно, можно сказать "нельзя!" и это будет как деление на ноль ;)

База данных является краеугольным камнем любого проекта.

Посмотрел на несколько последних проектов, в которых участвовал.

SIP софтсвич. Общается с чем-то, представляющим себя как биллинг, по кастомному протоколу (RADIUS с вендорскими расширениями). Ну база тоже есть, но очень вспомогательная.

Компонент радиосоты, управление локальной конфигурацией, которая задаёт направление потоков данных через кастомизированное железо. О "базе данных" можно говорить только в плане состояния этой конфигурации в памяти между ребутами. Есть, конечно, центральная база (на всяких etcd), но это конфигурация, которую в основном правят руками.

Можно продолжать...

Я не против статьи в целом, но слишком много упрощений. И почему мне кажется, что вся статья была написана ради одного слова "Swagger"? И чем же он так хорош, что использовать его, а не 100500 аналогов? "Тема <xxx> не раскрыта" (c).

Я не смог нагуглить цитату и контекст, слишком много мусора в поиске. Есть точная ссылка?

при этом нет никаких проблем с производительностью при работе через виртуальные функции

Потому что на 1 единицу затраты времени на вызов виртуальной функции приходится 1000 или 100000 затрат на энкодинг-декодинг, даже с учётом всего ускорения через вылизанный векторный код поверх последнего SSE, BMI2 и прочих вкусняшек.

И поэтому же какие-нибудь считаемые на GPU нейросети работают под запускалкой на Python - затраты Python, в 30-100 раз больше даже самого неоптимального кода на C, не имеют значения.

А вот где нет такого отношения времён, там вы не отделаетесь. Во внутренностях кодеков как раз инлайнинг на интринсике сидит, вектором погоняет, и виртуальным функциям там не место.

Более того если бы видео плеер был построен с использованием шаблонов пришлось бы каждый раз все перекомпилировать при добавлении нового
формата данных, нового кодека.

А теперь загляните внутрь самого кодека...

Что именно из высказываний Вирта вы тут имеете в виду?

Ну например вот функция сложения двух чисел

{"type": "function", "name": "adder", "args": [["x", "int"], ["y", "int]], "result_type": "int",
 "body": [
   {"st": "return", "expr": ["+", "x", "y"]
   }
]}

Такой себе AST в виде списков и деревьев, только на JSON.

В реальном, конечно, будет много отличий (например вместо "x" в выражении, скорее всего, будет что-то вроде {"local":"x"}), но внешне будет достаточно похоже.

европа, китай, индия и сша. Ставка 30 долларов в час это средний доход.

Нет, вы слишком хорошо думаете о среднем доходе. Разделите минимум на два. Для Индии ещё больше.

AWS вам подойдет как ответственный сервер? S3 стоит $0.0125 per GB, стоимость мегабайта в рублях посчитайте сами.

S3? Конечно, не подойдёт, это потоковое хранение, а не устройство прямого доступа, и не обязательно настолько быстрое даже как HDD, часто - в разы медленнее (его могут держать на очень медленных дисках типа черепичной записи, через забитые каналы, и всё такое).

Как активный диск у Амазона (пусть мы смотрим таки на Амазон) надо смотреть, например, на EBS, и вот тут уже видно - provisioned IOPS (мы ж хотим гарантированную полосу?) это 125$/TB/месяц (открыло Ohio, пусть будет оно). Это соответствует расходу одного такого диска в месяц, или комплекта RAID за 4 месяца. Деля ещё на 2 за on-demand вариант (а не предоплаченный на 3 года, как аналог персонального железа), соответствует 8 месяцам. Ну, износить SSD за год активным общением это как пить дать. Кстати, там в цене ещё сами IOPS надо добавить, а не только хранилище для них:) Так что Амазон тоже на активном дисковом хранилище использует какой-то RAID, как я и описывал.

Собственно, упоминания S3 достаточно, чтобы понять, что вы упорно сравниваете паровозы с апельсинами, и, или 1) не понимаете вообще, что сравниваете несравнимое, или 2) активно троллите. Выбирайте сами.

200GB диск, желязка, полминуты на скачивание - какие-то истории из 2004
года. Ваша "желязка" случайно не по модему в 28800 бод соединение
держит?

​2024. Нет, это чистая реальность из этого года. Головная станция интернет-доступа. И тоже или даже не подумали калькулятор взять, или троллите. Полминуты на 28800 это ~86kB, а не гигабайт. Мне уже как-то надоедает вести беседу на таком уровне.

Причему тут стековые фреймы, что за каша началась.

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

Если это для вас каша... вместе с вашими странностями арифметики, которые должны были быть исправлены где-то в средней школе, я не думаю, что эту дискуссию имеет смысл продолжать.

Жесткий диск в 1 терабайт стоит как два часа работы среднего программиста

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

​1. Какой "жёсткий диск"? HDD? Замечательно. В типовом лаптопе сейчас SSD на M.2. За 1TB это будет 100$. "Средний программист" exUSSR получает где-то 2000$/месяц, то есть это уже день, а не два часа. Это пока что уровень разработки. Или вы про "среднего программиста" Кремниевой долины? Там, конечно, и час будет, но таких мало от общего числа по миру.

​2. Если мы говорим про ответственный сервер, то там цена быстрого надёжного хранилища будет равна минимум 4 таким дискам плюс контроллер для RAID 5/6/Z. Ладно, контроллер софтовый (не всегда адекватно, но упростим) - всё равно умножили на 4. Не буду считать это в 4 днях работы разработчика, хотя сколько тех серверов нужно для реального сервиса - может, и 1000... это уже 11 лет зарплаты одного такого программиста. Ладно, 3 года, если из Фремонта или Санта-Анны. И 20-30 лет, если из Бангалора:))

​3. Теперь, говорим про железяку на выносе (мой последний случай именно такой). Диск - флэшка на ~200GB, SD card. Уже занято ~70% на старте, ещё ~20% выделено на логи. И ещё требуется скорость обновления, каждые 10 секунд на счету, потому что это массовое падение сервиса - железяка обслуживает несколько тысяч клиентов. Лишний гиг несжимаемого (именно так) бинаря, по мегабайту на тысячу рабочих программ - реально, полминуты на скачивание (по совсем не свободным каналам, у юзеров звонки и трафик, а на сервере драка сотен скачивающих) плюс где-то столько же на заливку на флэшку.

Понимаете, почему расчёт на один HDD это, ничего личного, просто ламерство? И почему, например, убунтовцы в 24.04 говорили "очень-очень-очень извините, но наши стековые фреймы стоят пару процентов места и времени, но нам всем эта пара процентов много даёт непоправимой пользы, поэтому мы таки сделали"?

Я надеюсь, всё вышенаписанное это шутка.

Нет, конечно.

Если нет - бегите оттуда.

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

Место на диске ничего не стоит

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

Я полагаю каждый такой эксцесс (головомойка когда выясняется что приехал
пожилой человек, а не младенец) стоит компании кратно выше, чем
"экономия на тестах", "экономия на байтах" и пр..

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

Ну и в целом, если писать код не ногами, то никаких особенных тестов на >100 и не нужно.

Нужно - на каждый элемент обстановки. Число пишется в распечатке? Изменение формата. Кто-то должен описать требования, что сохраняется, что меняется, как тестировать. Где-то от этого поплыло форматирование, форма не влезла на страницу, скандал, переделка. Число вводится вручную? 3 цифры вместо 2, продумать новый лимит (не 999 же позволять?), сколько - 120? 150? 199? 200? Вопрос сложный, хоть на высшее руководство поднимай, принять самостоятельное решение на нижнем уровне побоятся. 2 байта в структуре вместо одного? Где-то фиксированные смещения заложены, всё поплыло, 99% мест починили, одно сломалось. Какой-то формат данных не позволяет 2 байта, позволяет только или 1, или 8 (вспоминается ZeroMQ) - выход за границы размера какой-то датаграммы, буфера переполнены, в тесте не найдено, потому что в тесте никто не подумал совместить одновременно такой возраст, звание "доктор" вместо "мистер" и одновременно 10 скидок на разные аспекты полёта. Я могу этот поток сознания про разные хохмы продолжать ещё долго только на своём опыте...

Напомнило историю, как у кого-то в свидетельстве о рождении было указано 31 ноября. Что именно вбивать в базе данных детсада, решалось в итоге волевым решением директора.

Может, это и хорошо, что закончилась. Потому что её ж тут намеренно ограничивают.

(Конечно, лучше было бы наоборот - динамическая только там, где явно разрешено.)

Но при этом растет доля проектов(в основном веб-сервисов), написаных на более простых языках - typescript, C#/java, go.

Ну вот у вас или CAD с базами данных, или веб-сервисы. А промежуточного вы не видите. Когда-то такие задачи, как email сервер, VoIP-софтсвич, IDE (смотрим на пучок от JetBrains) - можно было писать только на полностью компилируемых языках с ручным управлением памятью, другое не работало. Сейчас IDE - на Java, C#. Свич - какие-нибудь кодекоконвертеры и передатчики RTP - ладно, C/C++, но сигнализация - нафига там C++ когда Java справляется не хуже (а я до сих пор парой пальцев ноги в проекте где Python). Email - аналогично, накой там C++, Java пробовалась уже с 2000 (если это не что-то масштаба Google), хотя Go дышит в затылок. И так далее.

А завтра и CAD будут забирать у C++, потому что нафиг там такое не нужно, кроме, может, пары критичных алгоритмов какой-нибудь сложной разводки. И то, хорошо оптимизированный язык типа C# вполне может за-JITʼиться в сравнимый код. Игровые движки - сколько игр не требуют 144fps и вполне бегают на Unity, а то и на чистом JS?

Постоянное выдавливание классических языков с ManMM, включая C и C++, из всё большего числа применений - это голый факт. C++ позволяет, до какой-то степени, притормозить этот процесс, но не более.

Я к этому думаю также, что если бы Go и Rust не старались паковать всё в один статический бинарник - то уже давно большинство содержимого всяких /usr/bin было бы на них. Сейчас они сами себе тормозят это продвижение (намеренно или нет - понять сложно).

А на какого размера выборке основываются ваши наблюдения о "мало кто
толком понимает..."? Вы же вроде как чуть ли не в одиночку работаете.

Я на двух последних проектах работал в команде (считаем, по сотне человек в каждом). Телеком, полу-свои железки. Команда - люди стараются, конечно, но простые вызовы ASIO и замыкание на пару параметров для них предел. Уровень выше дают ну может до 5 из всех, скорее 3. Это пойдёт как уже значимая выборка? 3-5%.

(Как пример, дважды рассылался "циркуляр" про правильное использование erase-remove в итераторах, после того, как один кусок крэшился из-за erase() на map без него. Там вообще хватало простого clear(), но все пропустили.)

С остальным примерно согласен. Но при крайне слабом контроле качества кода это всё превращается в невнятную кашу.

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

Это есть, безусловно. Но самые простые случаи составляют большинство использования - это раз. После того, как написано и проверено, побочные эффекты (кроме раздувания кода;)) все отловлены - это два. Этого хватает, чтобы от макров избавляться по максимуму. Ну а на остаточный набор случаев, уже говорил, хочется что-то поумнее #define с прямой подстановкой цепочки лексем.

А большинство проблем с макросами растет от того, что в C/C++ не макропроцессор, а препроцессор, противоестественно отделенный от компилятора.

Да.

черная дыра, аналогичной массы

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

Всё это пока впустую. "Планета" тут является сокращением для "небесное тело невыясненной природы компактного характера с гравитацией", все кто в теме понимают.

Крэш-тесты устраивают и самолётам. Разумеется, какому-нибудь 737MAX - вряд ли, хотя, при минимуме набивки только на голой обшивке - возможно, и делали (ну, с макетами набивки). А средствам подешевле и помассовее - тем более.

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

Давайте остановимся на общем выводе что краш-тесты тоже имеют право на жизнь :)

Безусловно :)

Вместо SetGT используем SetLL - он ставит указатель перед первой записью с указанным значением ключа.

Перед записью или на записи?

SetLL (KeyValue) MyIdx; if %equal(MyIdx);

И вылетаем на пустом ответе?

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

Если select только полей из индекса в SQL, можно тоже не тратить время на чтение записи. Есть такая оптимизация. DB2 её не умеет?

Длиннее по коду, но эффективнее:

Реализуемо в большинстве "взрослых" движков SQL как хранимая процедура. И с перебором курсора, и с промежуточными представлениями результатов выборки.

Пока что весь этот рассказ выглядит как пример типа "DB2 туповата, обходим вручную"...

Ведь эти заходы про миллионы лет, они же для лохов. При обсуждении вечных двигателей и тестирования они не уместны. Вечный двигатель или работает вечно, или нет. Тестирование либо даёт гарантии, либо нет (и нет, оно их не даёт).

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

Автор тестов делает то же самое.

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

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

Он просто выискивает потенциально проблемные ситуации и добавляет проверки.

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

Когда компилятор делает свои наивные проверочки, ему доступна, ещё раз, только грамматика языка.

И я вынужден повториться, что вы крайне примитивно думаете про возможности компилятора, не говоря уже о том, что ошибаетесь в терминологии. Что выражает конкретный тип это уже не грамматика, это семантика, и эту семантику компилятор может проверить - и часто проверяет. Если у вас один тип имеет границы значений [0..100], а другой [200..300], то присвоение первого второму может вызвать ошибку компиляции. Если у вас должно быть число, а вы передали строку - типовая ошибка в JavaScript - лучше, если это будет отловлено на компиляции, а не в рантайме.

И вот это практика, а не все те философские конструкты, которые вы зачем-то тут навернули, уходя от реальности, и, похоже, просто забалтывая.

Поэтому я зверею, когда слышу от нубов, которые не знают ничего кроме JS
и TS или JS и C++ (никого из присутствующих в виду не имею), что
статическая типизация + компиляция что-то добавляет к безопасности.

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

Я поскипал неуместные выплески философии. Хотел бы сказать, что к сожалению, но будет неправда...

Информация

В рейтинге
2 259-й
Откуда
Киев, Киевская обл., Украина
Дата рождения
Зарегистрирован
Активность