FDS>>>>>А теперь представим себе, что это не просто матрица, а часть другой матрицы (это не надуманная задача). Тогда к каждой функции ещё надо будет прибавлять по два параметра — начальные и конечные индексы суммирования. M>>>>Первое, что приходит в голову — Граничный объект. Рефакторинг "Введение граничного объекта (объекта параметров)" FDS>>>Честно говоря, не понимаю, как это сделать так, что бы написать неотстойны код. Поясните, пожалуйста, на примере (в смысле — код на естетсвенном языке)
M>>К сожалению, не получилось найти готового примера. Но хорошие примеры точно есть в книге «Рефакторинг» Мартина Фаулера
(Fowler's "Refactoring"). Если где-то поблизости от Вас имеется экземпляр, рекомендую обратиться именно к нему.
FDS>Где-то поблизости нету. Я имею ввиду — представьте своё видение решения описанной мной задачи на естественном языке, оформелнном в виде кода. Я думаю, Фаулер об этой задаче и не заикался, к тому же я и сам могу привести примеры к этому правилу, только я не понимаю, как вы собираетесь его применять к моей задаче.
FDS>
Есть группа параметров, естественным образом связанных друг с другом.
FDS>Замените их объектом.
FDS>Где тут группа параметров?
Вы сами их назвали в описании деталей Вашей задачи.
1й очевидный проход — группа параметров выделена жирным в Вашей цитате.
Два параметра — начальные и конечные индексы суммирования — превращаются в один — диапазон суммирования.
Если по прежнему отстой — 2й проход — граничный объект выделен жирным курсивом
Часть другой матрицы (MatrixPart) — это матрица с диапазоном суммирования.
Наш организм может позволить и дальнейшие абстракции.
Сложнее будет. если функция Ваша уже является членом Вашего класса матриц. но и это излечимо. Всё излечимо.
Что это нам даёт или может нам дать в дальнейшем, а также что делать, если опять отстой — об это лучше говорить на языке паттернов проектования...
Рекомендую однакомиться с паттернами проектирования Go4:
online (примеры на C#) anoter online (просто список, среди других групп паттернов) book (примеры на С++) another book (этого издания я в руках еще не держал. Судя по оглавлению — перепечатка book)
Re[8]: Тривиальная задача - как неотстойно написать?
Здравствуйте, moudrick, Вы писали:
FDS>>>>>>А теперь представим себе, что это не просто матрица, а часть другой матрицы (это не надуманная задача). Тогда к каждой функции ещё надо будет прибавлять по два параметра — начальные и конечные индексы суммирования. M>>>>>Первое, что приходит в голову — Граничный объект. Рефакторинг "Введение граничного объекта (объекта параметров)" FDS>>>>Честно говоря, не понимаю, как это сделать так, что бы написать неотстойны код. Поясните, пожалуйста, на примере (в смысле — код на естетсвенном языке) FDS>>
Есть группа параметров, естественным образом связанных друг с другом.
FDS>>Замените их объектом.
FDS>>Где тут группа параметров?
M>Вы сами их назвали в описании деталей Вашей задачи.
M>1й очевидный проход — группа параметров выделена жирным в Вашей цитате. M>Два параметра — начальные и конечные индексы суммирования — превращаются в один — диапазон суммирования.
Это даже ещё неудобней — мне придётся создавать структуру или даже объект, который будет хранить эти диапазоны — лишний код, к тому же ещё более загромождённый.
M>Если по прежнему отстой — 2й проход — граничный объект выделен жирным курсивом M>Часть другой матрицы (MatrixPart) — это матрица с диапазоном суммирования.
Нельзя: матрица — неделимый объект. Опять же по вопросам экономии памяти и эффективности.
M>Наш организм может позволить и дальнейшие абстракции.
Хм...
M>Сложнее будет. если функция Ваша уже является членом Вашего класса матриц. но и это излечимо. Всё излечимо.
M>Что это нам даёт или может нам дать в дальнейшем, а также что делать, если опять отстой — об это лучше говорить на языке паттернов проектования...
M>Рекомендую однакомиться с паттернами проектирования Go4:
Хм. Не понял, чем они помогут... Тут в том то и прикол, что задачка в общем то функциональная с одной стороны, а с другой стороны — в объекты её запихивать 1. довольно не эффектино, 2. Нечитаемо, так как задачка всё-таки именно для функционального стиля и добавление классов получается надуманным (пока я не увидел другого).
Здравствуйте, moudrick, Вы писали:
K>>Если в процессе разработки резко возникает необходимость в неизвестной ранее фиче, это всего лишь означает, что ПМ ее проворонил на стадии формирования списка фич. M>Насколько часто формируется этот список фич?
После выпуска каждой версии.
K>>Далее, эта фича либо откладывается на следующую версию (если получится), либо поступает в разработку со сдвигом сроков сдачи. M>На сколько?
Зависит от фичи.
K>>В любом случае, это проблема менеджемента — не разработчиков. M>Ага, давайте опять все спишем на ПМ. У него голова (читай — зарплата) большая — пусть думает. А ты сам не боишься оказаться на его месте?
Я уже на его месте Хоть формально и не ПМ.
K>>Но я прекрасно понимаю, что в реальности довольно часто сдвига сроков не бывает, и что разгребать все это приходится разработчикам. То есть, хорошим разработчикам однозначно стоит быть к этому готовыми, да и получается частенько само (с TDD, рефакторингами и пр.). M>Ну вот вы же сами и показали, что мое восприятие ближе к реальности, чем Ваше.
Гм. Это и мое восприятие тоже
K>>Но это совершенно не означает, что ПМ должен перманентно подкидывать такие задачки. M>Традиционная методика разработки ПО. Существует и дает иногда неплохие результаты. Имеет право на существование. Не является гибкой и потому неспособна решать "гибкие" задачи.
Значит, у нас работает некая комбинация традиционной разработки и Agile Programming. Что есть, имхо, хорошо, потому что устраивает как разработчиков (которые мотивированы и готовы писать надежный и тестируемый код с частыми релизами), так и менеджмент (задачи которого выполняются в предсказуемые и не слишком большие сроки). Истина — она всегда где-то посередине
M>Кстати, в XP тоже есть некий порядок в планировании имплементации фич. Но в силу "Small Releases" ими можно гибче управлять, чаще добавлять/изменять без ущера качеству разрабатываемого продукта. Частота зависит от длительности итерации. Итерации обычно короткие — неделя или две. Подкидывать можно перманентно, где перманентно означает — в начале итерации.
У нас так и происходит. И для этого совсем не обязательно внедрять XP. Хотя, апологеты XP думают иначе, конечно
M>А где гарантия, что эти изменения/добавления ничего существующего не сломали?
В юнит-тестах для кода, написанного с помощью TDD (которое включает в себя рефакторинг).
M>Поверьте, в agile-технологиях не брезгуют хорошим проектированием. Agile-методики не отрицают, а дополняют хорошее проектирование. А хорошее проектирование, кстати, включает в себя Unit-тестирование. Как правило — в виде неотъемлемой части.
А я нигде и не отрицал положительного влияния TDD на архитектуру и юнит-тестов на надежность кода.
K>>А архитектуру на ходу рефакторить... Мы сейчас именно этим и занимаемся. Тот еще экстрим, уж поверьте. Да и не рефакторинг это уже, а тренировка саперов на настоящем минном поле. M> Самое время рассмотреть возможность применения методик XP. Я серьёзно.
Не поможет тут XP. Оно поможет, если мы выкинем старое, и начнем делать новое. Сейчас рефакторинг помогает привести существующий код в такое состояние, при котором изменение архитектуры скажется на работе системы как можно менее безболезненно. Но совсем безболезненно — не получится. Это реальность. Те же законы Мерфи.
If a shark stops swimming, it will die. Don't stop swimming, Mr. Mulder.
Every epic equalizer is iso (c)
Re[8]: Тривиальная задача - как неотстойно написать?
M>>1й очевидный проход — группа параметров выделена жирным в Вашей цитате. M>>Два параметра — начальные и конечные индексы суммирования — превращаются в один — диапазон суммирования.
FDS>Это даже ещё неудобней — мне придётся создавать структуру или даже объект, который будет хранить эти диапазоны — лишний код, к тому же ещё более загромождённый.
Если класс устранит дублирование, лишний небольшой код при его определении
обязательно компенсируется большей понячтностью и местами сокращением кода
1. в местах вызова метода с граничным объектом
2. в теле фунции при использовании параметров.
Загроможденности представить не могу. Это надо натуру смотреть.
M>>Если по прежнему отстой — 2й проход — граничный объект выделен жирным курсивом M>>Часть другой матрицы (MatrixPart) — это матрица с диапазоном суммирования. FDS>Нельзя: матрица — неделимый объект. Опять же по вопросам экономии памяти и эффективности.
Как же так? Вы же пишете на С++? (Думаю, да, перед Вами же Дамокловым мечом висит требование эффективности)
Дык а С++ ведь позиционирует себя как язык, в котором парадигмы ООП можно применить на практике при требовании бескомпромиссной эффективности (неточная перефразировка слов из книги Б.Страуструпа "Дизайн и эволюция С++". Если надо — поищу точную цитату)
Для этого в языке предусмотрен целый ряд средств и соглашений,
вполне согласованных с реализацией ООП в С++, как-то: ссылочные типы (references, &), шаблоны (templates), inline-методы, указатели на члены. всего сразу и не вспомнишь...
Если ваш компилятор неэффективно компилирует эффективный код — что ж.
Возможно Вы неверно написали Ваш код и ошибочно считаете его эффективным.
А возможно Вам енадо сменить компилятор.
Я предполагаю первое с большей вероятностью.
Либо Вы совсем не пишете этот код, не знаю, как ег онаписать эффективно.
Вас никто не заставляет делить Ваш объект. Вам всего лишь надо его инкапсулировать.
С++ при правильном его использовании позволит Вам это сделать без потери эффективности как по сокости выполнения, так и по занимаемой памяти.
M>>Что это нам даёт или может нам дать в дальнейшем, а также что делать, если опять отстой — об это лучше говорить на языке паттернов проектования...
M>>Рекомендую однакомиться с паттернами проектирования Go4:
FDS>Хм. Не понял, чем они помогут... Тут в том то и прикол, что задачка в общем то функциональная с одной стороны, а с другой стороны — в объекты её запихивать 1. довольно не эффектино, 2. Нечитаемо, так как задачка всё-таки именно для функционального стиля и добавление классов получается надуманным (пока я не увидел другого).
Если Вы видите задачу как функциональную — так и решайте.
Однако, об избавлении кода от отстойности в рамках функционального стиля мне ничего неизвестно...
Кстати, Вы натолкнули меня на мысль (возможно. неверную), что функциональный стиль местами не в состоянии бороться с отстойностью кода...
Если это так — тогда перед Вами выбор. Выбирайте с умом (с) Dave Astels
фK>>>Если в процессе разработки резко возникает необходимость в неизвестной ранее фиче, это всего лишь означает, что ПМ ее проворонил на стадии формирования списка фич. M>>Насколько часто формируется этот список фич?
K>После выпуска каждой версии.
[........поскипано.........]
M>>Кстати, в XP тоже есть некий порядок в планировании имплементации фич. Но в силу "Small Releases" ими можно гибче управлять, чаще добавлять/изменять без ущера качеству разрабатываемого продукта. Частота зависит от длительности итерации. Итерации обычно короткие — неделя или две. Подкидывать можно перманентно, где перманентно означает — в начале итерации.
K>У нас так и происходит. И для этого совсем не обязательно внедрять XP. Хотя, апологеты XP думают иначе, конечно
Я апологет XP. Я с Вами согласен — не обязательно. Но прошу согласиться со мной в том, что можно.
А я бы даже добавил — рекомендательно.
Кроме того. Вы не уточнили размер итерации.
XP характеризуется предельно кортокими итерациями.
Чаще всего это 1 неделя или 2 недели — Small releases.
Потому добавка фичи у Вас и добавка фичи при использовании XP по срокам могут отличаться на месяцы.
Re[2]: Тривиальная задача - как неотстойно написать?
Здравствуйте, FDSC, Вы писали:
FDS>Дык, во всех вариантах код — отстой. Во всех, я сам убедился (судя по этой статье). Может кто знает другой вариант?
Еще есть вариант ипользовать стиль "литературное программирование", когда код пишется как прийдется, а подстрочником человеческим языком объясняется что он делает, зачем и почему. Для любых хоть сколько-то математических алгоритмов самое то.
Здравствуйте, anvaka, Вы писали:
A>Здравствуйте, FDSC, Вы писали:
FDS>> [..] допустим мне нужно написать код перемножения двух матриц [..] FDS>> Может кто знает другой вариант?
A>На самом верхнем уровне, код выглядит примрено так:
A>
A = B * C;
Это он в C++ так выглядит. И даже там он так не выглядит: как мне записать не внутреннее произведение матриц, например AjiBjk?
A>Как выдлеить подматрицу из матрицы? A>
A> B1 = B.GetMinor(i, j);
A>
Ну и, то есть в B1 мне нужно копировать часть матрицы?
Или там будут только указатели на нужные данные? Это конечно, приемлемо.
Re[9]: Тривиальная задача - как неотстойно написать?
Здравствуйте, moudrick, Вы писали:
M>>>1й очевидный проход — группа параметров выделена жирным в Вашей цитате. M>>>Два параметра — начальные и конечные индексы суммирования — превращаются в один — диапазон суммирования.
FDS>>Это даже ещё неудобней — мне придётся создавать структуру или даже объект, который будет хранить эти диапазоны — лишний код, к тому же ещё более загромождённый.
M>Если класс устранит дублирование, лишний небольшой код при его определении M>обязательно компенсируется большей понячтностью и местами сокращением кода M>1. в местах вызова метода с граничным объектом M>2. в теле фунции при использовании параметров.
M>Загроможденности представить не могу. Это надо натуру смотреть.
Хм. Тут в "тривиальном ответе" нечто подобное предложили. Я кажется понял, хотя это только пол решения
M>>>Если по прежнему отстой — 2й проход — граничный объект выделен жирным курсивом M>>>Часть другой матрицы (MatrixPart) — это матрица с диапазоном суммирования. FDS>>Нельзя: матрица — неделимый объект. Опять же по вопросам экономии памяти и эффективности.
M>Как же так? Вы же пишете на С++? (Думаю, да, перед Вами же Дамокловым мечом висит требование эффективности)
В плане создания временного объекта "матрица", который только указывает на данные решение сойдёт.
M>Если ваш компилятор неэффективно компилирует эффективный код — что ж. M>Возможно Вы неверно написали Ваш код и ошибочно считаете его эффективным.
То есть вы считаете, что если код медленно работает, то он просто не эффективный? Значит, вы не встречались с вычислительно трудоёмкими задачами.
M>Если Вы видите задачу как функциональную — так и решайте. M>Однако, об избавлении кода от отстойности в рамках функционального стиля мне ничего неизвестно...
M>Кстати, Вы натолкнули меня на мысль (возможно. неверную), что функциональный стиль местами не в состоянии бороться с отстойностью кода...
С мыслью согласен. Хотя ещё не всё решено и в ООП
Re[3]: Тривиальная задача - как неотстойно написать?
Здравствуйте, Miroff, Вы писали:
M>Здравствуйте, FDSC, Вы писали:
FDS>>Дык, во всех вариантах код — отстой. Во всех, я сам убедился (судя по этой статье). Может кто знает другой вариант? M>Еще есть вариант ипользовать стиль "литературное программирование", когда код пишется как прийдется, а подстрочником человеческим языком объясняется что он делает, зачем и почему. Для любых хоть сколько-то математических алгоритмов самое то.
Я очень не люблю этот стиль, хотя часто я так и делаю (стараясь, что бы и код был понятен).
Но ведь тут вся загвоздка, что писать его то же не удобно
Да и потом — это же только пример, как трудно написать неотстойный код даже в такой лёгкой задаче
Re[10]: Тривиальная задача - как неотстойно написать?
M>>Если ваш компилятор неэффективно компилирует эффективный код — что ж. M>>Возможно Вы неверно написали Ваш код и ошибочно считаете его эффективным.
FDS>То есть вы считаете, что если код медленно работает, то он просто не эффективный? Значит, вы не встречались с вычислительно трудоёмкими задачами.
Встречался. Правда, крайним разом это было на моей дипломной работе, т.е. достаточно давно.
В бизнес-практике мне не приходилось сталкиваться с такими задачами, либо же они так или иначе решались без участия моего кода.
Я хотел сказать, что в С++ можно выбрать достаточно много разных вариантов представления,
И чтобы выбрать наиболее эффективный для решения Вашей задачи, надо очень хорошо представлять, что Вы делаете, и что потом будет делать компилятор с Вашим кодом. А для этого нужно очень хорошо знать философию языка.
А насчёт вычислительной трудоёмкости — мне известны не только вычислительно трудоёмнкие задачи, но и вообще неразрешимые (алгоритмически)
Re[4]: Тривиальная задача - как неотстойно написать?
Здравствуйте, FDSC, Вы писали:
FDS>Вопрос по неотстойному написанию: допустим мне нужно написать код перемножения двух матриц.
FDS>Я могу его написать 4 функциями, соответствующими AijBjk; AjiBjk; AijBkj; AjiBkj; FDS>Но это будет дублирование кода, причём почти copy-paste — то есть код — отстой
[...]
Не отстоем будет макра, которая сгенерит хороший и оптимальный код в зависимости от параметров.
И в ней, понятное дело, никакого "почти copy&paste" не будет.
FDS>В итоге я прихожу к самому удобному (я не шучу, я так и делал) варианту — когда нужно что-то перемножать я просто пишу код этого перемножения (цикл с двукратной вложенностью) прямо в код, без всяких вызовов.
А я в этой ситуации использую макрос. Который, конечно же, компилируется в тот же самый код, что у вас. Только мой код читабельней и сопровождабельней вашего на пару порядков.
FDS>Дык, во всех вариантах код — отстой. Во всех, я сам убедился (судя по этой статье). Может кто знает другой вариант?
Мой вариант — не отстой. Легко тестируемый, хорошо комментируемый, никакого дублирования функциональности.
А, ну ещё проблемка — не во всех языках это возможно. К некоторым особенно ущербным языкам даже внешних макропроцессоров не полагается. Хорошо, что для Java такой макропроцессор имеется в наличии!
Re[3]: Тривиальная задача - как неотстойно написать?
Здравствуйте, Miroff, Вы писали:
M>Еще есть вариант ипользовать стиль "литературное программирование", когда код пишется как прийдется, а подстрочником человеческим языком объясняется что он делает, зачем и почему. Для любых хоть сколько-то математических алгоритмов самое то.
Код пишется не как попало, а с чёткой структурой и с разделением на функциональные единицы. Для этого в большинстве средтсв литературного программирования есть простенькая макпроподстановка, так что можно писать:
Функция делающая бла-бла-бла по растакому-то алгоритму, оценка производительности делалась так-то, и вообще, вот вам цитата из Пушкина:...
void thefunction(blabla bubu) {
Тело этой функции полностью совпадает с телом функций такой-то, так что здесь мы это комментировать не будем...
@<FunctionCode>
}
Здравствуйте, Владислав Сивяков, Алексей Мудрик (перевод), Вы писали:
ИМХО совершенно идиотская статья. Идиотская по многим причинам.
Во-первых, автор ничему не учит, ничего не доказывает, не объясняет. Нет. Он говорит — "Вы все дебилы, один я умный. Айда за мной!". Мне не очень нравится когда мне такое говорят
Во-вторых, автор глубоко убеждён что тестирование это панацея. Ну можно было бы отшутится на тему, "серебрянных пуль нет" или ещё что-нибудь такое банальное сказать, но в данном случае можно и конкретне. Всерьёз считать, что тестирование кода действительно улучшает код это полный бред. Начать с того, что очень маленький объём кода поддаётся автоматическому тестированию. Например, недавний мой баг — в текстовом редаторе, если выделять строку и следующая строка короче выделяемой, то выделение рисуется неправильно. Может я что-то в этой жизни упустил, но я себе совершенно не представляю как можно отследить подобную ошибку автоматически. Зато человеком она была найдена меньше чем за минуту. Хотя нет, можно было бы в момент отрисовки заполнять некоторой массив параметрами форматирования символов и потом проверять, что выделенные символы отформатированные правильно. А проверяли бы мы это той самой неправильной функцией, которая до этого неправильно эти параметры установила. Вот мы и подошли к следующему тезису — юнит-тесты должны быть крайне простыми иначе нам потребуются юнит-тесты для юнит-тестов. Более того, даже написание простых тестов отнимает время и силы.
Пользуюсь ли я юнит-тестами? Конечно нет! Правильно ли я сложил два числа я проверять не буду, я в себе уверен. А найти и исправить руками действительно сложную ошибку гораздо проще и быстрее, чем ломать голову над написанием теста. Многие скажут, а если ошибка вернётся? Ведь придётся заново её искать и исправлять. Ну что же, если у вас в проекте не ошибки, а птицы-фениксы, значит у вас серьёзные проблемы с архитектурой. Правильная архитектура в гораздо большей степени способствует уменьшению количества ошибком, нежели юнит-тесты, а неправильную никакие юнит-тесты не спасут.
В-третьих, про фреймворки идёт совершенно бессмысленный набор слов. Автор просто не знал что хочет сказать, но очень хотелось на эту тему поговорить. Слово "модный" полностью раскрыло полное непонимание механизма выбора библиотек. Модный это не аргумент для программиста, оставьте это маркетологам. Распространённый, документированный — вот аргументы. Меня совершенно не интересует мода, но между плохой библиотекой, которую знаю 100 человек и хорошей, которую знает 3 лучше выбрать плохую. Лучше, потому что когда и о второй библиотеке будут знать 100 человек она тоже будет казаться нам плохой. Но уже как-то по своему. А про глюки первой библиотеки мы уже хорошо знаем. Извечный пример MFC — библиотека по современным меркам так себе, но зато какой накоплен опыт!
Обратите внимание на забавную вещь. Содержание статьи — банальные мысли, которые высказывались не раз, в контексте рефакторинга, в контексте методологии XP, и в общих работах по разработке ПО. Но там против них никто не протестовал (наверное даже многие их не заметили). А стоило обернуть их в такую форму, как поднялась жаркая дискуссия Поздравляю, старый способ привлечь внимание сработал на вас. По такому же принципу работает передача "Окна", куча рекламы, полит.агитации, желтая пресса, психологические тренинги т.д.
a>Он говорит — "Вы все дебилы, один я умный. Айда за мной!".
Давай перефразируем по пунктам:
— код должен работать
— надо стараться разбивать систему так, чтобы как можно больше её частей тестировались автоматически
— код должен быть читабельным
— код должен быть понятным
— надо думать своей головой, а не тупо следовать методологии
— устраняйте дублирование (рефакторинг)
Разве тут что-то странное или новое? Но напиши статью по этим пунктам, и все скажут "ну и что? мы это и так знаем".
Здравствуйте, Кодёнок, Вы писали:
Кё>- код должен работать Кё>- надо стараться разбивать систему так, чтобы как можно больше её частей тестировались автоматически
Нет. Он говорит, что если тестов нет, то код нельзя считать работающим. А это бред, потому что есть дофига кода не тестируемого автоматически.
Кё>- надо думать своей головой, а не тупо следовать методологии
Ага. 20 человек в команде и каждый подумал своей головой Зашибись.
Здравствуйте, moudrick, Вы писали:
M>>>Кстати, в XP тоже есть некий порядок в планировании имплементации фич. Но в силу "Small Releases" ими можно гибче управлять, чаще добавлять/изменять без ущера качеству разрабатываемого продукта. Частота зависит от длительности итерации. Итерации обычно короткие — неделя или две. Подкидывать можно перманентно, где перманентно означает — в начале итерации. K>>У нас так и происходит. И для этого совсем не обязательно внедрять XP. Хотя, апологеты XP думают иначе, конечно M>Я апологет XP. Я с Вами согласен — не обязательно. Но прошу согласиться со мной в том, что можно. M>А я бы даже добавил — рекомендательно.
Я бы порекомендовал изучить несколько методик разработки ПО. Потом хорошенько подумать. Потом еще раз хорошенько подумать и решить, какие принципы этих методик удовлетворяют внутриконторной планке "цена внедрения/отдача". Потом еще раз хорошенько подумать и начинать по одному их внедрять, внимательно наблюдая за эффектом. После внедрения, хорошенько подумав, решить, а принесут ли другие, "забытые" принципы методик схожий эффект? При утвердительном ответе, хорошенько подумав, повторить.
Это я к тому, что XP — не панацея. Где-то оно сработает, а где-то совсем нет. Где-то оно могло бы сработать без парного программирования, но из-за того, что апологет был апологетом, он не стал его внедрять. Think different!
M>Кроме того. Вы не уточнили размер итерации.
От двух недель до месяца.
If a shark stops swimming, it will die. Don't stop swimming, Mr. Mulder.
Every epic equalizer is iso (c)