7/22/2010 4:52:51 PM

Давно, очень давно собирался написать что-то на эту тему, но всё никак не формировалось. Не формируется и сейчас, поэтому просто мысли.

Я уже давно пришёл к выводу, что многие люди неправильно понимают, что такое “просто”. Это касается не только программирования, а часто и вообще любых жизненных ситуаций, но я всё же немного с этим уклоном…

Очень часто, к сожалению, люди путают “просто” и “сложно”. То есть, когда они что-то делают “просто”, то получается в результате “сложно”.
Почему так получается? Да просто потому, что это самое “просто” изначально определено неверно в их головах.

Люди ведь как думают? Они думают, что “просто” – это когда не надо думать, не надо “париться”, бац – и сделал. Ну, вы понимаете, сделать “просто”, “по быстрому”. Потом спрашиваешь: отчего такая фигня получилась? А они в ответ: “ну, хотелось просто сделать”.
То есть, такой себе эгоистический достаточно подход получается: человек делал “просто”, и пока он делал, ему, возможно, и было “просто”, он не думал, он спустя рукова (если не мозг) работал, но вот всем остальным потом.. Им же ведь иметь дело с результатом. А результат в этом случае далеко не прост выходит. Он по большей части получается невнятный, запутанный, многосмысленный результат-то.

Правильное понятие о простоте, я думаю, должно складываться именно из результата.
Вот я прихожу, смотрю на код – а его так просто поддерживать и изменять, что ну никаких проблем с этим не возникает. Всё разложено по полочкам, разобрано по смыслам, не допускает двойных толкований. Легко читать, легко понять, что имеется в виду.
Вот это – просто. Я и коллеге скажу: “да там всё просто написано, сразу всё понятно”.
И это вовсе не означает, что человек, который писал этот код, не прилагал усилий. Это в 99% случаев означает совершенно обратное, кстати.

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

И, мне кажется, если мы будем смотреть на слово “просто” с точки зрения не процесса, а результата, то многое станет дейтвительно проще и осмысленнее.

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

7/13/2010 1:14:13 PM

Читая Мишины отзывы и ссылки, думал тут про тестеров.
Там кто-то говорит про "плохих" и "хороших" программистов и тестеров, кто-то объясняет, что программисты делают "тяп-ляп" потому, что "типа тестер всё равно проверит", а тестеры типа относятся к программерам как к "багоделам".

Это показалось мне странным, я думал-думал и пришёл к такому вот выводу: что-то тут не так :)

Потому, что лично я, как программист, пишу код не для тестеров. И не с расчётом на тестирование. И для меня никаким критерием не является то, нашли тестеры баг, или не нашли, и если нашли, то сколько. Я об этом не думаю, когда пишу код. Я не думаю о тестировании, когда пишу код. Я не думаю о тестерах, понимаете?
Да, имеет значение, есть баги в коде или нет. Но я не думаю о тестерах как о некой страховке! Предполагая, что в коде может быть баг, я подсознательно предполагаю (и прямо вижу, так сказать), как этот баг находит кастомер, не тестер.
Я делаю задачу, и для меня, когда я сдаю эту задачу, эта задача закончена. То есть, с моей точки зрения задача выполнена полностью. Я сделал, я написал юнит-тесты на всё, что хотел и что имело смысл проверить, я проверил, как оно работает...
Такой мысли, что "если чё - тестеры найдут" просто не возникает.

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

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

Когда программист начинает думать про тестеров как о страховке, когда он начинает думать "сейчас я зачекиню, они проверят, и, если чё - я пофиксю", то он начинает думать о незаконченной задаче как о законченной, то появляется сама возможность, там, в голове, сдать полузаконченную задачу.
Когда программист думает о тестерах как о неком фильтре, который за него разберётся что он сделал “так”, а что “не так” и выдаст назад результат в виде “вот тут ещё доделай и вот тут подкрути”, начинается такая фигня, и потом эта фигня вырастает в “ну чё он придирается”.

Тестер для программиста никогда не должен быть некой сущностью, которая проверяет домашнее задание непоседливого школьника, указывая на недостатки и недоработки. А школьник этот вертится на стуле и стремится поскорее “ответреться”. А если тут ещё ПиЭм неправильный, который типа контроллирует и типа требует результата – то и вообще атас (это я всё о том же).

