суббота, 17 декабря 2011 г.

Конференция Яндекс.План-Б

Сегодня побывал на конференции Яндекс.План Б. Хочу поделиться своими заметками и комментариями по докладам, которые довелось послушать:
  1. "Фэйлы внедрения планирования" (Роман Чернин)

    В итоге доклад был совершенно не связаны с этой темой, о чем Роман и предупредил. Типа "планы изменились". :)
    Речь, в общем, шла о том, что в продуктовой разработке, по большому счету, нет ни сроков, ни заказчиков, ни требований. Как это решать? Яндекс для этого выделяет отдельных Product Manager'ов. Эти самые Product Manager'ы и берут на себя роль заказчиков, и именно в их ведении оказывается конечный результат. Так, чтобы работа разных команд сошлась в одном едином продукте, который понравиться бы пользователям. Лично я с такой системой знаком не понаслышке. И в ней очень важно, чтобы этот самый Product Manager сам четко понимал, что он хочет получить на выходе, и кому всё это надо.
  2. "Framework для планирования проекта с точки зрения менеджера продукта" (Ольга Павлова)

    Доклад и сам стиль презентации заставили проснуться всех тех, кто еще этого не сделал. Основные тезисы, которые я для себя отметил:
    • "Управление продуктом - это управление мечтой заказчика". И результатом работы должно быть именно воплощение этой мечты.
    • "Точных формулировок не бывает" - как бы вы не пытались формулировать изначально, все равно получиться не то, что хотел заказчик. Чтобы в итоге удовлетворить заказчика, надо ему показывать промежуточные результаты. Но результаты должны непременно соответствовать уровню интеллекта заказчика.
    • "Делаем игрушки" - т.е. в процессе работы для демонстрации заказчику нужно создавать игрушки, которые бы он понял. Для одних это могут быть прототипы, для других скетчи, а кому то, может, и диаграмм Ганта будет достаточно.
    • "Работа менеджера - отвечать на вопросы" - т.е именно PM должен знать что, зачем и почему делается, и что будет дальше.
    • "Сроки часто срываются из-за того, что в них не закладывается время на согласование".
    • "Не нужно бояться делать на выброс" - не стоит пытаться дождаться ситуации, когда все станет понято, и лишь тогда начинать. Начинать надо сразу, и прямо сразу показывать полученые прототипы. Да, многие из них будут выброшены, но именно так удастся лучше и быстрее понять, что же все-таки хочет заказчик.
    • "План проекта не лестница, а лабиринт"
    • Обсуждения должны вестись с разработчиками. Не планируите в одиночку. Каждый специалист должен вносить свою часть в план.
  3. Полёт на Марс, или как не обидеть слона (Георгий Липатов)

    • "Нельзя ставить слишком жесткие сроки"
    • "Большинство разработчиков хотят делать хорошо. Надо лишь дать им такую возможность"
    • Тестирование должно быть сосредоточено внутри команды, и быть единым процессом с разработкой. Люди делают одно дело, на общее благо, и не должно быть эффекта противостояния.
    • Разработчики в идеале должны работать на FullTime на один проект.
  4. "Планирование аналитической части проекта" (Иван Потапов)

    Лично на мой взгляд, самый скучный доклад из тех, что я слышал, сводящийся к одной фразе "аналитики должны анализировать". Возможно там была какая-то специфика, связанная с аутсорсингом, но лично я для себя кроме фразы "во всем виноваты аналитики" ничего более не вынес.
  5. "Изменение процессов планирования в растущей команде тестирования" (Станислав Комарницкий )

    Очень интресный доклад об организации тестирования в Яндексе. Поразило отношение количества разработчиков к количеству тестеров: 10 к 1. Интересный подход с тем, что тестеры это что-то вроде пограничного пункта. Границу можно перейти в другом месте, но при этом тестеры ответственность за результат не берут.
    Лично мое отношение, что тестеры в принципе не должны брать на себя ответственность за результат, они лишь помогают своим опытом и силами найти то, что не нашли разработчики.
  6. "Трудности планирования в удаленных и географически распределенных командах" (Дмитрий Григорьев)

    Впервые слушал рассказ о команде, где люди работают в разных странах, часовых поясах, и даже никогда не видели друг друга. И судя по докладу автора у них получается вполне хорошо координировать работу 60! человек. При этом они не требуют одновременного online'а всей команды.
    Еще удивило то, что они учитывают время работы (выполнения конкретной задачи) каждого сотрудника с точностью до 10 минут.

    Опять же мое отношение к удаленной работе неоднозначно. Сужу по себе. Производительность моя дома выше, но сложно обеспечить стабильный рабочий день - слишком много отвлекающих факторов в лице домашних. Касательно же учета времени я вообще резко против. Из моего опыта это вреда приносило больше, т.к. люди не работой занимались, а думали как оправдать время.
  7. "Планирование для продуктового менеджера" (Михаил Карпов)

    • "Команде должно быть удобно работать"
    • "Команда должна быть в курсе происходящего в проекте"
    • 3 горизонта планирования: "Хотелки" , "Описания", "ТЗ". Т.е. в горизонте на год у нас приоритезированые "Хотелки", в 3х месячном горизонте они обрастают описаниями, которые в месячной перспективе в результате обсуждении с командой превращаются в "ТЗ". Яндекс использует для хранения результатов обсуждений Wiki.
    По каждому проекту есть некая страничка, где одним взглядом можно понять всё: над чем работаем сейчас, что будем делать, где найти всю инфу. При этом команда Михаила не использует TDD и Code Review и, я так понял, особо не страдает.
  8. "Планирование в распределенных командах" (Мария Петрова)

    Еще один опыт распределенных команд.
    • "В распределенных командах не должно быть испорченного телефона" - именно по этому все разговоры и все общение жестко фиксируется в вики или письмах, иначе потом концов не найти.
    • "Люди сами себе назначают сроки" - когда человек сам говорит, что он это сделает за какой-то период времени, то винить ему потом некого.
    • "Доверие" - очень важный аспект работы любой команды.
    • "Есть люди, которые в принципе не могут работать удаленно".
    • "Собеседовать человека удаленно не получается" - по опыту Марии, проще слетать в командировку, чем через некоторое время уволить человека. Данный тезис несколько противоречит утверждениям Дмитрия Григорьева, но у каждого свой опыт.
