Vitalii Tsybulnyk / Виталий Цыбульник

On Software Development / О софтверной разработке

About the author

    Vitalii Tsybulnyk
Vitalii Tsybulnyk is a Software Development Expert, Software Engeneer at Mictosoft.
E-mail me Send mail

Recent comments

Disclaimer

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

© Copyright 2008-2010

Design Guidelines for Developing Frameworks and Class Libraries

After I've spent last couple of months designing some class library for Windows Azure engineering infrastructure, I realized that design principles for frameworks and class libraries are not exactly the same as for 'off the shelf' or enterprise applications and systems. Fundamental difference is that in case of applications customers don't care about your code at all, so you can use all techniques you want to make your design elegant and easy to maintain. In case of framework/library quite the contrary your code is in some meaning a user interface, which customers see, use, and care about a lot. Believe it or not, this difference significantly influences your architecture and OOD decisions in many ways you even don't expect.

In this post I collected some advices I'd give to framework/library designers. They are based on the sources[1-2], however the most of them I can give you from my own experience. Some of these advices might contradict traditional design principles, so be careful and use them for public API/frameworks only.

Fundamentals

1. Framework designers often make the mistake of starting with the design of the object model (using various design methodologies) and then write code samples based on the resulting API. The problem is that most design methodologies (including most commonly used object-oriented design methodologies) are optimized for the maintainability of the resulting implementation, not for the usability of the resulting APIs. They are best suited for internal architecture designs—not for designs of the public API layer of a large framework. When designing a framework, you should start with producing a scenario-driven API specification. This specification can be either separate from the functional specification or can be a part of a larger specification document. In the latter case, the API specification should precede the functional one in location and time. The specification should contain a scenario section listing the top 5-10 scenarios for a given technology area and show code samples that implement these scenarios.

2. Common scenario APIs should not use many abstractions but rather should correspond to physical or well-known logical parts of the system. As noted before, standard OO design methodologies are aimed at producing designs that are optimized for maintainability of the code base. This makes sense as the maintenance cost is the largest chunk of the overall cost of developing a software product. One way of improving maintainability is through the use of abstractions. Because of that, modern design methodologies tend to produce a lot of them.

The problem is that frameworks with lot of abstractions force users to become experts in the framework architecture before starting to implement even the simplest scenarios. But most developers don’t have the desire or business justification to become experts in all of the APIs such frameworks provide. For simple scenarios, developers demand that APIs be simple enough so that they can be used without having to understand how the entire feature areas fit together. This is something that the standard design methodologies are not optimized for, and never claimed to be optimized for.

Naming Guidelines

3. The code samples should be in at least two programming languages. This is very important as sometimes code written using those languages differs significantly. It is also important that these scenarios be written using different coding styles common among users of the particular language (using language specific features). The samples should be written using language-specific casing. For example, VB.NET is case-insensitive, so samples should reflect that. Think about different languages even when you name classes, e.g. don't make mistakes like the NullReferenceException class which can be thrown by VB code, but VB uses Nothing, not null. Avoid using identifiers that conflict with keywords of widely used programming languages.

4. The simplest, but also most often missed opportunity for making frameworks self-documenting is to reserve simple and intuitive names for types that developers are expected to use (instantiate) in the most common scenarios. Framework designers often “burn” the best names for less commonly used types, with which most users do not have to be concerned. For example, a type used in mainline scenarios to submit print jobs to print queues should be named Printer, rather than PrintQueue. Even though technically the type represents a print queue and not the physical device (printer), from the scenario point of view, Printer is the ideal name as most people are interested in submitting print jobs and not in other operations related to the physical printer device (such as configuring the printer). If you need to provide another type that corresponds, for example, to the physical printer to be used in configuration scenarios, the type could be called PrinterConfiguration or PrinterManager.

Similarly, names of most commonly used types should reflect usage scenarios, not inheritance hierarchy. Most users use the leaves of an inheritance hierarchy almost exclusively, and are rarely concerned with the structure of the hierarchy. Yet, API designers often see the inheritance hierarchy as the most important criterion for type name selection. For example, naming the abstract base class File and then providing a concrete type NtfsFile works well if the expectation is that all users will understand the inheritance hierarchy before they can start using the APIs. If the users do not understand the hierarchy, the first thing they will try to use, most often unsuccessfully, is the File type. While this design works well in the object-oriented design sense (after all NtfsFile is a kind of File) it fails the usability test, because “File” is the name most developers would intuitively think to program against.

Classes vs. Interfaces

5. In general, classes are the preferred construct for exposing abstractions. The main drawback of interfaces is that they are much less flexible than classes when it comes to allowing for evolution of APIs. Once you ship an interface, the set of its members is fixed forever. The only way to evolve interface-based APIs is to add a new interface with the additional members. A class offers much more flexibility.

6. Abstract types do version much better, then allow for future extensibility, but they also burn your one and only one base type. Interfaces are appropriate when you are really defining a contract between two objects that is invariant over time. Abstract base types are better for define a common base for a family of types.

7. When a class is derived from a base class, I say that the derived class has an IS-A relationship with the base. For example, a FileStream IS-A Stream. However, when a class implements an interface, I say that the implementing class has a CAN-DO relationship with the interface. For example, a FileStream CAN-DO disposing.

Methods vs. Properties

There are two general styles of API design in terms of usage of properties and methods: method-heavy APIs, where methods have a large number of parameters and the types have fewer properties, and property-heavy APIs, where methods with a small number of parameters and more properties to control the semantics of the methods.

8. All else being equal, the property-heavy design is generally preferable.

9. Properties should look and act like fields as much as possible because library users will think of them and use them as though they were fields.

