Здравствуйте, Ikemefula, Вы писали:
I>ПиЭм так не поступает. он такие тикеты никогда вручную не создаёт. Он даже создание тикетов верхнего уровня, типа эпиков, фич и тд делегирует тимлиду.
Ну естественно. Потому что в твоем варианте, хитрый ПМ не делает вообще практически ничего из того, что должен делать.
В принципе — тоже вариант, если программисты достаточно наивны или бесхребетны, чтобы на это купиться.
Ад пуст, все бесы здесь.
Re[48]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Ikemefula, Вы писали:
I>Во первых, на практике мы видим, что ты не в курсе, что инлайн метода есть противоположный рефакторинг для композ метод.
Как я только жил без этого глубочайшего прозрения
I>Проблема с рефакторингом в основном в том, что он дает довольно большую площадь коммита, т.к. для консистенси ты меняешь вообще все. Можно конечно дубликаты оставлять, что бы изменений было меньше, но это только добавляет хаоса.
Начинаешь немного понимать. Но всё станет еще печальнее, когда (или если) ты перейдешь от игрушечных проектов к настоящим, а от "рефакторинга" в виде инлайна метода — к настоящему рефакторингу.
Ад пуст, все бесы здесь.
Re[61]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Poopy Joe, Вы писали:
PJ>Я вообще не понял причем тут этот ответ? От факта существования не-функциональных требований не меняется факт, что функциональные требования могут быть любые. Это ортогональные вещи.
При том, что требования к потреблению памяти и быстродействию обычно относят к нефункциональным.
PJ>Я называю рефакторингом любое изменение кода, если целью не ставилось изменение функциональных требований. При этом он может проводится как вместе с реализацией фич или фиксами багов, так и отдельно. Иногда просто реафакторинга достаточно, чтобы пофиксить баг. Вот был баг, никто не мог найти, провели рефакторинг он пропал. В твоем уютном мирке, очевидно, все откатывается назад, потом рефакторится так, чтобы баг сохранился, ибо религия.
В моём уютном мирке такое явление означает, что рефакторинг проводили неаккуратно. Целью не ставилось изменение функциональных требований, значит цель не достигнута.
PJ>Без понятия. Продукту более 20 лет, меня там не стояло. Думаю, если в первой версии и не было, то в следующей уже было.
PJ>Я не знаю, что означает фраза "реальная задача." Любая задача где программа захватывает данные должна предполагать, что их куда-то надо писать. От фотокамеры и телефона, до рабочих станций.
Угу.
PJ>Это какой-то метод 80х годов, типа водопад. В 2020 если ситуация не описана, а проблема есть, то ее просто обсуждают и добавляют в требования формальное описание. Взять тот же место на диске. У тебя есть функция записи она что-то возвращает и, возможно, ошибку, то эту ошибку (ну, если писать нормально, а не просто кидать исключения в надежде, что кто-то их где-то поймает) мне надо обработать, хотя бы просто окошко пользователю показать, потому что операция провалилась. А если пользователю что-то показывается, то это неплохо бы перевести. Итд итп. И вот она уже в требованиях.
Это если у нас есть ресурсы на это улучшение. На практике зачастую оказывается дешевле просто написать KB Article на эту тему — потому что окошко это требования, локализация, документация, собсно разработка, тестирование.
Ой, нет, мы не готовы выложить 400 человеко-часов на эту проблему, которая стреляет в 0.00001% случаев.
PJ>Откуда в разговоре взялся прикладной софт?
Потому что мы не пишем системный. PJ>И почему это должно являться оправданием кривого дизайна и игнорирования ошибок?
Ну кривой рефакторинг же вы почему-то оправдываете, почему бы не быть кривому дизайну? If done poorly, design doesn't reach the intended goals. PJ>И я не понимаю почему ты решил, что это дорого?
Из опыта и наблюдений. PJ>Поддерживать некачественную программу дорого.
Смотря что считать некачественной программой. Программу, которая игнорирует ошибки, поддерживать значительно дешевле, чем ту, которая их все аккуратно обрабатывает.
Просто потому, что в аккуратной программе кода больше — больше площадь поверхности зависимостей.
К примеру, вот наша конкретная программа была вынуждена специально обрабатывать ситуацию, когда Microsoft не принимает адрес конечного пользователя. То есть у нас есть общая ветка, типа 4xx — что-то пошло не так, пишем в лог, фейлим операцию. В таких случаях потом приходит поддержка, разбирается что там было, чинит параметры, перезапускает. Но это — дорогостоящая штука; если проблема в адресе, то надо об этом написать пользователю, и дать ему возможность самому исправить ошибку — наш партнёр экономит 70-150 долларов на каждый такой инцидент.
Так вот, теперь ушлые парни из Редмонда в среднем полтора раза в год меняют то код ошибки, то расположение в теле ответа деталей ошибки. И каждый раз нам это стоит усилий — на очередной ресёрч, проверку, изобретение способа обработать и старый и новый форматы (потому что накатывается это изменение не на весь мир сразу, а поэтапно), тестирование, выпуск новой версии.
При этом Редмонд ни в чём не виноват — в их спецификации вообще ничего не сказано ни про коды, ни про структуру тела. Сказано, что если вернулось 4xx, то "тело ответа будет содержать error и может содержать errorCode, а также другие детали, полезные для анализа причин неудачи". Так что формально контракт не меняется.
PJ>Практически ты никогда не знаешь когда она выпуститься, всегда уши вылезут — хвост увязнет. Конечно если в современных условиях не использовать современные технологии, тот же DDD или FP, который дает сильно больше, чем факториалы через рекурсию, то писать придется больше, а качество будет низким. И иногда придется продажу выдавать за подписку. Ну так это просто "стратегия" стрельбы по своим ногам, ССЗБ.
Тут мне сложно судить — я отвечаю только за маленькую изолированную часть огромного продукта. Наша часть выходит предсказуемо, по расписанию, хотя иногда и приходится выдавать продажу за подписку.
Ей пользуются примерно 3.5 миллиона конечных пользователей, плюс ещё O(logN) администраторов, реселлеров, менеджеров и прочего обслуживающего персонала.
S>>Это замечательно, реально, вы одни из очень и очень немногих, кто так делает. PJ>Так делают многие, уж точно все (ну или большинство) кто пишет софт для промышленности. Да и у вас неужели нормально, если память будет течь?
У нас — нет. Но у нас рефакторинг не меняет паттерны использования памяти, поэтому ситуация "до рефакторинга текло, а потом — перестало" или наоборот не встречается никогда.
PJ>А что кто-то проводит рефакторинг с целью получить утечку? Тут значение имеет не результат, а намерения. Если по результату хотели одно, а получили утечку, то это просто "poorly done", но все же рефакторинг.
Ну, ок. Я больше внимания уделяю результату, отсюда и догматизм. Если мы хотели, чтобы программа научилась сохранять файлы в PDF, а по факту она переполняет стек и падает — то это баг, а не poorly done фича.
PJ>А что забавного? Если бы парадом командовал я, то я бы не выставлял факт подписки, чтобы кто-то что-то с этим делал. Я бы выставил конкретный api для конкретного use case. И возможно там нужна была не подписка, а какое-то производное от нее. Типа оплачено. Или еще как. Чем меньше потребитель api знает о потрохах, то лучше спит.
По прежнему возникает вопрос — как обеспечить консистентность totals при выдаче ордеров за месяц через старый API.
PJ>Ты не особо и смотришь, ты просто доказываешь, что у вас все правильно и это жизнь такая. Но это не важно, даже если надо вносить изменения, ну сделали ошибку, то это все равно не должно быть такой уж проблемой, чтобы еще большие костыли прикручивать.
Пока что вы не сказали мне ничего такого, чего я бы не знал. Про версионирование протоколов и про то, как делать их обратно совместимыми на per-call level я знал уже и не помню когда. Не уверен, что год тогда с цифры 2 начинался.
Вопрос, в который упираемся мы — как обеспечивать обратную совместимость с инвариантами, которые не исчерпываются одним DTO и одним вызовом.
Несмотря на то, что в контрактах API такие штуки практически никогда не бывают выражены явно, они существуют и на них полагаются пользователи (это к вопросу знания о потрохах).
PJ>Опять же если у тебя твой софт нормальный, то за полгода можно и легко изменить API, а если нет, то это уж точно не проблема MS, решайте свои технический долги.
Мы опять начинаем мериться кругозором. Что такое "твой софт"? В реальности мы имеем ситуации типа клиент Х — телеком корпорация, заказал пять лет назад разработку интеграции с Microsoft. Люди её выполнили, передали всё клиенту в эксплуатацию и ушли. Люди в Х, которые хотя бы стояли рядом с этим проектом, там давно уже не работают.
Всё что есть — это исходник (неизвестно как документированный), и инструкция "если сломалось А, давите на Б".
Теперь им надо за полгода внести изменения вот в этот вот софт. Может он и нормальный — кто знает? У них три месяца уйдёт только на то, чтобы поработать с экспертами, которые посмотрят в старый софт, в новую спеку, и оценят стоимость этих изменений. Это находится за пределами технических проблем, которые вам кажутся самыми главными.
PJ>Ты хочешь сказать, что все байки про интервью в МС, где они отбирают лучших это все вранье и потом эти высокооплачиваемые "неодоумки" просят со стороны обучить их API делать?
Понятия не имею про то, как устроены интервью в МС. Кое-какие вещи там делают люди, которые на десятичный порядок умнее меня. Некоторых из них я имею честь знать лично.
Но таких людей — единицы, и большинство из них работает ближе к "центру", то есть всякие ядра всяких сервисов. Ну, там, SQL Azure — это реально монстры, которым я бы был готов кофе носить только за право посмотреть, что они обсуждают на внутренних митингах.
"Периферию" — т.е. гуй и API к их сервисам — пишут не пойми кто. В полном смысле "не пойми кто" — т.е. этих людей держат подальше от коммуникаций, так что мы не знаем их фамилий. Зато видим результат — ошибки проектирования, за которые на втором курсе университета студентов отправляют на пересдачу. Видим в продакшне баги, которые были бы отловлены самым примитивным авто-тестированием (например, наши автотесты их ловят).
И да, таки просят. У меня, к сожалению, обрезали архив почты, поэтому нет того письма, где я объяснял новому менеджеру syndication program, что API должен обладать как минимум консистентностью и идемпотентностью.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[62]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Sinclair, Вы писали:
S>При том, что требования к потреблению памяти и быстродействию обычно относят к нефункциональным.
Если память утекла, то ни одна из функций работать не будет.
S>В моём уютном мирке такое явление означает, что рефакторинг проводили неаккуратно. Целью не ставилось изменение функциональных требований, значит цель не достигнута.
Озвучь еще раз, в явном виде, если в результате рефакторинга исчез баг, то это рефакторинг неаккуратненький и цель не достигнута?!
S>Это если у нас есть ресурсы на это улучшение. На практике зачастую оказывается дешевле просто написать KB Article на эту тему — потому что окошко это требования, локализация, документация, собсно разработка, тестирование. S>Ой, нет, мы не готовы выложить 400 человеко-часов на эту проблему, которая стреляет в 0.00001% случаев.
Что-то сильно не так со... всем и вся. Если проще написать KB Article, чем исправить ошибку.
PJ>>Откуда в разговоре взялся прикладной софт? S>Потому что мы не пишем системный.
Раз за вас, только что это меняет? Типа прикладной софт можно и нужно криво писать?
PJ>>И почему это должно являться оправданием кривого дизайна и игнорирования ошибок? S>Ну кривой рефакторинг же вы почему-то оправдываете, почему бы не быть кривому дизайну? If done poorly, design doesn't reach the intended goals.
Я не оправдываю кривой рефакторинг, а я говорю о том, что кривой рефакторинг все еще называется рефакторинг. И ты, не смотря на свой догматизм, называешь его так же, как и кривой дизайн.
PJ>>И я не понимаю почему ты решил, что это дорого? S>Из опыта и наблюдений.
- А я тебе говорил — место проклятое!!! А то всё "руки из жопы, руки из жопы"
PJ>>Поддерживать некачественную программу дорого. S>Смотря что считать некачественной программой. Программу, которая игнорирует ошибки, поддерживать значительно дешевле, чем ту, которая их все аккуратно обрабатывает.
Ну поддерживать-то ее может и дешевле, а вот как на ней заработать? В моей реальность эдак не только не заработать, а и на деньги попасть можно.
S>Просто потому, что в аккуратной программе кода больше — больше площадь поверхности зависимостей.
Неа. В аккуратной программе кода меньше. Хотя бы потому, что он лучше структурирован и меньше дублирования, и уж точно меньше зависимостей.
Сколько раз переписывал c# на f#, в результате размер кода всегда примерно в три раза меньше, при более высоком качестве.
S>К примеру, вот наша конкретная программа была вынуждена специально обрабатывать ситуацию, когда Microsoft не принимает адрес конечного пользователя. То есть у нас есть общая ветка, типа 4xx — что-то пошло не так, пишем в лог, фейлим операцию. В таких случаях потом приходит поддержка, разбирается что там было, чинит параметры, перезапускает. Но это — дорогостоящая штука; если проблема в адресе, то надо об этом написать пользователю, и дать ему возможность самому исправить ошибку — наш партнёр экономит 70-150 долларов на каждый такой инцидент.
Я может чего не понял, но че-то не впечатлился масштабом проблемы заменить один код, на другой три раза за два года.
S>Ей пользуются примерно 3.5 миллиона конечных пользователей, плюс ещё O(logN) администраторов, реселлеров, менеджеров и прочего обслуживающего персонала.
Ну ты просто посмотри на это с точки зрения MS, они тоже могу сообщить о количестве "пользователей, администраторов, реселлеров, менеджеров и прочего обслуживающего персонала." А ты про них говоришь "недоумки".
S>У нас — нет. Но у нас рефакторинг не меняет паттерны использования памяти, поэтому ситуация "до рефакторинга текло, а потом — перестало" или наоборот не встречается никогда.
Меняет. Почти невозможно его провести не изменив хотя бы чуть-чуть. Чисто физически. Ну и если вы в дотнете, то это вообще не аргумент. А вот какое-нибудь многопоточное изменение состояние вы поймать может запросто. Думаю и ловили.
S>Ну, ок. Я больше внимания уделяю результату, отсюда и догматизм. Если мы хотели, чтобы программа научилась сохранять файлы в PDF, а по факту она переполняет стек и падает — то это баг, а не poorly done фича.
Так любой баг это "poorly done фича" или вы их отдельным процессом вносите?
S>По прежнему возникает вопрос — как обеспечить консистентность totals при выдаче ордеров за месяц через старый API.
Хождение по кругу. Не зная задачи в деталях, я не могу сказать точно, что вам надо было делать и что надо делать сейчас. И я не пытаюсь решать ваши проблемы.
Мы обсуждали технический долг. Мой поинт был в том, что технический долг возникает не в момент когда покупку объявляешь подпиской, а в момент когда ты вместо выдавания totals или еще какой производной от ордеров, выдаешь сами ордера чтобы клиент с ними что-то делал. Потому что так проще и надо меньше делать. В момент, когда это стало важно, вместо уменьшения долга вы его еще больше увеличиваете. Следующий костыль будет еще больше кривым. Цепочка подобных изменений всегда ведет к том, что продукт начинает гнить и разлагаться. И, в конечном итоге, его проще выкинуть и написать заново.
S>Вопрос, в который упираемся мы — как обеспечивать обратную совместимость с инвариантами, которые не исчерпываются одним DTO и одним вызовом.
Так ты его и не обеспечил. Инвариант это неизменность свойства при любых трансформациях. У тебя покупка стала подпиской. Это не инвариант.
S>Несмотря на то, что в контрактах API такие штуки практически никогда не бывают выражены явно, они существуют и на них полагаются пользователи (это к вопросу знания о потрохах).
Ну так может стоит начать их выражать явно? Глядишь в следующий раз грабли уже не ударят по лбу.
S>Теперь им надо за полгода внести изменения вот в этот вот софт. Может он и нормальный — кто знает? У них три месяца уйдёт только на то, чтобы поработать с экспертами, которые посмотрят в старый софт, в новую спеку, и оценят стоимость этих изменений. Это находится за пределами технических проблем, которые вам кажутся самыми главными.
Вот я примерно про такое и говорю. Гниение и разложение. А все потому, что технические проблемы не казались главными или важными. Три месяца, чтобы понять что делать... Ты же сам говорил, что вы настолько даже не планируете?!
Здравствуйте, Sinclair, Вы писали:
S>У нас — нет. Но у нас рефакторинг не меняет паттерны использования памяти, поэтому ситуация "до рефакторинга текло, а потом — перестало" или наоборот не встречается никогда.
Вы это откуда можете знать, если инлайн метода вполне может поменять паттерн использования памяти?
Кодом людям нужно помогать!
Re[63]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Poopy Joe, Вы писали:
PJ>Если память утекла, то ни одна из функций работать не будет.
Опять: для очень широкого класса приложений это не так. Веб приложения вообще по умолчанию рестартят каждые 15 минут.
PJ>Озвучь еще раз, в явном виде, если в результате рефакторинга исчез баг, то это рефакторинг неаккуратненький и цель не достигнута?!
Тут самое время задаться вопросом: если намерения починить баг не было, но он таки починился — это что же, разработчик не понимал, что он делает?
Ну, ок, один баг он починил. А сколько добавил?
На самом деле, конечно, я не предложу откатывать такой рефакторинг. Да меня никто и не спросит — я в техническую часть разработки уже много лет почти не влезаю.
PJ>Что-то сильно не так со... всем и вся. Если проще написать KB Article, чем исправить ошибку.
Добро пожаловать в реальный мир, Нео. Я когда впервые читал статью про то, что MS часто вместо респина релиза выкладывает KB, тоже был сильно удивлён.
Прошли годы, я сам поварился в продуктовой части разработки, осознал мудрость старших товарищей.
PJ>Раз за вас, только что это меняет? Типа прикладной софт можно и нужно криво писать?
Да, конечно. Любой софт должен решать поставленные перед ним задачи. Вот вы действуете в молчаливых предположениях, что можно точно знать все сценарии использования публичного АПИ. Возможно, для какого-то системного софта это так и есть (неспроста же производители железа дают доступ к своим datasheet вовсе не всем подряд). А для обычного гражданского прикладного софта — вроде того, который нас окружает в повседневной действительности — это недостижимая утопия.
Зато нет жёстких требований к утечкам памяти и корректной обработке всех fail path.
PJ>Я не оправдываю кривой рефакторинг, а я говорю о том, что кривой рефакторинг все еще называется рефакторинг. И ты, не смотря на свой догматизм, называешь его так же, как и кривой дизайн.
S>>Из опыта и наблюдений. PJ>
PJ>- А я тебе говорил — место проклятое!!! А то всё "руки из жопы, руки из жопы"
PJ>
Место ни при чём. Во всех местах, с которыми мы взаимодействуем, происходит примерно то же самое. В большинстве мест — хуже, чем у нас.
S>>Смотря что считать некачественной программой. Программу, которая игнорирует ошибки, поддерживать значительно дешевле, чем ту, которая их все аккуратно обрабатывает. PJ>Ну поддерживать-то ее может и дешевле, а вот как на ней заработать? В моей реальность эдак не только не заработать, а и на деньги попасть можно.
А в моей — нет. Другой бизнес-ландшафт. В моей действительности есть более-менее критичные пути — например, нельзя брать деньги за покупку дважды. А есть некритичные пути — например, если заказ "не удалось разместить", то это более-менее ок, если происходит не слишком часто. Это как телеком — если вы, набирая номер, услышите пик-пик-пик, или посреди разговора связь оборвётся, или там начнутся разрывы в звуке — ну, пустяки, дело житейское, радиоволны — штука малоизученная. А вот если вас соединят вместо сбербанка с ИК-18, то это ай-яй-яй.
Так и у нас — мало ли, почему нам не удалось принять заказ. Там цепочка вызовов проходит через десяток систем — каждая могла лажануть. Где-то место для логов кончилось, где-то админ накриворучил, где-то связь с апстримом легла на 10 секунд. Никто не требует и не ожидает от фронт-енда всеведения и способности уникальным образом обработать каждую из полуторых сотен возможных неисправностей.
По факту, многие компоненты ухитряются даже не хранить подробности проблемы — типа "в лог насрали — можно и упасть". А потом оказывается, что логи ротируются каждые 48 часов, так что к моменту, когда реквест доезжает до инженеров, смотреть уже некогда. Это, кстати, не "наш" компонент — чтобы вы не подумали, что я вам опять рассказываю, какие мы тут самые убогие.
И, кстати, этот не наш компонент прекрасно зарабатывает большие деньги. NDA миллионов долларов в месяц.
PJ>Неа. В аккуратной программе кода меньше. Хотя бы потому, что он лучше структурирован и меньше дублирования, и уж точно меньше зависимостей.
Мы говорим про разную аккуратность. Как ни крути, а программа с catch(Exception e) { log.Write(e)} короче, чем программа с 10 сatch на разные типы исключений.
PJ>Я может чего не понял, но че-то не впечатлился масштабом проблемы заменить один код, на другой три раза за два года.
Отож. Это если совсем нечего больше делать — то нет проблемы. Ну, и если забыть про то, что код стоит не только у нас в лабе, а ещё и партнёров, и каждый хотфикс требует раскатывания каждому из них, а у них, естественно, свои политики тестирования в стейджинге и прочее.
А если не забывать, то становится понятно, что одна вот такая безответственная выходка приносит убыток в размере от сотни тысяч до миллиона долларов.
PJ>Ну ты просто посмотри на это с точки зрения MS, они тоже могу сообщить о количестве "пользователей, администраторов, реселлеров, менеджеров и прочего обслуживающего персонала." А ты про них говоришь "недоумки".
Ну да. Потому что это их количество пользователей, администраторов, реселлеров, менеджеров и прочего обслуживающего персонала получено в значительной мере благодаря усилиям технологических партнёров вроде нас.
Кто стоит между недоумками и конечными потребителями, корректируя недоработки детишек из Бельвью и Редмонда.
PJ>Меняет. Почти невозможно его провести не изменив хотя бы чуть-чуть. Чисто физически. Ну и если вы в дотнете, то это вообще не аргумент.
Конкретно мы — в дотнете. PJ>А вот какое-нибудь многопоточное изменение состояние вы поймать может запросто. Думаю и ловили.
В рамках рефакторинга — нет. У нас не F#, безумцев, которые в рамках рефакторинга будут менять схему раскладывания задач по потокам, нету.
В рамках переделок, не сводящихся к рефакторингу — да, там сколько угодно. Ну, если многопоточное изменение понимать в широком смысле — у нас практически нет кода, асинхронного в рамках одного процесса.
Там скорее код бизнес-процессов, где мы обрабатываем цепочки событий, порождая свои события. И вот там-то запросто можно напороть, типа "а давайте мы перенесём вот эту штуку с этого шага на вон тот" — и потом что-то идёт не так, потому что параллельно с этим выполняется какой-то чужой код.
Ну там, простейшая штука — конвертируем trial to paid. С точки зрения пользователя это одно событие "разместить change order, указав новый период подписки и нужное количество лицензий". А в системе это два разных события "period change" и "quantity change". И ядру всё равно, в каком порядке посылать, а микрософту — нет, потому что у триалов изменять количество нельзя.
Поэтому когда на стороне ядра системы делается рефакторинг, в результате которого порядок этих событий из (непреднамеренно) детерминированного становится случайным, внезапно отваливаются некоторые привычные сценарии.
(На всякий случай поясню: ядро системы — не на дотнете. У нас с ним вообще нет общей кодовой базы; и нет никакого build tool, который бы запустился и сказал "ой, у вас тут несоответствие типов — один из модулей использует ваши события вот таким способом). PJ>Так любой баг это "poorly done фича" или вы их отдельным процессом вносите?
Отдельным процессом
В нынешнем состоянии продукта большинство багов — это результат изменения внешней системы. Типа того же Microsoft, который в какую-нибудь из пятниц выкатывает breaking change без предупреждения.
PJ>Хождение по кругу. Не зная задачи в деталях, я не могу сказать точно, что вам надо было делать и что надо делать сейчас.
Ну да. Но при этом вы почему-то уверены, что мы делаем всё неправильно.
PJ>Мы обсуждали технический долг. Мой поинт был в том, что технический долг возникает не в момент когда покупку объявляешь подпиской, а в момент когда ты вместо выдавания totals или еще какой производной от ордеров, выдаешь сами ордера чтобы клиент с ними что-то делал.
А им не нужен totals как таковой. Нужна гарантия, что если через систему прошло 11 миллионов долларов, то у нас должны выдаваться ордера на всю эту сумму.
Ну ок, мы можем выдать им отдельную операцию GetOrderTotals — толку-то? Ей всё равно придётся выбирать, с чем быть консистетной — с суммой всех ордеров или с суммой ордеров подходящего для GetOrdersV1 типа. PJ>И, в конечном итоге, его проще выкинуть и написать заново.
Ну, пока что мы пережили две попытки выкинуть и написать заново (это из тех, которые я знаю). Точнее не так; выкидывать продукты — слишком рискованный бизнес.
Приходили ковбои, которые говорили "ваш продукт нежизнеспособное говно, неспособное к быстрым изменениям. Мы в своём продукте любую из фич, которые вы пилите по три месяца, делаем к концу недели".
Практика показывала, что нет, не к концу недели. И что не любую из фич. Хрен с ним с тем, что у нас из коробки идут вещи, которые конкурентам пилить и пилить годами — даже прикручивание чего-то нового (вроде тех же однократных продаж) в нашей системе делается быстрее и работает надёжнее.
PJ>Так ты его и не обеспечил. Инвариант это неизменность свойства при любых трансформациях. У тебя покупка стала подпиской. Это не инвариант.
Игра словами. У меня по-прежнему деньги совпадают с деньгами. Это — самый главный инвариант. На фоне него то, что покупка называется "подпиской на вечную лицензию" — мелочь, не стоящая упоминания.
Ну, как в кофейнях на чеке написано имя клиента и 0,00 — это потому, что кассовая система не умеет учитывать имя клиента, и эта доработка стоила бы как самолёт.
Поэтому бариста пробивает "АННА 1шт" по цене в 0 рублей (а продажа штучных товаров мимо каталога в кассе уже есть), и все довольны.
PJ>Ну так может стоит начать их выражать явно? Глядишь в следующий раз грабли уже не ударят по лбу.
Ок, давайте. Выразите явно в контракте тот факт, что сумма от IEnumerable<Order> GetOrders() совпадает с суммой от IEnumerable<Invoice> GetInvoices().
А потом попробуйте добавить новый вид ордеров, не меняя ни этого факта, ни сигнатуры GetOrders(). При том, что Invoice-то как раз одинаковый для любого вида ордеров.
Может я научусь чему-то новому.
PJ>Вот я примерно про такое и говорю. Гниение и разложение. А все потому, что технические проблемы не казались главными или важными. PJ>Три месяца, чтобы понять что делать... Ты же сам говорил, что вы настолько даже не планируете?!
Вы невнимательно читаете. Я говорю не про нас — мы-то как раз любимчики у Microsoft. Я говорю про компании, которые потребляют те же API, что и мы, только работают по-другому. Например так, как я описал.
В приличной корпорации получить анализ проблемы за три месяца — это ещё хорошо. Представьте, что вам нужно получить экспертное заключение по непрофильному для вас виду деятельности. Сколько времени ваша компания будет выбирать подрядчика для этого заключения? По-хорошему, надо объявлять тендер. Вы же не будете проводить его "сегодня до вечера". Сначала вы объявите тендер — подготовка к нему займёт около недели. Потом ещё месяц вы будете собирать предложения. Ок, прошло пять недель — вы выбрали подрядчика. Теперь ваши юристы с его юристами занимаются согласованием взаимных NDA и утрясанием IP Rights, потому что вы не хотите попасть в ситуацию, когда этот подрядчик перепродаёт налево оплаченные вами наработки. А подрядчик, естественно, именно этого и хочет.
Если всё суперхорошо, и обе стороны полностью довольны документами друг друга, это займёт неделю. Если нет — то две-три. Иногда — месяц (обычно, если согласование юристами занимает больше месяца, то сделки не будет. но это не точно).
Ок, ладно, шесть недель прошло — наконец-то подрядчик получил доступ к вашему legacy и теоретически может начать анализ. На практике у него конечно же нет команды инженеров, которая плюёт в потолок в ожидании подписания сделки. Если подрядчик — хороший, то его инженеры сейчас пашут на другом проекте; кто-то освободится через пару недель как минимум.
С кодовой базой он не знаком; насколько она документирована — большой вопрос. Редко когда заказная разработка идёт с подробными комментариями, диаграммами пакетов и прочими артефактами. В хорошем случае инженеры подрядчика недельки через две будут готовы выдать предварительный результат. Уточнение и проверка займут ещё пару недель — потому что новый API почти похож на старый, но есть важные нюансы, и подрядчик не захочет рисковать выдачей заниженной оценки. Вот у нас уже три месяца и натикало — и это без неожиданностей типа "наш юрист заболел" или "начался мировой карантин, поэтому мы не сможем приехать к вам в офис".
Ещё раз подчеркну: это — совершенно нормальные, типичные для индустрии административные трудности. Очень легко рассуждать с позиции кодера: "да я внесу изменение в наш клиент к этому API за 15 минут".
Ну, так в наш код и я внесу, хоть я и менеджер — дальше-то что?
Лично мной мир не исчерпывается. И я более чем один раз наблюдал, как идеи "а давайте-ка выкатим ломающее изменение к февралю" откладываются на год-полтора. И у нас, и у Microsoft. Потому, что какой нибудь Telmex или Dell говорит "вы охренели", и архитектурные астронавты спускаются из стратосферы на землю грешную.
Потому как это вам оттуда кажется, что всё плохо там, где я работаю. А на практике оказывается, что как раз у нас-то всё более-менее лучше всех, по крайней мере в нашем сегменте.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[59]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Codealot, Вы писали:
I>>ПиЭм так не поступает. он такие тикеты никогда вручную не создаёт. Он даже создание тикетов верхнего уровня, типа эпиков, фич и тд делегирует тимлиду.
C>Ну естественно. Потому что в твоем варианте, хитрый ПМ не делает вообще практически ничего из того, что должен делать.
Наоборот, всё что необходимо — бюджеты, организация, стаффинг, приоритеты, планирование, сроки, риски, прогресс.
Re[49]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Codealot, Вы писали:
C>Как я только жил без этого глубочайшего прозрения
Очень просто — ты называл модным словом всё, чего бы не делал, не вникая в смысл. Поломал — рефакторинг, переписал — рефакторинг, а вот сам рефакторинг у тебя почемуто только в теории возможен
I>>Проблема с рефакторингом в основном в том, что он дает довольно большую площадь коммита, т.к. для консистенси ты меняешь вообще все. Можно конечно дубликаты оставлять, что бы изменений было меньше, но это только добавляет хаоса.
C>Начинаешь немного понимать. Но всё станет еще печальнее, когда (или если) ты перейдешь от игрушечных проектов к настоящим, а от "рефакторинга" в виде инлайна метода — к настоящему рефакторингу.
Здравствуйте, Poopy Joe, Вы писали:
S>>Вы, конечно же, можете называть "рефакторингом" процесс внесения или исправления багов или реализацию фич. PJ>Я называю рефакторингом любое изменение кода, если целью не ставилось изменение функциональных требований. При этом он может проводится как вместе с реализацией фич или фиксами багов, так и отдельно. Иногда просто реафакторинга достаточно, чтобы пофиксить баг. Вот был баг, никто не мог найти, провели рефакторинг он пропал. В твоем уютном мирке, очевидно, все откатывается назад, потом рефакторится так, чтобы баг сохранился, ибо религия.
называйте это лучше просто "программированием", потому что ваше определение рефакторинга кардинально разнится с тем, как этот термин понимаю я и все мне известные разработчики (а я знаю несколько сотен разработчиков, со всех частей света). Рефакторинг это изменение кода, не затрагивающее функциональное поведение. Т.е. в результате рефакторинга баг пропасть не может просто по определению рефакторинга.
Здравствуйте, Sharov, Вы писали:
S>Вы это откуда можете знать, если инлайн метода вполне может поменять паттерн использования памяти?
Либо я чего-то не понимаю, либо в дотнете такого быть не может. Профиль стека в нашем контексте неважен — во-первых, потому что у нас нет рекурсий, во-вторых, потому что у нас типичная глубина стека незначительна. Это ж же джавовский спринг с его километровыми стектрейсами
А профиль использования динамической памяти от инлайна никак не меняется. У нас более-менее те же объекты конструируются более-менее в те же моменты.
На поведение памяти в дотнете влияет время удержания ссылки — т.е. для того, чтобы затянуть время жизни объекта, надо ссылку на него сохранить в каком-то долгоживущем объекте. То есть — поменять логику кода, а не его структуру. Инлайн на такое неспособен.
Есть некоторый нюанс с заменой foreach на linq — там можно внезапно увеличить количество выделений на ровном месте, и, скажем, спровоцировать более частую сборку нулевого поколения.
Опять же — нам нагрузка на garbage collector непринципиальна, мы ж не видеоигра, где рулит плавность FPS. На общее потребление Gen0 не влияет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[64]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Sinclair, Вы писали:
S>Опять: для очень широкого класса приложений это не так. Веб приложения вообще по умолчанию рестартят каждые 15 минут.
Зачем же они тогда перезапускают? Очередной костыль и есть.
S>Тут самое время задаться вопросом: если намерения починить баг не было, но он таки починился — это что же, разработчик не понимал, что он делает?
Ну, допустим, есть мультипоточный спагетти код, в котором уже пару лет не могут поймать какой-то баг, как это часто бывает.
Работать с этим тяжело всегда, независимо от бага. Ну вот разработчик вместо ковыряния в говнокоде просто переписывает его нормально. Баг исчезает. Что разработчик сделал неправильно?
S>Ну, ок, один баг он починил. А сколько добавил?
Ну этого ты никогда не знаешь, даже при самом безобидном изменении. Опять получается, что рефакторинга нет?
S>На самом деле, конечно, я не предложу откатывать такой рефакторинг. Да меня никто и не спросит — я в техническую часть разработки уже много лет почти не влезаю.
Ну, т.е. на самом деле ты не такой уж пурист?
S>Добро пожаловать в реальный мир, Нео. Я когда впервые читал статью про то, что MS часто вместо респина релиза выкладывает KB, тоже был сильно удивлён.
Ну это-то как раз нормально. Невозможно выпустить релиз вообще без дефектов. Ты это подал как часть нормального процесса. Типа не будет на это внимание обращать, просто KB сделаем. Это совсем не то же самое, что респин релиза.
S>Прошли годы, я сам поварился в продуктовой части разработки, осознал мудрость старших товарищей.
Чем-то напоминает историю про обезьян в клетке.
S>Да, конечно. Любой софт должен решать поставленные перед ним задачи. Вот вы действуете в молчаливых предположениях, что можно точно знать все сценарии использования публичного АПИ.
Это не то, что я сказал. Я бы выставлял API для конкретных сценариев. Там нет никаких предположение, по-определению. Уж точно я бы не стал выставлять модель, чтобы делали что хотели.
S>Возможно, для какого-то системного софта это так и есть (неспроста же производители железа дают доступ к своим datasheet вовсе не всем подряд). А для обычного гражданского прикладного софта — вроде того, который нас окружает в повседневной действительности — это недостижимая утопия.
Достижимо, разумеется. Что тут недостижимого?
S>Место ни при чём. Во всех местах, с которыми мы взаимодействуем, происходит примерно то же самое. В большинстве мест — хуже, чем у нас.
Проклятие веба?
S>А вот если вас соединят вместо сбербанка с ИК-18, то это ай-яй-яй.
Как человек 15 лет проработавший в телекоме ответственно заявляю — ниче не будет, все это байки из склепа.
S>И, кстати, этот не наш компонент прекрасно зарабатывает большие деньги. NDA миллионов долларов в месяц.
Спасибо кэп, но речь не о том, как работает система. Любая система имеет ошибке, везде с ними как-то мирятся или не мирятся. Перезапускают или еще как выкручиваются. Вопрос в том, почему ты считаешь нормальным закладываться на это в момент разработки?
Из твоих слов я делаю вывод, что вы делаете абы как, на предположениях, потому что у всех так. И типа это дешевле. Я наблюдал банкротство двух компаний где это было нормой, а они тоже зарабатывали миллионы долларов.
S>Мы говорим про разную аккуратность. Как ни крути, а программа с catch(Exception e) { log.Write(e)} короче, чем программа с 10 сatch на разные типы исключений.
Нет, конечно, не короче. После этого будет еще три экрана спагетти кода, чтобы разрулить ситуацию. Ведь, де-факто, операция тут провалилась и по этому поводу не сделано ничего.
S>А если не забывать, то становится понятно, что одна вот такая безответственная выходка приносит убыток в размере от сотни тысяч до миллиона долларов.
Ты осетра урезать не хочешь? Оно понятно хочется впечатлить суммами от одного кода ошибки, но и меру надо знать.
S>Кто стоит между недоумками и конечными потребителями, корректируя недоработки детишек из Бельвью и Редмонда.
Ну ща ты договоришь до того, что МС живо только благодаря вам.
S>В рамках рефакторинга — нет. У нас не F#, безумцев, которые в рамках рефакторинга будут менять схему раскладывания задач по потокам, нету.
Ну там мне вас жаль. Если вижу запрос нескольким узлам, который выполнен последовательно, когда может быть параллельным, то я это сразу исправлю. В 99% это две строки изменений. У вас должно быть это планирование за три месяца с привлечением дюжины экспертов.
S>Ну там, простейшая штука — конвертируем trial to paid. С точки зрения пользователя это одно событие "разместить change order, указав новый период подписки и нужное количество лицензий". А в системе это два разных события "period change" и "quantity change". И ядру всё равно, в каком порядке посылать, а микрософту — нет, потому что у триалов изменять количество нельзя. S>Поэтому когда на стороне ядра системы делается рефакторинг, в результате которого порядок этих событий из (непреднамеренно) детерминированного становится случайным, внезапно отваливаются некоторые привычные сценарии.
Я вижу только пренебрежение инвариантами и зависимость от сайд-эффектов. Рефакториг тут вообще не причем.
S>(На всякий случай поясню: ядро системы — не на дотнете. У нас с ним вообще нет общей кодовой базы; и нет никакого build tool, который бы запустился и сказал "ой, у вас тут несоответствие типов — один из модулей использует ваши события вот таким способом).
Не имеет значения. Бизнес логика твоя, то и инварианты твои. Все что приходит извне заведомо подозрительное и подлежит обработке. Логика в принципе не должна зависеть от сторонних эффектов.
S>В нынешнем состоянии продукта большинство багов — это результат изменения внешней системы. Типа того же Microsoft, который в какую-нибудь из пятниц выкатывает breaking change без предупреждения.
Да ну прям. Вот прям свободный от внутренних багов бэклог? Осётр все больше...
S>Ну да. Но при этом вы почему-то уверены, что мы делаем всё неправильно.
Т.е. ты считаешь, что превращать продажу в подписку это правильно?
S>А им не нужен totals как таковой. Нужна гарантия, что если через систему прошло 11 миллионов долларов, то у нас должны выдаваться ордера на всю эту сумму. S>Ну ок, мы можем выдать им отдельную операцию GetOrderTotals — толку-то? Ей всё равно придётся выбирать, с чем быть консистетной — с суммой всех ордеров или с суммой ордеров подходящего для GetOrdersV1 типа.
Я не могу сказать что тут ок, а что нок, поскольку я не знаю сценариев. Судя по всему вы и сами не знаете. В этом и суть проблема.
В виде спекуляции: если бы вы выдавали изначально не номер подписки, а просто абстрактный uuid, который привязана к подписке, но не является подпиской. Т.е. клиент не знает подписка это или нет, просто некая транзакция. Так и проблемы бы такой не было. Для покупок бы вставляли другой тип id.
PJ>>И, в конечном итоге, его проще выкинуть и написать заново. S>Ну, пока что мы пережили две попытки выкинуть и написать заново (это из тех, которые я знаю). Точнее не так; выкидывать продукты — слишком рискованный бизнес.
Ой да ладно, регулярно и везде случается. Не всегда получается, да. Потому что на ошибках не учатся.
PJ>>Так ты его и не обеспечил. Инвариант это неизменность свойства при любых трансформациях. У тебя покупка стала подпиской. Это не инвариант. S>Игра словами. У меня по-прежнему деньги совпадают с деньгами. Это — самый главный инвариант. На фоне него то, что покупка называется "подпиской на вечную лицензию" — мелочь, не стоящая упоминания.
Это у тебя игра словами. То у тебя мега догаматическое определение рефакторига, то весьма фривольное и вообще не к месту определение инварианта, свойств у которого может быть более одного.
S>Ок, давайте. Выразите явно в контракте тот факт, что сумма от IEnumerable<Order> GetOrders() совпадает с суммой от IEnumerable<Invoice> GetInvoices().
Не, ты пытаешься не пересмотреть правильность своего решение, а доказать, что вот в вашем API по другому не выйдет. Я не убежден, что изначально API верный.
S>Ещё раз подчеркну: это — совершенно нормальные, типичные для индустрии административные трудности. Очень легко рассуждать с позиции кодера: "да я внесу изменение в наш клиент к этому API за 15 минут". S>Ну, так в наш код и я внесу, хоть я и менеджер — дальше-то что?
Ну так и внеси, а не запускать процесс на 5 недель.
S>Потому как это вам оттуда кажется, что всё плохо там, где я работаю. А на практике оказывается, что как раз у нас-то всё более-менее лучше всех, по крайней мере в нашем сегменте.
Если у других хуже, не значит, что у вас все правильно. Хотя про все я вообще ничего не говорил и ваша правильность меня не парит, не моя проблема. Мы же тут о рефакториге и архитектуре, не?
Оттуда где я выглядит как, как нового вы боитесь, дико забюрократизированы, и беспокоитесь только о бонусах, а не о состоянии проекта. Вероятно еще не доверяете разработчикам. Ничего нового. Я такое наблюдал.
Re[62]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Мирный герцог, Вы писали:
МГ>называйте это лучше просто "программированием", потому что ваше определение рефакторинга кардинально разнится с тем, как этот термин понимаю я и все мне известные разработчики (а я знаю несколько сотен разработчиков, со всех частей света). Рефакторинг это изменение кода, не затрагивающее функциональное поведение. Т.е. в результате рефакторинга баг пропасть не может просто по определению рефакторинга.
Еще один голос сотен разработчиков. Скажи, а вы баги формально в функциональные требования вносите до, или обновляете после?
Re[63]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Poopy Joe, Вы писали:
PJ>Еще один голос сотен разработчиков. Скажи, а вы баги формально в функциональные требования вносите до, или обновляете после?
сам придумал, сам посмеялся? или это уже истерическое? ну и да, я бы на твоём месте крепко задумался, что если тебе несколько людей с опытом разработки в 10+ лет не на самых последних ролях прямо указывают на то, что ты не прав, то разумно предположить, что есть не малая вероятность что ты таки не прав, и стоит хотя бы на минуту остановится и провентилировать вопрос, поспрашивать разработчиков из контактлиста, как они понимают рефакторинг, задать вопрос на фриноде ##programming, спросить на хабре, на рсдн можешь устроить голосовалку, погуглить наконец, а то пока всё это выглядит как в анекдоте "Алло, дорогая, только что по радио передали, что один псих едет по встречке. Будь осторожнее. — Один??? Да их тут тысячи!". Главное помнить, что мы все ошибаемся. Но баран лишь тот, кто не умеет свои ошибки признавать.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Sharov, Вы писали:
S>>Вы это откуда можете знать, если инлайн метода вполне может поменять паттерн использования памяти? S>Либо я чего-то не понимаю, либо в дотнете такого быть не может. Профиль стека в нашем контексте неважен — во-первых, потому что у нас нет рекурсий, во-вторых, потому что у нас типичная глубина стека незначительна. Это ж же джавовский спринг с его километровыми стектрейсами S>А профиль использования динамической памяти от инлайна никак не меняется. У нас более-менее те же объекты конструируются более-менее в те же моменты. S>На поведение памяти в дотнете влияет время удержания ссылки — т.е. для того, чтобы затянуть время жизни объекта, надо ссылку на него сохранить в каком-то долгоживущем объекте. То есть — поменять логику кода, а не его структуру. Инлайн на такое неспособен.
Я имел в виду вообще, но дотнет так донет. Что касается глубины стека, то мало ли какие приложения бывают. В целом для управляемых сред это действительно не так важно. Но вот неверняка будут измерения, если как-то метод вызывался в цикле на критическом участке кода(hot path). А мы потом взяли и заинлайнили его. Наверное это будет ощутимо( в лучшее сторону), и наверное профиль использования памяти поменяется (меньше обращений под стек)?
Кодом людям нужно помогать!
Re[64]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Мирный герцог, Вы писали:
МГ>сам придумал, сам посмеялся? или это уже истерическое?
Я ничего не придумывал. Ты сам сообщил, что баг у тебя функциональное требование.
МГ> ну и да, я бы на твоём месте крепко задумался, что если тебе несколько людей с опытом разработки в 10+ лет не на самых последних ролях прямо указывают на то, что ты не прав, то разумно предположить, что есть не малая вероятность что ты таки не прав, и стоит хотя бы на минуту остановится и провентилировать вопрос, поспрашивать разработчиков из контактлиста, как они понимают рефакторинг, задать вопрос на фриноде ##programming, спросить на хабре, на рсдн можешь устроить голосовалку, погуглить наконец, а то пока всё это выглядит как в анекдоте "Алло, дорогая, только что по радио передали, что один псих едет по встречке. Будь осторожнее. — Один??? Да их тут тысячи!".
Авторитеты закончились или еще есть на кого сослаться?
МГ> Главное помнить, что мы все ошибаемся. Но баран лишь тот, кто не умеет свои ошибки признавать.
Ну кроме тебя, разумеется. Ведь к себе-то ты не применяешь.
Re[65]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Poopy Joe, Вы писали:
PJ>Я ничего не придумывал. Ты сам сообщил, что баг у тебя функциональное требование.
нет, я этого не сообщал. похоже у тебя серьёзные когнитивные проблемы.
PJ>Авторитеты закончились или еще есть на кого сослаться? PJ>Ну кроме тебя, разумеется. Ведь к себе-то ты не применяешь.
разумеется я его к себе применяю. впрочем, довольно, очевидно что не в коня корм, ариведерчи.
нормально делай — нормально будет
Re[66]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Мирный герцог, Вы писали:
МГ>нет, я этого не сообщал. похоже у тебя серьёзные когнитивные проблемы.
Именно это ты и сообщил.
Рефакторинг это изменение кода, не затрагивающее функциональное поведение. Т.е. в результате рефакторинга баг пропасть не может просто по определению рефакторинга.
МГ>разумеется я его к себе применяю.
явно не постоянно.
МГ>ариведерчи.
и ты не кашляй.
Re[65]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Poopy Joe, Вы писали: PJ>Зачем же они тогда перезапускают? Очередной костыль и есть.
PJ>Работать с этим тяжело всегда, независимо от бага. Ну вот разработчик вместо ковыряния в говнокоде просто переписывает его нормально. Баг исчезает. Что разработчик сделал неправильно?
Всё сделал правильно. Вот только это не рефакторинг, а совершенно обычная разработка.
PJ>Ну этого ты никогда не знаешь, даже при самом безобидном изменении.
Юношеский максимализм. Вся идея рефакторинга — сделать так, чтобы изменение было не просто "безобидным", а безопасным.
Да, иногда так не получается. Но разработчики инструментов тратят специальные усилия на то, чтобы рефакторинг ничего не сломал. Ровно потому, что именно этого ожидают их пользователи. Просто "внести изменение без намерения изменить соответствие функциональным требованиям" можно и не привлекая понятие рефакторинга. Когда мы делаем рефакторинг, мы как раз хотим иметь более-менее гарантии того, что ничего не сломается.
Например, если я меняю порядок аргументов в методе, то инструмент рефакторинга должен поправить все места, где этот метод вызывается.
Без такого инструмента у нас остаётся только набор рукопашных приёмов + набор тестов. Сделали изменение — прогнали тесты — исправили — прогнали. Тесты сошлись — ок, считаем шаг рефакторинга завершённым. Не сошлись — нет, это был не рефакторинг, а что-то другое.
PJ>Опять получается, что рефакторинга нет?
Ну, вообще бывает всякое. Можно, например, обнаружить 30 мест, в которых используется почти одинаковый код, и вынести его в функцию. И тогда окажется, что subtle bug в одном из этих 30 мест исчез.
Но это скорее исключение, чем правило.
PJ>Ну, т.е. на самом деле ты не такой уж пурист?
Я поклонник идеи называть вещи своими именами.
PJ>Ну это-то как раз нормально. Невозможно выпустить релиз вообще без дефектов. Ты это подал как часть нормального процесса. Типа не будет на это внимание обращать, просто KB сделаем. Это совсем не то же самое, что респин релиза.
Да, именно вместо респина релиза просто сделаем KB. Часть нормального процесса.
PJ>Чем-то напоминает историю про обезьян в клетке.
PJ>Это не то, что я сказал. Я бы выставлял API для конкретных сценариев. Там нет никаких предположение, по-определению. Уж точно я бы не стал выставлять модель, чтобы делали что хотели.
Вот вы выставили API "для конкретных сценариев". Пользователи применили его не только для ваших конкретных сценариев, а для каких-то своих.
Естественно, вам они перед этим не звонили и не спрашивали "а можно я сделаю вот так". У вас нет доступа к их коду чтобы посмотреть, как и что они используют.
PJ>Достижимо, разумеется. Что тут недостижимого?
Невозможно знать что происходит на стороне клиента. У вас нет доступа к их коду — в лучшем случае (и то далеко не всегда) вы можете получить серверные логи того, что делают с вашим API клиенты. PJ>Проклятие веба?
Счастье плюрализма.
PJ>Как человек 15 лет проработавший в телекоме ответственно заявляю — ниче не будет, все это байки из склепа.
PJ>Спасибо кэп, но речь не о том, как работает система. Любая система имеет ошибке, везде с ними как-то мирятся или не мирятся. Перезапускают или еще как выкручиваются. Вопрос в том, почему ты считаешь нормальным закладываться на это в момент разработки?
Потому что закладываться на то, что ошибок не будет — нельзя. PJ>Из твоих слов я делаю вывод, что вы делаете абы как, на предположениях, потому что у всех так. И типа это дешевле. Я наблюдал банкротство двух компаний где это было нормой, а они тоже зарабатывали миллионы долларов.
Ну, прикольно. Я тоже всякое видал.
S>>Мы говорим про разную аккуратность. Как ни крути, а программа с catch(Exception e) { log.Write(e)} короче, чем программа с 10 сatch на разные типы исключений. PJ>Нет, конечно, не короче. После этого будет еще три экрана спагетти кода, чтобы разрулить ситуацию.
Нет там никакого спагетти кода. Всё, операция уже сфейлилась, дальше идёт }.
PJ>Ты осетра урезать не хочешь? Оно понятно хочется впечатлить суммами от одного кода ошибки, но и меру надо знать.
Не, не хочу. Знаю, сколько стоит внесение такого изменения в 1 компании; умножать на 30 я умею с 7 лет.
S>>Кто стоит между недоумками и конечными потребителями, корректируя недоработки детишек из Бельвью и Редмонда. PJ>Ну ща ты договоришь до того, что МС живо только благодаря вам.
Нет, не только. MS — это много всего, далеко не только cloud services.
PJ>Ну там мне вас жаль. Если вижу запрос нескольким узлам, который выполнен последовательно, когда может быть параллельным, то я это сразу исправлю. В 99% это две строки изменений. У вас должно быть это планирование за три месяца с привлечением дюжины экспертов.
Не, мы просто вообще так не делаем. Нет потребности.
PJ>Я вижу только пренебрежение инвариантами и зависимость от сайд-эффектов. Рефакториг тут вообще не причем.
PJ>Не имеет значения. Бизнес логика твоя, то и инварианты твои. Все что приходит извне заведомо подозрительное и подлежит обработке. Логика в принципе не должна зависеть от сторонних эффектов.
Да, всё снаружи — подозрительное. Увы, на одном этом утверждении далеко не уедешь. Есть задача, её надо решать. При помощи тех средств, которые дадены в наличии. Вот вы же могли просто сказать, что отказываетесь работать в таком окружении, где дисковое кэширование теряет результаты файлов. Нет — вам пришлось выпиливать из вазелина "надёжную ФС поверх ненадёжной", при этом ещё и не удалось это сделать прозрачно для модулей.
Нам приходится идти на какие-то другие компромиссы.
PJ>Да ну прям. Вот прям свободный от внутренних багов бэклог? Осётр все больше...
PJ>Т.е. ты считаешь, что превращать продажу в подписку это правильно?
В рамках данных нам ограничений? Конечно да. Был бы против — мы бы делали по другому.
PJ>Я не могу сказать что тут ок, а что нок, поскольку я не знаю сценариев. Судя по всему вы и сами не знаете. В этом и суть проблема.
PJ>В виде спекуляции: если бы вы выдавали изначально не номер подписки, а просто абстрактный uuid, который привязана к подписке, но не является подпиской. Т.е. клиент не знает подписка это или нет, просто некая транзакция. Так и проблемы бы такой не было. Для покупок бы вставляли другой тип id.
И чем бы один тип uuid отличался от другого такого же uuid? Ничем? Ну вот считайте, что у нас так и есть. И для удобства, этот uuid имеет название subscriptionID.
Потому что это облегчает жизнь пользователям API, которые 15 лет имели возможность посмотреть историю конкретной подписки при помощи GetOrderHistoryBySubscriptionId(), передав туда этот "абстрактный uuid, который привязан к подписке".
PJ>Ой да ладно, регулярно и везде случается. Не всегда получается, да. Потому что на ошибках не учатся.
Ждём.
S>>Ок, давайте. Выразите явно в контракте тот факт, что сумма от IEnumerable<Order> GetOrders() совпадает с суммой от IEnumerable<Invoice> GetInvoices(). PJ>Не, ты пытаешься не пересмотреть правильность своего решение, а доказать, что вот в вашем API по другому не выйдет. Я не убежден, что изначально API верный.
Ну, я же не цитирую настоящий API. Это приближённый к реальности выдуманный пример.
В реальном API всегда присутствуют подобного плана ограничения, которые никак не выражены на уровне типов.
Попробуйте спроектировать API, который явно выражает банальные ожидания непрерывности, вроде того, что если я сделал GetOrdersBatch(1), GetOrdersBatch(2), ...GetOrdersBatch(N) то их конкатенация совпадает с GetAllOrders().
Для чего это нужно? Чтобы пользователь мог получать список не одним большим блоком, а порциями (проклятие веба, да). Без этой гарантии мы, формально говоря, не можем утверждать, что клиент делает ровно то, что от него ожидает заказчик. Как описать эту гарантию в документации — мне понятно. Как это выразить в рамках сигнатур?
PJ>Ну так и внеси, а не запускать процесс на 5 недель.
.
S>>Потому как это вам оттуда кажется, что всё плохо там, где я работаю. А на практике оказывается, что как раз у нас-то всё более-менее лучше всех, по крайней мере в нашем сегменте. PJ>Если у других хуже, не значит, что у вас все правильно. Хотя про все я вообще ничего не говорил и ваша правильность меня не парит, не моя проблема. Мы же тут о рефакториге и архитектуре, не?
Отож. Мы говорим о том, что умеем гибко управлять техническим долгом так, чтобы максимизировать stakeholder value. Если надо — то мы не боимся взять "технический кредит". Умеем принимать решения в условиях неполной информации, и корректировать их по мере поступления отклика с мест. Если есть возможность — технический долг списываем; если нет возможности — отдаём. Модуль, за который я отвечаю, находится в весьма приличном техническом состоянии, что выражается не только объёмами продаж, но и низкими затратами на техподдержку в терминах incident per unit.
Я почти уверен, что если бы к нам пришли вы, то существенно улучшили бы все показатели в рамках модуля. А если бы перевели модуль с C# на F# — то вообще в разы. Но, за неимением в команде вас, приходится справляться тем, что есть.
А у вас вроде бы догматизм типа "техдолг можно только уменьшать", но при этом извести его совсем ну никак не получается.
Оттуда, где я, это кажется некоторым самообманом — вы в широком смысле слова делаете примерно то же, что и мы, только называете это другими словами.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sharov, Вы писали:
S>Я имел в виду вообще, но дотнет так донет. Что касается глубины стека, то мало ли какие приложения бывают. В целом для управляемых сред это действительно не так важно. Но вот неверняка будут измерения, если как-то метод вызывался в цикле на критическом участке кода(hot path). А мы потом взяли и заинлайнили его. Наверное это будет ощутимо( в лучшее сторону), и наверное профиль использования памяти поменяется (меньше обращений под стек)?
Ну, во-первых, почему вы думаете, что до рефакторинга этот метод не инлайнился компилятором?
Во-вторых, почему вы думаете, что это сильно повлияет на использование памяти? Если это hot path, то вряд ли там у этого метода какой-то огромный фрейм стека.
С точки зрения процессора, внутри этого цикла идут частые обращения в эпсилон-окрестности какой-то точки (куда там у нас показывал ESP в момент входа в цикл). Разница между "с вызовом" и "без вызова" — на десятки байт; она нивелируется кэшем. Т.е. ни паттерн доступа (локально или прыгая-по-адресам-с-большим-разбросом), ни пиковое потребление почти не меняются.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[66]: Годами не могу вырваться из некорректных вопросов на
Здравствуйте, Sinclair, Вы писали:
S>Всё сделал правильно. Вот только это не рефакторинг, а совершенно обычная разработка.
Рефакторинг это подмножество обычной разработки, без намерения изменять функциональные требования.
PJ>>Ну этого ты никогда не знаешь, даже при самом безобидном изменении. S>Юношеский максимализм.
Когда аргументов нет начинаются отсылки в авторитету, возрасту и должностям. Ты не знаешь меня, ты не знаешь мой возраст, ты не знаешь мой опыт. Если ты гадаешь на кофейной гуще здесь, возможно ты принимаешь так решения везде.
В данном случае это не максимализм, а теория. Это просто невозможно гарантировать. Ты всегда можешь нарваться на баг или неопределенной поведение компилятора (в с++ это реальность, например), или ос. Настаивая на строгих определениях следуй им до конца.
S> Вся идея рефакторинга — сделать так, чтобы изменение было не просто "безобидным", а безопасным.
Это у меня безопасный. Потому что все строго типизировано. Я могу все разобрать и собрать заново не опасаясь регрессий, потому что инварианты выражены в типах. У тебя он именно что безобидный. Боясь, что все развалится ты ограничиваешь себя потому ты ограничиваешь себя перестановкой параметров и ограниченными возможностями тулзов, от которых ты вынужденно зависишь. Так это не проблемы рефакторинга, это проблемы выбора инструментов и языков.
S>Но это скорее исключение, чем правило.
Это несущественно. Определение должно работать всегда, на то оно и определение.
S>Я поклонник идеи называть вещи своими именами.
Ты выдумал себе какие-то ограничение и решил, что все должны с тобой согласится. Кто-то согласиться, кто-то нет. Ты совершенно не глас истины и источник имен.
S> Вот вы выставили API "для конкретных сценариев". Пользователи применили его не только для ваших конкретных сценариев, а для каких-то своих.
Если ты выставил его для конкретного сценария, то выставишь ты минимально необходимые данные для этого. В идеальном случае их просто нельзя будет по другому использовать. Ну если уж совсем какие-то странные вещи не городить. Но вряд ли вы доходите до того, что вообще никогда ничего не меняете, потому что кто-то где-то может быть... Все это очень тяжело обсуждать не видя апи и реальных сценариев.
S>Нет там никакого спагетти кода. Всё, операция уже сфейлилась, дальше идёт }.
Это как? Операция сфейлилась, куда там идти дальше? Типа пытался считать файл, не вышло, ну и ладно...? Даже не знаю в каких случаях это будет работать.
S>Не, не хочу. Знаю, сколько стоит внесение такого изменения в 1 компании; умножать на 30 я умею с 7 лет.
Если компании стоит миллионы долларов изменение одного кода ошибки, то там все очень и очень плохо. Я впрочем, все равно не верю.
S>Нет, не только. MS — это много всего, далеко не только cloud services.
Т.е. cloud services живы только благодаря вам?
S>Да, всё снаружи — подозрительное. Увы, на одном этом утверждении далеко не уедешь. Есть задача, её надо решать. При помощи тех средств, которые дадены в наличии. Вот вы же могли просто сказать, что отказываетесь работать в таком окружении, где дисковое кэширование теряет результаты файлов. Нет — вам пришлось выпиливать из вазелина "надёжную ФС поверх ненадёжной", при этом ещё и не удалось это сделать прозрачно для модулей.
Не, нам пришлось в явном виде выражать то, что и так давно известно — мутабельность источник геморроя. Нет изменений — нет проблем. И вообще, не было такой проблемы как "сделать прозрачно для модулей". У нас нет страха менять код. Да, это была ошибка дизайна, считать что на диск можно полагаться. Соответственно ее надо исправить корректно, а не прозрачно. В конце-концов, для логики оно и прозрачно, это только персистенс-часть изменилась. Если сайд-эффекты устранены из логики, то это исключает целый класс ошибок.
S>И чем бы один тип uuid отличался от другого такого же uuid? Ничем? Ну вот считайте, что у нас так и есть. И для удобства, этот uuid имеет название subscriptionID.
Тем что он привязан к подписке, соответственно никто не ожидает по нему подписку. Если кому-то понадобились детали подписки, то можно было бы добавить в api функцию uuid -> subscription option. те же яйца вид в профиль, но клиент уже не ожидает подписку всегда, потому что ее никто не обещал. Как бы странно они не использовали это у себя — они не могут игнорировать этот факт. И покупка осталась бы покупкой и ордера бы сходились.
S>Ну, я же не цитирую настоящий API. Это приближённый к реальности выдуманный пример.
Ну да, ты мне пытаешься сказать "вот летит тебе в лоб черенок от граблей, как и по руке не получить и по лбу?"
А можно не наступать на них?
S>В реальном API всегда присутствуют подобного плана ограничения, которые никак не выражены на уровне типов. S>Попробуйте спроектировать API, который явно выражает банальные ожидания непрерывности, вроде того, что если я сделал GetOrdersBatch(1), GetOrdersBatch(2), ...GetOrdersBatch(N) то их конкатенация совпадает с GetAllOrders().
Первое что приходит в голову — считать контрольную сумму всех ордеров. Каждый вызов возвращает результат их свертки. А если еще помудрить с функцией контрольной суммы, то GetOrdersBatch(1) + GetOrdersBatch(3) сразу может выдать ошибку.
S>Для чего это нужно? Чтобы пользователь мог получать список не одним большим блоком, а порциями (проклятие веба, да). Без этой гарантии мы, формально говоря, не можем утверждать, что клиент делает ровно то, что от него ожидает заказчик. Как описать эту гарантию в документации — мне понятно. Как это выразить в рамках сигнатур?
Ну торренты это как-то делают очень давно.
S>Я почти уверен, что если бы к нам пришли вы, то существенно улучшили бы все показатели в рамках модуля. А если бы перевели модуль с C# на F# — то вообще в разы. Но, за неимением в команде вас, приходится справляться тем, что есть.
Вам нужен не я, а смена взгляда на привычные вам вещи. Это возможно, я проверял уже не один раз. Но, каждый раз, приходится народ тащить чуть ли не за шкирку в светлое настоящее. fp-course уже наизусть выучил.
S>А у вас вроде бы догматизм типа "техдолг можно только уменьшать", но при этом извести его совсем ну никак не получается.
Есть случае когда его приходится повышать, если альтернатива срывает релиз, например. Но если это не форс-мажор, а если он постоянный, то это еще большая проблема, то его нельзя повышать сознательно. К сожалению, и люди не совершенны и домен не всегда правильно понят итд и уже это ведет к постепенному росту долга. Хорошо бы хотя бы такой держать под контролем, а не еще специально добавлять.