Увы, после этих долкладов я вынужден был покинуть эту конференцию, и вторую часть, где были интерактивы, я уже не посетил. Резюмируя, конференция мне понравилась. Основными докаладчиками были именно менеджеры, а уж они говорить умеют много, долго и красиво, потому скучно не было.

Спасибо Яндексу за это. :)

суббота, 3 декабря 2011 г.

Бесплатные ИТ-конференции

На этой неделе мне посчастливилось побывать на двух бесплатных конференциях - HTML5Camp и Яндекс.Субботник. Я бы хотел попробовать суммировать свои впечатления об этих событиях и выразить свое мнение о самой идее организации ИТ-событии с бесплатным входом.

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

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

Наличие большого количества разработчиков из разных областей требует от докладчиков умения рассказывать легко и непринужденно о сложных вещах не стараясь уж слишком углубляться в детали. Отсюда заметно, что на сложных технических докладах, где докладчик мало работает с аудиторией - народ спит. А как только на сцене появляются докладчик умеющий зажигательно и легко рассказывать, народ оживает. Хорошие тому примеры доклады Гайдара Магданурова, Анастасии Ларкиной, Ольги Мегорской. 

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

Для себя я не сделал однозначного вывода о пользе посещения этих конференции. Так например Html5Camp, проходящий в рабочее время, я бы не стал рекомендовать к посещению сотрудникам нашей компании, а расценивал его, как некий эквивалент поощрения, вроде отгула. Яндекс.Субботник, проходит в выходные и каждый волен сам решать хочет ли он тратить на него свой выходной. Лично мне он был интересен, как возможность заглянуть в другой для себя мир поисковых технологии, высокой нагрузки и не самых популярных, в клиентской среде, ОС.

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