Так кто же такие тестеры получаются?
Тестеры “располагаются” уровнем выше, так сказать. Они располагаются на уровне продукта. Они не являются фильтром ляпов программиста, они отвечают за конечное качество продукта. За то, чтобы фичи, которые идут в релиз, работали так, как им допустимо работать. Поэтому, насколько я вижу тестеров, у них точно так же нет мыслей о том, что кто-то там наделал багов. Они просто не размышляют в категориях конкретных программистов, они мыслят на уровне “эту фичу я пропускаю к релизу, а вот эта не вполне соответствует спецификации + для релиза необходимо иметь вон ту штуку готовой”.

Такой подход + отсутствие персонального владения кодом (я не помню, писал про таковое, или посчитал очевидным, но это – Изначальное Зло, если оно есть в команде – срочно искоренять, а тех, кто это устроил – линчевать) ведут к естественному и правильному взаимодействию тестеров и программистов, которое выражается… в отсутствие персонального взаимодействия Smile

То есть, я не имею в виду, что тестеры с программистами не общаются, вовсе нет. Общаются, и ещё как! Но это общение вида: я делаю фичу, или чиню баг, у меня есть вопрос, я пошёл к тестеру и попросил объяснить, как это должно работать, или как это воспроизвести, или что-то ещё.
Но это не взаимодействие типа “я напишу, а я проверь там” и “я проверил, ты там доделай”.

Поэтому есть команда программистов и команда тестеров. Которые просто выполняют разные задачи, на разных уровнях, а вовсе не “фехтуют” друг с другом.
И описанных проблем не возникает.

7/5/2010 12:39:43 PM

Интересный и даже полезный инструмент для неудомимых TFS-миграторов: http://tfsintegration.codeplex.com/
Целая "платформа", позволяющая перекачивать и даже синхронизировать по-разному и Source Code и Workitems между TFS-серверами Поддерживаются 2008 и 2010, причём можно и 2008-2010 делать.
На сегодняшний день это единственный способ перенести проект из одной Collection в другую, который я знаю.
Или вообще добавить существующий проект в существующую коллекцию.

Tags:

Other

7/2/2010 2:14:03 PM

Завтра работаю, финальная миграция с TFS 2008 в одном домене на TFS 2010 в другом домене. В последнем случае у меня будет ещё 4 физических сервера для build agents, думаю, что build controller будет жить на одном из них, чтобы не грузить саму TFS-машину.

На сегодняшний день (не мною) было отсмотрено и оттестировано достаточное количество process templates, включая MS SCRUM v1.0, MS Agile, MS CMMI/MFC, ScrumForTeamSystem v3.0

"Победил" последний - ScrumForTeamSystem v3.0, который, хотя поначалу и кажется "перенавороченым", но вот потыкавшись там, понимаешь – ба, тут того нет, тут – этого… Причём вещи-то полезные.

Словом, Царина (человек, которому с этим всем работать) смотрит видео с PDC (мы с ней, кстати, были на той сессии Winking smile) и прочих конференций, посвящённых SCRUM, а я завтра “нажму кнопку”.

Надеюсь успеть быстро.

Карма в действии. В Акателе я TFS мигрировал два раза, тут тоже…

Tags:

Programming | Other

6/7/2010 3:06:47 PM

По поводу предыдущей заметкипро FlowChart.

Как совершенно правильно заметил Паша в баззе, проблема всего этого великолепия с “долгоиграющими” workflow заключается в том, их нельзя менять.

При попытке что-то добавить или удалить запущеные и сохранённые в БД экземпляры просто не будут оттуда загружаться, а Workflow Runtime будет выдавать страшное сообщение о том, что “дерево Activities изменено, и поэтому состояние не может быть восстановлено”.

Как это решается? А никак. Просто никак. Официально предложен следующий механизм решения конфликта: името параллельно несколько версий и настроить роутинг WCF-сообщений. Чтобы сообщения, содержащие контракт “v1” доставлялись на сервис V1, а сообщения, содержащие контракт “v2” доставлялись на сервис V2.

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

Далее предлагается поступить так, как в КВН у команды Астаны (Казахстан) было: “Ну их!” :)
То есть, “старые” процессы дорабатывают по старой схеме, а те, которые начинаются новые – идут по схеме новой.

Иногда это не лишено смысла, допускаю. Однако, что делать, если нужно банально исправить ошибку? Особенно, если у нас имеются “бесконечные” workflow, как, например, документы в системе: они просто переходят из одного статуса в другой, туда, обратно, раз в два месяца…
Ответа на этот вопрос, видимо, не существует :)

