среда, 17 декабря 2008 г.

Гуголь

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



На место встречи мы приехали на 30 минут раньше и все наши попытки самостоятельных исследований тут же пресекли местные охранники на идиотских электрических машинках.



Собственно тяга к электромобилям тут видна невооруженным взглядом. Вот, например, Брин и Пейдж приехали на работу.



Внутри офиса особого уюта нет. Люди в основном сидят без окон, в стандартных для армерики кубиках. Правда кубики не личные, а на команду. Обусловлено это тем, что в Гугл работают по Agile, небольшими командами по 3-6 человек.

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



Там же в кустах непонятно зачем стоит скелет динозавра. Много думал.



Если говорить по сути, то смысл подхода гуглов кроется в двух вещах: жестком отборе персонала и высоком доверии внутри компании. Прежде чем попасть на работу, кандидат проходит около пяти интервью, причем каждую кандидатуру ревьюит лично Брин. Каждая команда самостоятельно решает как и когда работать. Существует только 2 обязательных правила: code review и peer reviews (больше известный в россии как "360 градусов"). В целом, феномен гугла прост и понятен: большая концентрация профессиональных людей, которые обладают достаточным уровнем свободы и доступа к информации.

Рассказать можно еще многое, но лень все описывать. Если будут вопросы - пишите в комменты.

четверг, 11 декабря 2008 г.

вторник, 9 декабря 2008 г.

Привет, меня зовут Дмитрий Немцов. Хочу рассказать об одном антипаттерне, который не описан в имеющейся литературе, однако несколько раз был обнаружен в самых разных местах нашего проекта практически в неизменной виде. Я назвал его "Обиженный новичок". Кратко опишу суть этого антипаттерна.
Пусть имеется некий поставщик событий. На события подписываются и отписываются объекты - слушатели. Генерация события происходит при изменении состояния поставщика событий (приходе данных, редактировании настроек и т.п.).
Все подписанные объекты получают уведомления и тоже изменяют свое состояние. Новый объект - слушатель, подписавшийся к поставщику, не получит текущего состояния, пока оно не изменится. Состояние слушателя будет тем же, что и до подписки. Такое состояние корректно лишь в том случае, если до подписки этого объекта не было ни одного события.
Подобная ошибка может закрасться при проектировании моделей подписки на события, ориентированных на большую частоту поступления событий (это могут быть, например, биржевые данные реального времени, поступающие с частотой 10 - 100 порций в секунду). При этом ошибочное состояние нового подписчика остается незамеченным, поскольку оно длится недолго.
Проблемы начинаются тогда, когда частота поступления событий падает (например, до нуля, когда прекращаются торги).
При проверке незнакомого кода на предмет того, не кроется ли в нем описанный антипаттерн, можно руководствоваться следующим контрольным списком:
1. Проверить, что поставщики никак не могут инициализировать свое текущее состояние, кроме как через обратные вызовы их обработчиков. Это можно выяснить, взглянув на объявление интерфейсов слушателей, например:

interface ISomeEventListener
{
void OnSomeEvent(const SomeEvent& event) = 0;
}


2. Проверить, что происходит в коде поставщика событий в момент подписки нового слушателя. Зачастую такой код имеет вид
EventProvider::SubscribeListener(ISomeEventListener* newListener)
{
...
m_listeners.Add(newListener);
...
}

В окрестностях этого кода нужно поискать две вещи:
a) прямой вызов у нового подписчика обработчика события с неким закэшированным состоянием
...
m_listeners.Add(newListener);
...
newListener.OnSomeEvent(m_cashedEvent);
...

б) код, корорый как - либо запоминает нового подписчика (отдельно от старых подписчиков). Это может быть сделано с целью исключения непосредственного вызова обработчика у нового подписчика
...
m_newListeners.Add(newListener);
...


в этом случае вызов обработчика будет располагаться в другом методе и сопровождаться переносом нового подписчика к старым
...
m_newListeners[0]->OnSomeEvent(m_cashedEvent);
m_listeners.Add(m_newListeners[0]);
m_newListeners.Clear();
...


