• Принцип единственной ответственности: фундамент декомпозиции


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


      Определение


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


      Пример


      Lazy<T> — обертка для объекта, чье создание откладывается до первого обращения к нему.


      Антипример


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


      Еще антипример


      Локатор сервисов — позволяет получить доступ к любому сервису приложения. Это описание без исчерпывающего списка сервисов заведомо неполное.


      Назначение


      Упрощение создания, анализа и модификации программных систем.

      Читать дальше →
    • Задача о премировании: почувствуй себя менеджером

        1. Менеджмент некой компании уделяет большое внимание мотивации сотрудников.
        2. Для поощрения высоких результатов было решено выдавать премии командам по результатам соблюдения сроков и бюджетов проектов.
        3. Решение было доведено до сотрудников.
        4. Одна из команд занималась доработками зрелого и стабильного проекта, успешно выполнила все условия, получила премию.
        5. Другой команде достался новый сложный проект, люди работали над ним с неподдельным энтузиазмом.
        6. К сожалению, и запланированные сроки, и бюджет оказались превышены в разы.
        7. Получившийся в результате продукт дал компании рекордную прибыль.

        Если вы менеджер в этой компании, то станете ли премировать вторую команду и почему?

      • Критерии простоты

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


          Первый критерий


          Особенности мозга человека таковы, что он плохо хранит и отличает более 7-9 элементов в одном списке при оптимальном их количестве 1-3.


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

          Читать дальше →
        • Удобное создание Composition Root с помощью Autofac

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


            Важнейшей частью его реализации является Composition Root — точка сборки, обычно выполняемая по паттерну Register-Resolve-Release. Для хорошо читаемого, компактного и выразительного описания Composition Root обычно используется такой инструмент как DI-контейнер, при наличии выбора я предпочитаю использовать Autofac.


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

            Читать дальше →
          • Сверхлегкая BDD: малая механизация автономных тестов

              Тема автономного тестирования давняя, почтенная, разобранная до косточек. Кажется, что после отличной книги Роя Ошероува и сказать особо нечего. Но на мой взгляд есть некоторая несбалансированность доступных инструментов. С одной стороны монстры вроде SpecFlow, с огромным оверхедом ради возможности писать тесты-спецификации на квази-естественном языке, с другой — челябинская суровость фреймворков старой школы вроде NUnit. Чего не хватает? Инструмента для лаконичной, выразительной, легко читаемой записи тестов, по удобству и ортогональности аналогичного библиотекам для создания подделок, таких как FakeItEasy, или проверки утверждений вроде FluentAssertion.


              Их есть у меня
            • Наследование реализаций: закопайте стюардессу

                Ключевое противоречие ООП


                Как известно, классическое ООП покоится на трех китах:


                1. Инкапсуляция
                2. Наследование
                3. Полиморфизм

                Классическая же реализация по умолчанию:


                1. Инкапсуляция — публичные и приватные члены класса
                2. Наследование — реализация функционала за счет расширения одного класса-предка, защищенные члены класса.
                3. Полиморфизм — виртуальные методы класса-предка.

                Но еще в 1986 году была обозначена серьезнейшая проблема, кратко формулируемая так:


                Наследование ломает инкапсуляцию

                Как такое может быть?
              • Null, великий и ужасный

                  Ошибка дизайна


                  Именно так и никак иначе: null в C# — однозначно ошибочное решение, бездумно скопированное из более ранних языков.


                  1. Самое страшное: в качестве значения любого ссылочного типа может использоваться универсальный предатель — null, на которого никак не среагирует компилятор. Зато во время исполнения легко получить нож в спину — NullReferenceException. Обрабатывать это исключение бесполезно: оно означает безусловную ошибку в коде.
                  2. Перец на рану: сбой (NRE при попытке разыменования) может находится очень далеко от дефекта (использование null там, где ждут полноценный объект).
                  3. Упитанный пушной зверек: null неизлечим — никакие будущие нововведения в платформе и языке не избавят нас от прокаженного унаследованного кода, который физически невозможно перестать использовать.

                  Этот ящик Пандоры был открыт еще при создании языка ALGOL W великим Хоаром, который позднее назвал собственную идею ошибкой на миллиард долларов.

                  На самом деле все не так плохо
                • Disposable без границ


                    В своей предыдущей статье я рассказал, как объект может просто и надежно нести ответственность за свои ресурсы.

                    Но есть множество вариантов владения, которые не являются персональной ответственностью объекта:
                    • Ресурсы, которыми владеют зависимости. При использовании Dependency Injection объект класса не только не должен отвечать за жизненный цикл своих зависимостей, он просто физически не может это делать: зависимость может разделяться между несколькими клиентами, зависимость может реализовать IDisposable, а может не реализовать, но при этом у нее могут быть свои зависимости и так далее. Кстати, этот довод сразу ставит крест на любых бизнес-интерфейсах, расширяющих IDisposable: такой интерфейс требует от своих реализаций невозможного — отвечать за себя и за того парня (зависимости)
                    • Ресурсы, которые при некоторых условиях не надо очищать. Это, к примеру, дурная привычка StreamReader закрывать нижележащий Stream при вызове Dispose
                    • Ресурсы, которые являются внешними по отношению к зависимости, но требуются клиенту в процессе ее использования. Самый простой пример — подписка на события объекта при присвоении его свойству.

                    Что же может здесь помочь?
                  • Самая простая и надежная реализация шаблона проектирования Dispose


                      Казалось бы, данный шаблон не просто прост, а очень прост, подробно разобран не в одной известной книге.

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

                      Хочу поделиться своим способом реализации, который основан на минимизации изобретения велосипедов, максимальном уменьшении количества кода и увеличении его выразительности и прозрачности.
                      Читать дальше →
                    • Заповеди молодого разработчика Delphi

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

                        1 Коротко и неясно


                        1. ЧИТАЙ КОД!
                        2. Пиши код, который удобно читать всем остальным
                        3. Пиши в комментарии не ЧТО делает код, а ЗАЧЕМ
                        4. Предупреждения и подсказки опаснее ошибок компиляции — проект собирается без их устранения

                        2 Цикл разработки


                        1. Постановка задачи руководителем
                        2. Выработка решения
                        3. Рецензирование решения
                        4. Реализация решения
                        5. Рецензирование кода
                        6. Размещение в системе контроля версий

                        Читать дальше →
                      • Об «очевидном» и полезном или создание и уничтожение объектов Delphi

                          Когда читаешь о той или иной реализации механизмов ООП, то весьма забавно видеть, как та или иная конкретная особенность конкретного языка или библиотеки называется «очевидной». Особенно выделяется в этом отношении описание ООП в C++, в котором по факту реализация одна из самых непрозрачных и запутанных.
                          Так вот, я ничего не буду писать про очевидность, а расскажу про способ облегчить себе жизнь в критических точках жизненного цикла объектов, используя не «очевидные», но весьма полезные особенности реализации ООП в Delphi.

                          Читать дальше →