среда, 14 сентября 2011 г.

UI test for WPF applications with White framework

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

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

Оказывается при добавлении нового проекта я забыл прописать его библиотеку в конфиг WIX и она не попала в сетап.

Тогда я начал задумываться о том, как бы мне проверять моё WPF приложение в боевой обстановки, автоматически, без сторонних тулов типа TestComplete да еще и бесплатно.

Первым делом я наткнулся на фичу VS2010 Coded UI Test, но очень скоро оказалось что эта фича требует наличие более дорогой версии студии чем моя компания распологает.

После некоторых изыскании окзалось что в основе Coded UI Test лежит UI Automation API, которое ничего не стоит. Так же есть бесплатная и открытая библиотека White, позволяющая упростить работу с этим API.

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

Вот пример кода который это делает:

// Run application
var application = Application.Launch(@"C:\Reps\WPFApp.exe");

// Find main window
var window = application.GetWindow("Title of My WPF application", InitializeOption.NoCache);

// Click ribbon button by Id
var connectBtn = (Button)window.Get(SearchCriteria.ByAutomationId("AddFarmBtn"));
connectBtn.Click();

// Find wizard dialog
var conWz = window.ModalWindow("Add farm window");

// Type url into TextBox
var urlTextBox = (TextBox)conWz.Get(SearchCriteria.ByAutomationId("FarmTB"));
urlTextBox.Enter(@"http://superfarmurl.com");

// Click Add button
var addBtn = (Button)conWz.Get(SearchCriteria.ByAutomationId("AddBtn"));
addBtn.Click();

// Wait till dialog closed
conWz.WaitTill(() => { return conWz.IsClosed; });

// Check list box
var farmsList = (ListBox)window.Get(SearchCriteria.ByAutomationId("FarmsListBox"));
var resFarms = farmsList.Items.FindAll(li => { return li.Text == @"http://superfarmurl.com"; });
Console.WriteLine(resFarms[0]);

// Kill app
application.Kill();

Для просмотра всяких Automation ID достаточно удобно пользоваться UISpy

Но конечно не обошлось и без ложки дегтя, при работе c White из x64 (или Any CPU) приложении ф-ии Click() работают некорректно, кто уж в этом виноват я не знаю, но если запускать из x32 процесса все работает замечательно

воскресенье, 21 августа 2011 г.

Hyper-V: Managing labs with PowerShell

Последнее время я почти полностью перешел на Hyper-V, основной причиной стало то что свежая бесплатная версия ESXi не имеет возможностей для автоматизации работы с виртуальными машинами.
Для меня же возможность из скрипта запустить\выключить\откатить машину очень важна, т.к. это активно используется в тестах.
А вот у Hyper-V c автоматизацией все великолепно, используя вот эту библиотеку можно с легкостью писать скрипты на PowerShell

Вот например откат машины к последнему снэпшоту:

import-module hyperV
Get-VMSnapshot -VM LABNAME -Server HOSTNAME -newest | Restore-VMsnapshot -Force -Restart

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

Вот что из этого вышло:

PARAM ($vmName)
import-module hyperV
$serverslist = ( 'hostname1','hostname2','hostname3')
$serverslist | % { Get-VM -Server $_} | ? {$_.ElementName.ToUpper() -eq $vmName.ToUpper()} | Get-VMSnapshot -newest | Restore-VMsnapshot -Force -Restart

Очень удобно. Рекомендую!

среда, 11 мая 2011 г.

Родная и не родная архитектура приложения

Профессионально занимаясь разработкой софта уже более 10 лет весьма часто встречаю подходы к разработке продуктов и архитектур не поддающиеся моему пониманию. Я всегда разрабатывал под операционную систему Windows и, в основном, решения были той или иной степени "коробочности" и массовости. Это подразумевало что каждый пользователь мог сам инсталлировать версию продукта или провести ее обновление.

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