Приведу реальные примеры из нашего проекта.

I.
В нашем коде есть сущность под названием FontMgr. В ней объединены настройки шрифтов для всех окон. Вот её обработчик подписки(до исправления):

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

interface __declspec(uuid("7EF51E4B-28C3-4d86-9E55-F81E75235731")) IFontMgrEvents
{
virtual HRESULT STDMETHODCALLTYPE OnFontChanged(int index, LPCFONTSTRUCT font) = NULL;
virtual HRESULT STDMETHODCALLTYPE OnUseSettingsAsDefaults() = NULL;
};


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

HRESULT CFontMgr::Advise(IFontMgrEvents* e)
{
int index = m_events.Find(e);

if (-1 != index)
{
return S_FALSE;
}

m_events.Add(e);
return S_OK;
}

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

HRESULT CFontMgr::Advise(IFontMgrEvents* e)
{
int index = m_events.Find(e);

if (-1 != index)
{
return S_FALSE;
}

m_events.Add(e);
int fontsSize = m_fonts.GetSize();
if (0 < fontsSize)
{
for (int i = 0; i < fontsSize; ++i)
{
e->OnFontChanged(i, (LPCFONTSTRUCT)&m_fonts[i].font); // сообщение текущего состояния новому подписчику
}
}
return S_OK;
}

II.

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

interface IBarListener
{
virtual void OnBarBackFill(IBarSet *bs)=0;
virtual void OnBarBackFillComplete(IBarSet *bs)=0;
};


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

dataProvider->SubscribeBars(SubscriptionParams params, this)

данные начнут приходить к нему через обратные вызовы обработчиков. IBarSet представляет совокупность данных. Когда приходит очередная порция данных, вызывается OnBarBackFill. Он может вызываться много раз, в зависимости от объема запрошенных данных. После прихода последней порции данных, вызывается OnBarBackFillComplete. Приходящие данные кэшируются в поставщике событий. Если подписка на данные осуществляется не в первый раз, т.е. данные уже есть в кэше, то OnBarBackFillComplete не вызывается. Это является архитектурной проблемой, которая к настоящему моменту не исправлена. Чтобы узнать, полностью ли пришли данные, каждый слушатель должен каждый раз при вызове OnBarBackFill проверять у контейнера с данными свойство IsCompleted() и в зависимости от него принимать решение, что делать.

void SomeDataConsumer::OnBarBackFill(IBarSet *bs)
{
if (bs->IsCompleted())
{
UpdateGUI();
}
else
{
DoSomeCalculations();
}
}


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

III.

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

вторник, 2 декабря 2008 г.

Биржа Nasdaq

