All streams
Search
Write a publication
Pull to refresh
51
0.2
Valentin Nechayev @netch80

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

Send message
МДА. Ну или у вас аналитики действуют методом тыка, или вы путаете изменения ТЗ с дополнениями, из у вас какое-то "настоящее" программирование типа поддержи сайта.

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


Да, значительная часть хотелок превращалась в дополнения, но были и такие, которые требовали рефакторинга с самого нижнего слоя.


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

"У нас" точно так же стойка наблюдаемых железяк не начинала улетать в космос, и даже переместиться в соседний ряд не могла. И печь блины не начинала. Но когда оказывалось, что сокращение предельного времени реакции на событие X означало, что вся старая логика детекта этого события на основании характерных свойств последовательности значений датчиков не работает, и надо менять алгоритм детекта или вводить новые датчики — в некоторых местах уровень проблем от изменения был более чем заметным.
Никакая "реальность" задачи, в Ваших терминах, не защитит от таких проблем.


Точно так же я понимаю, что на компе может не быть часов, а в байте неожиданно может оказать 32 бита,

У нас без часов там не бывало, и 32 бита на системе наблюдения — тоже, хотя для этого не нужно гоняться за изделиями загадочной российской военщины — простой Cray тоже отлично подойдёт на это. Некоторым приближением к таким диверсиям были вычислительные модули на Cell.


Так что если я решил, что какого-то изменения не будет, а оно произошло — это моя ошибка.

Вот тут принципиально расходимся. Не ошибка. Ошибка — это когда на такое изменение не успеешь отреагировать. А когда оно просто непредсказуемо, но ты сохраняешь способность реагировать на новости — это как раз нормальное рабочее состояние.


В качестве мини-примера: одно из таких направлений, очень перспективное, сорвалось из-за того, что генподрядчик попал под санкции. (Это было ещё в 11-м году, так что с нынешней политикой прямо не связано.) В результате были запущены другие направления развития. Несмотря на материальность сферы, предсказать такое невозможно. Можно только быть готовым держать систему наготове к движению в любую разумную сторону.
И да, мы могли предсказать, что направление A потребует такого-то изменения, B — другого. Но пока нет никаких достоверных данных о движении в эту сторону — браться менять смысла нет. А изменения между собой слабо совместимы, скорее конфликтуют. Так зачем спешить вводить одно, даже если видишь, куда и как оно могло бы двинуться? Чем проще и прямее реализация на каждом этапе под его требования и под гарантированную (а не предполагаемую) перспективу, тем лучше.


Чтобы было понятней — вспомните дискуссию про goto сороколетней давности. Код с goto -очень гибкий. Но и некрасивый.

Я скорее отношусь к тем, кто "GOTO considered harmful" considered harmful. Потому что и return из середины, и break/continue это смягчённое goto, и автогенерация кода может их рожать пачками, и в машинном коде оно, а не if/while, и ваще. Сам иногда применяю в типичных шаблонах (например, на голом C — объединить код cleanup-веток некоторой функции). У меня критерий к нему — чтобы код был понятен тем, кто не заражён религиозной неприязнью.


И вот это


Код с goto -очень гибкий. Но и некрасивый.

неадекватно потому, что важно не то, что "некрасивый", а потому, что бесконтрольное использование GOTO приобрело ужасающие формы совершенно без причины, и никак не на пользу производительности или другим объективным показателям.


Делая код эффективным — мы теряем в его универсальности. Делая код красивым — опять теряем в универсальности.

Второе совсем сомнительно. Первое, как правило, верно (оптимизация под конкретные частные случаи применения, если не вообще под компилятор и рантайм), но при этом ничто не мешает вернуться к универсальной версии, когда потребуется.


В моей юности процедуры на 5 страниц считались отличным (и понятным кодом). Именно в этом стиле и писали в журналах и книгах по программированию. Ну и блок глобальных данных — был вообще единственным способом эффективной связи по данным.

Не знаю, как это соотносится с моей юностью, но начинал я на Fortran. Common-блоки использовались скорее для удобства не-передачи контекста каждый раз и для замены не существовавших тогда структур, чем для собственно эффективности.
Процедуры на 5 страниц и более там и сейчас норма (на днях копался в BLAS), но в специфическом контексте, где это почти не мешает. В системном программировании такие или там, где ну очень тяжело разрезать иначе (как tcp_input() в классическом BSD), или в очень специфическом стиле (sendmail).
А что было неэффективным в случае иной связи? Слишком много возни с указателями?

RTFM, NTVDM — это основной компонент подсистемы WoW16:

Это никак не следует ни из процитированного Вами текста, ни из просто определения win-on-win. Скорее надо говорить, что NTVDM — нижележащее средство для WoW16.


Почитайте "Inside Windows 95" или Unofficail windows 95 — поймете, что только титаническим трудом они смогли заставить Win95 работать настолько стабильно.