10. Use a method, rather than a property, in the following situations:

 - The operation is orders of magnitude slower than a field access would be. If you are even considering providing an asynchronous version of an operation to avoid blocking the thread, it is very likely that the operation is too expensive to be a property. In particular operations that access the network or the file system (other than once for initialization) should likely be methods, not properties.

 - The operation returns a different result each time it is called, even if the parameters don’t change. For example, the Guid.NewGuid method returns a different value each time it is called.

 - The operation has a significant and observable side effect. Notice that populating an internal cache is not generally considered an observable side effect.

 - The operation returns an array. Properties that return arrays can be very misleading. Usually it is necessary to return a copy of an internal array so that the user cannot change the internal state. This may lead to inefficient code.

Events

11. Consider using a subclass of EventArgs as the event argument, unless you are absolutely sure the event will never need to carry any data to the event handling method. If you ship an API using EventArgs directly, you will never be able to add any data to be carried with the event without breaking compatibility. If you use a subclass, even if initially completely empty, you will be able to add properties to the subclass when needed.

Enums

12. Use enums if otherwise a member would have two or more Boolean parameters. Enums are much more readable when it comes to books, documentation, source code reviews, etc. Consider a method call that looks as follows.

FileStream f = File.Open (“foo.txt”, true, false);

This call gives the reader no context with which to understand the meaning behind true and false. The call would be much more usable if it were to use enums, as follows:

FileStream f = File.Open(“foo.txt”, CasingOptions.CaseSensitive, FileMode.Open);

Some would ask why we don’t have a similar guideline for integers, doubles, etc. Should we find a way to “name” them as well? There is a big difference between numeric types and Booleans. You almost always use constants and variables to pass numeric values around, because it is good programming practice and you don’t want to have “magic numbers”. However, if you take a look at real life source code, this is almost never true of Booleans. 80% of the time a Boolean argument is passed in as a literal constant, and its intention is to turn a piece of behavior on or off. We could alternatively try to establish a coding guideline that you should never pass a literal value to a method or constructor, but I don’t think it would be practical. I certainly don’t want to define a constant for each Boolean parameter I’m passing in.

Methods with two Boolean parameters, like the one in the example above, allow developers to inadvertently switch the arguments, and the compiler and static analysis tools can't help you. Even with just one parameter, I tend to believe it's still somewhat easier to make a mistake with Booleans ... let's see, does true mean "case insensitive" or "case sensitive"?

 

Sources

1. MSDN 'Design Guidelines for Developing Class Libraries'

2. Krzysztof Cwalina, Brad Abrams 'Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries'


Posted by Vitalii Tsybulnyk on Monday, July 26, 2010 2:07 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Пирамидальная карьера Рико Мариани

Rico Mariani занимает позицию Partner Software Architect в Microsoft и является неиссякаемым источником профессиональной мудрости для множества работающих с ним людей.

На одной из недавних презентаций, приуроченных к Microsoft Engineering Forum в этом году, Рико рассказал своё видение успешной карьеры IT профессионала, что волшебным образом совпало с моим представлением, так что я не смог не привести его здесь.

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

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

"Намного лучше начать с широкого базиса и строить вверх, опираясь на него и постоянно расширяя его ещё больше по мере роста". Широкий базис включает разнородные знания и умения, опыт работы в разных ролях и областях, что даёт очень устойчивое и надёжное основание для роста вашей карьеры вверх, образуя таким образом треугольник. Этот треугольник может быть неидеальным, с несколькими "пиками" в разных местах, однако именно широкое основание даёт представление об устойчивости этой фигуры. "Такая карьера намного труднее, занимает дольше, но это даёт лучший результат в долговременной перспективе". Для меня прелесть такой карьеры в том, что вы никогда не оказываетесь в ситуации, когда вы выросли настолько, насколько могли, и на этом ваша карьера достигла естественного максимума. При такой модели вы всегда можете переместиться "в сторону" вместо "вверх" и продолжить своё "строительство" там. Это перемещение может быть сменой технологий (desktop-> web, server -> client), ролей (manager -> individual contributor) или даже дисциплин.

Так мы получили треугольник, но ведь пирамида - это трёхмерная фигура. Что же в данном случае символизирует это третье измерение, что делает пирамиду объёмной? Этим третьем измерением Рико называет вашу индивидуальность, то что вас увлекает, обогащает, интересует в этой жизни. Это может быть семья, игра на музыкальном инструменте, путешествия, выращивание растений - всё что угодно, что приносит вам радость от жизни. Величайшая неординарность и одновременно жизненная мудрость Рико заключается в том, что он вносит этот аспект вашей личности как неотъемлемую и органичную часть успешной карьеры. Мудрость эта, во-первых, заключается в том, что вы не сможете всегда на 100% выкладываться в своей работе, если она лишает вас того, чем вы занимаетесь, чем вы живёте всё остальное время. Карьера никогда не должна убить эту вашу индивидуальность, поглотить всего вас. К сожалению, приходится видеть людей, не учитывающих этого и посвящающих всего себя работе, и это работает год, работает два, пока человек не превращается в раздражённого зомби, не удовлетворённого ни работой, ни всей своей жизнью в целом. Только счастливый, довольный своей жизнью человек может стабильно быть креативным и продуктивным в своей работе, а значит построить долговременную, устойчивую карьеру. Вторая мудрость - даже вне работы, вы всё ещё тот же человек, и тот жизненный опыт, те умения и качества, что вы приобретаете вне работы, те решения, которые вы принимаете, они обогащают всего вас, и вашу "рабочую" часть в том числе, они позволяют воспользоваться опытом и креативом, накопленным в повседневной жизни, в профессиональных целях. Человек, живущий богатой и полноценной жизнью, создаёт более широкий и устойчивый (основание пирамиды) базис для своей профессиональной карьеры.


Posted by Vitalii Tsybulnyk on Monday, June 14, 2010 9:44 AM
Permalink | Comments (2) | Post RSSRSS comment feed

The Surprising Truth About What Motivates Us