Как вариант можно попробовать (только мысли, сам не ковырялся) написать свой вариант сохранения/загрузки workflow в/из БД.
Делается это, вроде бы, совершенно не сложно: надо просто создать своего наследниеп System.Runtime.DurableInstancing.InstanceStore. А вот насколько будет сложно там, внутри, разобраться, что данные у нас от V1 и построить на основе них V2 – непонятно, надо пробовать :) Наверное, однозначно ответить нельзя: когда-то это сделать легко, а когда-то и невозможно просто потому, что данных не хватит…

Пример того, как сделать собственную “сохранялку” в XML есть в библиотеке примеров для WF и WCF, здесь.

Паша ещё предложил как вариант делать stateless workflows. Чтож, вариант, хотя и очень-очень сильно компромисный и не всегда приемлемый. К тому же, в WF4 нет State Machines, и как “сказать” Workflow, что сейчас она находится не вот в этом состоянии, а вон в том – я не знаю. Допустим, она “висит” на Delay где-нибудь в середине. Или на ждёт, что кто-то “дёрнет” WCF-метод.

По поводу сохранения ещё, раз уж Паша эту тему тоже затронул.
В WF4 это тоже переделано относительно 3.5. Теперь Workflow Runtime не сохраняет сам Instance, а сохраняет только некие его состояния, переменные, в результате чего объёмы получаются гораздо меньше, нежели они были раньше. Что, в принципе, правильнее и логичнее. Но вот поднять именно код из сохранённого состояния больше не выйдет.

По поводу ошибок теперь.
В WF4 есть activities для транзакций и обработки ошибок (try..catch). То есть, всё можно делать непосредственно там – о отлов, и компенсацию, и обработку.
Если же всё-таки где-то недосмотрели и “выпали” в событие UnhandledException, то в этом случае мы “теряем” только то состояние, которое находилось на момент ошибки в памяти. То есть, в следующий раз workflow будет продолжена с момента последнего сохранения в БД.
Кстати, есть там ещё замечательная Persist Activity. Понятно, что она делает ;) Так вот, сначала Persist, потом делаем перевод денег :) Если что-то не получилось – в следующий раз выполнение продолжится с того же самого места, как и было указано в Пашином примере.

Но с версионностью – засада, конечно. Надо ещё будет попробовать, возможно ли её разрешать автоматически хоть в простых случаях… Тогда, может быть, комбинация stateless (or minimum state) + такая вот собственная сохранялка хоть как-то сможет помочь…

6/6/2010 2:39:02 PM

Два дня потратил на то, чтобы более-менее разобраться в Workflow Foundation 4-й версии.

Из новых замечательных возможностей – FlowChart диаграмма и возможность выставить содержащую её Workflow в сеть в виде “обычного” WCF-сервиса.

Сама по себе FlowChart диаграмма очень удобна, прежде всего своей наглядностью (сразу понятно, как протекает процесс), а так же тем, что практически в точности отражает те блок-схемы, которые вырисовываются на досках и бумажках при продумывании схемы работы. Наиболее счастливые разработчики сразу получают задание от специалиста по требованиям в виде примерно такой вот схемы с фразой “я хочу, чтобы было так!” в заголовке :)

Программисту остаётся только открыть Visual Studio, выбрать там проект, который называется “WCF Workflow Service Application”, и начать определять свой сервис в файле Service1.xamlx (лучше переименовать, или создать новый ;))

Я попробовал сделать небольшой сервис по обработке tickets (извините, я буду писать “тикетов”, так как не сумел придумать нормальный перевод).
Система примерно такая: тикет регистрируется в системе, после чего может изменяться до тех пор, пока не перейдёт в состояние Cancelled или Closed.
При этом он может попасть в состояние WaitingForCustomer. В этом состоянии он может ожидать неделю. Если клиент ничего не ответил, то тикет закрывается.

В результате получается что-то вроде вот такой диаграммы:

FlowChart 

Блок “Receive and Update Ticket” – это просто Activity, определённая в отдельном .xaml-файле.
Он отвечает за то, чтобы получить тикет посредством WCF-метода, сохранить его где-то, возможно, изменив, и отправить изменённый тикет обратно (для отображения).
Выглядит это так:

 Получение тикета через сервис

Здесь я просто “перетянул” мышкой в дизайнере ReceiveAndSendReply Activity, в результате чего образовались два блока, отмеченные стрелками. Первый – это получение WCF-сообщения, второй – возвращение значения.
Между получением значения и возвращением результата можно делать какие-то действия. Любые, в общем-то. Можно туда ещё один workflow вставить, который будет что-то важное делать, подготавливая данные к отправке, например, ещё одну FlowChart диаграмму :)
В моём случае всё предельно просто: я только добавляю запись в коллекцию History у тикета и возвращаю его обратно. Хотя, неплохо было бы сначала изменить историю, а потом уже сохранить ;)
Понятно, что если значение возвращать не надо, то можно воспользоваться просто Receive Activity.

