Pull to refresh

Comments 66

Добавлю, что тесты (хотя бы интеграционные) очень помогают при рефакторинге. При любом более-менее серьезном рефакторинге лучше сделать их для всех роутов, иначе что-нибудь обязательно сломается :)
Рефакторят без тестов те, кто любит гулять, но не любит тратить деньги на презервативы.
По данным всемирной организации здравоохранения, ежегодно в мире выполняется примерно 46 миллионов искусственных абортов, что составляет 22 % от числа наблюдавшихся беременностей.

Так то, видать, многие занимаются рефакторингом без тестов.
Степень залёта в сравнимых вами ситуациях, имхо, обычно не сопоставима…
Но ситуации похожи. 15 минут сбегать в киоск и 15 минут написать тест на функцию перед рефакторингом.
Это если архитектура системы изначально поддерживает такую «тестябельность».
Кроме того, как показывает опыт, тесты пишутся только для понятой части рефакторящегося кода. Но т.к.
но вы можете просто не осознать всё величие шалаша из костылей
,
то очень велик шанс, что тесты пройдут, а что-то неожиданное все равно сломается.
> Не, даже не так. Я чертовски люблю рефакторинг. Я не переношу плохой код и плохую архитектуру.
Вам 15? Не переживайте, это пройдёт.

> Меня коробит, когда я пишу новую фичу, а в соседнем классе творится полный бардак.
А почему в соседнем классе бардак? Учитель не справляется? Пробовали обращаться к директору школы?
Слишком толсто, не для этой аудитории.
То есть Вы к своим 30 полюбили плохой код и наслаждаетесь плохой архитектурой? Наверное, это уже само не пройдет и, скорее всего, неизлечимо.
Вам 15? Не переживайте, это пройдёт.

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

А почему в соседнем классе бардак? Учитель не справляется? Пробовали обращаться к директору школы?

Не оценил вашего тонкого юмора, извините.
На вкус и цвет товарищей нет…
Если одному код кажется вершиной совершенства, то другой может тут же опустить этот код ниже плинтуса.
И тут я хочу задать Вам вопрос — каковы критерии совершенного кода?
Может код, о котором кто-то думает не лестно в силу своей ограниченности, на самом деле совершенен и проблема не в коде?
Я пока знаю всего лишь 2 объективных критерия:
1) Правильность работы, подтвержденная тестами
2) Скорость работы, подтвержденная бенчмарками

А как объективно формализовать понятие «плохая архитектура»?
На практике бывают такие проекты, осознать которые в целом можно только по прошествии нескольких лет плотной работы над проектом. А рефакторинг может растянуться на несколько человеко лет…
Так что видение «плохой архитектуры» совершенно не аргументирует рефакторинг…
Количество «WTF!» в минуту при чтении кода подойдет за объективный критерий?

А вот, что, например, Microsoft говорит по этому поводу:
social.msdn.microsoft.com/Forums/ru-ru/af2ebf9f-c8f1-4062-a409-0d7819c1de8f/-?forum=fordesktopru

Качество — это далеко не только правильность и скорость исполнения.
стоимость внесения изменения, например.
И тут я хочу задать Вам вопрос — каковы критерии совершенного кода?