The Royal Society for the encouragement of Arts, Manufactures and Commerce (RSA) recently published a very impressive video of Dan Pink presenting the surprising truth about what motivates us. This video definitely worth spending 40 minutes of your life to watch it, however there is a very nice smaller 10-min animated version of it for those who'd prefer to know a short summary instead of a whole story.

Dan's talk is built around the problem of motivation.

First surprising 'truth' he discovers is that money is not a real motivator in present world in fact. Money is a good motivator only for simple, straightforward jobs. For creative, complex jobs an absence of money is a demotivator, however once you pay enough to move money out of attention, they stop to be a motivator at all.

What are the real motivators then?

They are:

AUTHONOMY - our desire to be self-directed. Traditional goal of management 'to control' is invented in 1850-s and simply doesn't work in a today's world of complex creative jobs.

MASTERY - our desire to make a progress, to get better at what we do. This is one of the most significant components of our satisfaction from work.

PURPOSE - we want to be a part of something bigger, something that makes world better.

Dan provides many very impressive examples and research results, so I'd recommend to watch an original video to make your own impression.


Posted by Vitalii Tsybulnyk on Wednesday, June 09, 2010 10:08 AM
Permalink | Comments (2) | Post RSSRSS comment feed

Офисная байка про муравья

Не встретил никакой информации о правах на текст, так что привожу его здесь без правок и изменений.

 

Офисная байка про муравья

Каждый день, с утра по раньше приходил на работу продуктивный и весёлый МУРАВЕЙ.

Была у него хорошая производительность и весёлым он был. И деятельность фирмы была успешной но...

ШМЕЛЬ, генеральный директор фирмы где работал МУРАВЕЙ, решил, что МУРАВЕЙ не может работать сам по себе, так что была создана должность надсмотрщика и нанял он НАВОЗНОГО ЖУКА.

Самой главной заботой ЖУКА - НАВОЗНОГО была организовать работу МУРАВЬЯ. И заставил он МУРАВЬЯ делать отчёты о ежедневной проделанной работе.

Вскоре понадобилась должность секретаря, который бы помог жуку в чтении и регистрации отчётов МУРАВЬЯ.

Поэтому наняли ПАУЧИХУ, которая классифицировала документы и отвечала на телефонные звонки.

Между тем, счастливый МУРВЕЙ работал, работал, работал...

ШМЕЛЬ, был очень доволен отчётами НАВОЗНОГО ЖУКА, так что запросил дополнительные отчёты, прогнозы и расчёт различных показателей.

В таком случае, необходимо было нанять ТАРАКАНА в качестве ассистента НАВОЗНОГО ЖУКА. ... а также купить компьютер и цветной принтер.

Вскоре, производительный и счастливый МУРАВЕЙ, начал жаловаться на все разборки и отчёты который должен был предоставлять, и всё менее веселей ему становилось.

ШМЕЛЬ, генеральный директор, понимает, что необходимо принимать меры.

Так что, на месте где работал продуктивный и ещё весёлый МУРАВЕЙ бал создан департамент.

На должность начальника был назначен КУЗНЕЧИК. Он соорудил себе современный кабинет и оборудовал соответственно.

Новому начальнику департамента понадобился ассистент, который помог бы ему в подготовке стратегических планов и бюджета департамента в котором работал продуктивный и весёлый МУРАВЕЙ.

Но МУРАВЕЙ уже не пел как раньше и становился всё более раздражительным...

Однажды, генеральный директор, посмотрев на цифры, понял, что департамент где работает МУРАВЕЙ, не является уже таким же рентабельным как раньше.

Подумав, ШМЕЛЬ решил нанять в качестве консультанта СОВУ, для проведения диагностики.

СОВА просидела 3 месяца на фирме, и, после изучения дела, сделала заключение: "В департаменте слишком много персонала.." ...следуя совету специалиста, провели сокращение численности. МУРАВЕЙ оказался первым в списке, т.к. всё время был недоволен...

Мораль: Даже и не думай быть счастливым и продуктивным муравьём. Лучше быть некомпетентным и бесполезным. Некомпетентным не нужны надсмотрщики,... все и так понимают почему. И, если, несмотря на твои "усилия", ты всё же продолжаешь оставаться продуктивным, не показывай ни за что на свете что ты счастлив и весел. Тебе этого никогда не простят.

Но если вопреки сказанному выше, ты упрямо продолжаешь оставаться СЧАСТЛИВЫМ И ПРОДУКТИВНЫМ МУРАВЬЁМ, работай на себя, так чтобы не нести на своей спине шмелей, навозных жуков, тараканов, пауков, кузнечиков и сов.

 

И хотя я не совсем согласен с выводами в разделе "Мораль", многие события из байки честенько имеют место в реальной жизни...


Posted by Vitalii Tsybulnyk on Wednesday, May 19, 2010 5:03 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Рейнджеры и солдаты: о подчинении в софтверной индустрии

В мартовском номере российского журнала "Управление проектами" вышла статья вашего покорного слуги "Рейнджеры и солдаты: о подчинении в софтверной индустрии".

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

Основное внимание при рассмотрении вопросов управления проектами как правило уделяется поведению менеджера, при этом подчинение, как неотъемлемая часть процесса управления, часто ускользает из поля зрения специалистов. Предлагается рассмотреть два принципиально разных типа подчинения: подчинение типа 'Солдат' (безоговорочное подчинение, при котором от подчинённого не требуется понимания назначения и смысла его действий) и подчинение типа 'Рейнджер' (обсуждение задач и путей их реализации с последующим добровольным принятием на себя обязанностей по их выполнению). Констатируется важность и востребованность обоих типов подчинения в различных софтверных проектах, а также недостаточное внимание к подготовке технических специалистов с целью овладевания обоими типами подчинения.


Posted by Vitalii Tsybulnyk on Friday, April 02, 2010 11:59 AM
Permalink | Comments (2) | Post RSSRSS comment feed

Основные антипаттерны в софтверной разработке