Процесс проектирования был весьма условный и сводился к общим формулировкам типа "это все будет в виде сервиса и хранить все данные будем в SQL". Уже начиная с версии 2.0 продукт особой стройностью архитектуры не отличался.

Мне особо запомнился следующий случай - одна из больших частей системы писалась отдельной командой, влюбленной в Linux, и была написана и отлажена на С++\QT, но т.к. весь остальной продукт был сделан под Windows пользователям решили не мудрствуя лукаво поставлять виртуальную машину в которой работали окошки от этого компонента системы и взаимодействовали с основной частью по средствам CORBA . Поддерживать этот продукт было просто нереально. Даже просьба прислать логи превращалась в замечательный квест.

При разработке другого коробочного продукта под Windows .NET, разработчики решили, во чтобы то не стало воспользоваться языком Python, причем использовать именно его нативную версию т.к. IronPython на тот момент имел трудности при запуске на x64 машинах. Основными целями применения Python была именно скорость разработки, наличие исходного кода на стороне клиента и удобство написания тестов. И надо сказать что все эти цели были достигнуты, Python и правда очень приятный язык.

Дьявол как известно кроется в деталях. Оказалось что для того чтобы запускать этот код у клиента, нужно собрать MSI содержащий более 6000 файлов, включив туда уже установленный Python. А так как продукт предусматривал наличие веб интерфеиса, то пришлось тащить с собой и Apache и Django и еще огромную кучу всего. Так же в процессе разработки решались ряд специфичных трудностей с вызовом .NET API из Native Python через COM.

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

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

Сейчас я снова вижу очередной коробочный продукт под Windows на начальной стадии где пытаются использовать Java, MySQL и Apache TomCat... Простая попытка поставить этот продукт и посмотреть на чистой виртуальной машине заняла у меня почти пол дня, для того, чтобы правильно поставить и сконфигурировать все части. При этом, как давний пользователь Windows, я был удивлен видеть в корне моего системного раздела папки "var" и "etc"

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

Если пишется Enterprise level софт для Windows, то не грешно пользоваться .NET,IIS,ASP etc. Эти технологии тоже интересны и с ними также можно применять и Unit-тестирование,IoC,элементы функционального программирования и все другие техники.

В чужой монастырь со своим уставом не ходят!

вторник, 10 мая 2011 г.

Item ModerationInformation and SPListItem.UpdateInternal()

Столкнулся с необходимостью изменить значения нескольких полей включая Approval Status у ряда Item'ов, причем так, чтобы не изменились время модификации, Editor и не создалась дополнительная версия.

Первый способ был весьма прост:

var url = @"http://server/Lists/ContentApList";
var web = new SPSite(url).OpenWeb();
var list = web.GetList(url);
var item = list.GetItemById(1);
item["MyCheck"] = "test";
item[SPBuiltInFieldId._ModerationStatus] = 0;
item[SPBuiltInFieldId._ModerationComments] = "my coment";
item.SystemUpdate();
 
Но увы этот код просто валился с ошибкой Item does not exist. The page you selected contains an item that does not exist. It may have been deleted by another user.. Замена метода на UpdateOverwriteVersion() и Update() так же не помогла.

Вот такой вот вариант работает ,но :

var url = @"http://server/Lists/ContentApList";
var web = new SPSite(url).OpenWeb();
var list = web.GetList(url);
var item = list.GetItemById(1);
item["MyCheck"] = "test23";
item.ModerationInformation.Status = SPModerationStatusType.Pending;
item.ModerationInformation.Comment = "my coment";
item.SystemUpdate();
 
Но увы только для итемов. Похожий код для работы с файлами выдает исключение "You cannot change moderation status and set other item properties at that same time."

Попытка делать обновление в два этапа, увы так же не работает т.к. SystemUpdate, похоже, просто игнорирует обновление полей Moderation Information.