Стоимость поддержки.
Критерии совершенного кода — тема отдельная и очень сложная. По этому поводу можно несколько отдельных постов накатать, т.к. с формализмом тут всё очень сложно. Но можно начать отталкиваться от классической литературы, например:
Совершенный код
Чистый код
Читаемый код
А неформальные критерии стандартные: легкость чтения, гибкость, простота внесения изменений и поддержки и т.п. Но тут много субъективизма, так что по каждому пункту можно много рассуждать и холиварить, ведь у каждого свой подход. Например, Кент Бек с Мартином Фаулером любят говорить про плохие запахи кода как критерий.
Как бы говнокод еще и сильно зависит от вашего уровня программирования.
Кто-то не сумеет 5 десятков if объединить в бинарные операции, избавившись от условий в принципе.
Кто-то сумеет.
К примеру, те самые пять десятков if в итоге превратились в такое:

        //основная проверка
        bool prova = false;
        //массив проверок
        bool[] pr = new bool[13];
        for (int q = 0; q < 13; q++)
        {
            pr[q] = true;
        }
        //плоскость xy
        for (int j = 0; j < 4; j++)
        {
            pr[3] = pr[4] = pr[5] = pr[6] = pr[7] = pr[8] = true;
            for (int i = 0; i < 4; i++)
            {
                pr[0] = pr[1] = pr[2] = true;
                

                for (int k = 0; k < 4; k++)
                {
                    //плоскости
                    pr[0] &= board[i, k, j] == type;
                    pr[1] &= board[i, j, k] == type;
                    pr[2] &= board[k, j, i] == type;
                }

                prova |= pr[0]|pr[1]|pr[2];
                //боковые диагонали
                pr[3] &= board[i, i, j] == type;
                pr[4] &= board[i, j, i] == type;
                pr[5] &= board[j, i, i] == type;
                pr[6] &= board[i, 3 - i, j] == type;
                pr[7] &= board[j, i, 3 - i] == type;
                pr[8] &= board[i, j, 3 - i] == type;
            }
            prova |= pr[3] | pr[4] | pr[5] | pr[6] | pr[7] | pr[8] ;
            //главные диагонали
            pr[9] &= board[j, j, j] == type;
            pr[10] &= board[3 - j, j, j] == type;
            pr[11] &= board[3 - j, j, 3 - j] == type;
            pr[12] &= board[j, j, 3 - j] == type;

        }
        prova |= pr[9] | pr[10] | pr[11] | pr[12];

        if (prova)
            SomeWin(playertype);
    }


п.с. если сумеете еще улучшить — буду рад :-)
Можете попробовать отправить вышеприведённое на codereview.stackexchange.com. Там иногда дают очень дельные советы по улучшению кода.
Это проверка выигрыша в трехмерных 4x4x4 крестиках-ноликах?
Что-то я думал-думал, но идеологически что-то более хитрое, чем проверять поочередно все варианты, ничего не придумывается.

Могу предложить только косметические улучшения, а то сейчас работа c массивом из 13 bool-ов выглядит зловеще :)

Как-нибудь так, например:

var win = false;
var range = Enumerable.Range(0, 4);
Func<Func<int,int>, bool> checkLine = getCell => range.Select(n => getCell(n)).All(c => c == type);

foreach(var a in range) {
    foreach(var b in range) {
        win |= checkLine(n => board[n, a, b]);
        win |= checkLine(n => board[a, n, b]);
        win |= checkLine(n => board[a, b, n]);
    }
}

foreach(var a in range) {
    win |= checkLine(n => board[a, n, n]);
    win |= checkLine(n => board[n, a, n]);
    win |= checkLine(n => board[n, n, a]);

    win |= checkLine(n => board[a, n, -n]);
    win |= checkLine(n => board[n, a, -n]);
    win |= checkLine(n => board[n, -n, a]);
}

win |= checkLine(n => board[n, n, n]);
win |= checkLine(n => board[-n, n, n]);
win |= checkLine(n => board[n, -n, n]);
win |= checkLine(n => board[n, n, -n]);

return win;
адский код на Си
#include <stdio.h>
#include <inttypes.h>

inline void board_set(uint16_t *board, int x, int y, int value)
{
	const int boardSize = 4;
	int bitPos = x*boardSize + y;

	uint16_t mask = 1 << bitPos;
	*board |= mask;		

	if (value == 0) {
		*board ^= mask;
	}
}