Антипаттерны организации и управления:

  • Аналитический паралич (Analysis paralysis): Неоправданное внимание и затраты времени/ресурсов на стадию анализа.
  • Дойная корова (Cash cow): Прибыльный и успешный продукт, высокая прибыль от которого зачастую приводит к чрезмерной расслабленности в разработке новых версий продукта или новых продуктов.
  • Разработка комитетом (Design by committee): Результат вклада в разработку многих участников, но отсутствие единого видения.
  • Эскалация обязательств (Escalation of commitment): Неспособность отказаться от решения даже когда доказана его ошибочность.
  • Драконовские меры (Management by perkele): Авторитарный стиль управления, отвергающий инакомыслие.
  • Moral hazard: Отделение человека, принимающего решения, от последствий этих решений.
  • Управление грибами (Mushroom management): Стиль управления, при котором работникам предоставляется минимум информации и эта информация искажается (управлять грибами - содержть в темноте и прикрмливать навозом) .
  • Управление основанное на числах (Management by numbers): Уделение избыточного внимания численным критериям управления, когда они неважны или стоимость их получения слишком высока
  • Дымоход (Stovepipe): Организационная структура, при которой потоки информации циркулируют преимущественно вверх-вниз, но не горизонтально, между подразделениями.
  • Замкнутость на продавце (Vendor lock-in): Чрезмерная зависимость системы от внешней компоненты.
  • Сваливание расходов (Cost migration): Перенос расходов на проект к уязвимому отделу или бизнес-партнёру.
  • Путь камикадзе (Death march): Все знают, что проект обречён, кроме главы, вплоть до "дня X". Также применяется для стиля руководства, когда сотрудники вынуждаются к сверхурочной работе для достижения нереальных сроков.
  • Расползание рамок (Scope creep): Дозволение рамкам проекта расти без должного контроля.
  • Groupthink: Никто не хочет выдвигать идеи, противоречащие комфортному консенсусу.
  • Дым и зеркала (Smoke and mirrors): Демонстрация заказчику заранее заготовленных "обманок" вместо рабочей функциональности.
  • Раздувание ПО (Software bloat), Функции для галочки: Каждая следующая версия продукта требует всё больше системных ресурсов без явной выгоды для пользователя.
  • Ползущий улучшизм (Creeping featurism): Добавление новых улучшений в ущерб качеству системы.
  • Продолжительное устаревание (Continuous obsolescence): Выделение непропорционально больших усилий портированию системы в новые окружения.
  • Bystander apathy: Дизайн или требования неверны, но те, кто это знают, ничего не предпринимают по этому поводу, т.к. для этого необходимо вовлечение большего числа людей.
  • Tester Driven Development: Новые требования к продукту возникают из отчётов об ошибках.
  • Я тебе это говорил (I told you so): Когда игнорируется предупреждение эксперта, являющееся оправданным
  • Единственный знающий человек (Single head of knowledge): ЕЗЧ (SHOK) применим в том случае, когда единственная личность во всей организации контролирует жизненно-важную область ноу-хау или информации о внутренностях системы.
  • Рыцарь на белом коне (Knight in shining armor): РНБК (KISA) происходит тогда, когда личность, которая не совершает ошибок, появляется на сцене и пытается починить всё, без сообщений о том, какие изменения он/она сделал/сделает и почему.
  • Gold plating: Работа над проектом после момента, когда уже усилия перестают приносить прибыль или создавать добавочную стоимость.
Антипаттерны дизайна и реализации: 

 

Источники

1. Anti-pattern on wikipedia.org

2. Антипаттерн на wikipedia.org


Posted by Vitalii Tsybulnyk on Tuesday, December 22, 2009 4:27 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Учимся делегировать

Старая истина гласит “Если хочешь сделать что-то хорошо - сделай это сам”, однако это не всегда верно, когда дело касается управления проектами. Важно всегда помнить, что вы не можете всё сделать сам или "клонировать себя", поэтому умение делегировать является неотъемлемой характеристикой успешного руководителя проекта.

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

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

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

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

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

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

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

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

 

Источники

1. Become Better at Delegation on www.project-management-knowledge.com

2. Delegate Without Losing Control on www.project-management-knowledge.com


Posted by Vitalii Tsybulnyk on Wednesday, December 16, 2009 5:54 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Искусство "хаопорядоченного" лидерства

Рассуждая в своей работе [1] о лидерстве и руководстве в современных командах и организациях, Ди Хок вводит понятие "хаопорядоченного" ('chaord' = 'chaos' + 'order') лидества. По его мнению, успешное руководство в самоорганизующихся, самоуправляющих, адаптивных, нелинейных, сложных организмах, коими являются современные огранизации и команды, должно гармонично сочетать многие зачастую противоречивые характеристики: хаоса и порядка, соперничества и взаимопомощи, теоретических знаний и практических умений. Результатами его умозаключений является перечень замечательных рекомендаций, которым по моему мненю должен следовать любой успешный лидер:

- Власть: Власть никогда не используется. Если вы пользуетесь властью - вы никогда реально ею не обладаете.

- Человеческие отношения: Когда имеете дело с подчинёнными, повторяйте про себя: "Ты для себя так же хорош, как и я для себя, следовательно мы равны". Когда имеете дело с вышестоящими, повторяйте про себя: "Я для себя так же хорош, как и ты для себя, следовательно мы равны".

- Критицизм: Активная критика - это ценнейшее приобретение. Она позволяет без малейших затрат времени и усилий устранить наши промахи и ошибки, а альтернативным решениям быть высказанными. Мы только должны слушать внимательно, отсеивая всё, что идёт от незнания, зависти или злобы, и выделяя то, что действительно ценно.

- Компенсация: Деньги не мотивируют ни лучших людей, ни лучшее в людях. Они могут арендовать тело и влиять на сознание, но они не могут тронуть сердце или душу, это подвластно только доверию, принципам и этике.