var url = @"http://server/Lists/ContentApList";
var web = new SPSite(url).OpenWeb();
var file = web.GetFile("CheckDocLib/logo.gif");
var item = file.ListItemAllFields;
item["MyComments"] = "test23";
item.SystemUpdate();

item.ModerationInformation.Status = SPModerationStatusType.Denied;
item.ModerationInformation.Comment = "my coment";
item.SystemUpdate();
 
Замена же на UpdateOverwriteVersion() приводит к тому что меняется время модификации.

Казалось бы приплыли, решения нет. Но пока еще бесплатный Reflector при просмотре ф-ии Update(), UpdateOverwriteVersion() и SystemUpdate() выдает что все они вызывают один и тот же метод:

internal void UpdateInternal(bool bSystem, bool bPreserveItemVersion, Guid newGuidOnAdd, bool bMigration, bool bPublish, bool bNoVersion, bool bCheckOut, bool bCheckin, bool suppressAfterEvents, string filename)

 

Табличка параметров вызова UpdateInternal из каждой ф-и.

Method bSystem bPreserveItemVersion newGuidOnAdd bMigration bPublish bNoVersion bCheckOut bCheckin suppressAfterEvents
Update() false false Empty false false false false false false
SystemUpdate() true false Empty false false false false false false
UpdateOverwriteVersion() false false Empty false false true false false false
MySystemUpdate() true false Empty true false false false false false

Немного поэсперементировав оказалось, что если выставлять флаги bSystem и bMigrate обновление ModerationInformation работает и при этом не происходит создания дополнительных версии. Вот итоговый код:

static void UpdateInternal(SPListItem item , bool bSystem, bool bPreserveItemVersion, Guid newGuidOnAdd, bool bMigration, bool bPublish, bool bNoVersion, bool bCheckOut, bool bCheckin, bool suppressAfterEvents)
{
    Type type = typeof(SPListItem);
    MethodInfo method = type.GetMethod("UpdateInternal",
                                        BindingFlags.Instance | BindingFlags.NonPublic,
                                        null,
                                        new Type[] { typeof(bool), typeof(bool), typeof(Guid), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool) },
                                        null
        );

    var parameters = new object[] {
            bSystem,
            bPreserveItemVersion,
            newGuidOnAdd,
            bMigration,
            bPublish,
            bNoVersion,
            bCheckOut, bCheckin,
            suppressAfterEvents };

    object obj = method.Invoke(item, parameters);
}

static void UpdateMigrate(SPListItem item)
{
    UpdateInternal(item, true, false, Guid.Empty, true, false,false, false, false, false);
}

static void CheckList5()
{
    var url = @"http://server/Lists/ContentApList";
    var web = new SPSite(url).OpenWeb();
    var file = web.GetFile("CheckDocLib/logo.gif");
    var item = file.ListItemAllFields;
    item["MyComments"] = "test23ddd";
    item.ModerationInformation.Status = SPModerationStatusType.Approved;
    item.ModerationInformation.Comment = "my coment";
    UpdateMigrate(item);
}
 

Буду рад если кому пригодится.

пятница, 15 апреля 2011 г.

SharePoint 2010: How to add custom page to Central Administration

Появилась цель добавить некоторую информацию о нашем продукте в Central Administration. В MSDN есть пример как это сделать используя VS2010, но на мой взгляд это слишком сложно.

Я нашел более простое решение, основанное на WSPBuilder. Обращаю внимание на то, что использовать надо именно BETA-версию, т.к. последний релиз не поддерживает SharePoint 2010.

Прежде всего создаем структуру каталогов:

В MyPageFolder кладем файл Extension.aspx , содержащий:

<%@ Page MasterPageFile="~/_admin/admin.master"%>
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
Hello World!
</asp:Content>
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
My Product Extension
</asp:Content>
<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
My Product Extension
</asp:Content>
 

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

