Comments 77
> Потому что программисты не покрывают тестами свой код

Тьюринг полнота намекает, что покрыть тестами ВЕСЬ свой код невозможно. А вот если взять некоторое ограниченное подмножество от языка, то для него можно показать корректность. Именно этим и занимается статическая типизация. Доказывает, что некоторые элементы программы, которые целиком укладываются в это подмножество — корректны. Конечно, у вас есть опасные связи между этими островками безопасности, которые нарушают гарантии, но вы знаете где именно вам надо пытаться искать ошибки тестами — на границе!

> Они предполагают, что вы знаете, какие классы должны быть открыты для наследования, а какие нет.

Начните с final. По мере необходимости можете final снимать. Но вообще final очень полезная штука для escape analysis.
Пусть пробует D — хороший баланс фич сделает его шерсть мягкой и шелковистой.
С трудом дочитал до конца — уровень истерики и субъективизма зашкаливает.
Дефекты — это ошибка программистов. Это программисты создают дефекты, а не языки.

image

Языки, в свою очередь, иногда этому способствуют.


Псст, парень, не хочешь объехать этот мучительный участок на потайном велосипеде?
А блин, я только заметил — это же мой любимый Роберт Мартин, гений тоталитаризма в софтверном менеджменте. До сих пор при одном упоминании о книге «The Clean Coder» хочется убивать, даже несмотря на то, что там по сути довольно здравые вещи. Но стиль изложения все перечеркивает — собственные шишки достижения преподносятся как неотъемлемая часть профессионального роста любого программиста, что позволяет с высоты своего, так сказать, опыта поплевывать на седины измучившихся и жаждущих ценного совета салаг. Ну прямо как на форуме рожениц — девочка, которая «уже», не минует возможности поучить тех, кто только ждет своей участи.

То есть тезисно получается, что язык программирования что-то должен разработчику/Бобу?

Если после текста заинтересовало мнение «другой стороны» — этот пост недавно как раз обсудили в интервью на Хабре Андрей Бреслав, возглавляющий Kotlin, и Антон Кекс, пишущий на Kotlin:

«Антон: Андрей, а ты видел интереснейший пост Uncle Bob как раз на тему Kotlin и nullability? Он хорошо прошёлся по этой nullability, мне интересен твой комментарий.

Андрей: Он написал в общей сложности три поста, посыл примерно такой: когда-то были языки без типов, потом языки с типами, потом снова стали популярны языки без типов, такой маятник качается туда-сюда, сейчас маятник качнулся в сторону типов и ушёл за точку баланса. У нас больше типов, чем надо.

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

Во-вторых, там есть некоторые конкретные аргументы «как же, если я, например, сделал какой-нибудь тип в своей программе nullable, то мне ж теперь надо поменять всю остальную программу, чтобы эта программа скомпилировалась». Этот момент я не понимаю, потому что — да, конечно, нужно что-то поменять, это содержательно. Если какой-то тип стал nullable, значит, код, который этот тип использует, должен учесть этот факт, иначе он будет неправильно работать! И, конечно, этот код надо поменять. Ну, можно его запустить, получить исключение, и поменять потом, а можно просто сразу поменять. Вот в Kotlin надо сразу.

Там ещё есть какие-то аргументы, аналогии с const в C++, ещё чем-то — эта аналогия не совсем корректная, по-моему.

Антон: При всём уважении к Uncle Bob, мне тоже кажется, что он просто использовал возможность ещё раз сказать «вы всё равно должны писать тесты для своего кода, и компилятор вас не спасёт». В чём он, в принципе, прав, но мне лично очень нравится в Kotlin эта фича с nullability, может быть, для меня это даже одна из основных фич, ради которых хочу писать на Котлине. С другой стороны, бывает такое, когда Kotlin не позволяет мне легко описать то, что я хочу, компилятор говорит, что я должен где-то поставить либо ?, либо !!.. В последнее время, когда у меня всё больше опыта с языком, мне всё меньше приходится бороться с компилятором, но есть такие кейсы. Для этого есть ещё ключевое слово lateinit, которое иногда помогает. Так что есть и плюсы, и минусы, но мне кажется, что всё-таки уклон ушёл в правильную сторону, что от этого больше пользы, чем неудобства.

Андрей: Безусловно, я согласен, что минусы есть, но за всё надо платить. Если мы хотим, чтобы компилятор что-то гарантировал, то требуется какое-то количество работы с нашей стороны. Здесь просто вопрос, что более оправданно. По-моему, опыт нас самих и всех остальных людей с Kotlin показывает, что введение nullable-типов вполне оправдано, получилось хорошо. »

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

UFO landed and left these words here

В статье есть и на это ответ :)


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

Я за Option.)

UFO landed and left these words here
Так о том-то и речь собственно, что проблема кардинально не решена.
Просто пальцем заткнули дырку…
Не совсем понимаю, с чего бы переменной на пустом месте становится nullable. Если это изменение в бизнес-логике — часть кода придётся переписать, от этого не уйти. Если это изменения в используемых библиотеках — можно либо остаться на старой версии, либо переписать код. Как правило, над обратной совместимостью тоже думают и не будут менять тип переменной туда-сюда. Но если уж изменили — нужно переписать код, и это не проблема nullable.

Других сценариев «переменная взяла и стала nullable» я, честно говоря, не вижу.
Я не первый раз слышу про проблемы Kotlin и ?: и даже местами понимаю автора. Здесь вот интересно, можно ли провести аналогию с Generic в Java — определенную избыточность на уровне синтаксиса, особенно до появления Diamond Operator? Просто я помню свои возмущения когда приходилось писать полностью Map<String, String> someName = new HashMap<String, String>(); Мне таки казалось эта конструкция невозможной многословностью — ведь я сам знаю, что пишу!
UFO landed and left these words here

Из статьи больше всего понравилась ссылка на языкомешалку. Это действительно проблема, поскольку, несмотря на то, что новые языки не добавляют почти ничего концептуально нового по сравнению с языками 70-х — 80-х годов, они всё-же разняться в множестве мелких деталей и требуют много времени на освоение. Лучше бы это время потратить на программирование или создание новых подходов к программированию, как это делается для того же JavaScript, даже для старой версии которого было написано немало оригинальных фреймворков.

UFO landed and left these words here
C++ — самая наглядная демонстрация кривости подхода «старым языкам — новые подходы».
Пока вы один, вы можете писать самый чистый и идеологически верный код в мире, но стоит команде расшириться, начинается пыщь пыщь ололо. Пойдут линты, хуки на коммиты, тренинги, в крайних случаях придется ставить грязный, вонючий, весь в солидоле костыль, минуя все хуки и линты, потому что прод упал, а возиться с идеологией некогда. Рано или поздно придет кто-то не знающий о правилах поведения и начнет совать код в стиле «я так тридцать лет пишу, что вы меня учите?». В то же время запрет городить фигню на уровне компилятора резко сужает необходимость распыляться на мелочи и больше внимания уделить тому, что ты, собственно, хочешь сделать.

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

У современного C++ есть дизайн, но проблема в том, что в нем для совместимости оставлены практически все старые фичи.

А можете посоветовать книжку или проект, где этот дизайн демонстрируется? Я примерно на Срр03 его потерял

новые языки не добавляют почти ничего концептуально нового по сравнению с языками 70-х — 80-х годов

define «почти ничего» и «языки 70-80гг»

В современных языках трудно найти какую-либо существенную фичу, которой меньше 30 лет. Отличия языков друг от друга, и от более "старых" языков всё больше сводятся к вкусовщине вроде нюансов наименований ключевых слов и синтаксическому сахарку.

Это я уже понял. Так какие именно языки вы имеете в виду? Приведите характерных примеров.

Примеры чего? Давно реализованных фич? ООП, корутины, сборка мусора — Simula-67, 1967 год. Исключения — PL/I, 1964 год. Функциональное программирование — LISP, 1958 год.

Лихо вы всё функциональное программирование лиспом ограничили. Ну ладно, а pattern matching?

Nuprl, в 80-х появился, сама теория ещё в 30-х. Не сказал бы, что это сильно распространённый подход в современных языках.

