четверг, 1 сентября 2011 г.

MQL4unit

Ну вот, наконец-то я поборол лень и написал краткий мануал для своей мини-библиотечки

MQL4unit – библиотека для юнит-тестирования функций, написанных на языке MQL4 компании MetaQuotes.

Автор: я)))

Идея библиотеки взята из статьи «Повышаем качество кода при помощи Unit Tests»(articles.mql4.com/ru/936), но текущая реализация доработана до стандарта xUnit. Используемая лицензия – GNU/GPL v 2.0 (http://infolex.narod.ru/gpl_gnu/gplrus.html).

Подробнее о практике Unit Testing можно прочитать в книге Кента Бека «Экстремалное программирование. Разработка через тестирования» (Beck Kent “Extreme Programming. Test Driven Development”, Addison-Wesley, 2000). Так как MQL4 является процедурным языком, минимальным тестировочным юнитом будет являться одна функций (процедура). Результаты тестирования можно посмотреть во вкладке «Эксперты» (“Experts”) торгового терминала.

Функции инициализации и деинициализации набора тестов.

void UnitTestStart(string TestName) – функция инициализации набора тестов. Принимает один параметр типа string, обозначающий название набора тестов. Рекомендуется применять осмысленные названия для более четкой идентификации результатов тестирования. Должна быть вызвана до каких-либо других функций библиотеки, так как она инициализирует счетчики успешных и проваленных тестов, общего количества. В противном случае общий результат тестирования будет некорректен.

bool UnitTestEnd() – функция деинициализации набора тестов. Возвращает true в случае прохождения всех тестов, false – в противном случае. Должна быть вызвана после всех обращений к функциям библиотеки в пределах одного набора тестов.

Функции тестирования единичных значений.

bool AssertTrue(bool var) – функция для тестирования логической переменной на ожидаемое значение "истина".

Параметр: bool var.

Возвращаемое значение: true, если входная переменная содержит значение "истина"; false, если входная переменная содержит значение "ложь".

bool AssertFalse(bool var) – функция для тестирования логической переменной на ожидаемое значение "ложь".

Параметр: bool var.

Возвращаемое значение: true, если входная переменная содержит значение "ложь"; false, если входная переменная содержит значение "истина".

bool AssertBoolsEqual(bool gotten, bool needed) – функция для тестирования двух булевых переменных на равенство (полученной в результате работы тестируемого юнита и ожидаемой).

Параметры: bool gotten – значение, полученное в результате работы тестируемого юнита, bool needed – ожидаемое значение.

Возвращаемое значение: true, если значения входных переменных равны; false, если значения входных переменных не равны.

bool AssertIntsEqual(int gotten, int needed) – функция для тестирования двух целочисленных переменных на равенство (полученной в результате работы тестируемого юнита и ожидаемой).

Параметры: int gotten – значение, полученное в результате работы тестируемой функции, int needed – ожидаемое значение

Возвращаемое значение: true, если значения входных переменных равны; false, если значения входных переменных не равны.

bool AssertDoublesEqual(double gotten, double needed, int pres) – функция для тестирования двух переменных типа double на равенство (полученной в результате работы тестируемого юнита и ожидаемой).

Параметры: double gotten – значение, полученное в результате работы тестируемой функции, double needed – ожидаемое значение, int pres – требуемая точность сравнение (кол-во знаков после запятой).

Возвращаемое значение: true, если значения входных переменных равны; false, если значения входных переменных не равны.

bool AssertColorsEqual(color gotten, color needed) – функция для тестирования двух (цветовых) переменных типа color на равенство (полученной в результате работы тетстируемого юнита и ожидаемой).

Параметры: color gotten – значение, полученное в результате работы тестируемой функции, color needed – ожидаемое значение.

Возвращаемое значение: true, если значения входных переменных равны; false, если значения входных переменных не равны.

bool AssertStringsEqual(string gotten, string needed) – функция для тестирования двух строковых переменных типа на равенство (полученной в результате работы тестируемого юнита и ожидаемой)

Параметры: string gotten – значение, полученное в результате работы тестируемой функции, string needed – ожидаемое значение.

Возвращаемое значение: true, если значения входных переменных равны; false, если значения входных переменных не равны.

Функции сравнения массивов.

bool AssertBoolArraysEqual(bool gotten[], bool needed[]) – функция для тестирования двух массивов булевых переменных на равенство (полученного в результате работы тестируемого юнита и ожидаемого).

Параметры: bool gotten[]– массив, полученный в результате работы тестируемой функции, bool needed[] – ожидаемый массив.

Возвращаемое значение: true, если массивы равной длины и совпадают поэлементно, false – в противном случае.

bool AssertIntArraysEqual(int gotten[], int needed[]) – функция для тестирования двух массивов целочисленных переменных на равенство (полученного в результате работы тестируемого юнита и ожидаемого).

Параметры: int gotten[] – массив, полученный в результате работы тестируемой функции, int needed[] – ожидаемый массив.

Возвращаемое значение: true, если массивы равной длины и совпадают поэлементно, false – в противном случае.

bool AssertDoubleArraysEqual(double gotten[], double needed[]) – функция для тестирования двух массивов вещественных переменных на равенство (полученного в результате работы тестируемого юнита и ожидаемого).

Параметры: int gotten[] – массив, полученный в результате работы тестируемой функции, int needed[] – ожидаемый массив.

Возвращаемое значение: true, если массивы равной длины и совпадают поэлементно, false – в противном случае.

bool AssertStringArraysEqual(string gotten[], string needed[]) – функция для тестирования двух массивов строковых переменных на равенство (полученного в результате работы тестируемого юнита и ожидаемого).

Параметры: string gotten[] – массив, полученный в результате работы тестируемой функции, string needed[] – ожидаемый массив.

Возвращаемое значение: true, если массивы равной длины и совпадают поэлементно, false – в противном случае.

bool AssertColorArraysEqual(color gotten[], color needed[]) – функция для тестирования двух массивов значений цвета на равенство (полученного в результате работы тестируемого юнита и ожидаемого).

Параметры: color gotten[] – массив, полученный в результате работы тестируемой функции, color needed[] – ожидаемый массив.

Возвращаемое значение: true, если массивы равной длины и совпадают поэлементно, false – в противном случае.

bool AssertDatetimeArraysEqual(datetime gotten[], datetime needed[]) –функция для тестирования двух массивов дат на равенство (полученного в результате работы тестируемого юнита и ожидаемого).

Параметры: datetime gotten[] – массив, полученный в результате работы тестируемой функции, datetime needed[] – ожидаемый массив.

Возвращаемое значение: true, если массивы равной длины и совпадают поэлементно, false – в противном случае।


Код с полной документацией лежит тут.

понедельник, 18 июля 2011 г.

Размышления о киберорганике

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

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

Основная проблема в этом кроется как раз во втором подходе. К сожалению, люди при создании новой технологии сначала стараются применить ее к уничтожению себе подобных и захвата максимально жирного куска или теплого места. Это, конечно, результат естественного отбора и в природе было бы нормально, другое дело что в природе это все находится в том равновесии, которое позволяет выживать глобальной экосистеме, поддерживая все звенья цепочек питания на оптимальном уровне. Но технологии уже нарушили этот хрупкий баланс, а киберорганика может привести к еще большим последствиям из-за невозможности животного мира противостоять таким киборгам. Недаром в «Дао Дэ Цзин» и других трактатах древних мудрецов так много уделяется внимания сохранению равновесия в мире и каждом человеке. Как мне кажется, человечество вообще должно чаще присматриваться к восточной культуре, которая более созерцательная и меньше направлена на подавление окружающего мира. В то же время кибернетизированный человек может довести уровень своей роботизации до такого состояния, что он сам не будет осознавать, кто он теперь – человек или машина. Наиболее ярко такие рассуждения показаны от лица майора Кусанаги в известной анимации «Призрак в доспехах». И кто знает, какой ответ в такой ситуации окажется правильным и где заканчивается сознание человека и начинается сознание машины, если таковое существует. Над решением этой проблемы бьются многие философы и вполне может случиться, что на практике ответ на этот вопрос будет получен гораздо раньше, чем в кулуарах философских саммитов и коллегий. И есть ненулевая и даже не очень малая вероятность того, что этот ответ может не обрадовать ни самого роботизированного человека, ни тех самых философов.

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

Это все - мое конкурсное эссе на конкурс октября 2010

понедельник, 12 апреля 2010 г.

Основа программирование - полное проектирование

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

Можно себе представить влияние таких реформ на строительную отрасль в целом, но что будет на вершине айсберга? Как бы изменилась работа архитекторов и дизайнеров, если расходы на строительство были бы незначительны? Сегодня, физические и компьютерные модели строятся и тщательно проверяются, прежде чем начинается вложение денег в строительство. Будем ли мы беспокоиться об этом, если строительство в основном бесплатно? Если конструкция рушится, ничего особенного - просто выяснить, что пошло не так, и наши волшебные роботы построят все заново. Будут и другие отличия. Строения, построенные по устаревшим моделям и дизайну будут совершенствоваться до получения приемлемого результата. У стороннего человека могут возникнуть затруднения с различием полуфабриката и конечного изделия.

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

Конечно, давление конкуренции остается в силе. При минимальной стоимости строительства лидером на рынке станет та компания, которая сможет организовать самое быстрое проектирование. Таким образом, ускорение процесса проектирования становится главной задачей инженеров. Безусловно, некомпетентный в данной области человек при виде непроверенной, но выпущенной раньше других конструкции может сказать: "Это выглядит достаточно хорошо".

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

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

К счастью, эта модель также предлагает подсказки о том, каким образом получить лучший результат. Физическое моделирование в данном случае аналогично автоматизированному тестированию; разработки программного обеспечения не является завершенной, пока программный продукт не прошел большое количество строгих тестов. Для того чтобы проводить такие испытания более эффективно, мы находим пути, чтобы обуздать огромное пространство состояний больших систем. Улучшенные языки программирования и методы проектирования дают нам надежду. Наконец, есть один неоспоримый факт: выдающиеся продукты производятся выдающимися проектироввщиками, посвятившими себя оттачиванию своего мастерства. И программирование не является исключением.

Перевод: Протченко Алексей a.k.a Severyanin
Лицензия: [http://creativecommons.org/licenses/by/3.0/us/ Creative Commons Attribution 3]

Оригинал: Code Is Design
Автор [[Райан Браш]]
Лицензия: [http://creativecommons.org/licenses/by/3.0/us/ Creative Commons Attribution 3]

среда, 7 апреля 2010 г.

Пишите на языке предметной области

Сравните две нотации написания кода.

В одной вы увидите:

if (portfolioIdsByTraderId.get (trader.getId ())
  . ContainsKey (portfolio.getId ())) {...}


Не сразу можно понять, что делает этот код. Кажется, это - получение идентификатора объекта trader, с его дальнейшим использованием для получения карты, то есть, по-видимому, карты карт, и проверка на существование в этой внутренней карте идентификатора объекта portfolio. Вы чувствуете, что надо думать дальше. Объявление portfolioIdsByTraderId выглядит следующим образом:

Map <int, Map <int, int>> portfolioIdsByTraderId;


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



В другой нотации вы столкнетесь со следующим:

if (trader.canView (portfolio)) {...}



Не нужно чесать голову в раздумьях. Также Вам не нужно знать, что представляет собой объект trader. Может быть, одна из этих карт, состоящих из карт, спрятана где-то внутри. Но это забота объекта trader, а не Ваша

Итак, с какой из этих нотаций записи кода Вы предпочли бы работать?

Давным-давно у нас были только самые основные структуры данных: биты, байты и символы (на самом деле просто байт, но мы хотели бы сделать вид, что это были буквы и знаки препинания). С десятичными числами было немного сложнее, так как эта система счисления не совсем сочетается с двоичном форматом работы аппаратной части, поэтому мы вынуждены были использовать несколько типов данных с плавающей запятой. Потом появились массивы и строки (на самом деле это были просто разные типы массивов). Тогда мы получили возможность работать со стеком, очередью,хэш-таблицей, связанным списком, разреженным списком и множеством других интересных''структур данных, которых не существует в действительности''. IT-специалисты тратили много усилий на отображение объектов реального мира в рамках нашего ограниченного набора структур данных. Настоящие гуру даже помнят, как им это удавалось.

И наконец, мы получили определяемые пользователем типы! Хорошо, это не ново, но это полностью меняет условия игры. Если ваша модель процесса содержит такие понятия, как торговцы и портфели, вы можете моделировать их собственными типами, скажем, Trader и Portfolio . Но гораздо важнее то, что вы можете моделировать''отношения между ними'', используя терминологию предметной области.

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


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

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

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

Перевод: Протченко Алексей a.k.a. Severyanin

Лицензия: [http://creativecommons.org/licenses/by/3.0/us/ Creative Commons Attribution 3] 

Оригинал: Code_in_the_Language_of_the_Domain

Автор [[Dan North]]
Лицензия: [http://creativecommons.org/licenses/by/3.0/us/ Creative Commons Attribution 3]