После этого необходимо создать фичу в рамках которой будет работать наша страничка. Для этого в каталоге MyFeatureName создаем два файла elements.xml и feature.xml

elements.xml:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <CustomActionGroup
       Id="MyProduct"
       Location="Microsoft.SharePoint.Administration.GeneralApplicationSettings"
       Title="My Product"
       Sequence="100"
    ImageUrl="/_layouts/images/centraladmin_generalapplicationsettings_myproduct_page_32x32.png" />
    <CustomAction
       Id="MyProductAction"
       GroupId="MyProduct"
       Location="Microsoft.SharePoint.Administration.GeneralApplicationSettings"
       Sequence="10"
       Title="Some Action"
       Description="Description of Action">
        <UrlAction Url="_admin/MyPageFolder/Extension.aspx" />
    </CustomAction>
</Elements>

В elements.xml указываем, что хотим добавить отдельную группу My Product во вкладку Central Administration\General Application Settings (Microsoft.SharePoint.Administration.GeneralApplicationSettings) и создать в ней ссылочку с именем Some Action открывающую нашу страничку.

Файл feature.xml будет содержать описание фичи:

<Feature Id="952BA447-450D-47E1-9C7E-940A494E8333"
   Title="My Product"
   Scope="Farm"
   Description="Description of my product"
   xmlns="http://schemas.microsoft.com/sharepoint/">
    <ElementManifests>
        <ElementManifest Location="elements.xml" />
    </ElementManifests>
</Feature>
 

Так же в каталог IMAGES кладем файл с иконкой продукта и именем centraladmin_generalapplicationsettings_myproduct_page_32x32.png (на него мы ссылались в elements.xml)

Теперь остается лишь запустить WSPBuilder в этом каталоге
"C:\Program Files (x86)\WSPTools\WSPBuilderExtensions\WSPBuilder.exe" -WSPName MyProduct.wsp
И получим готовый солюшен для развертывания на SharePoint 2010.

Деплоим:
stsadm -o addsolution -filename MyProduct.wsp
stsadm -o deploysolution -name MyProduct.wsp -immediate

А вот что должно получится:

пятница, 21 января 2011 г.

SharePoint 2010: How to work with Taxonomy Fields using Client Object Model

Продолжу тему работы с Managed Metadata полями в SharePoint 2010, затронутую в прошлом посте.

Если посмотреть внутрь TaxonomyField, то оказывается, что это почти обычный LookUpField, который ссылается на скрытый лист TaxonomyHiddenList, живущий в рутовом сайте по адресу http://server/Lists/TaxonomyHiddenList. Этот лист содержит все Term'ы, которые использовались в данной коллекции. Хочу особо подчеркнуть, что именно использовались, т.к. если Term был добавлен, но ни разу не использовался в этом листе его не будет. Создается, он автоматически, при вызове метода SetFieldValue()()

К сожалению, Client Object Model ничего не знает о типах TaxonomyField и TaxonomyFieldValue и всем прочем, что находится в сборке "Microsoft.SharePoint.Taxonomy.dll". И как следствие полноценная работа с Taxonomy через Client OM невозможна.

Но не все так уж плохо. TaxonomyFieldValue имеет строковое представление, очень похожее на строковое представление LookUp полей:

5;#SuperNewTerm|f8b19ce9-ea14-4831-8284-e230026e6476

и следовательно его можно установить через Client OM, используя вот такой код:

var webUrl =  "http://server";
using (var clientContext = new ClientContext(webUrl))
{
    var itemCreation = new ListItemCreationInformation();
    itemCreation.UnderlyingObjectType = FileSystemObjectType.File;
    var lst = clientContext.Web.Lists.GetByTitle("TaxList");
    var item = lst.AddItem(itemCreation);
    item["Title"] = "Csom created";
    item["MyTerm"] = "5;#SuperNewTerm|f8b19ce9-ea14-4831-8284-e230026e6476";
    item.Update();
    clientContext.ExecuteQuery();
}
 