Настоящие и стОящие теории требуют вдумчивой проверки временем и длительного осмысления, после чего они превращаются в непотопляемый и неподвластный моде фундамент. Развитие современных ЯП состоит в создании эффективных механизмов для воплощения фундаментальных идей и в поиске современных задач, решаемых "старыми" методами. Изоморфизм Карри-Ховарда, в конце концов, сводит большинство "новых" подходов в программировании к "старым" подходам в алгебре, логике или топологии. Но это не значит, что всё уже "украдено до нас" и "всё в географии открыто".
Кстати, находка по-настоящему удачного синтаксического сахара к полезной, но неудобоваримой теоретической конструкции — это очень важная составляющая прогресса. Изобретение бра и кет векторов для исчисления состояний, оператора Гамильтона для представления дифференциальных операторов в теории поля, диаграмм Фейнмана для описания механики частиц, регулярных выражений для представления конечных автоматов, введение do-нотации для монад и адаптация коалгебры для комонады косостояния в виде изящных линз в Haskell, "толстые" стрелки для представления громоздких делегатов… все эти синтаксические нововведения не являются чем-то фундаментальным, но они позволяют просто и последовательно рассуждать о сложных концепциях, не теряя внутренней структуры концепции. Это сродни открытию нового представления для группы или построения изоморфизма между абстрактной "невидимой" структурой и житейским "обозримым" понятием. Это классная, красивая, хоть и непростая и небыстрая часть прогресса!

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


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


Представьте себе, что было бы, если бы математическая нотация была фрагментирована также, как языки программирования: в нотации А пишут sin(x), в нотации B вместо этого пишут Math.sin(x), в нотации C — (sine x), а в объявлениях по трудоустройству требовался бы именно математик-специалист по нотации A, или C, или B, с опытом работы 1-3 года.

Последний абзац, скажем так, неверен — проблема Чернобыля не в переопределении мер безопастности, а в том. что персонал станции плохо понимал физику процесса — в большей степени они были теплотехниками, а не ядерщиками.
И кстати они нарушили основную меру безопасности — минимальное число управляющих стержней в реакторе
Но в целом идеи статьи соответствует — если специалисты, применяющие языкы программирования, слабо ими владеют, то меры предосторожности им не помогут. Сильных программистов они будут раздражать.

Одной из проблем Чернобыля была такая конструкция реактора, в которой при введении стержней в зону на некотором участке их хода реактивность не падала, а возрастала… Кто ещё не читал — всем рекомендую Дятлова, физика процесса там подробно описана.

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

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


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

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

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

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


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

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

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

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

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

Да — кстати причем тут стержни — какая работа должна быть сделана — их нужно добавить?, то есть сделать новые каналы — или как? Напомню в действующем реакторе

Кстати на последующих моделях РБМК модификация заключалась в увеличении мощности от РБМК1000 к РБМК1500 и так далее
Проблема была в том, что конструктора реактора отрицали наличие в нем «уязвимости». На момент аварии о ней никто толком не знал, несмотря на то, что она себя уже проявляла ранее.
Вы, думается сами понимаете, что не существует в принципе неуязвимых конструкций, и этого ни один конструктор и ни один инженер утверждать не будет — это журналистские бредни
Любая конструкция может разрушится в силу случайного или преднамеренного стечения обстоятельств
Бык надежен, пока у него в носу кольцо.
Как я писал подобная авария была прежде на америкаской АЭС, разница только в последствиях — урон от Чернобыля выше (значительно) — американцам повезло. Но результат один блок — находится под саркофагом
Согласно информации (и не только этого источника) РБМК после Чернобыля, на станциях, оснащенных реакторами РБМК, были осуществлены мероприятия по модернизации, с целью повышения надежности и безопасности. И как мне видится Смоленская АЭС именно поэтому получила высокую оценку. Я думаю, что реактор Чернобыльской АЭС вряд ли бы сейчас получил оценку подобную Смоленской АЭС.
Ваша ссылка не показывает принципиальные изменения — просто ужесточен контроль, который был бы излишен, если бы персонал был достаточно хорошо подготовлен как специалисты в области физики ядерных реакторов —
Эти все организационные меры так называемая защита от дурака — а нужно ли дурака ставить на управление реактором
UFO landed and left these words here