int main()
{
	int board[4][4][4] = {
		1, 1, 0, 1,
		0, 0, 0, 0,
		0, 1, 0, 0,
		1, 1, 0, 0,

		1, 1, 0, 1,
		0, 0, 0, 0,
		0, 1, 0, 0,
		1, 1, 0, 0,

		1, 1, 0, 1,
		0, 1, 0, 0,
		0, 0, 0, 0,
		1, 1, 0, 0,

		1, 1, 0, 1,
		0, 1, 0, 0,
		0, 1, 1, 0,
		1, 0, 0, 1
};
	uint16_t vertical_start = 0x1111;
	uint16_t horizontal_start = 0xf;
	uint16_t diag1 = 0x8421;
	uint16_t diag2 = 0x1248;

#define CHECK_MATCH(board, winmask) ((board & winmask ) == winmask)

#define CHECK_V_LINE(board, line) CHECK_MATCH(board, vertical_start << line)
#define CHECK_V_LINES(board) (CHECK_V_LINE(board, 0) || CHECK_V_LINE(board, 1) || CHECK_V_LINE(board, 2) || CHECK_V_LINE(board, 3))

#define CHECK_H_LINE(board, line) CHECK_MATCH(board, horizontal_start << line*4)
#define CHECK_H_LINES(board) (CHECK_H_LINE(board, 0) || CHECK_H_LINE(board, 1) || CHECK_H_LINE(board, 2) || CHECK_H_LINE(board, 3))

#define CHECK_LINES(board) (CHECK_V_LINES(board) || CHECK_H_LINES(board))

#define CHECK_DIAGS(board) (CHECK_MATCH(board, diag1) || CHECK_MATCH(board, diag2))

#define CHECK_WIN(board) (CHECK_LINES(board) || CHECK_DIAGS(board))
	
	// original board contains 0 for empty cell, 1 and 2 for players' marks
	const int playerToCheck = 1;

	int playerWin = 0;
	for (int i=0; i<4 && !playerWin; i++) {

		// board bitmap for selected player
		uint16_t miniboard = 0;

		// fill bitmap
		for (int j=0; j<4; j++) {
			for (int k=0; k<4; k++) {
				board_set(&miniboard, j, k, (board[i][j][k] == playerToCheck));
			}
		}

		playerWin |= CHECK_WIN(miniboard);
	}

	printf("win: %d\n", playerWin);

	return 0;
}




Суть такова, что каждую плоскую доску представляем в виде 16-битного числа и затем сравниваем побитово с масками. Это конечно ад, но мне просто показалась прикольной эта идея. Да и маски получились тоже с красивыми числами. Трехмерные диагонали не осилил, так как интерес к этому времени уже приостыл
оказалось, что всё это время Германия нещадно заколачивала 5 мячей Бразилии :(
Как-то так? (не проверял)
bool test(int[,,] board, int type){
    for(int i=4;i<=8;i++){
	int vx=i/4-1,x0=i%4;
	for(int j=3;j<=8;j++){
	    int vy=j/4-1,y0=j%4;
	    for(int k=3;k<=8;k++){
	        int vz=k/4-1,z0=k%4;
		if(vx*4+vy*2+vz<=0) continue;
	    	bool pr=true;
		for(int s=0;s<4;s++) pr&=(board[x0+vx*s,y0+vy*s,z0+vz*s]==type);
		if(pr) return true;
	    }
        }
    }
    return false;
}

Или так…
        static bool testwin(int[, ,] board,int type) {
            ulong mask=0;
            for(int i=0;i<64;i++) mask=(mask<<1)+(board[i/16,(i/4)%4,i%4]==type ? 1u : 0);
            ulong res=(mask & mask>>1 & mask>>2 & mask>>3 & 0x1111111111111111UL);
            res|=(mask & mask>>4 & mask>>8 & mask>>12 & 0x000f000f000f000fUL);
            res|=(mask & mask>>16 & mask>>32 & mask>>48 & 0x000000000000ffffUL);
            res|=(mask & mask>>5 & mask>>10 & mask>>15 & 0x0001000100010001UL);
            res|=(mask & mask>>3 & mask>>6 & mask>>9 & 0x0008000800080008UL);
            res|=(mask & mask>>17 & mask>>34 & mask>>51 & 0x0000000000001111UL);
            res|=(mask & mask>>15 & mask>>30 & mask>>45 & 0x0000000000008888UL);
            res|=(mask & mask>>20 & mask>>40 & mask>>60 & 0x000000000000000fUL);
            res|=(mask & mask>>12 & mask>>24 & mask>>36 & 0x000000000000f000UL);
            res|=(mask & mask>>21 & mask>>42 & mask>>63 & 0x0000000000000001UL);
            res|=(mask & mask>>19 & mask>>38 & mask>>57 & 0x0000000000000008UL);
            res|=(mask & mask>>13 & mask>>26 & mask>>39 & 0x0000000000001000UL);
            res|=(mask & mask>>11 & mask>>22 & mask>>33 & 0x0000000000008000UL);
            return res!=0;
        }
Не согласен с грубым троллингом выше, но я примерно понимаю его мотив.

Я к своим 32 тоже начал скептически относиться к слову «рефакторинг». Не к процессу улучшения качества кода, а именно к слову. В основном потому что у меня оно ассоциируется с другими баззвордами из ООП.

Когда я слышу «рефакторинг», у меня сразу подсознательно возникает такая картина: товарищ, недавно прочитавший книжку по ООП-дизайну, не особенно разбираясь, переделывает работающий метод на страницу кода в две фабрики, четыре стратегии и три каких-нибудь Manager-а. От этого алгоритм не становится сильно более расширяемым, но при этом становится намного менее прозрачным и понятным. И все это — ради соотстветсвия каким-то навязанным канонам, типа про «методы должны быть не более пяти строк».

А со сказанным в статье — в согласен, да.
Согласен с вашей мыслью, со словом «рефакторинг» действительно часто происходит подмена понятий. В статье я имел ввиду улучшение кодовой базы без видимого добавления нового функционала. Это вовсе не означает, что мы должны немедленно воткнуть в нашу архитектуру 600 паттернов проектирования, один лучше другого. Понятно, что к любой переработке кода нужно подходить разумно и без фанатизма, имея на то особый резон. И должны это делать люди, которые понимают, что они делают.
Основная проблема в том что на написание «рабочего кода» нужно X времени, а на написание «хорошего рабочего кода» 2X времени. И пусть даже современный заказчик готов оплатить эти 2Х времени, зачастую возникает ситуация, когда зарелизиться нужно через X времени (а как правило вчера). Поэтому иногда написание нормального (а как позже покажется — плохого), но главное рабочего кода — это необходимость а уже после есть время этот код зарефакторить.
Увы, всё так. Бизнес-модель накладывает свои ограничения на тёплый и уютный процесс разработки. Эту тему я уже обсуждал отдельно.
Статья хорошая.

Единственное хотелось упомянуть еще о таком моменте. Разработчики, особенно молодые, мало работающие в Команде (с большой буквы) часто очень категорически оценивают старый код в виде плохой\хороший. И норовят очень много зарефаторить\переписать. И тут как мне кажется дело не только в нецелевом, раннем и других видах рефакторинга. Важную роль играет отсутствие связи кода с контекстом в котором он разрабатывался. Код писался же не сам по себе. Он пишется всегда в контексте и совокупности имеющихся у нас ограничений и с целью выполнения конкретных задач.

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


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

В итоге рассматриваемый код надо классифицировать по менее эмоциональной шкале плохой\хороший. А все эмоциональное стремиться к категоричности — переписать полностью :) Гораздо правильней использовать более конструктивную шкалу: подходит, слабо подходит или не подходит под текущие требования (в том числе и к написанию\оформлению кода). И тогда полный рефакторинг это не «переписать все с нуля», а «взять за основу», «создать аналог с использование другого подхода\архитектуры\библиотек». Это позволит подойти к процессу еще более прагматично и эффективно.
И тогда ДАЖЕ полный рефакторинг это не «переписать все с нуля», а «взять за основу», «создать аналог с использование другого подхода\архитектуры\библиотек» и т.д. Это позволит подойти к процессу еще более прагматично и эффективно.

PS: акцент не на полном рефакторенге, а на его примере — как может измениться отношение.
Полностью согласен с вами, хорошие дополнения.
UFO just landed and posted this here
Это не объяснение. Это отмазка.
Куда смотрели сеньоры и лиды, когда такой код уходил в продакшн?
На РП, который сказал «нет времени, сегодня выкатываем как есть».
Не стоит рефакторить код, который кажется ужасным, потому что ты его не понимаешь

Рефакторить нужно всегда перед введением новой фичи — закладывайте +40% времени на совмещение старого кода с новой фичей.
закладывайте +40% времени на совмещение старого кода с новой фичей

Очень хорошее правило. Если бы все в своих бизнес-планах закладывали время на улучшение кодовой базы, то мир бы стал чуточку лучше.
А если из понимающих этот код остался в команду один единственный человек и тот уже за давностью лет плохо всё это помнит?
В таких случаях, как мне кажется, отдельное упорядочивание данного кода более чем необходимо. + Иногда и хотелось бы добавить в этот участок какую-то новую фичу… но особзнание, сколько придется потратить на это сил и времени(понять как работает, добавить, убедиться что ничего не сломалось, описать как работает теперь), что все просто боятся с этим связываться.