Сложность состоит в том, что при начальном формировании TermSet'ов TaxonomyHiddenList пуст. Но покопавшись в коде TaxonomyField.SetFieldValue() я нашел способ заполнения этого листа без непосредственного создания ссылающихся item'ов. К сожалению делать это приходится используя Server OM.

var url = "http://server/Lists/TaxList";
using (var site = new SPSite(url))
{
    using (var web = site.OpenWeb())
    {
        var lst = web.GetList(url);
        var taxfld = lst.Fields["MyTerm"] as TaxonomyField;
        var tSes = new TaxonomySession(site);
        var tStore = tSes.TermStores[taxfld.SspId];
        var tSet = tStore.GetTermSet(taxfld.TermSetId);
        foreach (var term in tSet.Terms)
        {
            int effectiveLcid = tStore.DefaultLanguage;
            string text = term.GetDefaultLabel(effectiveLcid) + TaxonomyField.TaxonomyGuidLabelDelimiter + term.Id;
            var tv = new TaxonomyFieldValue(taxfld);
            tv.PopulateFromLabelGuidPair(text);
        }
    }
}
 

После того как все Term'ы пред созданы с ними можно работать через Client OM.

PS: Только не забывайте что Term'ы могут содержать внутри себя другие Term'ы, и в моем коде, для простоты, это не учтено. :)

среда, 19 января 2011 г.

SharePoint 2010: How to set value to taxonomy list field

В SharePoint 2010 появился интересный сервис - Managed metadata, который позволяет создавать целые иерархии метаданных, централизовано ими управлять и использовать на всей ферме.

Мне понадобилось устанавливать значения для таких полей через код.

Для работы необходим reference на 'Microsoft.SharePoint.Taxonomy.dll' и namespace Microsoft.SharePoint.Taxonomy

Пример того как из существующей в листе колонки "MyTerm" получить определение "termName" и установить его в качестве значения колонки

var url = "http://server/Lists/TaxList";
using (var site = new SPSite(url))
{
    using (var web = site.OpenWeb())
    {
        var lst = web.GetList(url);
        var item =  lst.Items.Add();
        item[SPBuiltInFieldId.Title] = "super title";
        var taxfld = lst.Fields["MyTerm"] as TaxonomyField;
        var tSes    = new TaxonomySession(site);
        var tStore  = tSes.TermStores[taxfld.SspId];
        var tSet    = tStore.GetTermSet(taxfld.TermSetId);
        var tCol     = tSet.GetTerms("termName", true);
        if (tCol.Count > 0)
        {
            var term = tCol[0];
            var tv = new TaxonomyFieldValue(taxfld);
            taxfld.SetFieldValue(item, term);
        }
        item.Update();
    }
}
 

понедельник, 10 января 2011 г.

Мнение классиков по поводу переписывания кода

Недавно прочел книжку Джоэла Спольски "Джоэл о программировании" и сейчас читаю "Психбольница в руках пациентов" Алана Купера. Зацепился за то, что авторы крайне противоположно относятся к идеи "полного переписывания" кода.

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

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

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

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

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

А что думают о переписывании проектов мои уважаемые читатели?

суббота, 8 января 2011 г.

Mercurial and WinMerge as diff tool

Под Windows пользоваться hg diff не очень то удобно и наглядно. Для удобного diff и merge есть более подходящие средства, например WinMerge (открытый и бесплатный).

Чтобы он начал работать под hg в файл ".hgrc", из домашнего каталога, добавляем вот такие строчки:

[extensions]
hgext.extdiff =

[extdiff]
cmd.wdiff=winmergeu

[merge-tools]
winmergeu.args=/e /ub /dl other /dr local $other $local $output
winmergeu.regkey=Software\Thingamahoochie\WinMerge
winmergeu.regname=Executable
winmergeu.fixeol=True
winmergeu.checkchanged=True
winmergeu.gui=True

После чего можно смело писать hg wdiff myfile.txt

И видеть вот такой результат: