Рефакторинг — это что-то типа полироля для кода. Если по какой-то причине возвращаешься к своему, старому коду (не для того, что бы его лишний раз облизать, а вполне по делу) и что-то в нем не нравится надо пройти вполне конкретную формальную процедуру: ответить себе на вопрос, а что же конкретно плохо; определить стратегию исправления (возможно на несколько итераций вперед)… В общем ничего нового.
У меня например, есть библиотеки чей код я обожаю — к нему я возвращаюсь (по делу!!!) минимум раз в пол года. Есть проекты, чей код устраивает — которым было уделено больше двух итераций. А есть, чей не нравится — который писался до того как определилась природа описанных в нем сущностей (если вернусь, немного перераспределю обязанности).
Фаулер этому явлению предложил название — «запах»
Факт того, что код мне не нравится, я объясняю не тем что вчера был тупее. А тем, что уделил ему суммарно мало времени. Если возникнет необходимость уделю больше.
А что вам мешает заменить цикл на LINQ только в этом месте? Почему это надо делать обязательно везде и сразу?
Я к тому, что локальный рефакторинг и «все стереть к чертовой матер» это немного разные вещи. За первое я двумя руками «за», второе же кажется немного странным поведением.
Это происходит потому, что в момент возврата к коду через месяц, вы не до конца помните что там есть и зачем это все. Отсюда недоверие.
Чуть-чуть скорректировать архитектуру вы не в состоянии по той же самой причине — не помните тонкостей. Да и страшно: «сейчас ведь работает». Отсюда и желание написать все заново.
Пишите больше автоматических тестов (TDD или не TDD — вопрос десятый) и начнете себе доверять. Сможете лучше оценивать объем ранее сделанной работы и начнете понимать, что переделывать придется попросту Очень много — легче изменить часть которая действительно не устраивает.
Не понял причем здесь "… научных расчётов". Скорей это гайд настройки тестовой среды для программы на C.
Понравилась фраза: Потому, что какой это научный расчёт, если код, его осуществляющий, не протестирован должным образом? Ну, это просто помимо того, что с тестированием разработка в протекает сильно быстрее.
Как-то читал пост на аналогичную тему, с обратным поворотом сюжета (типа тесты для математических вычислений — это извращение). Версия автора этого поста мне ближе.
1. Помоему любой cast — это «запах», говорящий о том что введен лишний уровень абстракции: мы как бы говорим, что яблоки и автомобильные шины «родственны», но при работе с ними все равно применяем конкретно яблоки и конкретно шины. В чем тогда «родственность»?
2. Я возможно заблуждаюсь (потому, что не вижу весь код целиком и не доконца представляю его окончательный вид), но помоему Object и его потомки «бедноваты». Они являются носителями данных и только: accept выполняющий передачу управления переданному в параметре визитору выглядит странно. С таким же успехом это мог бы выполнить клиент этих классов.
Лучше чем специально обученные люди креатив ни кто не сделает. Большинство из которых кстати дизайнеры, потому что их учат тому что пипл схавает, а что нет. Психология там всякая. Это к слову.
Под креативом вы наверняка подрузамеваете «идею» совершенно нового продукта. Не старой галоши завернутой в фальгу, а реального perpetuum mobile. Что бы как Бил Гейтс в старом анекдоте сказать: «Окна». И муравьи послушно начали пилить, потому что всем сразу стало все ястно.
Если это так, то вы Марк Цукерберг и за 1000 баксов перевернете мир.
По моему это имено оно и означает. Эффективное управление это не только стоять над душой и говорить где какую линию добавить, а где убрать мерцание. Это планирование, растановка приорететов, поиск индивидуальных подходов… да и много чего еще. На эту тему книги пишут и доклады читают. А полемика в это области ведется не меньшая, чем о TDD.
Юзабилити стоит затрат ресурсов. На тот же Apple работает большое количество матерых дизайнеров мнение которых более приоритетно, чем мнение программистов. Отсюда и результат. Разделение труда, однако.
Если следовать вашей логики, то сложность поиска по массиву не есть O(n), ведь с вероятность 1/n элемент может находится в первой ячейке. А по хешь таблице может быть и O(n), ведь
Месяц назад, мне захотелось в первые за год написать комментарий на строку кода (внутри метода). Я ее написал, пошел дальше. Подумал, вернулся и разделил строку на две или три. Комментарий удалил. Завтра, если я ее увижу и подумаю, что она все равно сложная — еще чего-нибудь сделаю.
Абзацы — надо делить на отдельные функции с внятными именами.
Возможность сворачивать — это фича. Она, как и наличие коментариев (методанных), не влияет на качество кода. Мне нравится мысль Фаулера: если для объяснения кода нужен коментарий попробуйте отрефакторить его (почти дословно).
Помоему, изначально Вы писали тесты функций, а не поведения. В этом и проблема.
У автора статьи есть фраза:
введение иерархий: методы инкапсулируются в классы, классы в пакеты, пакеты в библиотеки
Каждая из этих частей — есть модуль, пусть и разного уровня. Тесты, по моему, надо писать на тот уровень, где строятся требования — не выше (будет сложно их делать), не ниже (постоянно будет происходить описанный эффект домино).
А «до 30-40 тестов» вообще похоже на coverage 100%
Производительность — однозначна спорная вещь, я на ней не настаиваю. К тому же при выполнении sql-запросов. Просто замечание. Факт просадки может определить только профайлер.
А вот с интерфейсами — выигрыш по моему спорен. У вас упоминание о типе объектов просто переехало в другое место.
Производительность на нескольких процессорах с ГГц-ами — конечно не главное, но… Рефлексия на каждый чих достаточно жестокая вещь.
А потом я не понял особой разницы между new BaseRepository().AllItems и new DBContainer().UnitSet. Конструкции по моему равнозначные (без полиморфизма же). По длине и по сложности очень похожие.
Прикольно. С помощью полиморфизма мы решаем проблему «мерзких проверок».
Говоря о ленивости я имел введу отсутствие членов у класса исключения. А значит он имеет хороший потенциал по их принятию (в результате «переноса метода») от других классов.
Я понял, что вам тоже понравилось. За предыдущее высказывание хотел поставить плюс. Но у меня принцип — не оценивать непосредственного собеседника :). Разговаривая с вами, стараюсь понять все грани обсуждаемой идеи.
Несколько try..catch блоков. Получается что-то типа цепочки обязаностей. Вариант. Но по архитектурной сложности это почти тоже самое (по одному методу на catch). Вопрос стоит только в расположении методов.
Я понимаю, что try..catch..catch… — в конкретном месте необходим. Но ощущение дублирования от этого не уменьшается. Понимание необходимости притупляет желание исправить, но код не улучшает.
Кстати. Больше половины моих исключений выглядит так:
class MyException: Exception {}
До меня сейчас дошло — он же ленив. Вот, что значит новый взгляд на знакомые вещи.
У меня например, есть библиотеки чей код я обожаю — к нему я возвращаюсь (по делу!!!) минимум раз в пол года. Есть проекты, чей код устраивает — которым было уделено больше двух итераций. А есть, чей не нравится — который писался до того как определилась природа описанных в нем сущностей (если вернусь, немного перераспределю обязанности).
Фаулер этому явлению предложил название — «запах»
Факт того, что код мне не нравится, я объясняю не тем что вчера был тупее. А тем, что уделил ему суммарно мало времени. Если возникнет необходимость уделю больше.
Я к тому, что локальный рефакторинг и «все стереть к чертовой матер» это немного разные вещи. За первое я двумя руками «за», второе же кажется немного странным поведением.
Чуть-чуть скорректировать архитектуру вы не в состоянии по той же самой причине — не помните тонкостей. Да и страшно: «сейчас ведь работает». Отсюда и желание написать все заново.
Пишите больше автоматических тестов (TDD или не TDD — вопрос десятый) и начнете себе доверять. Сможете лучше оценивать объем ранее сделанной работы и начнете понимать, что переделывать придется попросту Очень много — легче изменить часть которая действительно не устраивает.
Понравилась фраза:
Потому, что какой это научный расчёт, если код, его осуществляющий, не протестирован должным образом? Ну, это просто помимо того, что с тестированием разработка в протекает сильно быстрее.
Как-то читал пост на аналогичную тему, с обратным поворотом сюжета (типа тесты для математических вычислений — это извращение). Версия автора этого поста мне ближе.
2. Я возможно заблуждаюсь (потому, что не вижу весь код целиком и не доконца представляю его окончательный вид), но помоему Object и его потомки «бедноваты». Они являются носителями данных и только: accept выполняющий передачу управления переданному в параметре визитору выглядит странно. С таким же успехом это мог бы выполнить клиент этих классов.
Под креативом вы наверняка подрузамеваете «идею» совершенно нового продукта. Не старой галоши завернутой в фальгу, а реального perpetuum mobile. Что бы как Бил Гейтс в старом анекдоте сказать: «Окна». И муравьи послушно начали пилить, потому что всем сразу стало все ястно.
Если это так, то вы Марк Цукерберг и за 1000 баксов перевернете мир.
На самом деле за единичную операцию при оценке работы с хешь таблицами берется операция в которой может возникнуть коллизия
Абзацы — надо делить на отдельные функции с внятными именами.
У автора статьи есть фраза:
введение иерархий: методы инкапсулируются в классы, классы в пакеты, пакеты в библиотеки
Каждая из этих частей — есть модуль, пусть и разного уровня. Тесты, по моему, надо писать на тот уровень, где строятся требования — не выше (будет сложно их делать), не ниже (постоянно будет происходить описанный эффект домино).
А «до 30-40 тестов» вообще похоже на coverage 100%
А вот с интерфейсами — выигрыш по моему спорен. У вас упоминание о типе объектов просто переехало в другое место.
А потом я не понял особой разницы между new BaseRepository().AllItems и new DBContainer().UnitSet. Конструкции по моему равнозначные (без полиморфизма же). По длине и по сложности очень похожие.
С человеческим восприятием спорить глупо. В именовании фикстур проверок я ставлю на первое место слово Assert. Например: AssertReadonly.
Говоря о ленивости я имел введу отсутствие членов у класса исключения. А значит он имеет хороший потенциал по их принятию (в результате «переноса метода») от других классов.
Несколько try..catch блоков. Получается что-то типа цепочки обязаностей. Вариант. Но по архитектурной сложности это почти тоже самое (по одному методу на catch). Вопрос стоит только в расположении методов.
Я понимаю, что try..catch..catch… — в конкретном месте необходим. Но ощущение дублирования от этого не уменьшается. Понимание необходимости притупляет желание исправить, но код не улучшает.
Кстати. Больше половины моих исключений выглядит так:
class MyException: Exception {}
До меня сейчас дошло — он же ленив. Вот, что значит новый взгляд на знакомые вещи.