P.S. к относительно свежим проектам, использующим в основном логику и целочисленную арифметику сказанное относится в меньше степени — их проще покрывать тестами. А вот если, например, проект — решатель специфических систем дифференциальных уравнений, который изначально еще на фортране писался местами, перенес переписывание на C++ и, в силу специфики вычислений с плавающей точкой, не всегда полностью удается покрыть тестами(тупо от перестановки действий, в специфичном случае, может ухудшаться сходимость решения из-за ошибок округления).
Ну в таком случае, надо оценить — зачем рефакторить? 90% рефакторинга делается не для «красоты», а для возможности повторного использования. «Старый код» часто сложно повторно использовать, но если надо, лучше сделать просто объектную оболочку, а потом работать с ней, без прямого обращения к «старому коду».
Есть два «но» конкретно в данном случае.
1) Код крайне критичен к производительности. Это самое горячее место программы, обертки явно делу не помогут.
2) Менять в нем рано или поздно что-то придется. Например делать вариант кода для 3D(существующий 2D).
Когда Вы пишите, что-то близкое к аппаратному коду на С++ (как это вы описали) — забудьте о рефакторинге и «чистоте кода» — для математики ООП, а следовательно и рефакторинг не нужен, нужно просто умело декомпозировать код на функции в структурном стиле.
Я согласен, что ООП тут вообще никчему. Простите, а с какой стати рефакторинг как-то связан с понятием ООП? Вроде бы рефакторинг это изменение внутренней структуры программ для улучшения читаемости, упрощения внесений изменений и тп без изменения функциональности.
И аналогично, как связаны «чистота» и ООП?
Понятный читаемый код нужен в любой области. А следовательно и рефакторинг при необходимости.

В данном случае речь о рефакторинге на функции с понятными и хорошими именами, узбавление от ада goto, вынос групп логических условий в отдельные переменные с понятными и отражающими суть именами, выкидывание мертвого кода и тд. Что вы так к ООП привязались то? Рефакторинг никак не связан с парадигмами.
Думаю Вы не правы чисто исторически. Рефакторинг появился для ООП и как бы внутри ООП. Думаю все мы читали классику от М. Фаулера, и все что он пишет там относится исключительно к ООП. Никто не спорит, что код улучшали и до ООП, но никто это не называл рефакторингом. И я бы так это и оставил. Так как речь идет в рефакторинге о улучшении структуры кода, а в структурном программировании — просто нет структуры, если только не считать те зачатки в виде функций за структуру. Можно конечно позаниматься и мелочами о которых вы говорили, но я бы не называл это рефакторингом. Это как бы самом собой разумеющиеся и относится скорее к стилю программирования, и хороший программист сразу пишет учитывая все эти пожелания (с понятными и хорошими именами, узбавление от ада goto, вынос групп логических условий в отдельные переменные с понятными и отражающими суть именами, выкидывание мертвого кода).

Опять же в структурном программировании нет понятия повторного использования (вызов функции дважды к этому не относится). Повторное использование подразумевает исключительно повторное использование классов (предметных сущностей). А значит и необходимости в рефакторинге не возникает.

Допускаю, что исторически я могу быть и не прав. Но вас действительно не смущет это:
Так как речь идет в рефакторинге о улучшении структуры кода, а в структурном программировании — просто нет структуры, если только не считать те зачатки в виде функций за структуру.

Кстати, управляющие конструкции это тоже элементы структуры.

А про хорошего программиста… он и в рамках ООП по идее должен сам всё сразу писать так, что рефакторинг, в том чисе в вашей трактовке, не нужен.
Далее…
Опять же в структурном программировании нет понятия повторного использования (вызов функции дважды к этому не относится). Повторное использование подразумевает исключительно повторное использование классов (предметных сущностей).

Это вообще как??? Даже затрудняюсь прокомментировать.

В обще, кажется разговор переходит куда-то не туда… Предлагаю сойтись на том, что «ООП рефакторинг» в данном случае не имеет смысла в силу слабого использования самого ООП, остальные виды, упомнятые тем же Фаулером в своей книге, вы рефакторингом называть не хотите… Ну, ваше право.
Ок, сошлись на этом. Единственно, должен дополнить про

А про хорошего программиста… он и в рамках ООП по идее должен сам всё сразу писать так, что рефакторинг, в том чисе в вашей трактовке, не нужен.