Важно здесь то, что прямо в этих avtivities указывается имя метода (ProcessTicket), тип контракта, который будет принимать/получать метод (или можно указать кучку параметров) и что этот метод будет возвращать (это в SendReplyToReceive). Всё остальное будет сделано автоматически, метод станет виден WCF-клиентам как самый обычный WCF-метод.

Конфигурация WCF-метода.

Здесь MessageType = Ticket – это тип принимаемого сообщения (я принимаю Ticket), в Message data = _ticket – это имя переменной, куда я хочу положить принятый результат.

А ещё, поскольку мы получаем данные, производим над ними работу, а потом отправляем результат назад, нам нужно обеспечить для каждого такого процесса свой собственный, выделенный экземпляр workflow. Сделать это просто: нужно в свойствах Receive Activity включить галку CanCreateInstance. Впрочем, если Вы забудете это сделать, то при запуске Вам напомнят, да.
Итак, после этого у нас каждый тикет будет обрабатываться собственным экземпляром workflow. Что нам, собственно, и надо, ибо жизненные пути тикетов различны…

LogTicketInfo Activity я описывать не буду, скажу только, что это просто класс, activity, унаследованная от CodeActivity и она не делает ничего полезного, кроме Debug.WriteLine(..).
В WF4 предполагается наследоваться от CodeActivity и CodeActivity<T> для выполнения каких-то программных действий, либо от NativeActivity и NativeActivity<T>, если нужно как-то при этом взаимодействовать с Workflow Runtime. Generic-версии используются в том случае, если нужно вернуть какой-то результат заданного типа.

Блок, отвечающий за ожидание ответа клиента в течение недели выглядит так:

Ожидание ответа клиента в течение 7 дней

Тут я использовал стандартную Pick Activity для выбора одного из “направлений движения”. Их у меня всего два: либо клиент ответил, и тогда ничего делать не надо (анализируем новый статус как обычно), либо клиент НЕ ответил в установленный срок, и тогда закрываем тикет.

Кстати, для получения ответа клиента я использую ту же самую activity, что в самом начале, то есть, в моём случае, используется тот же самый WCF-метод. Что уже, в принципе, должно навести на мысли… ;)

Ну вот, а после получения тикета и записи лога (см. flowchart, первую картинку) всё стекается в блок Switch по полю Status тикета, который и решает, что мы должны делать дальше.

Казалось бы – должно работать! И если мы запустим проект и откроем любимый WcfTestClient.exe, то увидим, что оно и работает! Но если поиграться чуть дольше (или догадаться чуть раньше), то станет понятно, что работает оно неправильно.

Неправильно по двум причинам:

  1. Все Workflow, находящиеся в статусе отличном от Cancelled или Closed, висят в памяти неопределённое время (пока ресурсы не кончатся).
  2. Сколько бы мы ни пытались сказать, что тикет такой-то переходит из состояния WaitingForCustomer в любое другое – мы всё время попадаем в начальный блок “Receive And Update Ticket”, а не в тот, что находится в “Wait For Customer”. Иначе говоря, каждое обращение к методу у нас фактически активирует новый процесс, так как наш сервис не понимает, что это тот же самый тикет продолжает свой жизненный путь, а не просто новый “с неба свалился”. Таким образом, экземпляры всё копятся и копятся в памяти.

Самое время решить эти проблемы.

Первую решить довольно-таки просто и очевидно: воспользоваться стандартным persistence service, который уже есть в WF4. Сделаем так, что если workflow не активна, то она сохраняет себя в базе данных SQL Server и не занимает места в памяти и прочих ресурсов. Там, в базе, она может лежать годами, и никому от этого плохо не будет.
Для этого нам всего лишь нужно подготовить таблицы в БД, выполнив последовательно вот эти два (отмечены галочками, в том же порядке) скрипта:

Схема БД

Они создадут структуру таблиц и необходимые процедуры. Делать это можно в любой базе данных, например прямо в БД Вашего приложения, ничего там не сломается, просто добавятся новые таблички :)

Далее нужно просто пойти в web.config файл и прописать там следующие строки (понятное дело, строка подключения к БД у каждого своя):
Web.Config

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

Хорошо, что в .NET 4.0 всё, что только можно, уже прописано в “базовые” конфигурационные файлы :) Все конфигурационные файлы стали на порядок легче. Поэтому он уже “знает”, что такое эти два тега и может их использовать.