- Эго, Зависть, Жадность и Амбиции: Четыре зверя, которые неизбежно поглощают своего хозяина. Задумаете прокатиться на их спинах - и вы закончите у них в желудке.

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

- Ошибки: Маленькие беззубые зверьки, которых вы можете распознать, признать, исправить, научиться на них, и перерасти их. Если же нет, то они отращивают клыки и наносят смертельный удар.

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

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

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

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

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

- Руководство: Управляйте собой, управляйте своими руководителями, управляйте равными себе и дайте своим людям делать то же самое.

 

Источники

1. Dee Hock The Art of Chaordic Leadership


Posted by Vitalii Tsybulnyk on Wednesday, December 02, 2009 4:24 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Как отстреливается большинство хороших идей

Очень наглядный эксперимент для демонстрации факта "отстрела" большинства хороших идей провёл Мэтью Мэй и описал результаты в своей работе [1].

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

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

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

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

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

Конечно, этот эксперимент носил некоторую долю розыгрыша, однако проблема от этого не исчезает и не становится менее серьёзной. Более формальное исследование вопроса "отстрела" хороших идей изложено в [2].

 

Источники

1. Matthew E. May 'Mind of the Innovator: Taming the Traps of Traditional Thinking'

2. Michael Iva '100 Ways to Kill a Concept: Why Most Ideas Get Shot Down'


Posted by Vitalii Tsybulnyk on Tuesday, November 24, 2009 4:14 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Документирование и распределённый мозг команды разработчиков

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

Ответом на это стало появление динамических методологий, основная масса которых относится к документированию приблизительно следующим образом: "Документирования нужно ровно столько, сколько решит команда и спонсор для данного конкретного проекта" [1].

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

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

Из этой модели следуют и очевидные рамки её применимости:

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

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

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

 - Чем больше новичков приходится подключать к проекту, тем больше маркеров и тем подробнее эти маркеры.

 

Источники

1. Alistair Cockburn 'How many work products are needed in software development?'

2. Alistair Cockburn 'The end of software engineering and the start of economic-cooperative gaming'


Posted by Vitalii Tsybulnyk on Sunday, September 13, 2009 7:13 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Лучшие практики удалённой разработки

К сожелению или к счастью, но оффшорный аутсорсинг и аутстаффинг уже стали неотъемлемой частью бизнес-модели современной разработки ПО. Ими пользуются компании всех "рангов" - от стартапов с командой из двух человек до софтверных гигантов. Обсуждение преимуществ и недостатков таких тенденций выходит за рамки данного поста, однако с учётом сложившейся ситуации мне представляется ценным сформулировать основные советы и рекомендации участникам процесса удалённой разработки. За последные несколько лет я побывал пожалуй во всех возможных ролях этого процесса, так что накопил некоторый собственный опыт в данной области, к тому же сегодня я буду апеллировать к наработкам ведущих мировых авторитетов [1].

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

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

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

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

 - Используйте вики для хранения общей информации. Рассчитывайте, что вам понадобится более детальное документирование.

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

 - Проводите совместные митинги по планированию итераций и регулярные статус-митинги.

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

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

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

 

Источники 

1. Martin Fowler 'Using an Agile Software Process with Offshore Development'


Posted by Vitalii Tsybulnyk on Friday, September 11, 2009 2:21 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Паттерны управления рисками

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

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

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

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

Сегодня я приведу набор паттернов уменьшения рисков, предложенный Алистэром Коуберном в [1]:

1. Знания: Рассеивание тумана (Clear the Fog)
Если вы не знаете риски и трудности проекта достаточно хорошо для того, чтобы разработать хороший план - попытайтесь выпустить хоть что-то, это даст вам понять в чём реальные трудности.
Частные случаи: "Ранние и регулярные выпуски", "Прототип", "Микрокосм".

2. Знания: Ранние и регулярные выпуски (Early and Regular Delivery)
Вы не знаете какие проблемы вам встретятся в процессе разработки - выпустите что-то как можно раньше и выясните то, чего не знаете. Выпускайте регулярно совершенствуясь каждый раз.

3. Знания: Прототип (Prototype)
Вы не знаете как некотрые архитектурные решения себя поведут - разработайте отдельный испытательный прототип и понаблюдайте как он на самом деле работает.

4. Знания: Микрокосм (Microcosm)
Вам нужно разработать реальный план, но вы никогда не занимались проектами такого рода - запустите 8-12 недельный "пилотный" этап и соберите данные о продуктивности и т.п. для вашего плана.

5. Командная работа: Целостное многообразие (Holistic Diversity)
Разработка некоторого модуля требует разных умений, а люди имеют узкую специализацию - создайте команду из людей с разными умениями.

6. Продуктивность: Золотой рывок (Gold Rush)
У вас нет времени ждать утверждённых требований - начните разработку немедленно, корректируйте её по последним требованиям еженедельно.

7. Владение: Один ответственный на продукт (Owner per Deliverable)
Иногда над чем-то работает много людей, иногда никто - убедитесь что у каждого продукта (выпуска) есть ровно один ответственный.
Частные случаи: "Владельцы функциональности и компонент", "Одна команда на задачу"

8. Владение: Ответственные за функциональность и компоненты (Function Owners / Component Owners)
Если вы организовываете команду по компонентам, то страдает функциональность, и наоборот - убедитесь что за каждую функциональность и каждую компоненту кто-то отвечает.

9. Помехи: Кто-то всегда движется к цели (Someone Always Makes Progress)
Помехи постоянно прерывают работу команды - убедитесь что кто-то движется к цели что бы не случилось.
Частные случаи: "Одна команда на задачу", "Жертва", "Ежедневная забота"

10. Помехи: Одна команда на задачу (Team per Task)
От команды требуется серьёзное отвлечение от основной задачи - пусть этим займётся часть команды, а основная команда продолжает идти к цели.

