четверг, 28 февраля 2013 г.

Типизация динамики или объективизация статики

Чтобы заснуть некоторые рекомендуют считать баранов. Раз баран, два баран, ... двести двадцать семь. Для меня не работает, но пока это не важно. Но вот что делать, если на 117 месте оказалась овца? Можно тоже считать. Но вот у вас слаботипизированная программа и может встретиться все что угодно. И понедельник, и смысл жизни, и зачет по диференциальным уравнениям. Их тоже считать?

А есть еще черная дыра, в просторечии известная как null. Хоар берет ответственность на себя, но до сих пор нормального (не то чтобы идеального) решения как-то не предложено. Это в итоге какой-то ужас. Единственное что можно делать, это сначала спросить: "А вы случайно не черная дыра?" В итоге программы в student-style выглядат как "Если не черная дыра, то считаем". Программа из "Сейчас я встану со стула, пойду на кухню и поставлю чайник на огонь" выглядит как "Если стул не Черная дыра, то (Если кухня не Черная дыра, то (Если чайник не Черная дыра, то (Если огонь не Черная дыра, то ...)))". Я видел такие проекты, с такими людьми я даже за руку здоровался (все отмыть не могу). Это то же от непонимания типов.

Есть тренд, когда в слаботипизированных языках добавляют недо-типы. Тот же python/cpython, аннотации в erlang, к названию языка приписать слева букву J или справа #. Тот же js внутри той же V8 внутри очень типизированный. Даже CoffeScript и javascript чем-то в названии похожи.

Понятно, откуда ноги растут. Только кажется можно растить и в другом направлении. Гибкости хватает, но надежность и скорость местами перевешивает.

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

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

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

Есть мнение, что один фиг, юнит-тесты и там и там писать. Будьто это и там и здесь все покроет и будет господство счатья и демократов. Для меня несколько очевидно, что чем раньше вы найдете косяки, тем оно дешевле/проще/быстрее и спокойнее. И еще из очевидного факта, что компиляция идет до рантайма тестов, следует что типизация - это хорошо.

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

Если бы я понимал зависимые типы, то я бы тоже был их приверженцем. Но, имхо, до чего-то жизненного они пока не доросли.

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

2 комментария:

vicont комментирует...

Программа из "Сейчас я встану со стула, пойду на кухню и поставлю чайник на огонь" выглядит как "Если стул не Черная дыра, то (Если кухня не Черная дыра, то (Если чайник не Черная дыра, то (Если огонь не Черная дыра, то ...)))".

Всё верно, но как этого избежать? В той же Java, например?

67108864 комментирует...

Принять религию "не создавать null".

null может быть получен по следующим причинам:
- явно возвращен null.
- неполная инициализация объекта
- явная передача аргумента null
- IoC/DI, некорректная инициализация

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

Главное, быть уверенным что все созданные объекты корректны и не писать студенческую лапшу вида

if (someOne == null)
{
return null;
}

Это лишь мешает обнаружению ошибки...

Нигде не возвращать null. Можно вернуть default object, например для строки это "" оно же string.Empty. Для своих классов можно сформировать аналогичный default object. Сравните с использованием null...

Не передавать null - использовать на крайний случай default object.

Осталось разобраться только с неполной инициализацией объекта. Собственно, где упало со стектрейсом, там и ошибка в этом объекта (так как у нас нет плохой практики с протаскиванием null). Тогда внимательно посмотреть на класс, рассмотреть все конструкторы и найти возможую неинициализацию.


Мне приводили пример, когда типа в базе данных поле nullable или подобъект джоинится на другую таблицу, а там нет данных.

Тут либо кривая иерархия классов (пусть это будет два разных класса, один с полем, другой без), можно опять default object, можно свою обертку на типом (nullable?). В крайнем случае поле - список из объектов. Пустой список как отсутствие объекта, это все равно не null.

Других случаев порождения черных дыр быть не должно.