Со второй проблемой несколько сложнее.
Она ведь в чём состоит, проблема-то? Состоит она в том, что для обработки каждого тикета Workflow Runtime создаёт отдельный экземпляр workflow, но когда в метод ProcessTicket приходит “тот же самый” тикет, Workflow Runtime снова создаёт экземпляр, вместо того, чтобы использовать уже существующий.
Почему это происходит? Да потому, что Workflow Runtime просто не знает, что значит “тот же самый”. Как только она научится это знать – так сразу всё встанет “на свои места”.

Такой процесс “узнавания” называется “кореляцией” (correlation). Иными словами, мы должны провести кореляцию между нашим тикетом и экземпляром workflow.
Делается это тоже несложно: в Workflow для этого предусмотрен специальный тип переменной, называемый CorrelationHandle.

Так, как я использовал ReceiveAndSendReply Activity, то он создал мне такую переменную автоматически.
Я не буду тут отвлекаться на различные аспекты кореляции, (коих несколько, и есть дажа пара activities на данную тему), это отдельный разговор, здесь мы просто решим “насущную” задачу: укажем, что кореляция проводится по идентификатору тикета.

Для этого достаточно пойти в свойства Receive Activity, кликнуть там поле CorrelatesOn и указать нужный нам correlation handler (был создан автоматически, смотрите список переменных) и параметр для кореляции (Id):

Кореляция по полю Id 

В результате получится что-то такое:

Опять кореляция

Это означает, что когда в наш сервис в метод ProcessTicket приходит сообщение, то происходит его анализ по полю, указанному вот в этом вот XPath выражении, что было построено автоматически. Если значение этого выражения совпадает с каким-либо экземпляром workflow, то это экземпляр будет “поднят” из базы данных и это сообщение и будет обрабатываться именно этим экземпляром, что нам и нужно было сделать :)
Поэтому, когда в экземпляр, ждущий ответа от клиента, приходит такое сообщение, он продолжает свою работу именно с блока “Жду клиента”, а не попадает в начало процесса.

И, вроде бы, всё должно работать. И всё будет работать! :) И всё будет хорошо!

Но недолго. Кто знает, до каких пор? ;)

5/29/2010 3:40:08 PM

Немного переделал всем известный логотип, хочу такой на футболку. Правда, я (пока?) не состою в секте….

FitnessFirstLogo

Tags:

Live

5/11/2010 3:56:43 PM

В прошлый раз я написал целую инструкцию по поводу того, как обновить TFS до 2010, да на новой машине, да в новом домене. Однако, ряд вопросов остался не решённым, в частности не работали репорты и документы, кроме того, пользователи не имели доступа к Sharepoint порталу проектов.

Проблема оказалась в том, что “TFSConfig identities” по всей видимости не делает remap для пользователей, прописанных в Sharepoint и в Reporting Services.

А для “старых”-то пользователей там, безусловно, всё есть.

Мигрировать пользователей в Sharepoint можно, видимо, двумя способами:

  1. С помощью команды “stadm –o migrateuser”. Делается это так:
    stsadm –o migrateuser –oldlogin LH\alexey.raga –newlogin INCITE\alexey.raga –ignoresidhistory
    Засада здесь в том, что stsadm не имеет опций для пакетного апдейта, поэтому каждого пользователя придётся мигрировать вручную. Сочувствую, если у Вас их сотни :)
    Ключ “ignoresidhistory” в документации (что я видел) описан очень невнятно, что он точно делает я не понял, но без него пользователь не мигрируется :)
    Для себя я решил, что поскольку это новый сервер с новой (чистой) инсталяцией Sharepoint, то использование этого ключа ничего лишнего ни дописать, ни удалить в правах пользователей не сможет. Ибо никаких прав для тех, кто там в –newlogin никогда задано не было.
  2. Да просто пойти в табличку UserInfo и сделать UPDATE туда.

Я делал всё через stsadm. Во-первых потому, что кто его знает, что он ещё делает, кроме обновления вышеуказанной таблички (есть овнования полагать, что ничего), а во-вторых некоторые имена пользователей не совпадают (был OLD\vpupkin, стал NEW\vasya.pupkin), поэтому просто сменить имя домена недостаточно, всё равно приходится обрабатывать таких вручную.
Ну и, как я говорил, это у меня тестовая миграция на тестовые серверы, с тем, чтобы всё проверить и сказать “Да! Мы можем это сделать!”.

А вот с Reporting Services грустнее.
Там, в базе, в таблице Users, хранятся не только имена пользователей, но и их SIDы. Понятное дело, что SIDы у “новых” пользователей будут иные, так что просто обновить имена недостаточно.
Утилиты для такой миграции я не нашёл. Понятно, что можно написать, или можно сделать вручную, но как-то это не так.
Поэтому, если у каких-то пользователей были почему-то заданы какие-то права в RS (чего в случае нормальной эксплуатации TFS делать, в общем-то, не приходится обычно), то права проще всего перенастроить заново.

А, да. Ещё темплейт проекта TFS.

Мы используем темплейт SCRUM от http://scrumforteamsystem.com/Products, версию 2.1.
Возможности обновить темплейт на проекте нет.
Как вариант – создать новый проект с нужным темплейтом. Если делать так, то TFS даже спросит, сделать ли новый пустой проект, либо же сделать ветку от другого проекта.

Сделать ветку, наверное, самый правильный вариант: сохраняется всё состояние на момент “до миграции” в нетронутом виде.
Однако, возникает неудобство в том случае, если в исходном проекте уже используются ветки. То есть, если в исходном проекте есть ветка A и от неё сделана ветка B, то после ветвления в новый проект мы получим ветки A1 и B1, где A1 есть потомок A, в B1 – потомок B.
Получается, что если в исходном проекте ветки A и B можно сливать друг в друга (B потомок А), то в результирующем – уже нет (B1 – потомок B, а не A1).
Да, в TFS2010 есть такая замечательная штука, как reparenting для веток, но тогда мы теряем связь с реальностью исходным проектом..
Надо попробовать :)

Сделать пустой проект – тоже вариант. В том смысле, что можно просто переместить код из предыдущего проекта в новый. Move. И всё. Все зависимости сохранятся, все workitems, к которым были “привязаны” предыдущие checkins – тоже.

В любом случае, у ребят из http://scrumforteamsystem.com/Products пока ещё нет релиза 3-й версии темплейта, так что, ждём.
Я, кстати, спросил у них: “Раз уж вы делаете шаблон для SCRUM, то, наверное, вы и сами используете SCRUM, следовательно, можете приблизительно сказать, когда же?
На что они ответили: “Да шаблон-то давно готов. Не готов guidance для него, а шаблон содержит ссылки на этот guidance. Так что, подождите немного”. Вопрос с датой обошли.
Вот, ждём.

Админы готовят “настоящие” серверы для “настоящей” миграции. А там уже и будем наступать на грабли :)

5/7/2010 3:03:25 PM

Взялся обновлять TFS, пока на тестовом сервере, чтобы проверить, что всё будет работать.

Я уже писал, что сама по себе установка TFS теперь – дело очень простое, оно даже умеет работать без Sharepoint Services, а если всё же хочется, то умеет установить и настроить их само.

Обновление с предыдущих версий TFS – тоже, в принципе, не проблема, теперь это можно сделать прямо в процессе установки (хотя предварительно и сделать кое-что руками).

Но в нашем случае обновление – это комбинация сразу трёх задач:

  1. Переезд на новый (физический) сервер;
  2. Переезд в новый домен;
  3. Собственно, обновление TFS.

Оказалось, что и это сделать не так страшно, как оно казалось.