В таких случаях приводят следующий пример: можно унаследоваться от ArrayList и сделать такой, при добавлении нового элемента, будет добавлять его 2 раза.
Теперь следите за руками. Тест, который выполнялся для родителя:


List<Integer> list = new ArrayList<>();
list.add(1);
assert list.size()==1;

не будет работать у потомка:


List<Integer> list = new DoubleList<>();
list.add(1);
assert list.size()==1;

Ну и, соответственно, если кто-то подложит в реализацию вместо ArrayList, DoubleList то логика в приложении пойдёт не по задуманным рельсам.

А это, насколько я понимаю, «фича» джавы — что любой метод, если не сказано обратное, виртуальный. В C# и C++ вот, например, не так, и ничего, живем.

Дык, разве против этого не такой же самый аргумент будет? Мол как всё final по умолчанию неудобно, так и отсутствие виртуальности (по умолчанию) тоже неудобно.


И я действительно встречал людей, которые считают, что (в С++) лучше писать virtual для каждой функции: мол так удобнее и гибче, а то вдруг автор оригинального класса что-то не продумал, а поменьять поведение в наследники уже нельзя. Переубедить не удалось.

UFO landed and left these words here
А вот зачем всё подряд делать финальным — убей не понимаю.

Возможно, для оптимизации.

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

Субъективно — в моем окружении джависты не страдают, поскольку с младых ногтей обучены оперировать интерфейсами и композицией вместо абстрактных классов. За прям всех, конечно же, не скажу.
Есть плагин Kotlin компилятора, который классы делает open по умолчанию. Или все, или помеченные определёнными аннтоциями (например, для Spring).
А теперь вопрос. Кто должен разруливать все эти риски? Язык? Или это работа программиста?


А кто должен писать тесты? Язык? Или это работа программиста?

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

Истерика про опциональные типы особенно доставила. Жаль, что не упомянули о том, что таким образом на 99.9% снижается вероятность краша приложения. Но разве это важно? )))

Такое ощущение, что человек написавший это, при всем уважении, не совсем понимает что такое Optional type.
Это не про NPE, а про, черт возьми, настоящую строгую типизированность. Когда сущность какого-то типа обозначает именно сущность этого типа, а не «Стринг — это, конечно, Стринг, но иногда еще и null».

Я не знаю кейса, когда из-за этого не хватило какой-то гибкости языка.

P.S.
А теперь вопрос. Кто должен разруливать все эти риски? Язык? Или это работа программиста?


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

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

Тут тоже не очень далеко от правды, имхо: больше дисциплины при программировании — меньше проблем в работе — меньше проблем в синхронизации участников команды — меньше поводов обращаться к «консультантам по аджайлу и ТДД».

Вот и смысл подвезли. Как говаривает один небезызвестный человек: "Если не понятно в чём дело, значит дело в деньгах".

Конечно, и бессмысленно рассматривать вопрос «что лучше» вне этого контекста.
Тсс, пожалейте беднягу — он ведь тоже кушать хочет, а если все начнут использовать строго формализованные безопасные языки, его работа станет не нужна )
А теперь вопрос. Кто должен разруливать все эти риски? Язык? Или это работа программиста?

Ну пусть пишет на азме. Это же его работа...


Спросите себя, почему мы пытаемся исправить дефекты языковыми функциями.

И что же программисты должны делать для предотвращения дефектов? Я загадаю вам загадку. Вот пара подсказок. Это глагол. Он начинается на букву «Т». Да. Вы поняли. ТЕСТИРОВАТЬ!

А как по мне, так это тестирование является костылем. Причем автору лень писать формальную спецификацию, и предлагает разменять формальную верификацию на ручное, все равно неполное, тестирование. Так где тут выгода, если все равно что-то придется дополнительно писать?


Чернобыль. Тесты.

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

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

Боб — пропагандист TDD. Очень маловероятно, что речь была про ручное тестирование.

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


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

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

Если бы не авторитет первоисточника, я бы подумал, что это очередной вброс. Воспринимается примерно как «выбор инструмента в работе не важен, виноват программист». Угу, даже дворники перешли от метлы к механизации, чтобы повысить производительность и качество.
Only those users with full accounts are able to leave comments. Log in, please.