11. Помехи: Жертва (Sacrifice One Person)
От команды требуется небольшое отвлечение от основной задачи - поручите это одному человеку.

12. Обучение: Ежедневная забота (Day Care)
Ваши експерты тратят всё свое время на обучение новичков - выделите одного эксперта курировать всех новичков, остальные разрабатывают систему.

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

 

Источники

1. Alistair Cockburn 'Project risk reduction patterns'


Posted by Vitalii Tsybulnyk on Saturday, August 29, 2009 5:18 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Разработка ПО как основанная на сотрудничестве игра

Когда в 1968 году на конференции НАТО впервые был введён термин “software engineering” для разработки ПО как одной из областей инженерии, эта классификация была скорее вызовом, стимулом для дальнейшей работы, чем основанной на реальном опыте моделью. Однако за неимением ничего лучшего она быстро прижилась, и на протяжении последующих 40 лет философы и методологи разработки ПО боролись с использованием этого подхода в основном по 4-м причинам:

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

Многие авторы предлагают свой собственный подход к этой проблеме. В этом посте я хочу поделиться моделью, предложенной Алистэром Коуберном [1]:

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

Такая модель действительно раскрывает все важные для успеха проекта проблемы: сотрудничество, коммуникации (а особенно их стоимость, доля и необходимое количество), индивидуальные таланты и умения, отношения между людьми-как-индивидуумами в парах и группах, ценность сохранения устоявшихся команд, уменьшающаяся отдача от детального моделирования и документирования [2], важность обучения и применения различных стратегий для различных обстоятельств.

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

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

 

Источники

1. Alistair Cockburn 'The end of software engineering and the start of economic-cooperative gaming'

2. Alistair Cockburn 'How many work products are needed in software development?'


Posted by Vitalii Tsybulnyk on Wednesday, August 26, 2009 2:06 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Инкрементная итерационная разработка

Для начала поговорим о понятиях: 

  • Инкрементная (incremental) разработка - это стратегия планирования стадий проекта, при которой различные части системы разрабатываются в разное время, а затем интегрируются (в противоположность стратегии "большого взрыва", когда все части разрабатываются одновременно, а в самом конце разработки интегрируются). При инкрементной разработке вся система разбивается на отдельные компоненты или модули, разработка каждого из которых планируется и осуществляется отдельно во времени, с последующей интеграцией в систему по мере готовности.
  • Итерационная (iterative) разработка - это стратегия планирования ревизий системы, во время которых система определённым образом дорабатывается или усовершенствуется (в противоположность стратегии, когда система планируется и создаётся сразу совершенной, идеальной). При итерационной разработке основным видом деятельности является усовершенствование, доработка существующей системы: не только производительности, качества кода и функциональных возможностей, но и требований, интерфейсов, технологий, архитектуры и алгоритмов.

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

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

 

Источники

1. Alistair Cockburn 'Using both incremental and iterative development'


Posted by Vitalii Tsybulnyk on Monday, August 24, 2009 2:11 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Какие бывают архитекторы и архитектуры

Мне кажется, что роль Архитектора - это пожалуй одна из самых значимых и одновременно самых неоднозначных ролей в процессе разработки ПО. Это связано с очевидной важностью, но тем не менее неоднозначностью самого понятия "архитектура".

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

Однако Мартин Фаулер считает это определение абсолютно надуманным [1], т.к. по его мнению у программных систем нет "высшего концептуального уровня", пользователь имеет обсолютно другое видение концепции системы, чем разработчики, пользователя абсолютно не волнует "структура наиболее значимых компонент". По мнению Фаулера "архитектура - это высший уровень концепта, который сложился у разработчиков о системе в её рабочем окружении. При этом учитывается видение разработчиков уровня эксперта, и именно это делает компоненты такими значимыми - так сказали эксперты." Таким образом, более корректным определением могло бы быть “В наиболее успешных софтверных проектах разработчики-эксперты, работающие над проектом, имеют общее пронимание строения этой системы, которое называется ‘архитектура’. Это понимание включает в себя деление системы на компоненты и их взаимодействие между собой через интерфейсы. Эти компоненты обычно состоят из более мелких компонент, однако архитектура включает в себя только те компоненты и интерфейсы, которые поняты всеми разработчиками." Такое определение лучше, поскольку оно отражает социальную природу арихитектуры, т.к. она не столько зависит от ПО как такового, сколько от того, каков групповой консенсус по поводу этого ПО [1].

Существует и другой стиль определения архитектуры: “арихитектура - это набор решений об устройстве системы, которые должны быть приняты на ранних стадиях проекта”, однако Фаулер не соглашается и с этим, т.к. "архитектура - это набор решений, которые хотелось бы сделать правильно на ранних стадиях проекта, однако это не значит что они окажутся верными с большей вероятностью, чем любые другие". Тем более, что согласно такому определеню, например выбор языка программирования был бы частью архитектуры для большинства проектов, хотя это не так. Всё это демонстрирует сложности формулировки точного определения понятия архитектуры. Говоря проще, "архитектура - это всё наиболее важное в проекте, что бы это ни было" [1].

Так мы приходим к заключению, что раз архитектура - это важные вещи, то Архитектор - это человек, занимающийся наиболее важными для проекта вещами. И вот на этом этапе Фаулер выделяет два типа архитекторов [1]:

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

 - Architectus Oryzus (если кто-то знает латынь, помогите с переводом) - этот вид архитекторов осведомлён о том, что происходит в проекте, выявляя важные загвоздки и устраняя их до того как они превратятся в серьёзные проблемы. Наиболее важная часть работы таких архитекторов - это интенсивное сотрудничество: работа с разработчиками над кодом, работа с бизнес-аналитиками над техническим смыслом и последствиями реализаций требований и идей на нетехническом языке и т.п. Ценность архитектора этого типа "обратно пропорциональна количеству решений, которые он принимает" [1].

