День триста четвёртый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
10. Тщательно выбирайте инструменты
Современные приложения очень редко пишутся с чистого листа. Они собираются с использованием существующих инструментов - компонентов, библиотек и фреймворков - по ряду веских причин:
1. Приложения увеличиваются в размерах и сложности, а время, необходимое для их разработки, сокращается. Это позволяет лучше использовать время и интеллект разработчиков, если они смогут сконцентрироваться на написании большего количества кода бизнес-логики и меньшего количества кода инфраструктуры.
2. Широко используемые компоненты и структуры, вероятно, будут иметь меньше ошибок, чем разработанные самостоятельно.
3. В сети доступно много высококачественного бесплатного программного обеспечения, что означает более низкие затраты на разработку и большую вероятность поиска разработчиков с необходимым интересом и опытом.
4. Производство и обслуживание программного обеспечения - трудоёмкая работа, поэтому покупка готового решения может быть дешевле, чем разработка.
Тем не менее, выбор правильного набора инструментов для вашего приложения может быть сложной задачей, требующей обдумывания. Делая выбор, вы должны иметь в виду несколько вещей:
1. Различные инструменты могут полагаться на разные предположения о контексте их использования: окружающей инфраструктуре, модели управления, модели данных, протоколах связи и т.д. Это может привести к несоответствию архитектуры приложения и инструментов. Такое несоответствие приводит появлению костылей и обходных путей, которые сделают код более сложным, чем необходимо.
2. Различные инструменты имеют разные жизненные циклы, и обновление одного из них может стать чрезвычайно сложной и трудоемкой задачей, поскольку новые функциональные возможности, изменения дизайна или даже исправления ошибок могут привести к несовместимости с другими инструментами. Чем больше инструментов, тем острее может встать эта проблема.
3. Некоторые инструменты требуют небольшой настройки, часто с помощью одного или нескольких файлов конфигурации, что очень быстро может выйти из-под контроля. Приложение может выглядеть так, как если бы оно было написано из файлов конфигурации и нескольких странных строк кода на каком-то языке программирования. Сложность конфигурации делает приложение трудным в обслуживании и расширении.
4. Зависимость от поставщика наступает, когда ваш код активно использует продукты конкретного поставщика, что в конечном итоге накладывает ограничения на код в плане расширяемости, лёгкости изменения, производительности, стоимости сопровождения и т.д.
5. Если вы планируете использовать бесплатное программное обеспечение, вы можете обнаружить, что оно не так уж и бесплатно. Возможно, вам придётся купить коммерческую поддержку, которая не обязательно будет дешёвой. Условия лицензирования имеют значение даже для свободного ПО. Например, в некоторых компаниях недопустимо использовать ПО с бесплатной лицензией GNU из-за его вирусной природы. То есть разработанное с использованием его ПО должно распространяться с открытым исходным кодом.
Моя стратегия по смягчению этих проблем - начать с малого, используя только те инструменты, которые абсолютно необходимы. Обычно первоначальный акцент делается на устранении необходимости участвовать в низкоуровневом программировании инфраструктуры, например, с использованием некоторого промежуточного программного обеспечения вместо использования сокетов напрямую для распределённых приложений. А затем можно добавлять новые слои, если необходимо. Я также стремлюсь изолировать внешние инструменты от объектов моей бизнес-области с помощью интерфейсов и слоёв, чтобы при необходимости можно было заменить инструмент с минимальными затратами. Положительным побочным эффектом этого подхода является то, что я обычно получаю приложение меньшего размера, которое использует меньше внешних зависимостей, чем первоначально прогнозировалось.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Giovanni Asproni
97 Вещей, Которые Должен Знать Каждый Программист
10. Тщательно выбирайте инструменты
Современные приложения очень редко пишутся с чистого листа. Они собираются с использованием существующих инструментов - компонентов, библиотек и фреймворков - по ряду веских причин:
1. Приложения увеличиваются в размерах и сложности, а время, необходимое для их разработки, сокращается. Это позволяет лучше использовать время и интеллект разработчиков, если они смогут сконцентрироваться на написании большего количества кода бизнес-логики и меньшего количества кода инфраструктуры.
2. Широко используемые компоненты и структуры, вероятно, будут иметь меньше ошибок, чем разработанные самостоятельно.
3. В сети доступно много высококачественного бесплатного программного обеспечения, что означает более низкие затраты на разработку и большую вероятность поиска разработчиков с необходимым интересом и опытом.
4. Производство и обслуживание программного обеспечения - трудоёмкая работа, поэтому покупка готового решения может быть дешевле, чем разработка.
Тем не менее, выбор правильного набора инструментов для вашего приложения может быть сложной задачей, требующей обдумывания. Делая выбор, вы должны иметь в виду несколько вещей:
1. Различные инструменты могут полагаться на разные предположения о контексте их использования: окружающей инфраструктуре, модели управления, модели данных, протоколах связи и т.д. Это может привести к несоответствию архитектуры приложения и инструментов. Такое несоответствие приводит появлению костылей и обходных путей, которые сделают код более сложным, чем необходимо.
2. Различные инструменты имеют разные жизненные циклы, и обновление одного из них может стать чрезвычайно сложной и трудоемкой задачей, поскольку новые функциональные возможности, изменения дизайна или даже исправления ошибок могут привести к несовместимости с другими инструментами. Чем больше инструментов, тем острее может встать эта проблема.
3. Некоторые инструменты требуют небольшой настройки, часто с помощью одного или нескольких файлов конфигурации, что очень быстро может выйти из-под контроля. Приложение может выглядеть так, как если бы оно было написано из файлов конфигурации и нескольких странных строк кода на каком-то языке программирования. Сложность конфигурации делает приложение трудным в обслуживании и расширении.
4. Зависимость от поставщика наступает, когда ваш код активно использует продукты конкретного поставщика, что в конечном итоге накладывает ограничения на код в плане расширяемости, лёгкости изменения, производительности, стоимости сопровождения и т.д.
5. Если вы планируете использовать бесплатное программное обеспечение, вы можете обнаружить, что оно не так уж и бесплатно. Возможно, вам придётся купить коммерческую поддержку, которая не обязательно будет дешёвой. Условия лицензирования имеют значение даже для свободного ПО. Например, в некоторых компаниях недопустимо использовать ПО с бесплатной лицензией GNU из-за его вирусной природы. То есть разработанное с использованием его ПО должно распространяться с открытым исходным кодом.
Моя стратегия по смягчению этих проблем - начать с малого, используя только те инструменты, которые абсолютно необходимы. Обычно первоначальный акцент делается на устранении необходимости участвовать в низкоуровневом программировании инфраструктуры, например, с использованием некоторого промежуточного программного обеспечения вместо использования сокетов напрямую для распределённых приложений. А затем можно добавлять новые слои, если необходимо. Я также стремлюсь изолировать внешние инструменты от объектов моей бизнес-области с помощью интерфейсов и слоёв, чтобы при необходимости можно было заменить инструмент с минимальными затратами. Положительным побочным эффектом этого подхода является то, что я обычно получаю приложение меньшего размера, которое использует меньше внешних зависимостей, чем первоначально прогнозировалось.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Giovanni Asproni
День триста пятый. #Оффтоп
Нелёгкая судьба программиста занесла меня в окрестности Майами. Поэтому сегодня будет совсем оффтоп, т.к. из-за длинного перелёта пост написать не смог. В общем, всем доброго утра с берегов Атлантики.
Нелёгкая судьба программиста занесла меня в окрестности Майами. Поэтому сегодня будет совсем оффтоп, т.к. из-за длинного перелёта пост написать не смог. В общем, всем доброго утра с берегов Атлантики.
День триста шестой. #МоиИнструменты
Качество кода. Начало
Улучшение кода может быть сложной задачей. Чем больше кодовая база, тем сложнее становится вручную находить и исправлять плохой код. Функции становятся более трудоемкими и рискованными для реализации, а ошибки возникают чаще. Стоимость обучения новых сотрудников также возрастает, потому что им требуется больше времени, чтобы понять, что делает код. Поиск путей улучшения качества кода крайне важен. Лучше всего учитывать качество кода изначально, но зачастую эта мысль приходит поздно. Однако плохо написанный код может со временем быть очищен.
Анализ кода и метрики являются отправной точкой для улучшения кодовой базы. Код - это данные, и есть инструменты его анализа. Однако в Visual Studio они практически отсутствуют, поэтому необходимы сторонние решения.
Что нужно знать о коде:
- объём кода
- соответствует ли он нашим стандартам кодирования
- наиболее подверженные ошибкам области кода
- какие части кода слишком сложны
- можно ли провести юнит-тестирование модуля
и так далее.
Resharper / Rider
JetBrains является лидером в области рефакторинга и анализа кода. Resharper помогает вам находить проблемный код и быстро его исправлять, в то время как Rider - это полноценная IDE, обладающая той же функциональностью. Resharper - самый популярный инструмент рефакторинга кода C#, который также анализирует HTML, XAML, JavaScript и многое другое.
Этот инструмент используется для получения метрик для проблемного кода. Вы можете просканировать один проект или всё решение. Это полезно, потому что помогает идентифицировать шаблоны в кодовой базе. Например, понять, что команда не знает о каких-то функциях C#, или что из раза в раз делает типичные ошибки.
Недостатком Resharper является то, что он раздувает IDE, добавляя пункты в меню и может нарушить обычную работу Visual Studio. Я отключаю его, когда не выполняю рефакторинг, и использую только тогда, когда пришло время очистить код. Некоторым нравится интерфейс Resharper, поэтому есть смысл приобрести IDE Rider и получить Resharper бесплатно.
NDepend
NDepend – фреймворк для анализа кода. Он имеет функционал, аналогичный Resharper, но более высокоуровневые инструменты. Его можно использовать как отдельное приложение или как расширение Visual Studio. Он также интегрируется с множеством других инструментов для предоставления дополнительной информации. Например, может интегрироваться с инструментами анализа покрытия кода тестами, такими как dotCover.
NDepend не просто анализирует ваш код. Он также измеряет изменение качества вашего кода с течением времени и показывает это на графике.
Кроме того, он может определить, какие типы в первую очередь подойдут для рефакторинга, исходя из срока технического долга.
Поначалу NDepend может показаться слишком сложным. Это комплексный инструмент, который требует некоторых усилий, чтобы понять его и подготовить ваше решение. Однако для крупных проектов он может предоставить то, чего не могут другие решения.
Автор: Christian Findlay
Источник: https://christianfindlay.com/
Качество кода. Начало
Улучшение кода может быть сложной задачей. Чем больше кодовая база, тем сложнее становится вручную находить и исправлять плохой код. Функции становятся более трудоемкими и рискованными для реализации, а ошибки возникают чаще. Стоимость обучения новых сотрудников также возрастает, потому что им требуется больше времени, чтобы понять, что делает код. Поиск путей улучшения качества кода крайне важен. Лучше всего учитывать качество кода изначально, но зачастую эта мысль приходит поздно. Однако плохо написанный код может со временем быть очищен.
Анализ кода и метрики являются отправной точкой для улучшения кодовой базы. Код - это данные, и есть инструменты его анализа. Однако в Visual Studio они практически отсутствуют, поэтому необходимы сторонние решения.
Что нужно знать о коде:
- объём кода
- соответствует ли он нашим стандартам кодирования
- наиболее подверженные ошибкам области кода
- какие части кода слишком сложны
- можно ли провести юнит-тестирование модуля
и так далее.
Resharper / Rider
JetBrains является лидером в области рефакторинга и анализа кода. Resharper помогает вам находить проблемный код и быстро его исправлять, в то время как Rider - это полноценная IDE, обладающая той же функциональностью. Resharper - самый популярный инструмент рефакторинга кода C#, который также анализирует HTML, XAML, JavaScript и многое другое.
Этот инструмент используется для получения метрик для проблемного кода. Вы можете просканировать один проект или всё решение. Это полезно, потому что помогает идентифицировать шаблоны в кодовой базе. Например, понять, что команда не знает о каких-то функциях C#, или что из раза в раз делает типичные ошибки.
Недостатком Resharper является то, что он раздувает IDE, добавляя пункты в меню и может нарушить обычную работу Visual Studio. Я отключаю его, когда не выполняю рефакторинг, и использую только тогда, когда пришло время очистить код. Некоторым нравится интерфейс Resharper, поэтому есть смысл приобрести IDE Rider и получить Resharper бесплатно.
NDepend
NDepend – фреймворк для анализа кода. Он имеет функционал, аналогичный Resharper, но более высокоуровневые инструменты. Его можно использовать как отдельное приложение или как расширение Visual Studio. Он также интегрируется с множеством других инструментов для предоставления дополнительной информации. Например, может интегрироваться с инструментами анализа покрытия кода тестами, такими как dotCover.
NDepend не просто анализирует ваш код. Он также измеряет изменение качества вашего кода с течением времени и показывает это на графике.
Кроме того, он может определить, какие типы в первую очередь подойдут для рефакторинга, исходя из срока технического долга.
Поначалу NDepend может показаться слишком сложным. Это комплексный инструмент, который требует некоторых усилий, чтобы понять его и подготовить ваше решение. Однако для крупных проектов он может предоставить то, чего не могут другие решения.
Автор: Christian Findlay
Источник: https://christianfindlay.com/
День триста седьмой. #ВопросыНаСобеседовании
Самые часто задаваемые вопросы на собеседовании по ASP.NET MVC
2. Какие преимущества у MVC?
- Поддержка нескольких представлений
Благодаря отделению модели от представления пользовательский интерфейс может отображать несколько представлений одних и тех же данных одновременно.
- Простота изменений
Пользовательские интерфейсы, как правило, меняются чаще, чем бизнес-правила (цвета, шрифты, дизайн для разных видов устройств и т.п.). Поскольку модель не зависит от представления, добавление новых представлений в систему не влияет на модель. В результате область изменений ограничена представлением.
- Разделение Ответственности (Separation of Concerns - SoC)
Это одно из основных преимуществ ASP.NET MVC. Инфраструктура MVC обеспечивает четкое разделение пользовательского интерфейса, бизнес-логики, модели или данных.
- Больше контроля
Среда ASP.NET MVC обеспечивает больший контроль над HTML, JavaScript и CSS, чем традиционные веб-формы.
- Простота интеграции с Javascript фреймворками
MVC дает возможность лёгкой интеграции с Javascript библиотеками и фреймворками (например, jQuery, Angular и т.п.).
- Тестируемость
Фреймворк ASP.NET MVC обеспечивает лучшую тестируемость веб-приложения и хорошую поддержку для разработки на основе тестирования (TDD).
- Легковесность
Платформа ASP.NET MVC не использует View State и, таким образом, до некоторой степени снижает нагрузку на сеть.
- Полнота возможностей ASP.NET
Одним из ключевых преимуществ использования ASP.NET MVC является то, что он построен поверх платформы ASP.NET, и, следовательно, предоставляет доступ к большинству функций ASP.NET, таких как поставщики членства, ролей и т.д.
Источник: https://www.c-sharpcorner.com
Самые часто задаваемые вопросы на собеседовании по ASP.NET MVC
2. Какие преимущества у MVC?
- Поддержка нескольких представлений
Благодаря отделению модели от представления пользовательский интерфейс может отображать несколько представлений одних и тех же данных одновременно.
- Простота изменений
Пользовательские интерфейсы, как правило, меняются чаще, чем бизнес-правила (цвета, шрифты, дизайн для разных видов устройств и т.п.). Поскольку модель не зависит от представления, добавление новых представлений в систему не влияет на модель. В результате область изменений ограничена представлением.
- Разделение Ответственности (Separation of Concerns - SoC)
Это одно из основных преимуществ ASP.NET MVC. Инфраструктура MVC обеспечивает четкое разделение пользовательского интерфейса, бизнес-логики, модели или данных.
- Больше контроля
Среда ASP.NET MVC обеспечивает больший контроль над HTML, JavaScript и CSS, чем традиционные веб-формы.
- Простота интеграции с Javascript фреймворками
MVC дает возможность лёгкой интеграции с Javascript библиотеками и фреймворками (например, jQuery, Angular и т.п.).
- Тестируемость
Фреймворк ASP.NET MVC обеспечивает лучшую тестируемость веб-приложения и хорошую поддержку для разработки на основе тестирования (TDD).
- Легковесность
Платформа ASP.NET MVC не использует View State и, таким образом, до некоторой степени снижает нагрузку на сеть.
- Полнота возможностей ASP.NET
Одним из ключевых преимуществ использования ASP.NET MVC является то, что он построен поверх платформы ASP.NET, и, следовательно, предоставляет доступ к большинству функций ASP.NET, таких как поставщики членства, ролей и т.д.
Источник: https://www.c-sharpcorner.com
День триста восьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
11. Программируйте на языке предметной области
Представьте две программы. В одной вы видите:
В другой программе вы видите это:
С какой из этих программ вы бы предпочли работать?
Когда-то у нас были только очень простые структуры данных: биты, байты и символы (на самом деле это тоже были байты, но мы притворялись, что это буквы и знаки пунктуации). С дробными числами было посложнее, потому что наши десятичные числа не очень хорошо работают в двоичном формате, поэтому у нас было несколько типов с плавающей точкой. Затем появились массивы и строки (на самом деле тоже массивы). Потом были стеки, очереди, хэшированные наборы, связанные списки и множество других интересных структур данных, которых не существует в реальном мире. Всё «программирование» состояло из попыток отобразить реальный мир в наших ограниченных структурах данных. Настоящие гуру могли даже вспомнить, как они это сделали.
Потом появились пользовательские типы! ОК, это не новость, но это немного меняет игру. Если ваш домен содержит такие понятия, как трейдеры и портфели, вы можете моделировать их с помощью таких типов, как, скажем, Trader и Portfolio. Но, что более важно, вы можете смоделировать отношения между ними, используя термины предметной области.
Если вы не программируете в терминах предметной области, вы создаёте молчаливое (читай: секретное) понимание того, что этот int здесь означает идентификатор трейдера, тогда как этот int означает идентификатор портфеля. (И лучше их не путать!) И если вы реализуете бизнес-концепцию «Некоторым трейдерам нельзя просматривать некоторые портфели, это незаконно» при помощи алгоритма, подобного поиску соответствия в таблице идентификаторов, то вы не даёте тем, кому придётся с этим разбираться, вообще никакой подсказки.
Следующий программист может не знать этого секрета, так почему бы не раскрыть его? Использование ключа для поиска другого ключа, который выполняет проверку существования, само по себе не очевидно. Как кто-то должен понять, что здесь применяются бизнес-правила, предотвращающие конфликт интересов?
Если в вашем коде явным образом изложены концепции предметной области, другие программисты смогут гораздо легче понять смысл кода, чем пытаясь встроить алгоритм в то, что они понимают в предметной области. Это также означает, что по мере развития предметной области (а она непременно будет изменяться и развиваться) вам легко будет изменять код. При грамотном использовании инкапсуляций велика вероятность того, что проверка, приведённая выше, будет существовать только в одном месте, и вы сможете изменить её в одном месте, не сломав зависимый код.
Программист, который будет работать с этим кодом через несколько месяцев, поблагодарит вас. Этим программистом вполне можете быть вы сами.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Dan North
97 Вещей, Которые Должен Знать Каждый Программист
11. Программируйте на языке предметной области
Представьте две программы. В одной вы видите:
if (portfolioIdsByTraderId.get(trader.getId())Вы чешете голову, гадая, для чего этот код может быть. Кажется, он получает идентификатор от объекта
.containsKey(portfolio.getId())) {...}
trader
и использует его, чтобы получить объект portfolio
из словаря, а затем проверяет, существует ли другой идентификатор объекта portfolio во внутреннем словаре. Вы, ещё немного почёсывая голову, ищите объявление portfolioIdsByTraderId
и обнаруживаете это:Map<int, Map<int, int>> portfolioIdsByTraderId;Постепенно вы понимаете, что это может иметь какое-то отношение к тому, имеет ли трейдер доступ к определенному портфелю. И, конечно, вы встретите тот же код для проверки этого - или, что более вероятно, похожий, но слегка различающийся фрагмент кода - всякий раз, где требуется проверка, имеет ли трейдер доступ к определённому портфелю.
В другой программе вы видите это:
if (trader.canView(portfolio)) {...}Всё понятно без объяснения. Вам не нужно знать, как объект trader это проверяет. Возможно, где-то внутри спрятана точно та же проверка в словаре из словарей. Но это дело объекта trader, а не ваше.
С какой из этих программ вы бы предпочли работать?
Когда-то у нас были только очень простые структуры данных: биты, байты и символы (на самом деле это тоже были байты, но мы притворялись, что это буквы и знаки пунктуации). С дробными числами было посложнее, потому что наши десятичные числа не очень хорошо работают в двоичном формате, поэтому у нас было несколько типов с плавающей точкой. Затем появились массивы и строки (на самом деле тоже массивы). Потом были стеки, очереди, хэшированные наборы, связанные списки и множество других интересных структур данных, которых не существует в реальном мире. Всё «программирование» состояло из попыток отобразить реальный мир в наших ограниченных структурах данных. Настоящие гуру могли даже вспомнить, как они это сделали.
Потом появились пользовательские типы! ОК, это не новость, но это немного меняет игру. Если ваш домен содержит такие понятия, как трейдеры и портфели, вы можете моделировать их с помощью таких типов, как, скажем, Trader и Portfolio. Но, что более важно, вы можете смоделировать отношения между ними, используя термины предметной области.
Если вы не программируете в терминах предметной области, вы создаёте молчаливое (читай: секретное) понимание того, что этот int здесь означает идентификатор трейдера, тогда как этот int означает идентификатор портфеля. (И лучше их не путать!) И если вы реализуете бизнес-концепцию «Некоторым трейдерам нельзя просматривать некоторые портфели, это незаконно» при помощи алгоритма, подобного поиску соответствия в таблице идентификаторов, то вы не даёте тем, кому придётся с этим разбираться, вообще никакой подсказки.
Следующий программист может не знать этого секрета, так почему бы не раскрыть его? Использование ключа для поиска другого ключа, который выполняет проверку существования, само по себе не очевидно. Как кто-то должен понять, что здесь применяются бизнес-правила, предотвращающие конфликт интересов?
Если в вашем коде явным образом изложены концепции предметной области, другие программисты смогут гораздо легче понять смысл кода, чем пытаясь встроить алгоритм в то, что они понимают в предметной области. Это также означает, что по мере развития предметной области (а она непременно будет изменяться и развиваться) вам легко будет изменять код. При грамотном использовании инкапсуляций велика вероятность того, что проверка, приведённая выше, будет существовать только в одном месте, и вы сможете изменить её в одном месте, не сломав зависимый код.
Программист, который будет работать с этим кодом через несколько месяцев, поблагодарит вас. Этим программистом вполне можете быть вы сами.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Dan North
День триста девятый. #Оффтоп
Важность алгоритмов
Часто встречаю вопрос: «Насколько важно знать алгоритмы, и какие нужно знать в первую очередь?» В принципе, конечно, неплохо хотя бы примерно представлять суть нескольких простейших алгоритмов. В конце концов, это, наверное, лучший способ проверить ваши когнитивные способности на собеседовании. Ну и конечно, если вы нацелились на низкоуровневую разработку, то тут без отличного знания алгоритмов не обойтись. Но в подавляющем большинстве случаев в практике ими пользоваться практически не придётся, т.к. все они уже реализованы в стандартных (и не очень) библиотеках. И гораздо более важную роль сейчас играет DDD (Domain Driven Development), то есть способность грамотно спроектировать предметную область. Это совсем не значит, что такие требования предъявляются только архитекторам или сеньорам. Проектирование отдельных классов и методов тоже немаловажная задача.
Вот тут Stefan Mischook подробнее рассуждает на эту тему.
Важность алгоритмов
Часто встречаю вопрос: «Насколько важно знать алгоритмы, и какие нужно знать в первую очередь?» В принципе, конечно, неплохо хотя бы примерно представлять суть нескольких простейших алгоритмов. В конце концов, это, наверное, лучший способ проверить ваши когнитивные способности на собеседовании. Ну и конечно, если вы нацелились на низкоуровневую разработку, то тут без отличного знания алгоритмов не обойтись. Но в подавляющем большинстве случаев в практике ими пользоваться практически не придётся, т.к. все они уже реализованы в стандартных (и не очень) библиотеках. И гораздо более важную роль сейчас играет DDD (Domain Driven Development), то есть способность грамотно спроектировать предметную область. Это совсем не значит, что такие требования предъявляются только архитекторам или сеньорам. Проектирование отдельных классов и методов тоже немаловажная задача.
Вот тут Stefan Mischook подробнее рассуждает на эту тему.
This media is not supported in your browser
VIEW IN TELEGRAM
День триста десятый. #ЧтоНовенького
Новинки Visual Studio 2019 версии 16.4
В Microsoft объявили о релизе Visual Studio 2019 версии 16.4. Её можно скачать тут, либо обновить свою IDE из меню Help. Помимо функций, ранее описанных здесь и здесь, вот что ещё интересного приготовили ребята из Редмонда.
Закрепляемые Cвойства
Идентификация объектов по их свойствам при отладке стала проще и доступнее при помощи инструмента Закрепляемые Свойства. Наведите курсор на свойство, которое вы хотите отобразить в оконе Watch, Autos или Locals. Нажмите на значок булавки и вы увидите нужную информацию об объекте в столбце значения (см. картинку).
Команда Перехода к Базовому Классу
Добавлена команда Go To Base, для перемещения вверх по цепочке наследования. Она доступна во всплывающем меню при нажатии правой кнопки мыши, либо по горячим клавишам Alt+Home, когда курсор установлен на нужном элементе.
Источник: https://devblogs.microsoft.com/visualstudio/tis-the-season-visual-studio-2019/
Новинки Visual Studio 2019 версии 16.4
В Microsoft объявили о релизе Visual Studio 2019 версии 16.4. Её можно скачать тут, либо обновить свою IDE из меню Help. Помимо функций, ранее описанных здесь и здесь, вот что ещё интересного приготовили ребята из Редмонда.
Закрепляемые Cвойства
Идентификация объектов по их свойствам при отладке стала проще и доступнее при помощи инструмента Закрепляемые Свойства. Наведите курсор на свойство, которое вы хотите отобразить в оконе Watch, Autos или Locals. Нажмите на значок булавки и вы увидите нужную информацию об объекте в столбце значения (см. картинку).
Команда Перехода к Базовому Классу
Добавлена команда Go To Base, для перемещения вверх по цепочке наследования. Она доступна во всплывающем меню при нажатии правой кнопки мыши, либо по горячим клавишам Alt+Home, когда курсор установлен на нужном элементе.
Источник: https://devblogs.microsoft.com/visualstudio/tis-the-season-visual-studio-2019/
День триста одиннадцатый. #DesignPatterns
Паттерны проектирования
1. Паттерн «Стратегия» (Strategy). Начало
Паттерн «Стратегия» является настолько распространенным и общепринятым, что многие его используют постоянно, даже не задумываясь об этом. Сортировка, анализ данных, валидация, разбор данных, сериализация, кодирование/декодирование, получение конфигурации — все эти концепции могут и должны быть выражены в виде стратегий или политик (policy).
Назначение: определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.
Причины использования:
- необходимость инкапсуляции поведения или алгоритма;
- необходимость замены поведения или алгоритма во время исполнения.
Стратегия нужна тогда, когда не просто требуется спрятать алгоритм, а важно иметь возможность заменить его во время исполнения.
Классическая диаграмма приведена на рисунке ниже:
- Strategy — определяет интерфейс алгоритма;
- Context — клиент стратегии;
- ConcreteStrategyA, ConcreteStrategyB,… — конкретные реализации стратегии.
Классический паттерн весьма абстрактен. Он не определяет, каким образом контекст получает экземпляр стратегии, или как стратегия получит данные, необходимые для выполнения своей работы.
Выделение интерфейса
Существуют сторонники и противники выделения интерфейсов. Это относится не только к паттерну Стратегия. Обязательно ли выделять интерфейс
У выделения интерфейса и передачи его в качестве зависимости есть несколько особенностей. Передача интерфейса классу увеличивает гибкость, но в то же время повышает сложность. Теперь клиентам класса нужно либо решать, какую реализацию использовать, либо переложить эту ответственность на вызывающий код. Важно понимать, нужен ли дополнительный уровень абстракции именно сейчас. Может быть, на текущем этапе достаточно использовать класс напрямую, а выделить интерфейс только тогда, когда в этом действительно появится необходимость.
Продолжение следует…
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 1.
Паттерны проектирования
1. Паттерн «Стратегия» (Strategy). Начало
Паттерн «Стратегия» является настолько распространенным и общепринятым, что многие его используют постоянно, даже не задумываясь об этом. Сортировка, анализ данных, валидация, разбор данных, сериализация, кодирование/декодирование, получение конфигурации — все эти концепции могут и должны быть выражены в виде стратегий или политик (policy).
Назначение: определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.
Причины использования:
- необходимость инкапсуляции поведения или алгоритма;
- необходимость замены поведения или алгоритма во время исполнения.
Стратегия нужна тогда, когда не просто требуется спрятать алгоритм, а важно иметь возможность заменить его во время исполнения.
Классическая диаграмма приведена на рисунке ниже:
- Strategy — определяет интерфейс алгоритма;
- Context — клиент стратегии;
- ConcreteStrategyA, ConcreteStrategyB,… — конкретные реализации стратегии.
Классический паттерн весьма абстрактен. Он не определяет, каким образом контекст получает экземпляр стратегии, или как стратегия получит данные, необходимые для выполнения своей работы.
Выделение интерфейса
Существуют сторонники и противники выделения интерфейсов. Это относится не только к паттерну Стратегия. Обязательно ли выделять интерфейс
AlgorithmInterface
(см. рисунок ниже)? Это зависит от того, нужна ли нам стратегия и хотим ли мы заменять эту стратегию во время исполнения или можем использовать конкретную реализацию и внести в неё изменения в случае необходимости.У выделения интерфейса и передачи его в качестве зависимости есть несколько особенностей. Передача интерфейса классу увеличивает гибкость, но в то же время повышает сложность. Теперь клиентам класса нужно либо решать, какую реализацию использовать, либо переложить эту ответственность на вызывающий код. Важно понимать, нужен ли дополнительный уровень абстракции именно сейчас. Может быть, на текущем этапе достаточно использовать класс напрямую, а выделить интерфейс только тогда, когда в этом действительно появится необходимость.
Продолжение следует…
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 1.
День триста двенадцатый. #DesignPatterns
Паттерны проектирования
1. Паттерн «Стратегия» (Strategy). Окончание
Интерфейс vs. Делегат
Поскольку некоторые стратегии содержат лишь один метод, в .Net часто вместо классической стратегии на основе наследования можно использовать стратегию на основе делегатов. Иногда эти подходы совмещаются, что позволяет использовать наиболее удобный вариант.
Классическим примером такой ситуации является стратегия сортировки, представленная интерфейсом
Паттерны проектирования
1. Паттерн «Стратегия» (Strategy). Окончание
Интерфейс vs. Делегат
Поскольку некоторые стратегии содержат лишь один метод, в .Net часто вместо классической стратегии на основе наследования можно использовать стратегию на основе делегатов. Иногда эти подходы совмещаются, что позволяет использовать наиболее удобный вариант.
Классическим примером такой ситуации является стратегия сортировки, представленная интерфейсом
IComparable<T>
и делегатом Comparison<T>
:class Employee {По сравнению с использованием лямбда-выражений, реализация интерфейса требует больше кода и приводит к переключению контекста при чтении (необходимости посмотреть реализацию функтора). При использовании метода
public int Id { get; set; }
public string Name { get; set; }
…
}
// функтор, реализующий интерфейс
class EmployeeByIdComparer : IComparer<Employee> {
public int Compare(Employee x, Employee y) {
return x.Id.CompareTo(y.Id);
}
}
// используем функтор
list.Sort(new EmployeeByIdComparer());
// используем делегат
list.Sort((x, y) => x.Name.CompareTo(y.Name));
List.Sort
есть возможность использовать оба варианта, но так бывает не всегда, например в случае с классами SortedList
или SortedSet
:var comparer = new EmployeeByIdComparer();В этом случае можно создать небольшой адаптерный фабричный класс, который будет принимать делегат
// Конструктор принимает IComparable
var set = new SortedSet<Employee>(comparer);
// Нет конструктора, принимающего делегат Comparison<T>
Comparison<T>
и возвращать интерфейс IComparable<T>
:class ComparerFactory {Теперь, используя этот класс, можно создать функтор из лямбда-делегата:
public static IComparer<T> Create<T>(Comparison<T> comparer) {
return new DelegateComparer<T>(comparer);
}
private class DelegateComparer<T> : IComparer<T> {
private readonly Comparison<T> _comparer;
public DelegateComparer(Comparison<T> comparer) {
_comparer = comparer;
}
public int Compare(T x, T y) {
return _comparer(x, y);
}
}
}
var comparer = ComparerFactory.Create<Employee>((x, y) => x.Id.CompareTo(y.Id));Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 1.
var set = new SortedSet<Employee>(comparer);
День триста тринадцатый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
12. Код это дизайн
Представьте себе, что назавтра вы просыпаетесь и узнаёте, что строительная отрасль совершила прорыв века. Миллионы дешёвых, невероятно быстрых роботов могут изготавливать материалы из воздуха, требуют минимум энергии и умеют ремонтировать себя. Больше того, роботам достаточно чёткой схемы проекта, и они смогут построить его без вмешательства человека с минимальными затратами.
Можно представить эффект от этого в строительстве, но что произойдёт в смежных отраслях? Как изменится поведение архитекторов и дизайнеров, если затраты на строительство станут незначительными? Сегодня, прежде чем начинается реальное строительство, строятся и тщательно тестируются физические и компьютерные модели. Будем ли мы беспокоиться об этом, если строительство станет фактически бесплатным? Если здание обрушится, ничего страшного - просто найдём проблему, и роботы построят ещё одно с учётом корректив. Будут и другие последствия. Без необходимости моделирования незавершённые проекты будут развиваться путём многократного строительства и улучшения, постепенно приближаясь к конечной цели. Случайный наблюдатель вряд ли сможет отличить незавершённый дизайн от готового продукта.
Исчезнет возможность прогнозировать сроки. Затраты на строительство легче рассчитать, чем затраты на проектирование - мы знаем стоимость кирпича и сколько кирпичей нам нужно. По мере того, как количество предсказуемых задач будет уменьшаться, начнёт доминировать менее предсказуемое время на проектирование. Результаты будут получаться быстрее, но за непредсказуемое время.
Конечно, конкуренция всё также будет влиять. При почти бесплатной стоимости строительства, компания, которая сможет быстро завершить проектирование, получит преимущество на рынке. Быстрая разработка дизайна станет главным фактором давления на инженеров. И неизбежно произойдёт следующее: неспециалист, неспособный отличить законченный дизайн от незаконченного, но зная о преимуществах раннего выпуска, скажет: «Ладно, и так сойдёт».
Некоторые жизненно важные проекты, конечно, будут более продуманными, но во многих случаях потребители привыкнут страдать от неполноты дизайна. Компании всегда смогут отправить своих волшебных роботов, чтобы «починить» разрушенные здания, которые они продают. Всё это указывает на поразительно нелогичный вывод: нашей единственной предпосылкой было резкое сокращение затрат на строительство, а в результате ухудшилось качество.
Это не должно удивлять. Такое случилось в программном обеспечении. Если мы допустим, что программирование - это дизайн (не механический, а творческий процесс), то это объяснит кризис программного обеспечения. Сейчас мы столкнулись с кризисом дизайна: спрос на качественные, проверенные проекты превышает наши возможности по их созданию. Мы ощущаем сильное давление ранних релизов и использования неполноценных программ.
К счастью, эта модель также подсказывает, как мы можем стать лучше. Физическое моделирование – то же самое, что автоматизированное тестирование; разработка программного обеспечения не завершена, пока оно не будет полноценно протестировано. Чтобы сделать такие тесты более эффективными, мы находим способы обуздать огромный массив вариантов состояний больших систем. Усовершенствованные языки и методы проектирования также дают нам надежду на лучшее. Наконец, есть один неизбежный факт: отличный дизайн получается у отличных дизайнеров, посвятивших себя оттачиванию мастерства в своем деле. Отличный код ничем не отличается.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Ryan Brush
97 Вещей, Которые Должен Знать Каждый Программист
12. Код это дизайн
Представьте себе, что назавтра вы просыпаетесь и узнаёте, что строительная отрасль совершила прорыв века. Миллионы дешёвых, невероятно быстрых роботов могут изготавливать материалы из воздуха, требуют минимум энергии и умеют ремонтировать себя. Больше того, роботам достаточно чёткой схемы проекта, и они смогут построить его без вмешательства человека с минимальными затратами.
Можно представить эффект от этого в строительстве, но что произойдёт в смежных отраслях? Как изменится поведение архитекторов и дизайнеров, если затраты на строительство станут незначительными? Сегодня, прежде чем начинается реальное строительство, строятся и тщательно тестируются физические и компьютерные модели. Будем ли мы беспокоиться об этом, если строительство станет фактически бесплатным? Если здание обрушится, ничего страшного - просто найдём проблему, и роботы построят ещё одно с учётом корректив. Будут и другие последствия. Без необходимости моделирования незавершённые проекты будут развиваться путём многократного строительства и улучшения, постепенно приближаясь к конечной цели. Случайный наблюдатель вряд ли сможет отличить незавершённый дизайн от готового продукта.
Исчезнет возможность прогнозировать сроки. Затраты на строительство легче рассчитать, чем затраты на проектирование - мы знаем стоимость кирпича и сколько кирпичей нам нужно. По мере того, как количество предсказуемых задач будет уменьшаться, начнёт доминировать менее предсказуемое время на проектирование. Результаты будут получаться быстрее, но за непредсказуемое время.
Конечно, конкуренция всё также будет влиять. При почти бесплатной стоимости строительства, компания, которая сможет быстро завершить проектирование, получит преимущество на рынке. Быстрая разработка дизайна станет главным фактором давления на инженеров. И неизбежно произойдёт следующее: неспециалист, неспособный отличить законченный дизайн от незаконченного, но зная о преимуществах раннего выпуска, скажет: «Ладно, и так сойдёт».
Некоторые жизненно важные проекты, конечно, будут более продуманными, но во многих случаях потребители привыкнут страдать от неполноты дизайна. Компании всегда смогут отправить своих волшебных роботов, чтобы «починить» разрушенные здания, которые они продают. Всё это указывает на поразительно нелогичный вывод: нашей единственной предпосылкой было резкое сокращение затрат на строительство, а в результате ухудшилось качество.
Это не должно удивлять. Такое случилось в программном обеспечении. Если мы допустим, что программирование - это дизайн (не механический, а творческий процесс), то это объяснит кризис программного обеспечения. Сейчас мы столкнулись с кризисом дизайна: спрос на качественные, проверенные проекты превышает наши возможности по их созданию. Мы ощущаем сильное давление ранних релизов и использования неполноценных программ.
К счастью, эта модель также подсказывает, как мы можем стать лучше. Физическое моделирование – то же самое, что автоматизированное тестирование; разработка программного обеспечения не завершена, пока оно не будет полноценно протестировано. Чтобы сделать такие тесты более эффективными, мы находим способы обуздать огромный массив вариантов состояний больших систем. Усовершенствованные языки и методы проектирования также дают нам надежду на лучшее. Наконец, есть один неизбежный факт: отличный дизайн получается у отличных дизайнеров, посвятивших себя оттачиванию мастерства в своем деле. Отличный код ничем не отличается.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Ryan Brush
День триста пятнадцатый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
13. Важность Форматирования Кода
Давным-давно я работал над системой Cobol, где сотрудникам не разрешалось менять отступы в коде, если они не меняли сам код, только потому что кто-то однажды что-то сломал, сделав неверный отступ в одном из специальных столбцов в начале строки. Этому правилу следовали, даже если форматирование кода вводило в заблуждение, поэтому нам приходилось очень внимательно читать код, потому что мы не могли доверять форматированию. Эта политика, должно быть, стоила целого состояния из-за времени, потраченного программистами на такое детальное чтение.
Исследования показывают, что программисты тратят гораздо больше времени на навигацию и чтение кода в поисках места для внесения изменений, чем на само изменение. Поэтому нужно оптимизировать чтение по следующим причинам:
1. Простота просмотра. Люди хорошо справляются с визуальным сопоставлении с образцом (пережиток того времени, когда нам приходилось замечать львов в саванне). Поэтому можно помочь себе, сделав так, чтобы всё, что не имеет прямого отношения к предметной области (вся «случайная сложность» большинства языков программирования), отошло на задний план, стандартизировав расположение блоков. Если код, который ведёт себя одинаково, выглядит одинаково, то наша система восприятия поможет нам выявить различия. Вот почему важно соблюдать соглашения о расположении частей класса в модуле: константы, поля, открытые методы, закрытые методы.
2. Выразительное форматирование. Мы все научились тратить время на поиск правильных имен, чтобы наш код как можно более чётко выражал, что он делает, а не просто перечислял инструкции. Форматирование кода также является частью этой выразительности. Во-первых, команда разработчиков должна согласовать автоматическое форматирование основных блоков, а затем можно внести изменения вручную во время написания кода. Если не будет сильных разногласий, команда быстро согласится на использование единого стиля. Но только автоматическое форматирование не сможет выразить моих намерений (я это знаю наверняка, поскольку однажды я его реализовывал), а для меня важно, чтобы разрывы строк и группировка блоков выражали именно намерения, а не только синтаксис языка.
3. Компактный формат. Чем больше кода помещается на экране, тем больше я смогу увидеть, не нарушая контекст, не прокручивая страницу или не переключаясь между файлами, что означает, что меньше придётся запоминать логики в голове. Длинные комментарии к процедурам и большое количество пробелов имели смысл при использовании восьмисимвольных имен и строчных принтеров, но теперь у нас есть IDE, которая выполняет раскрашивание синтаксиса и позволяет переходить к определению метода или класса. Пиксели - вот ограничивающий фактор, поэтому я хочу, чтобы каждый из них внёс свой вклад в моё понимание кода. Я хочу, чтобы форматирование помогало мне понять код, но не более того.
Один из моих друзей непрограммистов однажды заметил, что код выглядит как поэзия. Я чувствую это, глядя на действительно хороший код: у каждой детали в тексте есть цель, и она находится в этом месте, чтобы помочь мне понять идею. К сожалению, программирование не имеет такого романтичного ореола, как написание стихов.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Steve Freeman
97 Вещей, Которые Должен Знать Каждый Программист
13. Важность Форматирования Кода
Давным-давно я работал над системой Cobol, где сотрудникам не разрешалось менять отступы в коде, если они не меняли сам код, только потому что кто-то однажды что-то сломал, сделав неверный отступ в одном из специальных столбцов в начале строки. Этому правилу следовали, даже если форматирование кода вводило в заблуждение, поэтому нам приходилось очень внимательно читать код, потому что мы не могли доверять форматированию. Эта политика, должно быть, стоила целого состояния из-за времени, потраченного программистами на такое детальное чтение.
Исследования показывают, что программисты тратят гораздо больше времени на навигацию и чтение кода в поисках места для внесения изменений, чем на само изменение. Поэтому нужно оптимизировать чтение по следующим причинам:
1. Простота просмотра. Люди хорошо справляются с визуальным сопоставлении с образцом (пережиток того времени, когда нам приходилось замечать львов в саванне). Поэтому можно помочь себе, сделав так, чтобы всё, что не имеет прямого отношения к предметной области (вся «случайная сложность» большинства языков программирования), отошло на задний план, стандартизировав расположение блоков. Если код, который ведёт себя одинаково, выглядит одинаково, то наша система восприятия поможет нам выявить различия. Вот почему важно соблюдать соглашения о расположении частей класса в модуле: константы, поля, открытые методы, закрытые методы.
2. Выразительное форматирование. Мы все научились тратить время на поиск правильных имен, чтобы наш код как можно более чётко выражал, что он делает, а не просто перечислял инструкции. Форматирование кода также является частью этой выразительности. Во-первых, команда разработчиков должна согласовать автоматическое форматирование основных блоков, а затем можно внести изменения вручную во время написания кода. Если не будет сильных разногласий, команда быстро согласится на использование единого стиля. Но только автоматическое форматирование не сможет выразить моих намерений (я это знаю наверняка, поскольку однажды я его реализовывал), а для меня важно, чтобы разрывы строк и группировка блоков выражали именно намерения, а не только синтаксис языка.
3. Компактный формат. Чем больше кода помещается на экране, тем больше я смогу увидеть, не нарушая контекст, не прокручивая страницу или не переключаясь между файлами, что означает, что меньше придётся запоминать логики в голове. Длинные комментарии к процедурам и большое количество пробелов имели смысл при использовании восьмисимвольных имен и строчных принтеров, но теперь у нас есть IDE, которая выполняет раскрашивание синтаксиса и позволяет переходить к определению метода или класса. Пиксели - вот ограничивающий фактор, поэтому я хочу, чтобы каждый из них внёс свой вклад в моё понимание кода. Я хочу, чтобы форматирование помогало мне понять код, но не более того.
Один из моих друзей непрограммистов однажды заметил, что код выглядит как поэзия. Я чувствую это, глядя на действительно хороший код: у каждой детали в тексте есть цель, и она находится в этом месте, чтобы помочь мне понять идею. К сожалению, программирование не имеет такого романтичного ореола, как написание стихов.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Steve Freeman
День триста шестнадцатый. #DesignPatterns
Паттерны проектирования
2. Паттерн «Шаблонный метод» (Template Method). Начало
Шаблонный метод — это один из классических паттернов, который и по сей день используется в каноническом виде во многих приложениях. Он позволяет четко определить «контракт» между базовым классом и потомками.
Назначение: шаблонный метод определяет основу алгоритма и позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуры. То есть каркас, в который наследники могут подставить реализации недостающих элементов.
Причины использования:
Необходимость определить порядок действий, которому потомки должны строго следовать. Вместо дублирования логики в потомках можно описать основные шаги алгоритма в базовом классе и отложить реализацию конкретных шагов до момента реализации в потомках.
Классическая диаграмма приведена на рисунке ниже:
- AbstractClass — определяет невиртуальный метод TemplateMethod, который вызывает внутри себя примитивные операции PrimitiveOperation1(), PrimitiveOperation2() и т. д.;
- ConcreteClass — реализует примитивные шаги алгоритма.
Варианты реализации в .NET
1. Локальный шаблонный метод на основе делегатов
В некоторых случаях использование классического варианта шаблонного метода с наследованием является слишком тяжеловесным решением, поэтому в таких случаях переменный шаг алгоритма задается делегатом. Это устраняет дублирование кода и довольно часто применяется в современных .NET-приложениях, например, в WCF-сервисах.
Подход на основе делегатов может не только применяться для определения локальных действий внутри класса, но и передаваться извне другому объекту в аргументах конструктора.
2. Шаблонный метод на основе методов расширения
Реализация шаблонного метода в виде метода расширения для базового класса позволяет разгрузить базовый класс, убрав лишнюю функциональность (например, не соответствующую основной абстракции класса). Кроме того, класс и его методы расширения могут находиться в разных пространствах имен. Это позволит клиентам самостоятельно решать, нужно ли им импортировать метод расширения или нет (следование принципу разделения интерфейса). Также существует возможность разных реализаций метода в зависимости от контекста и потребностей. Например, метод может иметь одну реализацию в серверной части кода, а другую — в клиентской.
У этого подхода есть и недостатки:
- Переменные шаги алгоритма должны определяться открытыми методами.
- Может потребоваться приведение к конкретным типам наследников, если не вся информация доступна через базовый класс.
Продолжение следует…
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 2.
Паттерны проектирования
2. Паттерн «Шаблонный метод» (Template Method). Начало
Шаблонный метод — это один из классических паттернов, который и по сей день используется в каноническом виде во многих приложениях. Он позволяет четко определить «контракт» между базовым классом и потомками.
Назначение: шаблонный метод определяет основу алгоритма и позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуры. То есть каркас, в который наследники могут подставить реализации недостающих элементов.
Причины использования:
Необходимость определить порядок действий, которому потомки должны строго следовать. Вместо дублирования логики в потомках можно описать основные шаги алгоритма в базовом классе и отложить реализацию конкретных шагов до момента реализации в потомках.
Классическая диаграмма приведена на рисунке ниже:
- AbstractClass — определяет невиртуальный метод TemplateMethod, который вызывает внутри себя примитивные операции PrimitiveOperation1(), PrimitiveOperation2() и т. д.;
- ConcreteClass — реализует примитивные шаги алгоритма.
Варианты реализации в .NET
1. Локальный шаблонный метод на основе делегатов
В некоторых случаях использование классического варианта шаблонного метода с наследованием является слишком тяжеловесным решением, поэтому в таких случаях переменный шаг алгоритма задается делегатом. Это устраняет дублирование кода и довольно часто применяется в современных .NET-приложениях, например, в WCF-сервисах.
Подход на основе делегатов может не только применяться для определения локальных действий внутри класса, но и передаваться извне другому объекту в аргументах конструктора.
2. Шаблонный метод на основе методов расширения
Реализация шаблонного метода в виде метода расширения для базового класса позволяет разгрузить базовый класс, убрав лишнюю функциональность (например, не соответствующую основной абстракции класса). Кроме того, класс и его методы расширения могут находиться в разных пространствах имен. Это позволит клиентам самостоятельно решать, нужно ли им импортировать метод расширения или нет (следование принципу разделения интерфейса). Также существует возможность разных реализаций метода в зависимости от контекста и потребностей. Например, метод может иметь одну реализацию в серверной части кода, а другую — в клиентской.
У этого подхода есть и недостатки:
- Переменные шаги алгоритма должны определяться открытыми методами.
- Может потребоваться приведение к конкретным типам наследников, если не вся информация доступна через базовый класс.
Продолжение следует…
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 2.
День триста семнадцатый. #DesignPatterns
Паттерны проектирования
2. Паттерн «Шаблонный метод» (Template Method). Окончание
Шаблонный метод и обеспечение тестируемости
Типичным подходом для обеспечения тестируемости является использование интерфейсов. Определённое поведение, завязанное на внешнее окружение, выделяется в отдельный интерфейс, и затем интерфейс передается текущему классу. Затем с помощью mock-объектов можно эмулировать внешнее окружение и покрыть класс тестами в изоляции.
Однако, если у вас есть готовый класс (в легаси коде), можно воспользоваться разновидностью паттерна «Шаблонный метод» под названием «Выделение и переопределение» (Extract and Override). Я уже упоминал этот приём в посте про методы рефакторинга унаследованного (легаси) кода.
Суть техники заключается в выделении изменчивого поведения в виртуальный метод, поведение которого затем можно переопределить в тестовой среде.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 2.
Паттерны проектирования
2. Паттерн «Шаблонный метод» (Template Method). Окончание
Шаблонный метод и обеспечение тестируемости
Типичным подходом для обеспечения тестируемости является использование интерфейсов. Определённое поведение, завязанное на внешнее окружение, выделяется в отдельный интерфейс, и затем интерфейс передается текущему классу. Затем с помощью mock-объектов можно эмулировать внешнее окружение и покрыть класс тестами в изоляции.
Однако, если у вас есть готовый класс (в легаси коде), можно воспользоваться разновидностью паттерна «Шаблонный метод» под названием «Выделение и переопределение» (Extract and Override). Я уже упоминал этот приём в посте про методы рефакторинга унаследованного (легаси) кода.
Суть техники заключается в выделении изменчивого поведения в виртуальный метод, поведение которого затем можно переопределить в тестовой среде.
public class PersonRepo {Далее можно тестировать остальные методы класса
protected virtual IEnumerable<Person> GetPeople() {
// получение данных из БД
}
// остальные методы
}
// В тестах
class FakePersonRepo : PersonRepo {
// создаём mock-объект в personData
// и наполняем его «данными»
private readonly List<Person> personData = …;
protected override IEnumerable<Person> GetPeople() {
return personData;
}
}
PersonRepo
, получающие данные от GetPeople
, используя объект FakePersonRepo
. Однако, стоит иметь в виду, что даже при наличии тестов всей остальной функциональности через FakePersonRepo
, класс PersonRepo
не может считаться полностью протестированным. Сам исходный метод GetPeople
также может приводить к ошибкам.Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 2.
День триста восемнадцатый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
14. Обзоры Кода
Вы должны делать обзоры кода. Зачем? Потому что они повышают качество кода и снижают процент ошибок. Но не обязательно по тем причинам, о которых вы могли бы подумать.
Многие программисты не любят обзоры кода, из-за негативного опыта в прошлом. Я встречал организации, которые требовали, чтобы весь код проходил официальную проверку перед развёртыванием. Часто этот обзор выполнял архитектор или ведущий разработчик, и эту практику можно охарактеризовать как анализ архитектором всего на свете. Это было прописано в руководстве по процессу разработки ПО в компании, поэтому программисты должны были следовать ему.
Может быть, некоторым организацям нужен такой жесткий и формальный процесс, но большинству нет. В большинстве организаций такой подход контрпродуктивен. Рецензируемые могут чувствовать себя как на комиссии по условно-досрочному освобождению. Рецензентам требуется время, как на чтение кода, так и на то, чтобы быть в курсе всех деталей системы. Они могут быстро оказаться узким местом всего процесса, и смысл такого обзора быстро теряется.
Вместо того, чтобы просто исправлять ошибки в коде, целью обзоров кода должен быть обмен знаниями и установление общих правил кодирования. Совместное использование вашего кода с другими программистами приводит к коллективному владению кодом. Пусть случайный член команды пройдется по коду с остальной командой. Вместо того, чтобы искать ошибки, лучше просмотреть код, пытаясь изучить и понять его.
Будьте вежливы при проверке кода. Убедитесь, что ваши комментарии конструктивные, а не язвительные. Введите разные роли для обзорного собрания, чтобы избежать влияния субординации среди членов команды на проверку кода. Например, один рецензент может сосредоточиться на документации, другой - на исключениях, а третий - на функциональности. Такой подход помогает распределить бремя проверки между членами команды.
Проводите регулярные обзоры кода каждую неделю. Потратьте пару часов на обзорную встречу. Меняйте рецензируемого каждый раз просто по очереди. Не забывайте менять роли между членами команды на каждой обзорной встрече. Вовлекайте новичков. Они могут быть неопытными, но у них свежие университетские знания, и они могут предложить иную точку зрения. Привлекайте экспертов из-за их опыта и знаний. Они будут выявлять подверженный ошибкам код быстрее и с большей точностью. Обзор кода будет проходить легче, если у команды есть соглашения по кодированию, которые проверяются автоматически. Таким образом, форматирование кода никогда не будет обсуждаться на обзорах.
Пожалуй, самый важный фактор успеха – делать обзоры кода весёлыми. Главные в обзорах – люди, а не код. Если обзор будет болезненным или скучным, мотивировать кого-то будет сложно. Сделайте его неформальным, основной целью которого является обмен знаниями между членами команды. Оставьте саркастические комментарии снаружи, и вместо этого принесите туда кофе и печеньки.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Mattias Karlsson
97 Вещей, Которые Должен Знать Каждый Программист
14. Обзоры Кода
Вы должны делать обзоры кода. Зачем? Потому что они повышают качество кода и снижают процент ошибок. Но не обязательно по тем причинам, о которых вы могли бы подумать.
Многие программисты не любят обзоры кода, из-за негативного опыта в прошлом. Я встречал организации, которые требовали, чтобы весь код проходил официальную проверку перед развёртыванием. Часто этот обзор выполнял архитектор или ведущий разработчик, и эту практику можно охарактеризовать как анализ архитектором всего на свете. Это было прописано в руководстве по процессу разработки ПО в компании, поэтому программисты должны были следовать ему.
Может быть, некоторым организацям нужен такой жесткий и формальный процесс, но большинству нет. В большинстве организаций такой подход контрпродуктивен. Рецензируемые могут чувствовать себя как на комиссии по условно-досрочному освобождению. Рецензентам требуется время, как на чтение кода, так и на то, чтобы быть в курсе всех деталей системы. Они могут быстро оказаться узким местом всего процесса, и смысл такого обзора быстро теряется.
Вместо того, чтобы просто исправлять ошибки в коде, целью обзоров кода должен быть обмен знаниями и установление общих правил кодирования. Совместное использование вашего кода с другими программистами приводит к коллективному владению кодом. Пусть случайный член команды пройдется по коду с остальной командой. Вместо того, чтобы искать ошибки, лучше просмотреть код, пытаясь изучить и понять его.
Будьте вежливы при проверке кода. Убедитесь, что ваши комментарии конструктивные, а не язвительные. Введите разные роли для обзорного собрания, чтобы избежать влияния субординации среди членов команды на проверку кода. Например, один рецензент может сосредоточиться на документации, другой - на исключениях, а третий - на функциональности. Такой подход помогает распределить бремя проверки между членами команды.
Проводите регулярные обзоры кода каждую неделю. Потратьте пару часов на обзорную встречу. Меняйте рецензируемого каждый раз просто по очереди. Не забывайте менять роли между членами команды на каждой обзорной встрече. Вовлекайте новичков. Они могут быть неопытными, но у них свежие университетские знания, и они могут предложить иную точку зрения. Привлекайте экспертов из-за их опыта и знаний. Они будут выявлять подверженный ошибкам код быстрее и с большей точностью. Обзор кода будет проходить легче, если у команды есть соглашения по кодированию, которые проверяются автоматически. Таким образом, форматирование кода никогда не будет обсуждаться на обзорах.
Пожалуй, самый важный фактор успеха – делать обзоры кода весёлыми. Главные в обзорах – люди, а не код. Если обзор будет болезненным или скучным, мотивировать кого-то будет сложно. Сделайте его неформальным, основной целью которого является обмен знаниями между членами команды. Оставьте саркастические комментарии снаружи, и вместо этого принесите туда кофе и печеньки.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Mattias Karlsson
День триста девятнадцатый. #DesignPatterns
Паттерны проектирования
3. Паттерн «Посредник» (Mediator).
Посредник — это один из самых распространённых паттернов проектирования. Они десятками используются в любом приложении, хотя в именах классов это практически никогда не отражается.
Назначение: определяет объект, инкапсулирующий способ взаимодействия множества объектов. Другими словами, он связывает несколько независимых классов между собой, избавляя классы от необходимости ссылаться друг на друга и позволяя тем самым их независимо изменять и анализировать.
Причины использования:
Паттерн «Посредник» идеально подходит для объединения нескольких автономных классов или компонентов. Каждый раз, когда вы задаётесь вопросом, как изолировать классы А и Б, чтобы они могли жить независимо, подумайте об использовании посредника. В этом случае посредник будет содержать всю логику взаимодействия классов. Кроме того, посредник выступает барьером, который гасит изменения в одной части системы, не давая им распространяться на другие части. Любые изменения в одном компоненте приведут к модификации его и, возможно, посредника, но не потребуют изменений в другом компоненте или его клиентах.
Замечание: Не нужно разделять с помощью посредника тесно связанные вещи. Если классы всегда изменяются совместно, то, возможно, они должны знать друг о друге. Наличие посредника лишь усложнит внесение изменений: вместо изменения двух классов придется изменять три.
Классическая диаграмма приведена в верхней части рисунка ниже:
-
-
Обычно взаимодействующие компоненты не содержат общего предка (если не считать класса
Явный и неявный посредник
В классической реализации паттерна независимые классы не знают друг о друге, но знают о существовании посредника и всё взаимодействие происходит через него явным образом. Такой подход применяется в паттернах «Поставщик/Потребитель» (Producer/Consumer), «Агрегатор событий» (Event Aggregator) или в других случаях, когда классы знают о существовании общей шины взаимодействия. В то же время классы низкого уровня могут и не знать о существовании посредника. Это делает их более автономными, а дизайн — более естественным. Логика взаимодействия в этом случае содержится в посреднике. См. диаграмму в нижней части рисунка ниже.
Архитектурные посредники
Паттерн «Посредник» может применяться на разных уровнях приложения. Существуют классы-посредники, компоненты-посредники, есть целые модули или слои приложения, выполняющие эту роль.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 3.
Паттерны проектирования
3. Паттерн «Посредник» (Mediator).
Посредник — это один из самых распространённых паттернов проектирования. Они десятками используются в любом приложении, хотя в именах классов это практически никогда не отражается.
Назначение: определяет объект, инкапсулирующий способ взаимодействия множества объектов. Другими словами, он связывает несколько независимых классов между собой, избавляя классы от необходимости ссылаться друг на друга и позволяя тем самым их независимо изменять и анализировать.
Причины использования:
Паттерн «Посредник» идеально подходит для объединения нескольких автономных классов или компонентов. Каждый раз, когда вы задаётесь вопросом, как изолировать классы А и Б, чтобы они могли жить независимо, подумайте об использовании посредника. В этом случае посредник будет содержать всю логику взаимодействия классов. Кроме того, посредник выступает барьером, который гасит изменения в одной части системы, не давая им распространяться на другие части. Любые изменения в одном компоненте приведут к модификации его и, возможно, посредника, но не потребуют изменений в другом компоненте или его клиентах.
Замечание: Не нужно разделять с помощью посредника тесно связанные вещи. Если классы всегда изменяются совместно, то, возможно, они должны знать друг о друге. Наличие посредника лишь усложнит внесение изменений: вместо изменения двух классов придется изменять три.
Классическая диаграмма приведена в верхней части рисунка ниже:
-
Mediator
— определяет интерфейс посредника. На практике базовый класс посредника выделяется редко, поэтому класс Mediator
обычно содержит всю логику взаимодействия;-
ConcreteCollegue1
, ConcreteCollegue2
— классы одного уровня абстракции, которые взаимодействуют друг с другом косвенным образом через посредника.Обычно взаимодействующие компоненты не содержат общего предка (если не считать класса
object
) и совсем не обязательно знают о классе-посреднике. Иерархия посредников также применяется довольно редко.Явный и неявный посредник
В классической реализации паттерна независимые классы не знают друг о друге, но знают о существовании посредника и всё взаимодействие происходит через него явным образом. Такой подход применяется в паттернах «Поставщик/Потребитель» (Producer/Consumer), «Агрегатор событий» (Event Aggregator) или в других случаях, когда классы знают о существовании общей шины взаимодействия. В то же время классы низкого уровня могут и не знать о существовании посредника. Это делает их более автономными, а дизайн — более естественным. Логика взаимодействия в этом случае содержится в посреднике. См. диаграмму в нижней части рисунка ниже.
Архитектурные посредники
Паттерн «Посредник» может применяться на разных уровнях приложения. Существуют классы-посредники, компоненты-посредники, есть целые модули или слои приложения, выполняющие эту роль.
Источник: Тепляков С. "Паттерны проектирования на платформе .NET." — СПб.: Питер, 2015. Глава 3.
День триста двадцатый. #ЧтоНовенького
Улучшения в Поиске по Файлам
Поиск по Файлам (Find in Files) - это одна из наиболее часто используемых функций в Visual Studio. В Microsoft решили переписать её с нуля. Улучшенный функционал будет доступен в Visual Studio 2019 версии 16.5 Preview 1 в быстром поиске (Ctrl+Q), а также в инструментах «Найти в файлах» (Ctrl+Shift+F) и «Заменить в файлах» (Ctrl+Shift+H). Поиск полностью реализован на C#, что позволило избежать ненужных вызовов, снизило потребление памяти и повысило производительность. См. скриншот ниже.
Указание путей
В поле «Поиск в» (Look in) появилась новая опция «Текущий Каталог» (Current Directory) для поиска в папке, содержащей открытый в данный момент документ. Также можно включить прочие файлы (не являющиеся частью решения). В поле «Типы файлов» (File types) теперь можно исключать файлы. Любой путь или тип файла с префиксом «!» будет исключён из поиска.
Множественный поиск
Возможность сохранять результаты предыдущих поисков уже была в Visual Studio и продолжает поддерживаться с помощью кнопки «Сохранить результаты» (Keep Results). В настоящее время эта функция поддерживает до пяти результатов поиска. Если у вас уже есть пять результатов поиска, при следующем поиске будет повторно использована самая старая вкладка результатов. Также кнопка «Сохранить результаты» доступна для функции «Найти все ссылки» (Find All References).
Конструктор регулярных выражений
В версии 16.5 Preview 2 будет доступен конструктор регулярных выражений. Флажок «Использовать регулярные выражения» (Use regular expressions) позволит вам указать регулярное выражение в качестве шаблона для совпадения (например, для поиска многострочных выражений). Также будет доступен конструктор регулярных выражений, который выдаст несколько примеров и ссылку на документацию.
Источник: https://devblogs.microsoft.com/visualstudio/modernizing-find-in-files/
Улучшения в Поиске по Файлам
Поиск по Файлам (Find in Files) - это одна из наиболее часто используемых функций в Visual Studio. В Microsoft решили переписать её с нуля. Улучшенный функционал будет доступен в Visual Studio 2019 версии 16.5 Preview 1 в быстром поиске (Ctrl+Q), а также в инструментах «Найти в файлах» (Ctrl+Shift+F) и «Заменить в файлах» (Ctrl+Shift+H). Поиск полностью реализован на C#, что позволило избежать ненужных вызовов, снизило потребление памяти и повысило производительность. См. скриншот ниже.
Указание путей
В поле «Поиск в» (Look in) появилась новая опция «Текущий Каталог» (Current Directory) для поиска в папке, содержащей открытый в данный момент документ. Также можно включить прочие файлы (не являющиеся частью решения). В поле «Типы файлов» (File types) теперь можно исключать файлы. Любой путь или тип файла с префиксом «!» будет исключён из поиска.
Множественный поиск
Возможность сохранять результаты предыдущих поисков уже была в Visual Studio и продолжает поддерживаться с помощью кнопки «Сохранить результаты» (Keep Results). В настоящее время эта функция поддерживает до пяти результатов поиска. Если у вас уже есть пять результатов поиска, при следующем поиске будет повторно использована самая старая вкладка результатов. Также кнопка «Сохранить результаты» доступна для функции «Найти все ссылки» (Find All References).
Конструктор регулярных выражений
В версии 16.5 Preview 2 будет доступен конструктор регулярных выражений. Флажок «Использовать регулярные выражения» (Use regular expressions) позволит вам указать регулярное выражение в качестве шаблона для совпадения (например, для поиска многострочных выражений). Также будет доступен конструктор регулярных выражений, который выдаст несколько примеров и ссылку на документацию.
Источник: https://devblogs.microsoft.com/visualstudio/modernizing-find-in-files/