Нет, так не получается у любого хорошего программиста. Меняются требования к задаче, предусмотреть это не возможно на все 100% — отсюда нужен рефакторинг. Почему именно в ООП это возникает? Ну, согласитесь, что смена требований редко меняет смысл уже использованных переменных их названий, goto и прочие мелочи внутри функции на это не влияют. Смена требований для структурного программирования происходит просто — расширение новых параметров в функциях — все. Для ООП все на порядок сложнее могут меняться роли классов, есл при одних требованиях выносить некий код было не нужно из класса, то при дополнении требований становится ясно, что образуется новая сущность… и т.д.

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

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

Более того, из-за всего этого иногда имеет смысл перехода от структурного подхода к ООП или наоборот. Это, кстати, тоже один из вариантов глубокого рефакторинга по Фаулеру.
Теперь я с Вами согласен :)

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

Но раз Вы задумались о рефакторинге некого старого кода — то это скорее указание на то, что превышен порог «среднего количества объектов, сложных и многочисленных связей». Боюсь может оказаться, что объектная оболочка, о которой я говорил выше вас спасет, и совсем будет не критична к производительности. Тесты производительности после рефакторинга вам в руки :) Если сделать по уму, надо выделить места для рефакторинга, ориентируясь не на домыслы, а на тесты производительности, и окажется, что 80% кода можно превратить в ООП и прорефакторить, выполнив новые требования.
Смена требований для структурного программирования происходит просто — расширение новых параметров в функциях — все.

Какая прекрасная иллюзия. К сожалению, нет, все не так легко. Функции тоже меняют набор ответственности, их необходимо перепроектировать и так далее.
А вот этого в структурном программировании и пытаются всеми силами избежать. Отсюда «легче переписывать заново, чем изменять». И все потому, что когда «Функции тоже меняют набор ответственности» — это указывает на «превышен порог «среднего количества объектов, сложных и многочисленных связей»». И поэтому это повод переписать вначале на ООП, а не разваливать ПО перепроектированием без наличия инструмента для этого.
А вот этого в структурном программировании и пытаются всеми силами избежать

Кто старается?

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

Во-первых, иногда варианта «переписать на ООП» нет. А во-вторых, ошибочно думать, что за пределами ООП нет адекватных инструментов проектирования.
назовите хоть одно
ч.т.д.

Только я предпочитаю работать с конструкциями языка, а не играть в игры разума.
В чём ваша проблема? вы правда думаете, что кода без ООП не существует?
Или что к этому коду(не ООП) не применяется рефакторинг(изменение кода, без изменения функциональности, с целью повысить читаемость, поддерживаемость, производительность)?

Уверяю вас, проекты, где это ваше ООП — как корове седло, существуют…
бедный Хаскел, за что вы его так?
Вот чтобы работать с конструкциями языка, и нужны мозги. Тогда становится понятно, что ООП — не единственное прибежище сложных систем.
пруф из книги Фаулера, где он прямо связывает одно с другим

В течение последующей пары лет у меня были многочисленные возможности поговорить о рефакторинге
на внутренних совещаниях в AT&T BellLabs, на конференциях и семинарах в других местах. По ходу своих
бесед с практическими разработчиками я начал понимать, почему мои прежние обращения к слушателям не
были ими поняты. Отсутствие контакта было частично вызвано новизной объектно-ориентированной
технологии. Немногие из тех, кто работал с ней, продвинулись дальше первоначального релиза и потому еще не
столкнулись с трудными проблемами развития продукта, которые помогает решить рефакторинг.
И еще анализируйте ошибки приходящие из отдела тестирования — попробуйте понять, чем они вызваны, очень часто бывает так, что ошибки взаимосвязаны (логически), вы их исправляете вразных местах, но отдел тестирования возмущается, что они уже говорили об этой ошибке — но они для вас разные… как сделать рефакторинг в этом случае понять сложно — но думайте и однажды вы устраните целый поток однотипных ошибок.
Частенько случается, что вместо
Скорее всего, в процессе большого рефакторинга или переписывания отдельных частей вы замените старый работающий говнокод новым, идеально написанным кодом, но с багами.

получается просто
Скорее всего, в процессе большого рефакторинга или переписывания отдельных частей вы замените старый работающий говнокод новым.
Есть аналогичный сайт на английском, но с бо́льшим количеством контента: SourceMaking.com
UFO just landed and posted this here
Sign up to leave a comment.