Не менее интересную крассификацию архитектур и архитекторов предлагает Люк Хохман [2]. Он разделяет софтверную систему на два измерения:
 - tarchitecture (техтектура или “техническая архитектура”), за неё обычно отвечает традиционный архитектор или технический руководитель - tarchitect (техтектор)
 - marketecture (маркетектура или “меркетинговая архитектура”), её определяет продукт-менеджер, бизнес-менеджер или програм-менежер - marketect (маркетектор).

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

 

Источники 

1. Martin Fowler 'Who Needs an Architect?'

2. Luke Hohmann 'The Difference between Marketecture and Tarchitecture'


Posted by Vitalii Tsybulnyk on Saturday, August 22, 2009 7:21 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Методики успешных проектов: подрезаем хвост

Думаю, что методика "подрезания хвоста" (“trim the tail”) интуитивно используется многими менеджерами проектов, однако весьма полезно было бы ознакомиться с тем, как Алистэр Коуберн в своей статье [1] приводит довольно подробное описание и аргументацию эффективности этого подхода.

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

Согласно методике, стратегия работы над проектом состоит из двух основных стадий:

1. Как можно раньше определить наибольшие социальные и технические риски проекта (как правило, все и так это делают), разбить их на как можно более мелкие компоненты (задачи). Работать над этими "рискованными" задачами на как можно более ранней стадии проекта до перевода в статус "нерискованных". Таким образом происходит как можно более раннее накопление критических знаний о системе (рис.1).

2. Определить и расставить приоритеты самым ценным для бизнеса функциональным единицам проекта (как правило, все и так это делают) и работать над ними в порядке убывания приоритетности. Таким образом происходит максимально быстрое увеличение бизнес-ценности системы (рис.2).

Рисунок 1: раннее накопление критических знаний о системе. Рисунок 2: быстрое увеличение бизнес-ценности системы.

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

Рисунок 3: отрезаем хвост.

Это и состовляет наибольшую ценность подхода: спонсор в реальном времени получает безопасную с точки зрения рисков возможность "отрезать хвост" (рис.3): найти оптимальный для бизнеса балланс между временем выпуска системы и её фунциональной наполненностью.

 

Источники

1. Alistair Cockburn 'From Agile Development to the New Software Engineering'


Posted by Vitalii Tsybulnyk on Wednesday, August 19, 2009 5:30 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Антропология разработки ПО

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

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

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

Результаты такой работы дали бы возможность:
1. Распознать все культуры, вовлечённые в проект, и их ценности.
2. Найти людей, способных работать по обе стороны разных культур и которые бы способствовать эффективной коммуникации культур и сглаживанию основных противоречий.
3. Информировать каждую из групп о целях и ценностях других групп, относиться к ним с должным вниманием и уважением и в то же время знать и использовать всё, что другая культура может им предложить.
4. Применить наработанные этнографические и антропологические техники для изучения каждой группы и обнаружения их сильных и слабых сторон.

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

 

Источники

1. Alistair Cockburn 'What can OO programming learn from anthropology?'


Posted by Vitalii Tsybulnyk on Wednesday, August 19, 2009 4:04 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Рефакторим базу данных

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

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

Однако, прогресс не стоит на месте, мыслители и идеологи рефакторинга и гибких методолий конечно же не мирятся с таким упущением. Наглядное тому подтверждение - некоторые книги и статьи Мартина Фаулера и его соратников. Одна из первых таких публикаций - это статья Фаулера 'Evolutionary Database Design', которая собственно и натолкнула меня на написание данного поста.

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

1. База данных исполюзуется в одном приложении или системе, это не интегрированная база данных для многих систем.
2. База данных не должна работать бесперебойно 24/7

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

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

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

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

4. Все изменения в базе данных по ходу работы над проектом - это рефакторинги, поэтому применяйте к ним те же шаги и правила, что применяете к обычному рефакторингу (см. Martin Fowler 'Refactoring: Improving the Design of Existing Code')

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

6. Сообщайте о изменнениях в базе всем разработчикам, лучше через автоматическую отправку е-мейла.

7. Выделяйте в своей системе явно выраженный слой доступа к данным, это позволит свести к минимуму последствия рефакторинга базы для остального кода (воспльзуйтесь одним из паттернов, описанных Фаулером в 'Patterns of Enterprise Application Architecture').

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


Posted by Vitalii Tsybulnyk on Tuesday, August 11, 2009 4:25 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Как правильно проводить Scrum (stand-up) митинги

Основой для данного поста послужила статья Jason'а Yip'а 'It's Not Just Standing Up: Patterns of Daily Stand-up Meetings', пропущенная через призму моего собственного опыта ежедневных Scrum-митингов в Microsoft.

Вот перечень нескольких основных принципов, без следования которым ваш Scrum-митинг наверняка потеряет львиную долю эффективности:

Цели:  

 - Поделиться обязательствами. Это самая важная цель ежедневного stand-up'а, более важная, чем поделиться прогрессом или состоянием задач.

 - Обсудить статус, прогресс и планы с командой и наблюдателями. Обсуждение статуса наиболее всего отличает stand-up от любого другого вида статус-митингов, т.к. во время stand-up'а члены команды сообщают статус друг другу, а не своему менеджеру. Обсуждение статуса также даёт возможность команде быть в курсе всего, чем занимается команда каждый день.

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

 - Установить направление и приоритеты.

 - Тим-билдинг. Нельзя забывать, что основной фокус stand-up'а - это всё-таки не задачи, а люди, и stand-up призван решать именно человеческие проблемы и трудности.