Читал, и именно об этом и говорю. И там как раз написано, почему так — не потому, что просто вдруг оказался там кривой код (с их ресурсами они всё это исправили бы), а потому, что само построение ОС не давало шансов сделать беспроблемное устройство.


А линейка Win 3.1 загнулась после крайне неудачной WinMe:

Которую мало кто ставил.

Неужели непонятно, что красота и эффективность идет за счет специализации кода (по условиям ТЗ)?

EPARSE, простите. Красота и эффективность — следствие специализации кода, или они страдают (ухудшаются) из-за специализации кода?


Что вся декомпозиция — хороша лишь, пока программист верно понимает ТЗ и спектр его изменений?

Нет, непонятно. На практике можно считать, например, что через год изменятся 10% требований, а за десятилетний цикл развития — чуть менее, чем все. (Реальные цифры с одной из моих прошлых работ.) Но каким образом из этого следует рекомендация писать всё так, что не заботиться о его сопровождении? Ведь даже если 20% изменилось, остальные 80% те же, а сопровождать надо каждый день.


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

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


И вот вам пример, чем быдлокод лучше. Известная "Задача о восьми ферзях": Простой вариант с 8 циклами — легко обеспечивает переход к доскам непрямоугольной формы. А вот быстрый алгоритм Дейкстры…

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


Давайте разделим:
Быдлокод — это простой, некрасивый код, написанный в лоб.

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

Вы путаете разные вещи.

Нет, не путаю. Я явно указал, что тут два разных этапа избавления от этого наследия.


Одно дело — подсистема WoW

Про WoW я ничего не говорил. Говорил про то, что в линии NT называется NTVDM, а в 9x как-то иначе. Сейчас уточнил — да, оно в 32-битных версиях вроде бы есть и сейчас.


Но сказалась усталость кода…

Или скорее то, что альтернативный перспективный код был давно стабилизирован и готов к использованию.

Вы таки удивитесь, но таки Win2000 из линейки nt.

Я таки удивился, что Вы считаете, что я считаю иначе. Я не дал к этому никакого повода.


95 (+апгрейды), 98 (+апгейды), миллениум.

Спасибо, кэп. :)

На современной элементной базе полноценный barrel shifter дешевле, чем раскладка сдвига на много бит в цикл по одному биту.
Хотя x86 и сейчас не гарантирует быстрое выполнение для всяких нелепостей вроде RCR на несколько бит.

И любой работающий быдлокод — в 100 раз лучше неработающей красоты.

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


Пример с Doom и куском для NeXT, кстати, тут очень хорош дидактически :) С одной стороны, там очевидные странности в виде магических констант, которые по обычным нормативам надо описать в виде #define. Но я бы тут вместо этого поставил комментарий с описанием смысла конкретного числа.
С другой стороны, стиль, рекомендуемый во многих местах, потребовал бы сделать тут безусловно вызванное макро, которое было бы определено в непустое действие только для NeXT. А вот это уже хуже потерей локальности — надо идти неизвестно куда только для того, чтобы узнать, что для 99.999% случаев макро просто пустое.

Но верно и то, что линейка Win95 загнулась, потому что просто не смогла развиваться.

Связано ли это с качеством её кода? Или всё-таки с тем, что принципиально беззащитный дизайн перестал котироваться, а компы дотянули до мощности, когда NT-based решения перестали быть аццким тормозом?
Насколько я в курсе, там существенные затраты шли таки на проблемы совместимости с DOS. Избавление от неё сначала при переходе на Win2000, а затем (в Vista) при устранении DOS mode и 16-битки — были громкими праздниками.

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

Именно. Перевод на "мирные рельсы" без адекватного обеспечения (хотя и начальная разработка в таком опасном виде).


Но несоблюдение правил и непрофессионализм в том смысле о котором я сказал — и есть причина аварии

Неотъемлемая компонента причины, вместе с проблемами конструкции.

Кстати вы представляете себе, что такое переделать действующий реактор

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

если машину на скользком участке заносит от неудачного маневра, то виновата конструкция?

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


Кстати, Смоленская АЭС с реактором РБМК, как на Чернобыле, в 2011 году получила высокую оценку экспертами МАГАТЭ

После Чернобыльской аварии все РБМК подверглись коренной переработке управляющих конструкций и пересмотру правил эксплуатации.

Это очень удобно — называть всех на «вы», даже свою кошку.

И неудобно тем, что нет отличия между единственным и множественным числом. Всё-таки это различие в грамматике придумали не зря.
Есть языки, в которых даже в самом уважительном случае норма — "ты" (например, иврит). Есть такие, где отдельная пара ты/вы подчёркнуто уважительного вида (классический испанский с uste, usted, хотя регионально там и другие формы). Мне всё это кажется более полезным, чем просто выкидывание одной формы.

