Статьи

Плохая структура программы: комплектация

Степени плохости.

Многие программисты считают зависимости исходного кода круглыми или некруглыми, с круговыми зависимостями, представляющими Величайшее Воображаемое Зло (что, конечно, они делают), и некруглыми зависимостями, представляющими приемлемую, тусклую грань структуры исходного кода. Это второе представление не совсем верно. Цифровые боги не создают все некруглые зависимости одинаковыми.

На рисунке 1 показаны шесть методов, расположенных в двух независимых транзитивных зависимостях, цепочках методов: a () → b () → c () и d () → e () → f () . Прямые линии показывают зависимости вниз по странице, а изогнутые линии (которых пока нет) показывают зависимости вверх по странице.

Изображение сгенерировано Spoiklin Soice

Рисунок 1: Две переходные зависимости, связанные с их собственным бизнесом.

Однако, как только в реальном мире две переходные зависимости оказываются близко друг к другу, зависимости между цепочками начинают появляться. На рисунке 2, например, метод e () получил признание метода c () .

Изображение сгенерировано Spoiklin Soice

Рисунок 2: зависимость между транзитивными зависимостями.

Все идет нормально. Не круговая зависимость в поле зрения. Теперь рассмотрим транзитивную зависимость слева, которая образует вторую зависимость от своего аналога, причем f () вырастает зависимость от b () .

Изображение сгенерировано Spoiklin Soice

Рисунок 3: Кривый шар.

Вдруг что-то выглядит не так. Кажется, что переходная зависимость слева вызвала нездоровый интерес к правой. Две взаимосвязанные зависимости пересекаются, вызывая плетение или переплетение канатов. Богатый Хикки классно направил свою внутреннюю Джейн Остин, чтобы воскресить архаичный глагол, описывающий именно такое переплетение: «Собирать». В его честь мы назовем вышеуказанный тип зависимости а «комплектация» (мы не можем использовать «комплектация», поскольку это означает «внешний вид кожи, особенно лица»), хотя, как ни странно, комплекции имеют тенденцию давать программирует хилое завершение).

И это не просто эстетический момент. Сборники допускают математическое определение и объективный структурный анализ. Уменьшение волнового эффекта мотивирует всю большую структуру, и программисты могут измерить восприимчивость к волновому эффекту, посчитав количество методов, от которых зависит каждый метод; чем выше это значение, тем хуже структура. Это «Затронутый набор» программы. Обозначив каждый метод таким образом, мы можем перерисовать рисунок 3 следующим образом (в конечном счете, d () , например, зависит от 4 других методов):

Изображение сгенерировано Spoiklin Soice

Рисунок 4: Затронутый набор всех элементов.

На рисунке показан набор затрагиваемые 12. Если, однако, программа может быть переписана немного мельче , поднимая вызов F () из е () в г () , то цифра 5, что исключает комплектацию полностью, получили бы ,

Изображение сгенерировано Spoiklin Soice

Рисунок 5: Уменьшение глубины.

На рисунке 5 показано влияние 10, что на 17% меньше по сравнению с рисунком 4 за счет перемещения только одной зависимости метода.

Это, конечно, игрушечный пример, и часто программисту требуется именно то, что показано на рисунке 4. Но, по крайней мере, комплектации поднимают вопрос, и отсеивание ненужных комплексов может улучшить структуру. Ниже, например, два метода (сокращено для целей представления), createGraphicsContext () и colourBackground () , причем первый вызывает последний:

    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 изображает методы, как они появляются в дикой природе.

Изображение сгенерировано Spoiklin Soice

Рисунок 6: комплектация в реальном мире.

Композиция здесь возникает из-за того, что createGraphicsContext () и colourBackground () вызывают getBufferedImage () , когда тривиально переписать методы так, что createGraphicsContext () вызывает getBufferedImage () и передает возвращенный объект в colourBackground () (таким образом сокращая colourBackground () подвергается getBufferedImage () ):

    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.

Изображение сгенерировано Spoiklin Soice

Рисунок 7: Комплект исчез.

Резюме.

Сборники не самая большая проблема разработки программного обеспечения.

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

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