Место и время:

 - Продолжительность ежедневных stand-up'ов - не более 15 минут, т.к. после 15 минут среднестатистический человек начинает терять состредоточенность. Недопустимо потакание некоторым любителям поболтать и их "рассказыванию историй". Также не нужно немедленно решать возникшие проблемы. Обсудите только вопросы, удовлетворяющие целям stand-up'а, все остальные вопросы обсудите после митинга или вынесите на отдельный митинг. Для того, чтобы митинг не затянулся, проводите его стоя, что также придаёт дополнительную энергетику.

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

 - Проводите ежедневный stand-up в одном и том же месте в одно и то же время. Не ждите опаздывающих, даже если это менеджер или лидер, митинг проводится для всей команды а не для какой-то отделной персоны.

 - Проводите stand-up в начале дня. Если в команде гибкий рабочий график, проводите митинг в самом начале времени, к которому собираются все. Помните, что stand-up задуман как психологическое начало рабочего дня.

Участники: 

 - Все члены команды должны принимать участие в Scrum-митинге. Если кто-то не может учавствовать лично, он может поучавствовать по телефону или его статус должен огласить другой член команды.

 - К Scrum-митингам, как и к любым другим, нужно готовиться. “Что я делал вчера?... Не помню уже... Что я делаю сегодня?... Посмотрим по ходу...” - такого быть не должно, все должны чётко знать свои 'Вчера', 'Проблемы' и 'Сегодня'.

Управление:

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

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

 - Все знают, кто должен говорить первым, для этого не нужна команда ведущего. Заведите правило наподобие "Первым говорит тот, кто пришёл последним" или любое другое.

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


Posted by Vitalii Tsybulnyk on Sunday, August 09, 2009 9:04 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Как продавать свой программный продукт

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

Эрик Синк (Eric Sink) - хороший пример такого разработчика, так как он к тому же делиться опытом собственного стартапа на страницах своего блога.

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

 - 'Marketing is not a Post-Processing Step' ('Не оставляйте маркетинг на потом')

 - 'Closing the Gap' о том, как эффективно продавать свой программный продукт. Статья состоит из двух частей: Proactive sales и Responsive sales (в русском переводе нашёл только вторую часть).

Первая статья (что вполне явствует из названия) призвана развенчать весьма распространенное заблуждение, что маркетинг начинается там, где заканчивается программирование. Хороший маркетинг так работать не может. Его нельзя оставлять напоследок.

В качестве наиболее важного составляющего хорошего (т.е. раннего) маркетинга Синк называет позиционирование:

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

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

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

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

Вторая статья рассказывает о разрыве, существующем между вашим продуктом и вашим потенциальным клиентом, и о том, как этот разрыв ликвидировать:

Разрыв представляет собой расстояние, отделяющее потенциального клиента от вашего продукта. Пока оно существует, у клиента нет соответствующего программного обеспечения, а у вас - денег. Чтобы покупка состоялась, это расстояние необходимо преодолеть. До тех пор оно олицетворяет всевозможные проблемы и препятствия, которые мешают клиенту сделать покупку. Собственно говоря, у вас есть всего две возможности: "Сдвинуть" продукт к клиенту; "Сдвинуть" клиента к продукту.

Этим двум способам и посвящены две части статьи.

Первая часть посвящена активным продажам, во главе котоых стоит sales guy (распростанитель). Как бы многих из нас ни раздражали эти ребята, нужно признать, что некоторые бизнесы просто не могут без них существовать. Поэтому всякий, кто задумывается о стартапе, должен "учить мат. часть" и как минимум знать, что могут распространители и как этим пользоваться:

Стереотипы распространителей могут слегка варьировать, но есть одно абсолютно необходимое требование: хороший распространитель - это некто, кто мотивирован только деньгами. Одна из самых опасных ошибок, допускаемых при найме распространителей -  это нанимать распространителей, которых волнует что-то ещё.

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

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

Собственно, этому и посвящена вторая часть статьи, озаглавленная "Пассивные продажи":

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

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

Чтобы добиться успеха в пассивных продажах, Синк призывает помнить о семи важных вещах:

1. А знают ли потенциальные клиенты о вашем продукте? Если люди никогда не слышали о вашем продукте, то они никогда его и не купят. Осторожнее с рекламой. Можно потратить кучу денег и даже не понять, на что же они ушли. Я не говорю, что маленькие компании должны отказаться от рекламы. Просто делать это нужно осторожно. Участвуйте в выставках. Работайте "в открытую". Конечно, традиционные виды маркетинговых коммуникаций необходимы, но сейчас в маркетинге есть свои новшества. Учитывая повсеместную доступность интернета, лучше всего привлекать внимание к своему продукту, разрабатывая его "в открытую". Используйте веблоги и дискуссионные форумы, разрешайте людям "попробовать" ваш продукт, скачав демо-версию. Пусть клиенты наблюдают за процессом создания продукта, задают вам вопросы, обсуждают интересующие их возможности продукта. Представьте себя шеф-поваром китайского ресторана, который поджаривает на огромной сковородке креветки с овощами, пока клиент, сделавший заказ, наблюдает за процессом готовки.

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

3. Могут ли пользователи позволить себе ваш продукт? Цена тоже влияет на величину "разрыва" между клиентом и продуктом. Некоторые выбирают программное обеспечение точно так же, как я покупаю обувь. Покупать дорогой товар удобно тем, у кого мало времени на скрупулезные исследования рынка. Высокая цена привлечет тех, кому нужен престиж или безупречное качество продукта. Но и у невысокой цены есть свои преимущества. Дело в том, что большинство ваших потенциальных клиентов ограничены бюджетом. Если цена продукта намного превышает бюджет, то "разрыв" будет просто непреодолимым.

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

5. Отвечайте на вопросы.

6. Отведите специальное место для общения пользователей.

7. Сделайте процесс покупки через веб удобным и простым. Обходитесь без регистраций. Не нужно "корзины". Отдавайте продукт сразу.

И на последок ещё пару слов от Этика о том, почему это всё работает:

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


Categories: Books & Articles
Posted by Vitalii Tsybulnyk on Monday, August 03, 2009 6:16 AM
Permalink | Comments (0) | Post RSSRSS comment feed