Степени плохости
Многие программисты рассматривают зависимости исходного кода как циклические или некруглые, с циклическими зависимостями, представляющими Величайшее Воображаемое Зло (что, конечно, они делают), и некруглыми зависимостями, представляющими приемлемую, тусклую грань структуры исходного кода. Это второе представление не совсем верно. Цифровые боги не создают все некруглые зависимости одинаковыми.
На рисунке 1 показаны шесть методов, расположенных в двух независимых транзитивных зависимостях, цепочках методов: a () → b () → c () и d () → e () → f () . Прямые линии показывают зависимости вниз по странице, а изогнутые линии (которых пока нет) показывают зависимости вверх по странице.
Однако, как только в реальном мире две переходные зависимости оказываются близко друг к другу, зависимости между цепочками начинают появляться. На рисунке 2, например, метод e () получил признание метода c () .
Все идет нормально. Не круговая зависимость в поле зрения. Теперь рассмотрим транзитивную зависимость слева, которая образует вторую зависимость от своего аналога, причем f () вырастает зависимость от b () .
Вдруг что-то выглядит не так. Кажется, что переходная зависимость слева вызвала нездоровый интерес к правой. Две взаимосвязанные зависимости пересекаются, вызывая плетение или переплетение канатов. Рич Хикки классно направил свою внутреннюю Джейн Остин, чтобы воскресить архаичный глагол, описывающий именно такое переплетение: «Собирать». В его честь мы будем называть вышеуказанный тип зависимости a «Complectation» (мы не можем использовать «Complection», так как это означает «внешний вид кожи, особенно лица»), хотя, как ни странно, сложения имеют тенденцию давать программирует хилое завершение).
И это не просто эстетический момент. Сборники допускают математическое определение и объективный структурный анализ. Уменьшение волнового эффекта мотивирует всю большую структуру, и программисты могут измерить восприимчивость к волновому эффекту, посчитав количество методов, от которых зависит каждый метод; чем выше это значение, тем хуже структура. Это «Затронутый набор» программы. Обозначив каждый метод таким образом, мы можем перерисовать рисунок 3 следующим образом (в конечном счете, d () , например, зависит от 4 других методов):
На рисунке показан измененный набор из 12. Если, однако, программа может быть переписана немного поверхностнее, поднимая вызов f () с e () до d () , то рисунок 5, полностью исключающий сложность, получит ,
На рисунке 5 показано влияние 10, что на 17% меньше по сравнению с рисунком 4 за счет перемещения только одной зависимости метода.
Это, конечно, игрушечный пример, и часто программисту требуется именно то, что показано на рисунке 4. Но, по крайней мере, комплектации поднимают вопрос, и отсеивание ненужных комплексов может улучшить структуру. Ниже, например, два метода (сокращено для целей представления), createGraphicsContext () и colourBackground () , причем первый вызывает последний:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
private Graphics2D createGraphicsContext() { Graphics2D graphics2D = canvas.getBufferedImage().createGraphics(); colourBackground(graphics2D); graphics2D.setColor(options.getColour(ColourTag.FOREGROUND)); return graphics2D; } private void colourBackground(Graphics2D graphics2D) { BufferedImage bufferedImage = canvas.getBufferedImage(); Color background = options.getColour(ColourTag.BACKGROUND); graphics2D.setColor(background); graphics2D.fillRect( 0 , 0 , bufferedImage.getWidth(), bufferedImage.getHeight()); } |
Рисунок 6 изображает методы, как они появляются в дикой природе.
Композиция здесь возникает из-за того, что createGraphicsContext () и colourBackground () вызывают getBufferedImage () , когда тривиально переписать методы так, что createGraphicsContext () вызывает getBufferedImage () и передает возвращенный объект в colourBackground () (таким образом сокращая colourBackground () подвергается getBufferedImage () ):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
private Graphics2D createGraphicsContext() { BufferedImage bufferedImage = canvas.getBufferedImage(); Graphics2D graphics2D = bufferedImage.createGraphics(); colourBackground(graphics2D, bufferedImage); graphics2D.setColor(options.getColour(ColourTag.FOREGROUND)); return graphics2D; } private void colourBackground(Graphics2D graphics2D, BufferedImage bufferedImage) { Color background = options.getColour(ColourTag.BACKGROUND); graphics2D.setColor(background); graphics2D.fillRect( 0 , 0 , bufferedImage.getWidth(), bufferedImage.getHeight()); } |
Таким образом получая очень немного улучшенную фигуру 7.
Резюме
Сборники не самая большая проблема разработки программного обеспечения.
Это небольшая неприятность, небольшая возможность для улучшения исходного кода.
Но они показывают интересные самородки, которые можно найти во время панорамирования мерзлой воды структуры программы.
Ссылка: | Плохая структура программы: сборник от нашего партнера JCG Эдмунда Кирвана из блога о программном обеспечении блог. |