В наших с вами интернетах недавно поднялся нешуточный шум по поводу того, жив ли TDD сейчас, нужен ли он, и в каком виде. Все началось со статьи Дэвида Хансона "TDD is dead. Long living testing", после которой последовали статьи многих авторов и живые обсуждения этой проблемы включая hangout вместе с Дэвидом, Кентом Беком и Мартином Фаулером .
Но немногие знают, что за несколько дней до этого все тот же Мартин Фаулер постарался дать определение модульного теста (bliki:UnitTest), перевод которого представлен ниже. А после перевода идут кое-какие мои мысли по этому поводу.
---------------------------------
В мире разработки ПО очень часто говорят о модульных тестах, и я знаком с этим понятием на протяжении всей своей карьеры программиста. Однако, как и многие другие термины из мира разработки ПО, этот термин определен весьма плохо, и я часто сталкиваюсь с замешательством, когда разработчики думают, что он имеет более строгое определение, чем это есть на самом деле.
И хотя я очень часто пользовался модульными тестами, моя окончательная приверженность ими возникла, когда я начал работать с Кентом Беком и пользоваться семейством инструментов тестирования xUnit. (Мне даже иногда кажется, что более подходящим термином для этого вида тестирования будет "xunit testing".) Модульное тестирование также стало важной активностью в Экстремальном Программировании (XP – Extreme Programming), и быстро переросло в разработку через тестирование (TDD – Test-Driven Development).
Роль модульных тестов в XP с самого начала вызывала определенное беспокойство. Я четко помню обсуждение в группе usenet, в которой эксперт по тестированию ругал сторонников XP за неправильное использование термина "модульный тест". Мы попросили дать его определение, на что он ответил что-то вроде: "в самом начале моего учебного курса по тестированию я рассматриваю 24 разных определения модульного теста".
Несмотря на разногласия, в некоторых аспектах наши точки зрения сходились. Во-первых, существует представление, что модульные тесты являются низкоуровневыми и концентрируются лишь на небольшой части программной системы. Во-вторых, сегодня модульные тесты обычно пишутся разработчиками с использованием их обычных инструментов, к которым добавляется некоторый фреймворк для тестирования(*). В-третьих, ожидается, что модульные тесты будут существенно быстрее других видов тестов.
Но были и различия во взглядах. Существует разные точки зрения на то, что считать модулем. В объектно-ориентированном дизайне модулем принято считать класс, в процедурном и функциональном подходах модулем может считаться функция. На самом же деле, это ситуативное понятие: команда решает, что разумно считать модулем для понимания системы или ее тестирования. И хотя я начинаю с представления, что класс является модулем, я часто начинаю рассматривать набор тесно связанных классов, как единый модуль. Реже я могу рассматривать подмножество методов класса в качестве модуля. На сам деле, не имеет особого значения, как вы определите это понятие.
Изоляция
Более важным различием в подходах является вопрос: должен ли тестируемый модуль быть отделен от взаимодействующих объектов? Предположим вы тестируете метод вычисления цены класса заказа. Метод вычисления цены вызывает некоторые методы классов продукта и заказчика. Если вы следуете принципу изоляции взаимодействующих объектов, вы не захотите здесь использовать реальные классы продуктов и заказчиков, поскольку ошибки в классе заказчика приведут к падению тестов класса заказа. Вместо этого вы воспользуетесь подделками (Test Doubles) всех взаимодействующих объектов.
Но не все разработчики используют изоляцию. На самом деле, когда xunit-тестирование началось в 90-х мы не пытались изолировать тестируемый класс, если только коммуникация с другими объектами не была крайне неудобной (как, например, взаимодействие с удаленной системой проверки кредитных карт). У нас не возникало сложностей понять реальную причину сбоя, даже если при этом падали соседние тесты. Поэтому, с практической точки зреня, мы не считали отсутствие изоляции проблемой.
Хотя именно отсутствие изоляции в нашем определении "модульного теста" было причиной его критики. Я считаю, определение "модульного теста" подходящим, поскольку он тестируют поведение одного модуля. Мы пишем тест, предполагая, что все, кроме данного модуля работает корректно.
Когда xunit тестирование стало набирать популярность в 2000-е, идея изоляции вернулась с новой силой, по крайней мере, для некоторых. Мы видели подъем Мок Объектов (Mock Object) и фреймворков для поддержки мокинга. В результате появились две школы xunit тестировщиков, которые я называю классической школой и школой мокистов (mockists). Приверженцы классической школы не заморачиваются с изоляцией, как это делают мокисты. Я знаю и уважаю xunit-тестировщиков обоих школ (хотя сам отношусь к классической школе).
Даже представители классической школы (включая меня) при наличии сложных взаимодействий используют подделки (test doubles). Подделки являются бесценными для устранения неопределенности поведения при работе с удаленными сервисами. Некоторые представители классической школы считают, что любое взаимодействие с внешними ресурсами, такими как базы данных или файловая система, должны использовать подделки. Частично это мнение опирается на риск неопределенного поведения, частично на проблемы со скоростью. И хотя я считаю, что это полезная рекомендация, я не рассматриваю ее как абсолютное правило. Если обращение к ресурсу является стабильным и достаточно быстрым для вас, тогда нет причин, почему его нельзя использовать из модульных тестов.
Скорость
Существуют несколько общих свойств юнит тестов: маленькая область действия (small scope), они пишутся разработчиками, и они быстро исполняются – что дает возможность запускать их часто во время разработки. Действительно, это одно из ключевых свойств самотестируемого кода (Self-Testing Code). В этом случае программист может запускать модульные тесты после любого изменения в коде. Я могу запускать юнит тесты несколько раз в минуту, каждый раз, когда у меня появляется необходимость в компиляции кода. Это полезно, поскольку если я случайно что-то сломаю, то я хочу сразу же узнать об этом. Если я сломал что-то своими последними изменениями, то намного проще сразу же найти эту ошибку, поскольку мне не придется искать ее очень далеко.
ПРИМЕЧАНИЕ переводчика
Кент Бек развил идею запуска тестов при компиляции (а иногда даже без нее) и предложил идею непрерывного тестирования (Continuous Testing). Примеры таких инструментов: Mighty-Moose и NCrunch для .NET, JUnit Max для Java.
Когда вы запускаете тесты настолько часто, то вы не можете запускать их все. Обычно вам нужно запускать лишь те тесты, которые работают с кодом над которым вы сейчас работаете. В этом случае вы жертвуете глубиной тестирования в угоду длительности запуска тестов. Я называю этот набор тестов "набором компиляции" (compile suite), поскольку я запускаю их каждый раз при компиляции, даже на таких интерпретируемых языках как Ruby.
Если вы используете непрерывную интеграцию (Continuous Integration) вы должны запускать тесты, как один из ее шагов. Этот набор тестов, которые я называю "набором фиксации" (commit suite), должен включать все юнит тесты. Он также может включать в себя некоторые приемочные тесты (Broad-Stack Tests или End-to-End Tests). Как разработчик вы должны прогонять этот набор тестов несколько раз в день, конечно же, до фиксации своих изменений в системе контроля версий, а также в любое другое время, когда у вас есть такая возможность – во время перерыва или митинга. Чем быстрее выполняется набор тестов фиксации, тем чаще вы cможете их запускать (**).
У разных людей разные стандарты для скорости исполнения юнит-тестов и их наборов. Так, для Дэвида Хансона (David Heinemeier Hansson) достаточно, чтобы набор компиляции (compile suite) исполнялся несколько секунд, а набор фиксации (commit suite) – несколько минут. Гарри Бернхардт (Gary Bernhardt) считает это слишком медленным и настаивает, чтобы набор компиляции исполнялся около 300мс, а Дэн Бодарт (Dan Bodart) не хочет ждать исполнения набора фиксации дольше нескольких секунд.
Я не думаю, что есть единственный правильный ответ на этот вопрос. Лично я не видел разницы, когда набор компиляции исполняется долю секунды или пару секунд. Мне нравится правило Кента Бека, что набор фиксации не должен исполняться дольше 10 минут. Главная мысль здесь в том, что ваш набор тестов должен исполняться достаточно быстро, чтобы не отбить у вас охоту запускать его достаточно часто. А "достаточно часто" означает, что когда тесты найдут баг, вам придется перекопать небольшой объем кода и найти его довольно быстро.
Примечания
(*) Я говорю "сегодня", поскольку это изменилось именно благодаря XP. В спорах начала нового столетия, сторонники XP подвергались серьезной критике, поскольку общепринятая точка зрения гласила, что программисты не должны тестировать собственный код. В некоторых компания были специализированные "юнит-тестеры", единственной задачей которых было написание модульных тестов для кода разработчиков. Причина такой точки зрения заключалась в следующем: люди обладают "концептуальной слепотой" при тестировании своего кода; программисты являются плохими тестировщиками, поэтому полезно иметь некую форму противостояния между программистами и тестировщиками. Точка зрения сторонников XP заключалась в том, что программисты могут научиться быть хорошими тестировщиками, как минимум на уровне отдельного "модуля", а если привлечь дополнительную группу для написания тестов, то обратная связь, обеспечиваемая тестами, будет невероятно медленной. Инструменты XUnit играли в этом очень важную роль, поскольку они были разработаны специально, для минимизации накладных расходов при написании тестов.
(**) Если у вас есть полезные тесты, длительность исполнения которых превосходит длительность запуска тестов фиксации, то вам нужно построить "конвейер развертывания" (Deployment Pipeline) и поместить эти тесты в более поздние этапы конвейера.
---------------------------------
В этой статье Мартин осознанно не касается вопросов порядка написания кода и тестов, вместо этого он старается лишь дать определение модульного теста и показать существование разных точек зрения на само понятие модуля, на необходимость изоляции и скорость исполнения.
Сам я тоже довольно часто сталкивался с мнением, что модульный тест должен тестировать класс в полной изоляции от остального мира. Например, именно этот подход описывает Роберт Мартин в своей книге "Принципы, паттерны и методики гибкой разработки" и именно его я критиковал в статье "Критический взгляд на принцип инверсии зависимостей".
В моем понимании нет совершенно ничего плохого в использовании конкретных классов в модульных тестах, если их поведение является детерминированным и быстрым. Выделение лишних зависимостей может подрывать инкапсуляцию класса и в итоге снижать простоту понимания и сопровождения системы. Любые стабильные зависимости могут и должны использоваться напрямую, а выделяться должны лишь "изменчивые" зависимости, чье поведение не является детерминированным.
Оказывается, я являюсь сторонником классической школы модульного тестирования, и считаю, что нужно использовать реальные классы, если они не обращаются к недерминированным внешним ресурсам. Проблема с обилием моков в моем понимании заключается в том, что полученные тесты становятся слишком зависимыми на тестовое окружение, что делает их хрупкими, а обилие интерфейсов и косвенности ухудшает "понимаемость" системы добавляя гибкость, не нужную в 99% случаев.
Конечно, есть и другие точки зрения на использование моков. Так, Стив Фриман и Нэт Прайс в своей книге "Growing Object-Oriented Software Guided by Tests" придерживаются другой точки зрения. Но при этом они очень тщательно следят за простой тестов и не допускают ситуации, когда на каждую строку теста приходит 5 строк инициализации моков.
Абсолютно нормально придерживаться любому из двух лагерей: классиков или моккистов. Главное, чтобы ваш выбор был осознанным, а ваши тесты упрощали развитие и сопровождение, а не мешали этому.
А в чем собственно заключается проблема, что "полученные тесты становятся слишком зависимыми на тестовое окружение". При использовании DIP мы легко мигрировали с Moq на NSubtitute и также параллельно мигрировали и сам IoC контейнер с Unity на AutoFac. Да, работа была - но она была не очень критичная.
ОтветитьУдалитьПод тестовым окружением я имел ввиду "окружение, поднятое в тестах".
УдалитьЕсли нам нужно сделать тест для класса с тремя зависимостями, каждую из которых нужно замокать, то даже сам факт изменения количества зависимостей (изменение, которое могло быть связано с изменением деталей реализации класса) повлечет поломку всех существующих тестов.
В моем понимании, далеко не всегда нужно знать, с кем общается тестовый класс, если только этот "кто-то" не лазит во внешние системы.
DIP - это не решение проблемы в данном случае. Это ее причина. Подробнее - в статье "Критика DIP"
"Если нам нужно сделать тест для класса с тремя зависимостями, каждую из которых нужно замокать, то даже сам факт изменения количества зависимостей (изменение, которое могло быть связано с изменением деталей реализации класса) повлечет поломку всех существующих тестов.
УдалитьВ моем понимании, далеко не всегда нужно знать, с кем общается тестовый класс, если только этот "кто-то" не лазит во внешние системы.
"
-- вот у меня - ровно такое же ощущение
>"В моем понимании, далеко не всегда нужно знать, с кем общается тестовый класс, если только этот "кто-то" не лазит во внешние системы"
УдалитьНа мой вгляд именно под этим Мартин в статье понимал "модуль". Если группа классов имеет внутреннюю логическую связь (cohesion), то и тестировать их нужно как единое целое
@Vlad: да, но тот же Мартин пишет о том, что это мнение не единственное и есть люди, которые считают, что понятие "модуля" и "модульного теста" иное, и что модульный тест должен тестировать модуль и только его, без его соседей.
Удалить>>В результате появились две школы xunit тестировщиков, которые я называю классической школой и школой мокистов (mockists). Приверженцы классической школы не заморачиваются с изоляцией, как это делают мокисты. Я знаю и уважаю xunit-тестировщиков обоих школ (хотя сам отношусь к классической школе).
ОтветитьУдалить>>Частично это мнение опирается на риск неопределенного поведения, частично на проблемы со скоростью. И хотя я считаю, что это полезная рекомендация, я не рассматриваю ее как обсолютное правило.
Это хорошие цитаты к этому https://plus.google.com/108967431947412296254/posts/5MWE1D1CHku посту
ЗЫ _о_бсолютное ;-)
Очепятку поправил, спасибо.
УдалитьИ да, это и правда очень хорошо подтверждает, что авторы идеи являются более разумными и прагматичными людьми, нежели ярые сторонники этой идеи.
Интересная статья, Серёж, спасибо за перевод.
ОтветитьУдалитьПонравилась прагматичность Фаулера.
Паш, спасибо.
Удалитья правда ещё довольно мало работал через TDD
ОтветитьУдалитьНо попытки внедрить его в реальную систему и развили "думалку".
Я считаю пусть он хоть 10 мин исполняется, но он должен:
- Поднять нулевоую БД
- Внести данные в БД
- Начать гонять тесты системы
И никакие моки не спасают, да я знаю что это уже скорее интегрированное тестирование. И оно включает в себя модульное как "компонент системы тестирования".
Однако любое другое как по мне "замыливает глаза".
ИМХО
У меня очень много написано по поводу пользы модульного тестирования, так что не вижу смысла повторяться. Главная идея: модульное тестирование не враг интеграционному. Они ДОПОЛНЯЮТ друг друга.
УдалитьНу и исходя из мнения о тестах, у меня есть сомнение, что вы работали через TDD;)
Работал :-) но видимо не "дошёл до сути" :-)
УдалитьИ я не против моков. :) Надо и они.
ОтветитьУдалить"DIP - это не решение проблемы в данном случае. Это ее причина. Подробнее - в статье "Критика DIP""
ОтветитьУдалить"авторы идеи являются более разумными и прагматичными людьми, нежели ярые сторонники этой идеи"
;-)
У любого правила есть исключения;)
УдалитьДа и вообще, Мартин же это не придумывал, он все эти принципы собрал в одну кучу и популяризировал. Паттерн "стратегия" с наблюдателем, полиморфизм и объектная декомпозиция была давно. Он придумал лишь название.
мне нравятся приведённые цитаты :-)
УдалитьОк:)) Изначально не совсем понял суть комментария))
Удалить"При этом я также достаточно прагматично отношусь к времени выполнения тестов и не считаю, что все тесты должны выполняться за долю секунды. Тесты должны выполняться достаточно быстро, но в любой реальной системе длительность запуска всех тестов будет занимать все же минуты, а не секунды."
ОтветитьУдалитьСогласен.
-- у нас комплекты тестов отдельные идут и по два часа. И ничего - живём. Даже с "такими" - ЛУЧШЕ, чем без никаких..
Может быть я не до конца понимаю...
ОтветитьУдалитьНо основная идея моков, это же исключить негативное влияние других модулей. Т.е. что бы на результата теста не повлиял другой модуль. Поэтому тест и называется модульным. Т.е. тестируется именно поведение модуля, но не его взаимосвязь с другими модулями. Выполняя тест с моками, мы абсолютно уверены в том, что именно наш модуль не работает, но не какой то другой.
Использование IoC и моков, в данном случае, это лишь инструмент, помогающий "отцепить" модуль от других модулей.
Что думаете? Все сложнее?
Да, и за все приходится платить. Безусловно что при изменении зависимостей, придется переписать тест. Но по мне, это не очень серьезный аргумент против. При изменении интерфейсов и так придется переписывать тест.
УдалитьВадим, ведь именно об этом пишет Мартин в своей статье. Понятие модульного теста не определяет, что тестируется модуль в *полнейшей* изоляции.
УдалитьЛично я не вижу проблемы, что мы тестирум модуль целиком, со всеми его внутренними зависимостями. При этом я вижу в этом подходе несколько положительных моментов.
Во-первых, мы тестируем сразу связку модуля с его внутренними деталями реализации.
Во-вторых, если внутренний компонент будет сломан, то это даже хорошо, что упадут все тесты, которые его используют. Таким образом вы поймете, какое влияние на продакшн код оказывает данный строительный блок. Найти ошибку вы найдете и в этом случае быстро, но так будет понятна *важность* данного строительного блока для системы.
При эом предлжоенное "отцепление" имеет свою стоимость, поскольку увеличивает сложность системы (за счет ненужного увеличения числа интерфейсов), а также может подрывать инкапсуляцию системы, поскольку вы начинаете выставлять наружу то, что вы бы не выставляли в другом случае.
(ко второму комментарию). Да, я же не против выделения зависимостей. Я за стратегии, я за выделение изменчивых зависимостей, но я против выделения зависимостей только потому, что мне страшно использовать конкретные стабильные классы, в поведении которых я, по идее, должен быть уверен.
УдалитьМне всегда в таких случаях вспоминается знаменитая книга Буча "Объектно-ориентированный анализ и проектирования с примерами приложения", которая раз и навсегда изменила мое отношение к разработке ПО: *любая сложная система строится на основе хорошо работающей простой системы*. Это выражается в том, что мы объединяем проверенные и хорошо работающие компоненты низкого уровня во все более и более высокоуровневые абстракции. Боязнь использовать их напрямую означает, что мы хотим нарушить этот фундаментальный принцип.
Сергей, да, ваши слова вполне разумны.
УдалитьНо что делать, если система в процессе разработки. Один разработчик пишет один модуль, другой разработчик пишет другой модуль. Модули взаимодействуют через интерфейсы. Получается, что программист не напишет свой тест, пока не будет готов модуль другого программиста. Точнее напишет, но работать тест не будет. И разработчик, по сути, не будет иметь представления о работе своего модуля. В данном же случае без моков и инжектирования не обойтись... Или я ошибаюсь?
Но, если мы начнем строить правила, когда изолировать модуль, когда нет, то тогда мы все усложняем. Я же за простоту. Т.е. если подход с использованием моков решает все типовые задачи (при написании модульного теста), со своими плюсами и минусами, а классический подход не решает все типовые задачи, со своими плюсами и минусами, то не проще ли всегда использовать подход с моками?
> При эом предлжоенное "отцепление" имеет свою стоимость, поскольку увеличивает сложность системы (за счет ненужного увеличения числа интерфейсов), а также может подрывать инкапсуляцию системы, поскольку вы начинаете выставлять наружу то, что вы бы не выставляли в другом случае.
УдалитьКстати да, очень точно подмечено. Хорошая мысль. Спасибо.
По поводу первого вопроса: если система в процессе разработки.
УдалитьПонятие low coupling-а применяется как программным системам, так и командам или подкомандам. Именно поэтому хороший ПМ или архитектор разобьет работу так, чтобы люди (или подкоманды) работали на максимально изолированных модулях. Да, в этом случае интерфейсы выделяются, но это будут интерфейсы целых подсистем, т.е. это будут абстракции существенно более высокого уровня, чем те, о которых мы сейчас говорим.
При этом я тоже ничего не хочу усложнять. У меня есть правила выделения интерфейсов, описанные мною уже несколько раз: 1) выделяем интерфейсы, когда реально требуется полиморфное поведение (а не когда у интерфейса две реализации - нормальная и для тестов), 2) когда модуль общается с внешними ресурсами (так называемые изменчивые зависимости).
Если же нам нужно решить задачу параллелизма разработки, то решаем ее на более высоком уровне: один занимается модулем доступа к базе данных, а другой - модулем отображения. При этом дизайнится абстрактный (или не очень) интерфейс взаимодействия между этими модулями.
Наверняка вы слышали о модели Дрейфуса или о уровнях зрения под названием shu ha ri. Попытка формализации правил говорит о том, что человек, который этого хочет находится на ранних этапах этой модели. Проблема в том, что реальный мир - это не одно правило, а десятки правил с сотнями исключений. Ни одно правило или принцип разработки не должно использоваться слепо, от этого будет больше вреда, чем пользы. Такое слепое следование опасно тем, что решение будет слишком сложным, а также может выродиться в еще большую проблему, под названием культ карго.
"Лично я не вижу проблемы, что мы тестирум модуль целиком, со всеми его внутренними зависимостями. При этом я вижу в этом подходе несколько положительных моментов.
УдалитьВо-первых, мы тестируем сразу связку модуля с его внутренними деталями реализации.
Во-вторых, если внутренний компонент будет сломан, то это даже хорошо, что упадут все тесты, которые его используют. Таким образом вы поймете, какое влияние на продакшн код оказывает данный строительный блок. Найти ошибку вы найдете и в этом случае быстро, но так будет понятна *важность* данного строительного блока для системы."
-- именно так. По моему опыту. Я исповедую именно такие принципы.
"Но что делать, если система в процессе разработки. Один разработчик пишет один модуль, другой разработчик пишет другой модуль. Модули взаимодействуют через интерфейсы. Получается, что программист не напишет свой тест, пока не будет готов модуль другого программиста. Точнее напишет, но работать тест не будет. И разработчик, по сути, не будет иметь представления о работе своего модуля. В данном же случае без моков и инжектирования не обойтись... Или я ошибаюсь?"
Удалить-- я в этом случае стараюсь использовать "эталоны" ввода/вывода. Те же mock'и. Но не совсем.
http://18delphi.blogspot.ru/2013/04/blog-post_8791.html
С помощью "эталонов" мы даже рисование на канве в GUI тестируем.
Примерно так - http://18delphi.blogspot.ru/2013/04/blog-post_6244.html
"1) выделяем интерфейсы, когда реально требуется полиморфное поведение (а не когда у интерфейса две реализации - нормальная и для тестов), 2) когда модуль общается с внешними ресурсами (так называемые изменчивые зависимости).
УдалитьЕсли же нам нужно решить задачу параллелизма разработки, то решаем ее на более высоком уровне: один занимается модулем доступа к базе данных, а другой - модулем отображения. При этом дизайнится абстрактный (или не очень) интерфейс взаимодействия между этими модулями."
-- вот - ОЧЕНЬ ВЕРНО
"Получается, что программист не напишет свой тест, пока не будет готов модуль другого программиста. Точнее напишет, но работать тест не будет. И разработчик, по сути, не будет иметь представления о работе своего модуля. В данном же случае без моков и инжектирования не обойтись... Или я ошибаюсь?"
Удалить-- и ОШИБАЕТЕСЬ и НЕТ. Тут дело такое...
Проблему взаимодействия между ЛЮДЬМИ надо решать ИНДИвИДУАЛЬНО в каждом конкретном случае.
И далеко НЕ ВСЕГДА за счёт DI или mock'ов.
Далеко не всегда.
Что хочу ещё сказать...
ЛЮБАЯ практика или ТЕХНИКА, это НЕ ДОГМА, а один из возможных путей.
Что собственно Сергей и писал - "зачастую авторы техник гибче и прагматичнее, чем их последователи".
Как писал Джоэл - "fire and motion" - "огонь и движение"... Берём "первое попавшееся решение", пытаемся его применить, если оно "не подходит за РАЗУМНОЕ время" - берём ДРУГОЕ и так - "по-индукции". И "не заморачиваемся" на конкретном решении.
Ну и вот. Если к месту - http://18delphi.blogspot.ru/2013/04/blog-post.html
"Понятие low coupling-а применяется как программным системам, так и командам или подкомандам. Именно поэтому хороший ПМ или архитектор разобьет работу так, чтобы люди (или подкоманды) работали на максимально изолированных модулях. Да, в этом случае интерфейсы выделяются, но это будут интерфейсы целых подсистем, т.е. это будут абстракции существенно более высокого уровня, чем те, о которых мы сейчас говорим."
Удалить-- кстати - ДА.
МЕНЕДЖЕРСКИЕ решения ЗАЧАСТУЮ определяют ИНТЕРФЕЙСЫ подсистем.
И это работа хорошего МЕНЕДЖЕРА - сделать ХОРОШИЕ интерфейсы. Путём управления ЛЮДЬМИ.
У меня был один РУКОВОДИТЕЛЬ, который говорил - "можно программировать компьютеры, а можно (и НУЖНО) программировать людей".
Так вот - работа ХОРОШЕГО менеджера это именно ХОРОШО программировать людей.
Сергей, спасибо большое.
УдалитьПро модель Дрейфуса слышал, про второй термин не слышал. :) Очень понравилось! Спасибо! :)
Но, как мне кажется, тут ближе модель культа карго, чем проблемы начальных уровней Дрейфуса. Т.к. и Вы, и я понимаете, что некие маркеры/правила все равно нужны. Хотя бы для передачи Best Practise. Боже упаси, что я говорю, о том, что следовать надо всегда чему то одному. Простоя я хочу понять, есть ли смысл в другой точки зрения, в более широком понимании.
Про распределение задач, с учетом связанности, на более высоком уровне - да, согласен на все сто. Равно как и уверен в том, что есть компании/ситуации/люди, которые это сделать не могут на высоком уровне, из-за отсутствия компетентности и самодурства. И т.к. решение задачи на уровене организации проваливается, приходится переносить на более низкий уровень. Да, соглашусь скорее с вами, что это не аргумент. Но как вариант решения проблемы отсутствия верной организации процесса, можно рассматривать.
Александр Люлин, спасибо за комментарии. Соглашусь что
> ЛЮБАЯ практика или ТЕХНИКА, это НЕ ДОГМА, а один из возможных путей.
Про эталоны почитал. Интересное решение. Но, мне показалось, что не сильно перекликается с моками. Т.е. эталон - решение, которое решает некие задачи, но не является замещением моков.
* из-за отсутствия компетентности и самодурства = из-за отсутствия компетентности и присутствия самодурства
Удалить"> ЛЮБАЯ практика или ТЕХНИКА, это НЕ ДОГМА, а один из возможных путей.
УдалитьПро эталоны почитал. Интересное решение. Но, мне показалось, что не сильно перекликается с моками. Т.е. эталон - решение, которое решает некие задачи, но не является замещением моков."
-- ну... как сказать, мне кажется, что эталоны это "замена" mock'ам, вам кажется, что - нет.. обе точки зрения в общем имеют право на жизнь.. я же говорю - догмы нет...
буду рад, если "моё" решение вам вдруг пригодится
"Т.к. и Вы, и я понимаете, что некие маркеры/правила все равно нужны. Хотя бы для передачи Best Practise. "
Удалить-- согласен
Раскрытие темы про тесты и эталоны - http://programmingmindstream.blogspot.ru/2014/05/61.html
ОтветитьУдалитьЕсли интересно
Александр, спасибо за ссылку! Интересно.
УдалитьСергей, всегда пожалуйста, если интересно.
УдалитьИ если не утомил, то позволю привести себе ещё ссылку "в развитие темы" - http://programmingmindstream.blogspot.ru/2014/06/62.html
Если уже неинтересно - пишите :-)
И ещё - http://programmingmindstream.blogspot.ru/2014/06/621-tdd_11.html
УдалитьИ ещё - http://programmingmindstream.blogspot.ru/2014/06/7.html
Удалить