Итак, для этого потребовалось:

  1. Сделать backup всех баз данных с TFS2008, включая базы ReportingService и Sharepoint. Для Reporting Services, похоже, даже encryption key не надо бекапить и потом восстанавливать;
  2. Установить то, что требуется для TFS2010 на новый сервер, а именно (пошаговая инструкция, куда ткнуть и что написать есть в прилагаемом TFSInstall.chm, очень советую смотреть туда):
    • SQL Server Standard 2008 SP1 (да, оно больше не работает с SQL 2005. Можно даже Express-версию, если но там нет Analysis Services, а без него репорты не будут работать, но если они не нужны – то и отлично, можно вообще Reporting Services не ставить);
    • Sharepoint Services 3.0 SP2 (да, оно больше не работает с 2.0. Можно обойтись и без Sharepoint, и даже Web Access работать будет. Чего не будет, не помню, смотрите прямо в инсталлере, там всё написано. Ценители могут воспользоваться MS Sharepoint Server 2007, тоже поддерживается).
      Опять отсылаю к TFSInstall.chm, там сказано, какой порт указать для административного портала;
    • IIS, понятное дело.
  3. Восстановить бекапы из пункта 1) на новом сервере;
  4. Если устанавливали Reporting Services, то пойти в Configure Reporting Services и “починить” там всё:
    • Выбрать только что восстановленную базу данных на вкладке Database;
    • На вкладке Report Manage URL задать имя виртуального каталога “Reports” и нажать Apply. Если кнопка задизейблена – попечатайте что-нибудь в текстовом поле, чтобы она стала доступной :)
    • На вкладке Web Service URL задать имя виртуального каталога “ReportServer”, тоже Apply его на всякий случай.
    • На вкладке про encryption key удалить этот самый encryption key.
  5. Если ставили Sharepoint Services, то нужно подключить предыдущие коллекции сайтов. Для этого:
    • Пойти в админилку Sharepoint и убедиться, что там есть web site для Вашего http://<servername>:80. Если такового нет – тогда создать (спасибо Мише, подсказал в нужном направлении). Site Collection создавать не надо.
    • Подключить старую базу данных (от имени администратора):
      stsadm -o addcontentdb -url http://<ServerName>/sites -databasename <Wss_ContentDBName> -databaseserver <server\instance>
    • Дать пользователю TFSSETUP, от имени которого вы и делаете всё это, немного прав (от имени администратора):
      stsadm -o addpermissionpolicy -url http://<ServerName> -userlogin <TFSSETUP user> -permissionlevel "full control"
    • iisreset;
  6. Запустить, наконец-то, инсталяцию TFS. В списке типов инсталяции выбрать Upgrade, а там дальше всё будет прозрачно совсем. Только пройдитесь по всем вкладочкам визарда внимательно, там кое-где надо будет логин/пароль для TFSSERVICE указать, например… Сложного ничего нет.
    Вот тут есть в картинках.
  7. Непосредственно перед установкой оно попробует произвести проверку “всё ли правильно сконфигурировано”. У меня показывал два красных креста – на Reporting Services и на Sharepoint. Выяснилось, что я забыл в первом случае encryption key удалить, а во втором – уже не помню что.
    В общем, перед началом обновления всё должно быть зелёным. Ну, в крайнем случае жёлтеньким :)
  8. Пойти пообедать. Попить чаю с баранками, я не знаю. Поскольку данные он будет перегонять физически из всего того немереного количества баз данных, что были сбекаплены, в две всего, скорость напрямую зависит от скорости сервера и винтов. Говорят, что на 50-гигабайтную базу уходит где-то часа три. У меня столько не было, но я и обедать ходил. Вернулся – готово.
  9. Не спешить радоваться ;)
  10. Слазать в TFS Admin Console и убедиться, что URL’ы все нормально там выставлены. Апгрейд на этом закончен.
  11. Переехать пользователей TFS со старого домена в новый (если надо, мне – надо). Это чтобы все права, история, команды и т.д продолжали вестись. Чтобы Вася Пупкин как был Васей, так и остался Пупкиным.
    Для этого:
    • Запустить командную строку от имени администратора, пойти в каталог TFS, где-то в Program Files, там в каталог Tools.
    • Выполнить команду:
      TFSConfig identities /change /fromdomain:<FromDomainName> /todomain:<NewDomainName>
      Эта команда “переведёт” всех пользователей TFS из “старого” домена в “новый”. То есть, LH\alexey.raga станет INCITE\alexey.raga, например.
      НО: только для тех пользователей, которые есть в “новом” домене. То есть, имена должны совпадать.
      Если нужно перевести не всех, а кого-то одного, например, то там есть и такие ключики, смотреть здесь: http://msdn.microsoft.com/en-us/library/ms404883.aspx#MoveAccounts
      У меня, кстати, все перевелись, кроме меня самого. Не знаю почему, все операции я делал под TFSSETUP, то есть, просто совпадение :) Но вот именно мой пользователь не хочет мигрироваться.
    • Там же выполнить:
      TFSConfig Accounts /change /AccountType:ApplicationTier /account:<TFSSERVICE account> /password:<Password>
      Это потому, что TFSSERVICE-то теперь другой у Вас.
    • Если ставили Reporting Services, то там же выполнить:
      TFSConfig Accounts /change /AccountType:ReportingDataSource /account:<AccountName> /password:<Password>
    • Если ставили прокси (а его кто-то ставит?), то то же самое, но для /AccountType:Proxy и его аккаунта.
  12. Пойти в админилку Sharepoint, пробежаться по Site Collections и посмотреть, чтобы Primary и Secondary админы были правильными пользователями, а не старыми, из старого домена. У меня почему-то было так.

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

