Заметки по книге «Философия разработки ПО»


    Возможно, вы понимаете как писать хороший код, как придерживаться хорошего дизайна. Но структурировать эти знания не получается. Книга Джона Оустерхаута “A philosophy of software design” может помочь исправить это.


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


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


    О чем книга


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


    Он выделяет 2 пути борьбы со сложностью:


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

    Далее я буду использовать термин “Модуль”. Модулем может быть класс, функция, внешнее API и т.д. В том же значении этот термин использует автор книги.


    Что такое сложность


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


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

    Главные причины сложности:


    1. Большое количество зависимостей
    2. Неочевидные вещи в коде:
      • Общие названия переменных
      • несколько целей у переменных
      • плохая документация
      • неочевидные зависимости (или утечка зависимостей)

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


    По этой причине автор выделяет 2 подхода программирования, он называет их:


    • тактическое
    • стратегическое

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


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


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


    1. проактивности — мы учитываем изменения и потребности в будущем и думаем о документации и понятности кода.
    2. реактивности — исправляем очевидные проблемы в старом коде, а не только пишем новый.

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


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



    Автор предлагает тратить 20% своего времени на исправление старого кода, иначе сложность будет копиться, его понимание будет занимать много времени.


    Модули должны быть глубокими


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


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


    Интерфейс может быть:


    1. Формальный — это сигнатура, публичные методы, свойства класса и т.д.
    2. Неформальный — комментарии к модулю, нюансы работы.

    Простота кода сильно зависит от абстракции — это упрощение понимания модуля, за счет сокрытия не важной информации. У абстракции могут быть 2 проблемы:


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

    Если ваш модуль очень маленький, то скорее всего интерфейс этого модуля больше, чем его функционал.


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


    Утечка информации


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


    • Интерфейс
    • Через back-door. Знания не описанные в интерфейсе, например, когда о формате файла знают несколько классов, хотя они важны только для одного. Такая утечка гораздо хуже утечки через интерфейс.
      При обнаружении утечки, следует ответить на вопрос “Как изменить модули, чтобы знание влияло только на 1 класс?”. Возможно модули стоит объединить в один или вынести информацию наружу и обернуть её в более высокоуровневый модуль.

    Временна́я декомпозиция


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


    Общецелевые модули


    Это модули с заделом на будущее, с возможностью использовать где-то ещё.


    Преимущество таких модулей в том, что они не сильно привязаны к текущей задаче и склоняют вас делать интерфейс проще и универсальней.


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


    Вопросы, которые помогут создать общецелевой интерфейс:


    1. Какой самый простой интерфейс покроет все мои нужды?
    2. В скольких ситуациях этот метод будет использован? Если только в одной, то скорее всего вы делаете интерфейс неправильно.
    3. Насколько легко использовать интерфейс в данный момент?

    Разные слои, разные абстракции


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


    Какие проблемы на разных слоях абстракции могут возникать:


    • Прокинутые методы — когда результат выполнения метода просто прокидывается на более высокий уровень, без каких либо обработок. Выглядит это вот так:

    public function foo() {
      return this->bar();
    }

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


    • Прокинутые переменные — когда переменные прокидываются вглубь к более низкоуровневым классам без обработок. Выглядит это так:

    public function foo(SomeClass variable) {
      $this->bar(variable);
    }

    Проблема здесь в том, что зависимость никак не используется в промежуточных слоях. К тому же, усложняется интерфейс каждого метода, через который прокидывается переменная, потому что мы просто принимаем аргумент и ничего с ним не делаем, а только передаем дальше.
    Лучшее решения для такой ситуации — это использовать DI контейнер. Это не идеальное решение, оно может привести к неочевидным зависимостям, поэтому его следует использовать осторожно. Для того чтобы избежать многих проблем, переменные в контейнере можно делать неизменяемыми (immutable).


    Старайтесь не перекладывать ответственность на верхний уровень


    Не перекладываете ответственность на пользователей данного модуля насколько это возможно. Решайте как можно больше проблем внутри. (Пользователь — это не только человек, но и высокоуровневый модуль, который использует модуль).
    Например, мы можем дать возможность настроить параметры модуля снаружи. Но может оказаться такая ситуация, когда параметры окажутся несовместимы, и эту проблему придется решать пользователю. Сначала стоит подумать, возможно ли определить эти параметры автоматически внутри.
    Модуль должен выполнять свои обязанности до конца. В конце разработки модуля следует сделать дополнительные усилия и подумать, есть ли возможность скрыть лишние знания от пользователя.


    Разделить или объединить


    Для улучшения дизайна кода, часто, необходимо либо разделить модуль на несколько, либо наоборот объединить с другим. Чтобы понять, стоит ли объединять, рассмотрим признаки для объединения:


    1. Модули обращаются к общей информации.
    2. Используются совместно. Один нельзя использовать без другого.
    3. Решают общую задачу.
    4. Тяжело понять одну часть кода без другой.
    5. Если после объединения интерфейс упростится.

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


    Специализированный код — это та часть кода, которая очевидно нужна только в конкретной задаче.


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


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


    Работа с исключениями


    Здесь под исключением понимаются не только exception которые выкидываются в коде. Это любые ситуации, которые вызывают необычное поведение системы. Когда что-то происходит не так, как задумывалось.


    Исключения добавляют сложность в интерфейсе потому что:


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

    Исключение — это тоже часть интерфейса. Чем больше исключений у интерфейса, тем он сложнее.


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


    Способы скрыть исключение:


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

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


    Проектируй дважды


    Не стоит реализовывать первую пришедшую идею. Стоит рассмотреть несколько вариантов. Это позволит сэкономить время на переписывании кода.


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


    Стоит подумать о том:


    • какой из них проще
    • является ли вариант более переиспользуемым
    • будет ли реализация более производительной

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


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


    Зачем писать комментарии


    Для начала рассмотрим популярные аргументы того, почему не стоит писать код и опровергнем их:


    1. Хороший код — самодокументируемый. Этот подход ошибочный, потому что:
      • В коде нельзя дать высокоуровневое описание того, что делает метод или причину того, или иного решения в реализации.
      • Если пытаться упростить реализацию для легкого понимания, то придется разбивать модуль так, что это может усложнить его интерфейс.
      • Если пользователь читает всю реализацию, то ему приходится читать не только важную информацию, но и не важную, из-за чего теряется смысл в абстракции.
      • Некоторые нюансы передаваемых аргументов и свойств нельзя описать в коде.
    2. Нет времени писать комментарии. Отсутствие комментариев вынудит потратить дополнительное время на понимание кода в будущем, из-за чего оно будет потрачено в ещё большем объеме.
    3. Комментарии устаревают и вводят в заблуждение. На самом деле поддержка правильно написанных комментариев не занимает много времени. Это потребуется только если происходят большие изменения в коде.

    Главная идея в написании комментариев — записать важные мысли разработчика, которые нельзя описать в коде. Это позволит избежать ошибок, на которые попадется разработчик после него. Будут понятны намерения автора. Также это понизит когнитивную сложность.


    Как писать комментарии


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


    Я просто перечислю ряд важных советов которые дает автор.


    Хороший прием — использовать другие слова в комментарии чем в коде.


    Описывая переменные, думайте существительными, а не глаголами.


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


    Цель комментариев в реализации — дать понимание, что делает код (не как он это делает). Они нужны только для больших и сложных реализаций. Для простой реализации комментарий не нужен. Если разработчик поймет, что делает код, ему будет гораздо легче понять сам код.
    Также бывает так, что общая логика размазана по нескольким модулям, например отправка и получение http запроса. Комментировать это трудно, поскольку дублировать комментарии нежелательно.


    Для таких случаев лучше завести общий файл с заметками, и писать комментарий туда. Но будет одна проблема — комментарии находятся далеко от кода. При изменении кода, будет сложнее поддерживать комментарии.


    Комментарии лучше писать вначале


    Какие выгоды это дает:


    1. В процессе написания кода вы можете ориентироваться на написанные комментарии.
    2. Комментарии становятся инструментом проектирования дизайна кода. Если вы замечаете, что для интерфейса слишком длинный комментарий, скорее всего ваш интерфейс слишком сложный и лучше придумать что-то попроще.
    3. Раннее комментирование позволяет сформировать хороший дизайн и абстракцию ещё до написания кода.

    Именование переменных


    Именование — это одна из форм документирования.
    Правильное именование позволяет:


    • легче находить ошибки
    • уменьшает сложность
    • уменьшает необходимость в комментариях

    Имя должно быть:


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

    Консистентность кода


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


    • наименованиях
    • стиле кода
    • интерфейсе
    • в паттернах (например MVC улучшает консистентность)

    Консистентность дает:


    • Быстрое понимание того как работает код, если вы уже знакомы с похожими местами.
    • Уменьшает ошибки. Если похожие места сделаны по разному, то разработчику легче ошибиться, подумав, что здесь также.

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


    • Документации
    • Линтеров и других инструментов, не позволяющих пушить код, не соответствующий принятым стандартам.
    • При изменении кода смотреть, как сделано сейчас.

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


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

    Если ответ на любой вопрос “да”, то тогда можно нарушить консистентность.


    Тренды в разработке ПО


    Наследование в ООП


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


    Agile


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


    Unit тесты


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


    TDD


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


    Паттерны


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


    Геттеры и сеттеры


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


    Заключение от меня


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


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

    Комментарии 38

      +2
      Писать более понятный код. За счет хороших комментариев, правильного именования переменных, простого интерфейса и реализации.


      Это вот все имеет мало смысла начиная с определенного уровня сложности. Сложность, в том числе, возникает, когда есть много вариантов, веток, связей, взаимодействий между компонентами, и т.п. В динамике, в том числе.

      Хорошие комментарии и правильное именование возникновению такого рода сложности не мешают ни сколечки, потому что они описывают лишь статический аспект кода. А «простой интерфейс и реализация» — это вообще ни о чем, на этот глобус можно любую сову натянуть. Это совет из категории «чтобы снизить сложность, пишите проще». Ага, а то мы сами не знали?

      Реальная же борьба со сложностью лежит скорее в другой плоскости — например, в строгой типизации, чтобы нельзя было (лучше с проверкой во время компиляции) вызвать один компонент из другого неправильным способом. Иммутабельность — чтобы нельзя было изменить значение (в том числе из другого потока) непредсказуемым образом. Чистые функции, которые помимо прочего дают нам уверенность, что некоторые преобразования кода можно проделать, и он останется валидным.
        +1
        Человек честно пишет:
        Она позволила структурировать знания, накопленные мною за 3 года работы разработчиком
        думаю, еще лет через 7 он напишет уже более адекватную книгу :-)
          +2

          Но неопытным его тоже не назовешь. Оустерхаут — разработчик скриптового языка Tcl. Может, на самом деле не 3 года, а 30? К моменту написания книги ему было 63 года.

            0
            3 года это мой опыт, а не автора книги)
              0

              Точно, я и не заметил :-)

            0
            Не, ну читать книги можно и с нулевым опытом. Другое дело, что 3 года возможно маловато, чтобы понять для себя все полезное, что в произвольной книге есть — потому что опыт нужен и для понимания того, что на самом деле важно.
            0
            В том то и смысл, чтобы искать решение, при котором связей между модулями будет меньше. Иначе придется поддерживать больше кода, при изменении кода в одной части, исправлять другую.
            Простой интерфейс и реализация — это не бред. Сам часто встречаю в пулл реквестах слишком сложный интерфейс, когда например передают лишние данные в метод. Или приходится всегда вызывать несколько методов по очереди у одного объекта, хотя можно было сделать только один.
            С реализацией тоже самое. Например, бывает иногда добавляют проверки, которые никогда не сработают. И зачем тогда они нужны, в них придется больше вникать при попытке понять реализацию и возникнет больше вопросов, почему это здесь.
            На самом деле да, нужно просто писать проще. Очень банально, но этого и не хватает для хорошего дизайна. А уже как писать проще, об этом книга.
              +1
              >Он выделяет 2 пути борьбы со сложностью:
              Ну выже сами выделили вот это. Я предполагаю, что в хорошей книге эти два пункта будут раскрыты далее и будут реальными путями борьбы. А они не — во всяком случае я написал, почему первый не.

              >Простой интерфейс и реализация — это не бред.
              Нет конечно. Но дело в том, что этот совет неконструктивен, именно потому, что не определяет, что такое сложный. Не показывает, как измерять. А то что нельзя померять — нельзя ни повысить толком, ни понизить.

              >А уже как писать проще, об этом книга.
              Ну то есть дальше все же раскрыто, что такое проще?
                0
                Проще — значит менее сложно. Я в этих заметках описал что значит сложно через то, как она проявляется и по какой причине возникает.
                Проще, значит разработчику легче работать с этим кодов в будущем, легче его понять, меньше и быстрее переделывать и меньше ошибок возникнет в процессе использования модулей. Автор приводит много примеров разных ситуаций когда можно сделать проще.
                  +1
                  >Автор приводит много примеров
                  Ну возможно. Я не утверждаю, что книга плохая, я лишь говорю о том, что вы (с автором или сами) этот вопрос раскрыли на мой взгляд слегка не с той стороны. И неполно. Опять же — я сужу по обзору, а не по тексту книги.

                  Это не значит, что все прям плохо — мой первый коммент был скорее дополнением, попыткой взглянуть на сложность с другой стороны.
              0
              -
              0
              Что-то мне кажется, что слово «философия» в названии добавлено исключительно для хайпа (и, скорее всего, даже не автором). Что бы претендовать на такое название в книге должен быть хотя бы намек на систему знаний, а судя даже из минимальной рецензии ее нет.
              И критиковать надо прямо с базового понятия. Непонятно с чего автор считает понятие «сложность» присущем коду (кстати, код, автор, тоже не определил, но тут хоть более-менее понятно, что речь про что-то привычное ООПшное, а не, например, SQL). Но это явная ошибка, сложность тут однозначно выступает как проблема восприятия исходников человеком, а это вынуждает говорить не только о коде, а еще и о самих программистах. Дальше больше. Не определив метрику «сложности» (и, похоже, даже не попытавшись) автор пытается давать советы, как ее уменьшить. А уж после этого неизбежно возникнут вопросы, с чего бы мне следовать совету (к примеру, про комментарии), если я считаю, что это наоборот, усложняет код (ага, привет, потерянная часть «человек»)?
              В общем надо было назвать книгу «Бест практис» и не выдумывать про сложность и пытаться сделать умное лицо.
                +1
                Непонятно с чего автор считает понятие «сложность» присущем коду

                2.1 Complexity defined
                For the purposes of this book, I define “complexity” in a practical way. Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.

                вся глава 2.1 на эту тему
                  +1
                  Сложность это все, что мешает понимать и модифицировать. Раз «все», значит стройка за окном тоже мешает? Или недосып? А отсутствие профильного образования? И ведь любая из этих причин может оказать гораздо большее влияние, чем непосредственно архитектура кода. И я не придираюсь, без осознания того, что же такое «сложность» нельзя ее измерить, а следовательно и сравнивать два варианта, можно только какими-то субъективными ощущениями оперировать, типа так лучше, чем эдак.

                  Книга может и хорошая, не знаю. Но явно не более чем сборник советов.

                    0
                    С практической точки зрения, чтобы уменьшить сложно не нужно её измерять. Достаточно понимать, что один подход в решении проще другого. У сложности есть множество граней, их автор и показывает. В чем то код может быть сложнее, а в чем то проще. Меньше зависимостей — это проще, поэтому если я могу их уменьшить, значит я уменьшаю сложность.
                    Насчет стройки и недосыпа, автор в книге же четко написал
                    Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.

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

                      Так я и говорю, сборник советов.

                      Ну да, слона-то
                      related to the structure of a software system
                      я и не приметил :) Но даже в этом случае выбросив человека автор неявно подразумевает наличие у программиста определенных знаний и навыков (наверняка близких к тем, которыми он сам обладает). А это на сложность понимания и модификации очень сильно влияет, опять вспомню пример про комментарии.
                        0
                        Да, здесь достаточно много советов, но это не говорит о том, что это только сборник советов. Вы указали что это это
                        не более чем сборник советов
                        На основании чего вы так решили?
                          0
                          Отзыва, конечно. Разве это не очевидно?
                          Но вообще, чем дальше, тем больше убеждаюсь, что системы знаний там нет.
                            0
                            «там» это где?
                              0
                              В книге.
                                0
                                а вы ее читали?
                                  0
                                  Нет.
                                    0
                                    слушайте я конечно знаю анекдот про рабиновича котормоу хаим карузо по телефону напел и рабинович понял что карузо — халтурщик, фальшифит, сипит и вообще в ноты не попадает. но не ожидал что этот анекдот только что воплотится в реальность
                                      0
                                      Ну я же не виноват, что вы вместе с автором поста очень успешно выступаете в роли Рабиновича.
                                        0
                                        я?????
                                          0
                                          Ну а кто цитату из книги кинул?
                                            0
                                            так это ж всего два предложения из книги. которую вы не читали.
                                              0
                                              С удовольствием послушаю какие понятия рассматриваются в книге, как они взаимодействуют и как это все отражается на сложности.
                                              Ну вот для примера возьмем «тактическое программирование» и «стратегическое программирование». Судя по «определениям» если я на секунду задумался (но не факт что сделал) над выделением копипасты в отдельную функцию, я уже стратегически программирую? А если я бездумно леплю в новом типовом проекте MVC, то это уже тактическое?
                                              Вот что-то мне кажется, что все сложнее.
                                                0
                                                > С удовольствием послушаю

                                                нет уж вы лучше почитайте
                                                  0
                                                  Мои заметки возможно действительно выглядят как набор советов, но какой смысл описывать всю систему знаний.
                                                  Если я начну все это расписывать, то ещё одна книга получится. Если вам это правда интересно, прочтите книгу.
                                                    0
                                                    Злые вы :) Вот как вообще читать книгу после такой антирекламы? :)

                                                    С моей точки зрения, если бы книга претендовала на научность, в ней должно было бы быть что-то типа такого (могу ошибаться, просто направление мысли).
                                                    Сложность меряется в затраченном времени на поддержании работоспособности системы на всем в течении всего жизненного цикла.
                                                    Стратегическое и тактическое программирование — парные категории (т.е. не имеющие смысла друг без друга) и характеризующиеся смещением объема сложности к началу и соответственно концу жизненного цикла, в чистом (предельном) виде на практике, естественно, не встречаются.
                                                    И вот из трех определений сразу можно делать выводы, хочешь быстрее — используй тактическое, хочешь дешевле — используй стратегическое (обычно так получается). Аналогично с использованием старого кода, если нужно прототип, используй тактическое. Сразу становится понятно почему стартапы тяготеют к тактическому.
                                                    Дальше делим приемы и методики на тактическое/стратегическое, можно с проставлением различных коэффициентов.
                                                    Можно еще как-то делить приемы, например по степени загруженности отделов (проектирование, программирование, тестирование и т.д.) или еще как-то.
                                                      0
                                                      > С моей точки зрения, если бы книга претендовала на научность

                                                      книга не претендует на научность
                        0
                        > Раз «все», значит стройка за окном тоже мешает? Или недосып?

                        и даже то что вы книгу не читали а пытаетесь выводы делать — тоже мешает

                    0
                    книга хорошая. сам хотел сделать обзор и рекомендовать ее, но вот как всегда меня опередили.
                      0
                      Согласен со всем, кроме наследования. Не понимаю, почему его «не рекомендуют». Для меня всегда очевидно, должен ли обьект наследовать другой или нет. Например, груша должна наследовать фрукт, а яблоко не должно наследовать грушу. Иная реализация (например композиция) в случае, когда нужно наследовать, только усложняет код.
                        0
                        Проблема в том, что если у вашего фрукта 100500 наследников, то при изменении фрукта, может непредсказуемо измениться поведение какого нибудь из наследников. И тогда придется переделывать ещё и их.
                        Конечно бывают понятные примеры, когда можно использовать наследование, но это часто не так. Например, стоит ли делать родительский класс для репозиториев сущностей из базы данных? А если у дочернему классу не нужны методы родителя? Скорее всего нет.
                          0
                          Хоть миллион наследников будет, если все по-прежнему фрукты — проблем не будет. Если возникает проблема у наследников, значит либо фрукт уже не совсем фрукт, либо в наследники уже капуста затусовалась.
                          Делать ли родительский класс для репозиториев — зависит от задумки реализации, но когда есть сомнения — значит наследования не нужно.
                            0
                            но когда есть сомнения — значит наследования не нужно
                            я согласен, об этом и говорится в заметках. Понятное дело, что от наследования бывает польза. Просто пример с фруктами очень простой. Часто не так очевидно, что наследование здесь подходит. Поэтому и нужно быть с ним очень осторожными. От неправильного использования наследования может сильно усложниться код.

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

                      Самое читаемое