NASDAQ - самая крупная электронная торговая площадка в мире, которая адекватно отражает состояние дел практически всех основных компаний, связанных с компьютерным бизнесом. Здесь котируются акции "монополиста" Microsoft, гиганта Intel, легендарной Apple, могущественного Sun Microsystems, популярнейшего Yahoo и дерзкого Amazon.com.
NASDAQ - буквальный перевод названия "автоматизированное котирование Национальной ассоциации торговцев ценными бумагами" - National Association of Securities Dealers Automated Quotation - "NASDAQ". Сначала список низколиквидных ценных бумаг выставляемых на торгах включал около двух с половиной тысяч компаний, которые по тем или иным причинам не смогли пройти листинг Нью-йоркской фондовой биржи (NYSE) и Американской фондовой биржи (AMEX). Стремительное развитие электронного рынка NASDAQ, обусловленное не менее стремительным ростом индустрии, лежащей в основе "кузницы миллионеров", привело к тому, что сейчас число компаний, участвующих в системе NASDAQ, удвоилось и составляет пять тысяч корпораций, разбросанных по всему миру (более 400 неамериканских компаний).
Развитие торговой системы продолжалось, и год 1982 был ознаменован рядом новаций в работе электронной торговой площадки NASDAQ: компании, находившиеся в самом начале листинга, отделились и создали NASDAQ National Market. Для осуществления данной цели критерии и требования для участия компаний в деятельности на National Market были ужесточены. Оставшаяся часть акций (около 2/5 компаний сейчас) котируется в NASDAQ SmallCap Market. Кроме того, была введена в действие система исполнения небольших заказов, появилась возможность покупки ценных бумаг в кредит, были осуществлены и некоторые иные преобразования. Все изменения и новации не прошли даром, и в 1994 году NASDAQ по среднегодовому объему торгов обошла крупнейшую и престижнейшую Нью-йоркскую фондовую биржу.
В 1998 году состоялось структурное объединение двух колоссальных финансовых институтов - NASDAQ и AMEX. Обе торговые площадки принадлежат одной структуре - NASD (Национальной комиссии по ценным бумагам США), с той лишь разницей, что на AMEX котируется только ограниченное число компаний, и кроме этого членами AMEX могут быть только американские компании. После слияния появился NASDAQ AMEX Market Group. Это еще больше укрепило позиции NASDAQ, как самой крупной электронной торговой системы.
NASDAQ, как стержень "новой экономики", обладает повышенной отказоустойчивостью. К началу этого года электронная торговая площадка NASDAQ основывалась на 324 отказоустойчивых мейнфреймах Tandem (многопроцессорные системы, состоящие из большого количество двухпроцессорных модулей), более 50 серверах Dell и Compaq, 18 мейнфремах Unisys, огромном количество батарей и целой армии источников бесперебойного питания, трех мощнейших дизелях и огромных холодильных установках. Кроме этого, существует еще и резервная система в Роквилле, которая полностью дублирует все жизненно важные модули системы. Но и это еще не все. Наверняка будет интересен следующий факт: тестирование NASDAQ по вопросу перехода рубежа тысячелетий (пресловутая "Ошибка 2000") началось в 1996 году, в нем принимали участие 150 человек, было проведено 170 000 имитаций торгов в критический период, общая стоимость "Программы NASD по 2000 году" оценивается примерно в 55 миллионов долларов США. Все это позволяет говорить о колоссальной "железной" и "программной" мощи NASDAQ. Взлом системы практически невозможен, еще более нереально нарушение хода торгов. Однако... 15 сентября 1999 году группой хакеров United Loan Gunmen был взломан сайт NASDAQ! Предварительное исследование, проведенное аналитической фирмой Mi2g Software, показало, что хакеры воспользовались хорошо известными дырами в защите Internet Information Server. Однако при взломе никакого нарушения финансовых транзакций не произошло, и по утверждению представителя NASDAQ, сайт работал в обычном режиме. Тем не менее, специалисты по компьютерной безопасности были сильно обеспокоены инцидентом.
Понятно, что популярность торговой системы NASDAQ не могла не привести к возникновению аналогичных образований в других странах и регионах. На сегодняшний день существует достаточное количество подобных рыночных образований, однако лишь немногие из них могут быть хотя бы частично сопоставимы с системой NASDAQ, которая прошла большой путь развития и совершенствования, став зеркалом высокотехнологичных отраслей экономики всего мира.
Не смотря на то, что NASDAQ сама открыла свои представительства в Канаде, Японии, Гонконге и планирует сделать это в Европе, во всех этих регионах развиваются собственные Hi-Tech индексы и системы. Так существуют очень молодые образования JASDAQ, KOSDAQ, ROSDAQ. Это японский, корейский и даже румынский рынки. Однако количество компаний, зарегистрированных в них, не превышает нескольких десятков, поэтому говорить о серьёзной конкуренции "старому" NASDAQ не приходится. Что касается стран СНГ, то подобная NASDAQ торговая площадка пока не создана ни на одной фондовой бирже и торговой системе этих стран. Справедливости ради следует отметить, что попытка все-таки была предпринята весной прошлого года Московской межбанковской валютной биржей, инвестиционной группой "Русские Фонды" и компанией PricewaterhouseCoopers. Однако дальше планов по открытию на ММВБ сектора "Высокие технологии", где должно было происходить первичное размещение и вторичные торги акциями Интернет-компаний, провайдеров, разработчиков ПО и других высокотехнологичных компаний, дело пока не пошло.