Какие проблемы.

  1. У меня пока не работают репорты. Но я даже ещё не смотрел, в чём там дело, отчего-то папка с репортами вообще недоступна в Team Explorer. Может что-то с правами, может от того, что темплейт у проекта был нестандартный, не майкрософтовский.
  2. Никто из разработчиков не имеет прав на Sharepoint Portal проекта. В Team Explorer нет доступа в папку Documents. Это точно что-то с правами.

С этим разберусь в следующий раз и отпишусь.

P.S. Честно говоря, я не понимаю.. Если у TFS2010 и так есть web access, то зачем ему sharepoint сдался?!…

4/14/2010 3:56:17 AM

Лечу на родину, прилетел в Китай. Сижу в международном аэропорту Пекина, сидеть ещё долго буду, поэтому пост про него и про авиакомпанию Air China, которая меня сюда доставила. По порядку.

Приехал на регистрацию за полчаса до её закрытия, попросил место у аварийного выхода. Человек сказал мне: ничего себе, ты просишь! На такие места надо заранее приходить! Но, специально для тебя, у нас есть одно место.

Место оказалось хорошим, у аварийного выхода в начале отсека. Там перед стенкой просто одного ряда нет, поэтому можно ноги вытянуть – и ещё место останется. Два кресла всего в ряду, правда кресла маленькие какие-то.
Зарядников, понятное дело, нет, но, справедливости ради, я их не видел в эконом классе ни у бритишей, ни у японцев… Лена летала тайцами – тоже не было. Вот у Virgin в эконом премиум - есть. Но премиум – это несколько другие цены уже.

Кормили фастфудно. Рядом летящий мужик заявил, что Quantas кормит лучше, на что я возразил, что сам Квонтасом не летал, но за сервис их все ругают. Сошлись на том, что сервис в эконом классе у всех так или иначе одинаковый.

Дали на завтрак йогурт. Ну, такой, обычный, фруктовый, не питьевой. А из “приборов” – только пластиковый нож и пластиковая вилка. Подождал стюардессу, нет ли ложки, спрашиваю. Растерялась, посмотрела вокруг – китайцы так из пачки пьют. Рядом сидящий австрал тоже говорит: “и мне ложку!”. Ушла, через 3 минут принесла настоящую, металлическую, хромированую. Видимо, из бизнес-класса :)

В аэропорту всё серьёзно. Чуть ли не строем ходят сотрудники толи паспортного контроля, толи таможни. В синей форме, в общем. В Китай ходить не стал, хотя времени полно, пошёл сразу в транзитную зону. Основательно проверили паспорт, пришлось заполнить бумагу на тему “свиным грипом не болею, с больными не контактировал”.

Сам аэропорт (могу говорить за “заграничную” зону) хоть и небольшой совсем, но современный, чистый, удобный.

Интернет стоит дорого: 4 американских доллара за 15 минут. Это если сидеть в бизнес-центре за большим старым круглым ЭЛТ-монитором. А вот WiFi раздают бесплатно. В том же бизнес-центре. Только сидеть у них не дают, говорят “иди отсюда на второй этаж”. Сижу, вот, на втором этаже, где все магазины, гейты, кафешки. Сигнал хороший.

Вайфай, кстати, бесплатный для тех, кто сумеет его настроить :) Я ходил в бизнес-центр три раза. Сначала я пытался регистрироваться не с той опцией (зато там по английски можно). Потом я сходил – и мне показали, как зарегистрироваться на китайском. И даже зарегистрировали.
Но к тому моменту, как я пришёл к себе “наверх”, к облюбованной розетке в полу, подключение к интенет стало выдавать вот такую картинку:

internet_cn

Из всего этого я понял только то, что в скобках – это мой username. А англоязычной версии сайта там нет.
Пришлось вернуться обратно. Оказалось, что толи пароль, толи username надо сменить, и после 10 минут ковыряния мне всё настроили. Вот, сижу.

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

Cyber Por?

Непонятно, толи “t” пропустили, толи “n” :)

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

Но вообще, аэропорт, повторюсь, хороший. Есть даже небольшая детская площадка с какой-то штукой детям полазать и с горки покататься, есть пара китайских “садиков”, маленьких-маленьких совсем, но с водой и с традиционной верандой.

Водичка журчит, китайская музыка играет.. Пошёл фотографировать, да так тут и остался. Чёрт с ней, с розеткой :)

Китайский садик снаружи

Китайский садик изнутри

За качество фотографий извиняюсь, снимал айфоном, а другого фотоаппарата я с собой не взял…

Powered by BlogEngine.NET 1.6.0.0

About the author

Alexey Raga Alexey Raga
.NET software developer.

E-mail me Send mail

Twitter


Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Sign in