Аннотация:
Существует множество практик, принципов, паттернов и прочих страшных слов, которые мы используем в нашей повседневной профессиональной деятельности и очень часто даже не задаём себе вопрос зачем мы это делаем. Зачем это всё нужно, плохо это или хорошо, когда плохо и когда хорошо. Зачем нужны все эти принципы? На самом деле ответ до банального очевиден. Всё это в конце концов направлено на борьбу со сложностью разработки ПО. Теперь пришла очередь задать вопрос — а что же такое сложность и как знание того что это такое поможет нам лучше понять и использовать принципы, которые как раз и направлены на борьбу с ней?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Игорь Ткачёв, Вы писали:
ИТ>Существует множество практик, принципов, паттернов и прочих страшных слов, которые мы используем в нашей повседневной профессиональной деятельности и очень часто даже не задаём себе вопрос зачем мы это делаем. Зачем это всё нужно, плохо это или хорошо, когда плохо и когда хорошо. Зачем нужны все эти принципы? На самом деле ответ до банального очевиден. Всё это в конце концов направлено на борьбу со сложностью разработки ПО. Теперь пришла очередь задать вопрос — а что же такое сложность и как знание того что это такое поможет нам лучше понять и использовать принципы, которые как раз и направлены на борьбу с ней?
Статья себе противоречит:
Это плохо работает, когда мы пытаемся заранее выделить код, который по идее можно повторно использовать, но на практике его повторно использовать не получается. Дополнительную сложность в решаемую задачу мы внесли, а взамен ничего не получили.
Следовательно, если мы не будем пытаться "заранее выделить код", то взамен ничего не потеряем, сложность уменьшим.
Следовательно, утверждение "устраняя сложность в одном месте мы всегда добавляем её где-то в другом" — неверно.
Следовательно, законом сохранения сложности и не закон вовсе.
Здравствуйте, Lloyd, Вы писали:
L>Статья себе противоречит:
Там же в самом начале написано — сложность штука противоречивая. Это было написано специально для таких как ты.
L>Следовательно, если мы не будем пытаться "заранее выделить код", то взамен ничего не потеряем, сложность уменьшим.
Если ты не будешь пытаться, то ничего ни не потеряешь, ни не уменьшишь.
L>Следовательно, утверждение "устраняя сложность в одном месте мы всегда добавляем её где-то в другом" — неверно.
Предыдущий твой посыл был не верен, так что дальнейшие выводы не имеют смысла.
L>Следовательно, законом сохранения сложности и не закон вовсе. ;)
— Суслика видишь?
— Нет.
— А он есть!
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Lloyd, Вы писали:
L>Следовательно, если мы не будем пытаться "заранее выделить код", то взамен ничего не потеряем, сложность уменьшим.
Противоположность увеличения сложности — неувеличение, а не строгое уменьшение. Поэтой при нулевых поползновениях сложность не изменится.
1)Сложность восприятия и сложность обучения — практичеки одно и тоже, только взгляд с разных сторон.
2)Сложность восприятия, сложность обучения, количественная сложность — их преодоление является разовыми затратами, тогда как алгоритмическая сложность и сложность сложность изменения преслдуют постоянно.
3)Пониятие алгоритмической сложности слишком обобщено. Напрмиер разработка парсера языка и трехзвенной бухгалтерской системы обладают высокой сложностью, но причины сложности совершенно разные.
Здравствуйте, gandjustas, Вы писали:
G>2)Сложность восприятия, сложность обучения, количественная сложность — их преодоление является разовыми затратами
В общем случае, это неверно. Лично я забываю всякую ерунду очень быстро, и, как следствие, приходится помногу раз вникать в один и тот же проект. Соответственно, чем выше порог вхождения, тем больше тратится ресурсов на "переключение контекста" между проектами.
Здравствуйте, IT, Вы писали:
L>>Следовательно, если мы не будем пытаться "заранее выделить код", то взамен ничего не потеряем, сложность уменьшим.
IT>Если ты не будешь пытаться, то ничего ни не потеряешь, ни не уменьшишь.
Переход от решения A в котором "мы пытаемся заранее выделить код, который по идее можно повторно использовать" к решению B, в котором не было предпринято такой попытки, судя по постановке должно привести в уменьшению сложности. Разве не так?
Здравствуйте, gandjustas, Вы писали:
L>>Следовательно, если мы не будем пытаться "заранее выделить код", то взамен ничего не потеряем, сложность уменьшим. G>Противоположность увеличения сложности — неувеличение, а не строгое уменьшение. Поэтой при нулевых поползновениях сложность не изменится.
Тут не термодинамика, тут любой процесс можно повернуть вспять и очень легко — окрываешь сорсконтрол и делаешь Revert Changes. И если в ревизии 101 у тебя при прочих равных сложность выше, чем в ревизии 100, то откатившись на 100-ю ревизию получишь уменьшение сложности, которого по мнению автора статьи "не существует".
Здравствуйте, mrTwister, Вы писали:
T>Здравствуйте, gandjustas, Вы писали:
G>>2)Сложность восприятия, сложность обучения, количественная сложность — их преодоление является разовыми затратами
T>В общем случае, это неверно. Лично я забываю всякую ерунду очень быстро, и, как следствие, приходится помногу раз вникать в один и тот же проект. Соответственно, чем выше порог вхождения, тем больше тратится ресурсов на "переключение контекста" между проектами.
Если часто надо переключаться между проектами, то это хреновый менеджемнт и сложности не относится.
Здравствуйте, Lloyd, Вы писали:
L>Переход от решения A в котором "мы пытаемся заранее выделить код, который по идее можно повторно использовать" к решению B, в котором не было предпринято такой попытки, судя по постановке должно привести в уменьшению сложности. Разве не так?
Это зависит от того было ли в решении А повторное использование кода или нет.
Если было то решение В сложнее, а если не было то решение В проще.
Ибо превращение кода в повторно используемый всегда приводит к его усложнению.
Упрощение происходит только тогда когда мы несколько раз повторно используем этот код.
И если мы по факту не смогли этот код использовать повторно то мы добавили сложность в одном месте и не убрали в другом.
Таким образом приходим к эвристике: Превращай код в повторно используемый только после того как он понадобился повторно.
Конечно бывают случаи когда точно известно что код будет использован повторно но если 100%ной уверенности нет то см эвристику.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, WolfHound, Вы писали:
WH>Таким образом приходим к эвристике: Превращай код в повторно используемый только после того как он понадобился повторно.
Ага, и если так не делать, то приложения превращаются в набор "повторно используемого кода", который не может быть повторно использован.
Здравствуйте, gandjustas, Вы писали:
G>1)Сложность восприятия и сложность обучения — практичеки одно и тоже, только взгляд с разных сторон.
Сложность само по себе одно и тоже — затраченные усилия, и её виды — это как раз и есть взгляд с разных сторон. Разделение на виды само по себе вещь достаточно условная и интересно прежде всего для выявления, лучшего понимания и устранения проблемных мест. Возьмём, например, код, который плохо читаем, т.к. страдает отсутствием форматирования, соглашений, запутан и многословен. Что нужно сделать, чтобы он стал прощё? Его можно отформатировать, отрефакторить, распутать и убрать лишнее. В результате он станет проще за счёт уменьшения сложности восприятия. Теперь возьмём код, который легко читается, но базируется на технологии, которая изучающему этот код пока не известна. Пусть это будет WPF — как раз та вещь, которая обладает довольно высоким порогом вхождения. Поможет ли нам форматирование кода, его рефакторинг и распутывание лучше понять такой код? Ответ очевиден — не поможет, рефакторить можно хоть до посинения. Нужно брать в руки книжки и изучать технологию.
G>2)Сложность восприятия, сложность обучения, количественная сложность — их преодоление является разовыми затратами, тогда как алгоритмическая сложность и сложность сложность изменения преслдуют постоянно.
Это смотря как посмотреть. Плохо читаемый и многословный код придётся преодолевать каждый раз, когда он будет читаться. Сложность обучения придётся преодолевать каждому новому бойцу в команде, для которого порог вхождения в код выше его текущего предела.
G>3)Пониятие алгоритмической сложности слишком обобщено. Напрмиер разработка парсера языка и трехзвенной бухгалтерской системы обладают высокой сложностью, но причины сложности совершенно разные.
Какие?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Lloyd, Вы писали:
IT>>Если ты не будешь пытаться, то ничего ни не потеряешь, ни не уменьшишь.
L>Переход от решения A в котором "мы пытаемся заранее выделить код, который по идее можно повторно использовать" к решению B, в котором не было предпринято такой попытки, судя по постановке должно привести в уменьшению сложности. Разве не так?
Не так. Давай возьмём для примера следующий код:
var a = b + c;
Предположим, что мы можем здесь выделить операцию сложения в отдельный метод. Но мы этого не стали делать. До того как мы этого не стали делать у нас было a = b + c, а после того как мы этого не сделали у нас стало a = b + c. Было a = b + c, стало a = b + c. За счёт чего второе a = b + c, стало проще первого?
Если нам не помогут, то мы тоже никого не пощадим.
Понятием "сложность" занимается кибернетика. В частности, из возрастающей сложности управляемой системы она выводит необходимость иерарихии управляющих (под)систем. То-же самое происходит при создании софта, при этом программисты создают иерархию уровней абстракции. Собственно, она и решает те проблемы, о которых написано в статье. И приёмы уменьшения разных типов сложности (алгоритмическая сложноть, сложность восприятия и пр.) в целом тоже укладываются в эти уровни абстракции. Мы говорим о более или менее высокоуровневых языках программирования, фреймворках и т.п.
Увы, повышение уровня абстракции практически всегда приводит к ухудшению производительности программ. Это ухудшение невелико, когда эти уровни абстрации были созданы в рамках одного проекта для решения одной задачи. Но если их брать со стороны, брать некие готовые решения — то потеря производительности будет очень заметна — в разы на каждом уровне абстракции. Эта деградация производительности хороша заметна в ретроспективе развития производительности компьютеров и программного обеспечения — мы все видели, как скорость компьютеров увеличилась на несколько порядков, а вот функциональность софта — намного меньше.
Так бы и продолжалось дальше, но увы, экспоненциальное развитие скорости компьютеров практически закончилось. И просто увеличение количества уровней абстракции (вроде применения более высокоуровневых языков программирования) уже не поможет — железо не потянет. И выход тут я вижу только один — использовать компьютер. Он не имеет такого встроенного ограничения на уровень сложности программы, которую должен анализировать. Но увы, он не имеет и интеллекта, чтоб писать и анализировать программы. Вот когда этот интеллект у него появится — тогда и появится реальная альтернатива увеличению количества уровней абстракции в программе. Чтоб программы становились более сложными и функциональными, без экспоненциального увеличения требований к ресурсам.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, gandjustas, Вы писали:
G>>1)Сложность восприятия и сложность обучения — практичеки одно и тоже, только взгляд с разных сторон.
IT>Сложность само по себе одно и тоже — затраченные усилия, и её виды — это как раз и есть взгляд с разных сторон. Разделение на виды само по себе вещь достаточно условная и интересно прежде всего для выявления, лучшего понимания и устранения проблемных мест. Возьмём, например, код, который плохо читаем, т.к. страдает отсутствием форматирования, соглашений, запутан и многословен. Что нужно сделать, чтобы он стал прощё? Его можно отформатировать, отрефакторить, распутать и убрать лишнее. В результате он станет проще за счёт уменьшения сложности восприятия.
Этот рефакторинг выполняется автоматически и занимает минимум времени. Гораздо больше займет собственно понимание что делает код.
IT>Теперь возьмём код, который легко читается, но базируется на технологии, которая изучающему этот код пока не известна. Пусть это будет WPF — как раз та вещь, которая обладает довольно высоким порогом вхождения. Поможет ли нам форматирование кода, его рефакторинг и распутывание лучше понять такой код? Ответ очевиден — не поможет, рефакторить можно хоть до посинения. Нужно брать в руки книжки и изучать технологию.
Понимание что делает код не появится без понимания абстракций, которыми он оперирует.
Так что для "восприятия" нужно "обучение".
G>>2)Сложность восприятия, сложность обучения, количественная сложность — их преодоление является разовыми затратами, тогда как алгоритмическая сложность и сложность сложность изменения преслдуют постоянно.
IT>Это смотря как посмотреть. Плохо читаемый и многословный код придётся преодолевать каждый раз, когда он будет читаться.
Один программист читает код один раз когда разбирается как он работает.
IT>Сложность обучения придётся преодолевать каждому новому бойцу в команде, для которого порог вхождения в код выше его текущего предела.
Это еще более редкое явление.
Преодоление этих сложностей требует гораздо меньших затрат по сравнению с преодолением сложности изменений при постоянном развитии проекта.
G>>3)Пониятие алгоритмической сложности слишком обобщено. Напрмиер разработка парсера языка и трехзвенной бухгалтерской системы обладают высокой сложностью, но причины сложности совершенно разные. IT>Какие?
В случае парсера — нетривиальные алгоритмы — неочевидное преобразование входных данных в выходные, которое вряд ли получится декомпозировать на более протые части. В случае бухгалтерской системы все можно до элементарных вещей декопозировать, но возникает пролема распределения обязанностей между программными модулями и обеспечение их взаимодействия.
Здравствуйте, gandjustas, Вы писали:
G>Этот рефакторинг выполняется автоматически и занимает минимум времени. Гораздо больше займет собственно понимание что делает код.
Это зависит от кода. Можно так написать, что простой в понимании код вообще не будет читаться, а его рефакторинг займёт гораздо больше времени, чем его понимание. В общем, без конкретного кода я не стал бы даже это обсуждать.
G>Так что для "восприятия" нужно "обучение".
Возможно термин восприятие не очень удачен, но в моём определении важно как раз то, что он отделён от обучения и относится к форме кода, а не его содержанию. Если у тебя есть более точное определение предлагай.
IT>>Сложность обучения придётся преодолевать каждому новому бойцу в команде, для которого порог вхождения в код выше его текущего предела. G>Это еще более редкое явление.
G>Преодоление этих сложностей требует гораздо меньших затрат по сравнению с преодолением сложности изменений при постоянном развитии проекта.
Опять же это всё зависит от конкретного рассматриваемого случая. В моей команде используется всё, что сегодня доступно на рынке мэйнстрима: последние версии компиляторов и их новые возможности, последние технологии и т.д. Это позволяет нам перераспределить сложность наших проектов в сложность обучения и контролировать наш код малым числом людей. Я не возьму на работу человека далёкого от всего этого, например, такого, который застыл на уровен .NET 1.1. Не возьму по простой причине — затраты на его обучение не будут, как ты утверждаешь, меньше по сравнению с преодолением других видов сложности. Они будут значительно больше, и если это будет контрактник на 10 месяцев, то за это время он не успеет сделать ничего полезного.
G>>>3)Пониятие алгоритмической сложности слишком обобщено. Напрмиер разработка парсера языка и трехзвенной бухгалтерской системы обладают высокой сложностью, но причины сложности совершенно разные. IT>>Какие? G>В случае парсера — нетривиальные алгоритмы — неочевидное преобразование входных данных в выходные, которое вряд ли получится декомпозировать на более протые части. В случае бухгалтерской системы все можно до элементарных вещей декопозировать, но возникает пролема распределения обязанностей между программными модулями и обеспечение их взаимодействия.
Я думал об этом и пока не могу однозначено разделить две вещи: уровень интеллекта и способность удерживать в голове целиком задачу определённого размера. Мне кажется это суть одно и тоже, но, возможно, я не прав. Было бы интересно обсужить эти вещи подробнее.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Не так. Давай возьмём для примера следующий код:
IT>
IT>var a = b + c;
IT>
IT>Предположим, что мы можем здесь выделить операцию сложения в отдельный метод. Но мы этого не стали делать. До того как мы этого не стали делать у нас было a = b + c, а после того как мы этого не сделали у нас стало a = b + c. Было a = b + c, стало a = b + c. За счёт чего второе a = b + c, стало проще первого?
Предлагаю рассмотреть другой вариант.
Было var a = b + c; его отрефактирили в var a = Add(b, c);
Если мы теперь вернемся к первоначальному var a = b + c;, то получим решение, которое проще (чем var a = Add(b, c)).
Т.е получаем уменьшение сложности.
Здравствуйте, Lloyd, Вы писали:
L>Предлагаю рассмотреть другой вариант. L>Было var a = b + c; его отрефактирили в var a = Add(b, c); L>Если мы теперь вернемся к первоначальному var a = b + c;, то получим решение, которое проще (чем var a = Add(b, c)). L>Т.е получаем уменьшение сложности.
Уменьшение по сравнению с чём? Исходную сложность ты не уменьшил, а излишнюю да, устранил. Или вот ещё:
if (a == true)
{
return true;
}
else if (a == false)
{
return false;
}
else if (a != true && a != false)
{
throw new ApplicationException()
}
такой код упрощается до:
return a;
при этом сложность этого кода уменьшается. Но начальная сложность никуда не делась. Если задача ставится как, например, умножить два числа, то можно применить множество практик и техник, но умножение или заменяющий его алгоритм в том или ином виде в коде присутствовать должен. От этого никуда не деться и это указано в статье.
L>Я это имел в виду.
Возможно не все формулировки и объяснения получились достаточно чёткими и однозначными. Я над этим работаю
Если нам не помогут, то мы тоже никого не пощадим.
Законы сохранения действуют в обоих направлениях, соответственно, если бы такой закон был, то при искусственном увеличении сложности в реализации какой-то функции, сложность чего-то другого уменьшалась бы.
Скорее есть закон "минимально необходимой сложности", и он во многом пересекается со статьей, но называется никак не "закон сохранения".
Например, вместо применения формулы для решения квадратного уровнения можн онаписать подсистему, которая будет рисовать параболу, сохраняь в BMP формате, потом парсить пикселы из файла и находить приблизительное решение по точкам пересечения. Можно еще написать свой архиватор "для компактного хранения этих BMP" и драйвер HDD который будет оптимально хранить полученый архив на диске. Эти операции — многократное увеличение сложности по сравнению с вычислением дискриминанта, при этом только увеличивается (что опровергает гипотезу о законе).
Или я что-то не понял?
А вообще респект за тему — управление сложностью — самое важное в разработке.