При написании большого проекта на динамическом языке встаёт вопрос о надёжности кода.
Особенно когда проект начинался как небольшой по размеру, и вполне себе справлялся с работой по автоматизации внутренних нужд, но перерос в большой публичный код, используемый сторонними пользователями. Которые, разумеется, жаждут стабильности и минимума багов.
Конечно, все ошибки автоматически найти не получится, и в программах на статически типизированных языках тоже есть ран-тайм проверки и ошибки. Но их там намного меньше, или, по крайней мере, можно изменить программу так, что большинство из них будут отловлены на стадии компиляции.
А как это сделать в динамических языках — я себе не могу представить.
Есть ли подобные средства для них и как они работают?
Насколько у вас возрастают затраты времени на сопровождение при росте размера проекта и публичном использовании?
Есть ли какие-нибудь динамические языки, код которых можно аннотировать типами (и другими констрайнтами), позволяющими плавно перейти к верифицируемому коду?
Здравствуйте, mkizub, Вы писали:
M>А как это сделать в динамических языках — я себе не могу представить. M>Есть ли подобные средства для них и как они работают?
pylint?
Re: Написание сложных проектов на динамическом языке
Здравствуйте, mkizub, Вы писали:
M>Есть ли какие-нибудь динамические языки, код которых можно аннотировать типами (и другими констрайнтами), позволяющими плавно перейти к верифицируемому коду?
Erlang? Python3k? (с последним почти не знаком)
Re: Написание сложных проектов на динамическом языке
Здравствуйте, AndrewVK, Вы писали:
M>>А как это сделать в динамических языках — я себе не могу представить.
AVK>Очень просто. Заменяем проверки компилятора юнит-тестами.
Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных гарантированно имеющих поля с этими именами и этими типами данных)?
Здравствуйте, mkizub, Вы писали:
M>>>А как это сделать в динамических языках — я себе не могу представить.
AVK>>Очень просто. Заменяем проверки компилятора юнит-тестами.
M>Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных гарантированно имеющих поля с этими именами и этими типами данных)?
На уровне отдельной функции можно протестировать, что:
а) приняв на вход корректные данные, она отработает
б) приняв на вход некорректные данные, она обязательно вылетит (если это необходимо); с разумным предупреждением (если это необходимо); оставит окружающую среду в констинентом состоянии (если это необходимо)
Re[4]: Написание сложных проектов на динамическом языке
Здравствуйте, Гест, Вы писали:
Г>На уровне отдельной функции можно протестировать, что: Г>а) приняв на вход корректные данные, она отработает Г>б) приняв на вход некорректные данные, она обязательно вылетит (если это необходимо); с разумным предупреждением (если это необходимо); оставит окружающую среду в констинентом состоянии (если это необходимо)
Нельзя. Потому как эта функция вызывает другие функции, в зависимости от входящих аргументов и глобального состояния программы. Все возможные состояния программы проверить тестами невозможно, их слишком много.
И потом, даже если крыть всё тестами, то это на порядок больше работы (если не на два), по сравнению со статической типизацией, например.
Здравствуйте, mkizub, Вы писали:
M>Нельзя. Потому как эта функция вызывает другие функции, в зависимости от входящих аргументов
Юнит тестирование как раз таки и характеризуется тем, что тестируется не программа целиком, а ее маленькие модули.
M> и глобального состояния программы.
А вот нефик делать у программы глобальное состояние, в том числе и в статически типизированных языках.
M> Все возможные состояния программы проверить тестами невозможно, их слишком много.
Невозможно. И статическая типизация их тоже не все проверяет, а только определенный набор правил, описываемых контрактами, контроллирует. А сложность контрактов в современном статическом мейнстриме все еще совсем невелика.
M>И потом, даже если крыть всё тестами, то это на порядок больше работы (если не на два)
Не на порядок, и не на два, а процентов на 30-50 по оценкам. И не стоит забывать, что статическим языкам тесты тоже небесполезны.
... << RSDN@Home 1.2.0 alpha 4 rev. 1132 on Windows Vista 6.0.6001.65536>>
Здравствуйте, mkizub, Вы писали:
M>Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных гарантированно имеющих поля с этими именами и этими типами данных)?
А что тут неочевидного? Передать не тот тип аргументов и убедится, что это приводит к ошибке.
... << RSDN@Home 1.2.0 alpha 4 rev. 1132 on Windows Vista 6.0.6001.65536>>
Здравствуйте, mkizub, Вы писали:
AVK>>Очень просто. Заменяем проверки компилятора юнит-тестами.
M>Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных гарантированно имеющих поля с этими именами и этими типами данных)?
Python: isinstance, hasattr — как раз для такого рода проверок.
Re[4]: Написание сложных проектов на динамическом языке
Здравствуйте, Nuald, Вы писали:
AVK>>>Очень просто. Заменяем проверки компилятора юнит-тестами.
M>>Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных гарантированно имеющих поля с этими именами и этими типами данных)?
N>Python: isinstance, hasattr — как раз для такого рода проверок.
Ясно. Полное непонимание сторон
Я спрашиваю — как юнит-тестом можно гарантировать/протестировать, что функция в ран-тайме получит на вход только аргументы определённого типа?
Не то, что она кинет ошибку, а то, что она не получит неправильных данных — как?
Здравствуйте, mkizub, Вы писали:
M>Я спрашиваю — как юнит-тестом можно гарантировать/протестировать, что функция в ран-тайме получит на вход только аргументы определённого типа? M>Не то, что она кинет ошибку, а то, что она не получит неправильных данных — как?
Покрыть юнит-тестами все точки входа в функцию. При стопроцентном code coverage (хе-хе) все будет ровно. Вопрос тока как его получить?
Если интересует супер-крутое верифицируемое программирование, советую ознакомиться с Praxis’ Correctness by Construction development process. Вот это реально круто, хотел бы я в таком поучаствовать и поплевать во всякие питоны и руби с большой колокольни
Re[5]: Написание сложных проектов на динамическом языке
Здравствуйте, mkizub, Вы писали:
M>Здравствуйте, Nuald, Вы писали:
AVK>>>>Очень просто. Заменяем проверки компилятора юнит-тестами.
M>>>Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных гарантированно имеющих поля с этими именами и этими типами данных)?
N>>Python: isinstance, hasattr — как раз для такого рода проверок.
M>Ясно. Полное непонимание сторон M>Я спрашиваю — как юнит-тестом можно гарантировать/протестировать, что функция в ран-тайме получит на вход только аргументы определённого типа? M>Не то, что она кинет ошибку, а то, что она не получит неправильных данных — как?
— Здравствуйте, это молоток, им забивают гвозди
— Нет-нет, вы мне объясните, как этим молотком шуруп закрутить?
Я к тому, что "гарантировать, что функция получит только аргументы определенного типа" — не цель, а средство. "Паттерн, соответствующий статической типизации", грубо говоря. И этот "паттерн" — лишь одно из возможных средств обеспечения корректности программы.
А еще, вы знаете, в динамических языках даже бывают функции, могущие принимать на вход аргументы разных, зачастую несвязанных типов. Полиморфизм называется.
Re[5]: Написание сложных проектов на динамическом языке
Здравствуйте, mkizub, Вы писали:
M>Ясно. Полное непонимание сторон M>Я спрашиваю — как юнит-тестом можно гарантировать/протестировать, что функция в ран-тайме получит на вход только аргументы определённого типа? M>Не то, что она кинет ошибку, а то, что она не получит неправильных данных — как?
Никак. Только на всякий случай уточню, что принадлежность к какому-либо типу не столь уж сильный контракт, а вот как можно гарантировать, что функция в ран-тайме получит на вход только int x такой, что x > 6 и list<int> l такой, что l.length() < x?
Re[6]: Написание сложных проектов на динамическом языке
Здравствуйте, VoidEx, Вы писали:
M>>Не то, что она кинет ошибку, а то, что она не получит неправильных данных — как? VE>Никак. Только на всякий случай уточню, что принадлежность к какому-либо типу не столь уж сильный контракт, а вот как можно гарантировать, что функция в ран-тайме получит на вход только int x такой, что x > 6 и list<int> l такой, что l.length() < x?
Ну, типы — это наиболее частый контракт. Если есть варианты проверить и другие — тоже хорошо.
Как доказать? Очевидно, аннотациями и соответствующими верификаторами (в том числе и умеющими выводить нужную информацию из control/data flow).
Ясно, что проверить всё на свете не получится, да это и не надо. Просто хотелось-бы потерять ощущение ходьбы по минному полю.
Пока программа (на javascript, кстати) была не очень большой — она обозревалась легко. А теперь хотелось бы, чтоб компьютер мне мог помочь в ходьбе по этому минному полю.
Давали ссылки на erlang — прошерстил и нигде не нашёл ничего соответствующего.
На python3k — тоже только планы по введению опциональной аннотации типами, а в доке на него ничего не нашёл.
У меня же на руках есть SymADE, я думал — если нет ничего вообще из подобных верификаторов, то может имеет смысл загнать в него онтологию javascript-а, и написать свой верификатор. Но только я ума не приложу как это вообще верифицировать, если в любом момент можно загнать в объект новое поле или метод или поменять им тип... Я думал, посмотрю на эти существующие верификаторы и возьму у них идею как они это делают. Для того и спрашиваю.
> Не понял. Как можно юнит-тестом протестировать, что функция принимает на вход только аргументы определённого типа (структуру, набор данных > гарантированно имеющих поля с этими именами и этими типами данных)?
Результат, кстати, получается с гораздо более широкими возможностями, нежели просто проверка типов компилятором.
Необходимость unit-тестов при этом все равно не исчезает.
Re[5]: Написание сложных проектов на динамическом языке
M>Ясно. Полное непонимание сторон M>Я спрашиваю — как юнит-тестом можно гарантировать/протестировать, что функция в ран-тайме получит на вход только аргументы определённого типа? M>Не то, что она кинет ошибку, а то, что она не получит неправильных данных — как?
Так и в языке со статической типизацией, гарантировать, вообще говоря — никак. Ибо зачастую в нем присутствуют способы принудительного приведения типов, которые позволяют успешно прострелить себе ногу, несмотря на старания компилятора.
Например:
void foo(Bar*);
Biz* biz = new Biz();
foo((Bar*)biz);
и т.п. Так что, как говорил Остап Бендер, гарантию дать может только страховой полис.
А насчет "как протестировать" уже было сказано.
Re[6]: Написание сложных проектов на динамическом языке
Здравствуйте, VoidEx, Вы писали:
VE>Здравствуйте, targeted, Вы писали:
T>>Например:
T>>void foo(Bar*); T>>Biz* biz = new Biz(); T>>foo((Bar*)biz);
VE>А на Хаскеле такое же прокатит?