У меня претензия к именованию участников. Обычно в криптографии Алиса и Боб — две стороны защищённого взаимодействия, тут скорее Алиса держала бы сервер, выдающий токены, а Боб — законный пользователь. А воры токенов — это в первую очередь Крейг (Craig). Вот вроде полный список.
Результат — читая статью, на каждом абзаце приходится переименовывать в голове.
Данную статью уже не исправить из-за комментариев, где повторены эти имена, но на будущее прошу не сбивать в таких основах.

Кэши собственно данных, типа L0, в этом не участвуют, читать-писать основное содержимое страниц не нужно. А вот создать копию VM map процесса — задача достаточно затратная, включая карты physical maps с инкрементом счётчиков использования (вот тут наверняка кэш и насилуется).

1. Я не знаю, что такое «TCP\IP». Если Вы про весь стек TCP/IP, то UDP в него входит. Если только про TCP, то не надо к нему клеить «IP».
2. С чего Вы взяли, что у TCP выигрыш?
3. Фреймы подтверждения 802.11 не входят в размер IP пакета. Тем всё равно остаётся 1500, даже если WiFi их дробит на свои фрагменты.
4. Я не говорил про достижение 99% реальной полосы от формально возможного на 802.11. Речь шла исключительно про соотношение потока прямой передачи (данные TCP) против обратной (подтверждения), против Ваших ранее предположенных 50/50 (а иначе сложно понять слова про «что представляет собой пакет в обратную сторону, отсюда и деление на два»). Реальная скорость WiFi зависит от слишком большого количества параметров, чтобы что-то тут утверждать только на основании свойств IP.
> подтверждение доставки, что представляет собой пакет в обратную сторону, отсюда и деление на два.

Не так. TCP может, например, передать в одну сторону порцию (окно) ~60KB как 40 пакетов по полтора килобайта и получить в ответ 40-байтный ACK с подтверждением всего окна, после этого передать следующую порцию на 60KB… конечно, есть какие-то потери на задержки, но достичь >99% занятия канала потоком данных в одну сторону — легко.

Ну почему "даже" :) Что деление через умножение выгоднее, если деление на выбранный делитель делается хотя бы 2-3 раза, известно достаточно давно (с тех пор, как появилось O(1) умножение). Выбирая делитель (размер таблицы у ТС), можно вычислить необходимые параметры (в простейшем случае — множитель, величину финального сдвига и направление округления) и запомнить их до следующей смены размера.
Библиотека по ссылке значительно более продвинута, и может оказаться оверкиллом. Но по крайней мере сильно быстрее divl/divq каждый раз :)

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

LISP до начала стандартизации Common LISP или вообще весь со всеми диалектами? (тогда — нечестно)
Системы типов с автовыводом, а-ля ML, Haskell?
Или это уже не "классическая вычислительная парадигма"?

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

Насколько я вижу, всё, что он выдал там, действительно есть в объекте (то есть, при вызове по имени будет поднято по цепочке прототипов и найдено). Да, их много, но самое важное находится вверху списка. Если бы не было такой сортировки, разбираться было бы в разы сложнее.


Только для стандартных API и для JSDoc аннотаций (привет, статическая типизация)

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


Эту задачу решают "типы-суммы" и "типы-произведения". TypeScript, например, это умеет.

Хорошо, значит, прогресс в эту сторону идёт.


Скорее динамическую диспетчеризацию (которая приятно дополняет статическую типизацию).

Да, это правильный термин для данного случая.

Скажем, в C литерал 120 — это точно int

120 — да. 120000, например, уже не обязательно. В C99, например, сказано следующими словами:


The type of an integer constant is the first of the corresponding list in which its value can be represented.

Если на платформе int 16-битный, 120000 автоматически станет long.


Но тип константы тут не так важен. Важнее то, что будет, если мы обопрёмся на это вычисление типа при назначении его переменной, и значение потом будет меняться, а тип — нет. Например, если кто-то захочет опереться на то, что в Java или Go целочисленная арифметика всегда урезает до последних N бит, даже знаковые, и у него тип переменной всегда окажется int64 вместо int32, результаты будут неожиданными. Или в C# написать 2.5 вместо 2.5m; многим такое очень тяжело распознать, даже вглядываясь в код.


Поэтому автоматическое определение типа хорошо, если далее значение переменной не заменяется. "Внутреннее" изменение может быть; есть случаи, когда автоопределение удобно и при изменении — например, итераторы. Но даже "x += 1" уже даёт стрёмный вариант (а что, если это оказался float более чем 2**24 по модулю?), лучше избегать автоопределения и задавать тип явно.
(Хм, тут исключений больше. Например, стандартная арифметика над floatʼами может адекватно работать при любом их типе. Но это опять же не общий принцип.)

Information

Rating
2,754-th
Location
Киев, Киевская обл., Украина
Date of birth
Registered
Activity