возможность транслировать код из SwiftUI в UIKit и обратно тоже как бы намекает.
Ну и я собрал маленький пример. Скрины ниже.
Hidden text
Да, никто не запрещает Эплу полностью переписать внутреннюю реализацию без использования UIKit, но пока это не так. Планов по переписыванию я не встречал.
Да, на других платформах под SwiftUI будут другие фреймворки. Но смысл тот же - это всего лишь обертка.
Так что? Исправите статью под многочисленные комментарии к ней?
Вы "быстродействие" обосновываете "более быстрым и эффективным развитие фреймворка", "лёгкостью, читабельностью и удобством в работе", "опытом программиста" и т.д. Это все, естественно, не связано.
Если оставить только связанное, то остаются только структуры против классов.
Отбросим тезис про то, что структуры быстрее, чем классы, т.к.это тоже очень холиварный вопрос (там все не так однозначно, как писали в рекламных статьях, продвигающих Swift).
Сконцентрируемся на том факте, что SwiftUI – это всего лишь обертка поверх UIKit. Т.е. все ваши структуры под капотом все равно создают соответствующие классы UIKit и работают с ними. Т.е. никакого выигрыша в производительности Вы не получите просто по одной причине: вместо того, чтобы работать только лишь с одними классами, вы еще создаете, модифицируете, гоняете по памяти, удаляете эти самые структуры-обертки-описания этих самых классов. Большее количество работы ну никак не может быть быстрее, чем меньшее количество работы. Согласны?
Теперь про "сборку мусора". Ее на iOS нет. Вместо нее используется механизм подсчета ссылок. Вопрос, который проясняют с каждым джуном на собеседовании. Этот механизм считается очень быстрым и имеющим нулевые затраты на управление памятью (на самом деле не нулевые, но близкие к нулю). При этом точно такой же механизм используется и для определения момента удаления структуры из стека. Поэтому этот аргумент в пользу быстродействия SwiftUI и структур тоже сомнителен.
Но да, спасибо за проделанную работу. Осталось ее подкорректировать и получится очень классная статья-сравнение. Можно будет ссылаться на нее и на Вас в моих дискуссиях про 2 технологии :)
Отличная работа проделана. Вы молодец. Но многие вещи все же подтягиваются под необходимый ответ. К комментариям выше добавлю следующие.
Однако, в отличие от Swift, Objective-C не поддерживает жирные структуры. Следовательно, нет способа написать пользовательский интерфейс с помощью SwiftUI и импортировать его в приложение, написанное на Objective-C. Это означает, что разработчики, которые хотят использовать SwiftUI, должны перейти на Swift и создать новое приложение с нуля, если хотят использовать весь потенциал фреймворка.
В корне неверно. SwiftUI полностью совместим с ObjC. У Элла есть документация, какие оберточки Вам нужно сделать, чтобы иметь возможность использовать SwiftUI в ObjC.
Про скорость верстки очень неоднозначный момент. Да, в простых синтетических примерах, где надо только фрейм поменять, тут SwiftUI нет конкурентов. Но как только мы переходим в область комплексного UI и UX, так сразу начинаются проблемки и преимущество в скорости верстки резко превращается в мощный такой минус, перекрывающий полученный до этого выигрыш.
В теории разработки информационных систем считается, что View-компонент должен быть платформенно зависимым. Попытки делать его платформенно независимым делают его тяжелым, сложным и не гибким в настройке и расширении.
Проще написать отдельный UI для TVOS, watchOS и iOS в горизонтальной и вертикальной ориентации, чем пытаться описать все это единым языком с лапшой условий.
По Modern Concurrency. Вам ничего не мешает добавить подобный синтаксис к ObjC и использовать его с ObjC.
Эта проблема давным давно решена. Разделяй и властвуй. Не нужно весь UI приложения пытаться запихнуть в 1 xml-файл. Этих файлов может быть много. Тогда вероятность, что 2 разработчика полезут в один xml-файл резко сократится. А практики установления владения над кодом эту вероятность вообще к нулю сводят. Никаких проблем. Проверено на практике.
Но в новом синтаксисе появляется новая проблема: разработчику надо обязательно отписываться от наблюдения за изменениями свойства, иначе оно так и останется в памяти.
Это не так. Подписка автоматически удалится, когда удалится соответствующий токен. Функция invalidate() вызывается автоматически при удалении токена, что произойдет при удалении удерживающего его объекта в вашем примере. Никаких дополнительных действий по отписке осуществлять в новом синтаксисе не надо. Раз, два.
Что касается остальных примеров, то они похожи на совет не пользоваться ножом для нарезки масла, потому что нож острый и можно порезаться. Да, можно порезаться. Но мазать масло на хлеб без ножа будет довольно сложно и не очень вкусно. Лучше на мой взгляд все же сделать над собой усилие и освоить нож так, чтобы им никогда не резаться. Но дело Ваше.
1.1 Все же это адаптер получится по факту, т.к. вы примените принципы разбиения на слои, как Вы написали. Верхний не будет взаимодействовать с нижним, их интерфейсы не совместимы. При этом между ними и будет некая часть, которая их соединяет. В чистом виде - адаптер. Правда, в этом случае там будет еще куча функционала и будет нарушен принцип единой ответственности. Но функционал адаптера там точно есть.
1.2 Понял, адаптером Вы его назвали только из-за функции адаптации данных.
Но поглядите, что медиатор тоже "адаптирует" сигналы от одного модуля к другому и обратно. Из-за этого он не становится адаптером. Медиатор от адаптера как раз расположением в слоях и зависимостью различаются (кто выше, кто ниже, кто от кого зависит). Блок1 -> Адаптер -> Блок2 против Блок1 <- Медиатор -> Блок2. Это ключевое и, кажется, единственное, отличие между ними.
Ну, кажется, подробности того, как вы это все настроили, как оно работает, какие проблемы, какие выгоды. Почему именно так, а не иначе. Какие вообще варианты рассматривали, какие критерии выбора и т.д. Скрипты, утилиты и т.д. Советы.
Жду следующую статью. Там обсудим предметно. Но пока мы вот наоборот от хореографии обратно в оркестровку предпочитаем все возвращать (на медиаторах, не на адаптерах, это важно), ибо проще. Даже в большом проекте. У хореографии единственный плюс – когда есть шина и общий формат общения. Возможно, это ваш случай. Но если это не ваш случай, то осветите, пожалуйста, этот момент в следующей статье очень детально. Возможно, откроете для себя ошибки.
По сути, это реализация паттерна «Адаптер» на уровне модулей.
"Медиатор" же. "Адаптер" как раз в первом примере.
Последний вариант действительно очень мощный, но и неоправданно сложный. Особенно в больших проектах. При прочих равных его выбирать не стоит. Разница между вторым и третьим вариантом описывается разницей между оркестровкой и хореографией (это как раз из теории распределенных систем, о которых Вы в выводах упоминаете). Там вроде даже правило есть, что без особой необходимости надо предпочитать оркестровку (т.е.второй вариант из Вашей статьи).
Вот конкретно я бы хотел почитать про графы, артефакты сборки (не смотрели в сторону Nexus?) и все перечисленные Вами инструменты. Ссылки Вы дали (и спасибо за них), но хочется опыт и проблемы.
Какой, кстати, способ уменьшения критического пути выбрали? Я бы вот почитал еще и про сравнение второго и третьего пути. Оно пока интуитивное. Хоть я выше и дал некоторые ссылки, но однозначно утверждать пока не решаюсь. Эту статью бы тоже почитал, если у Вас есть информация.
Не функциональные зависимости как-то можно изолировать? Откуда эта градация? можно ссылку? Есть там что-то про то, как их влияние минимизировать? Те же адаптеры или что-то еще?
В заключение.
Статья – просто огонь. Давно не получал такого удовольствия от чтения материалов с Хабра. Настоящий инженерный труд. Спасибо за него. Ответить бы на мои вопросы выше – получится еще и отличный научный труд. ^.^ Ждем следующих статей.
Хороший коммент. Глубокий. Видно, что работу над ошибками Вы провели. Уважаю.
Вы правы про блокировку контекста полностью. Но глядите какая штука. Вы ведь не обязаны дочерний бекграунд поток делать от родительского main. Можно же и наоборот? Родительский у вас в бекграунде и работает напрямую с хранилищем, а вот дочерний от него работает на главном потоке и весь UI завязан на дочерний, а не на родительский контекст. С CoreData работал давно, но почему-то помню именно такую схему. Мне казалось, что как раз в книжке, на которую Вы ссылаетесь эту схему я и видел. Эта схема должна работать быстрее, потому что она отбирает ресурсы главного потока только на мёрдж изменений из родительского контекста в дочерний (без блокировки на запись в стор). Но это не точно :)
Вот как раз ответ из треда, на который Вы ссылаетесь, о том, что я и говорю.
В первом же куске кода у вас ошибка. Вы не имеете права вызывать замыкание в текущей очереди. Только в очереди контекста.
A private queue context (as defined by a NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType) creates its own queue upon initialization and can be used only on that queue. Because the queue is private and internal to the NSManagedObjectContext instance, it can only be accessed through the perform(:) and the performAndWait(:) methods.
Если бы Вы сделали правильно, то проблем бы не возникло:
func enqueueBackgroundWriteBlock(block: (NSManagedObjectContext) -> Void) {
let backgroundContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
context.parent = readContext
context.perform { // Вы пропустили вот это!
block(context)
do {
try context.save()
} catch {
context.rollback()
}
}
}
CoreData потоконебезопасна.
Это заблуждение. Методы выше, как раз и сделаны для того, чтобы кордатой пользоваться потокобезопасно.
Вот примерно так нежелание читать документацию приводит к выполнению абсолютно бесполезной работы. Вы проделали все то, что уже есть у Apple из коробки. Только у Apple тот код более надежен и учитывает кучу различных специфических ситуаций.
Удачи в чтении документации и приведении своего кода к рекомендациям Эпла.
Если коротко: проблема масштабирования - это когда при расширении фичи она начинает разбухать, потому что интуитивный подход к масштабированию - неправильный.
Чертовски верно определена причина. Поработайте над интуитивным подходом к масштабированнию и проблема решится. Почитайте, что ли, как теория рекомендует масштабировать системы в общем и фичи и код в частности? Ну, чтобы подход был научный, а не интуитивный.
Проблема разрыва логики
Тоже шикарнейшее название. Но вот над теорией тоже надо поработать... Это называется асинхронностью. Сей феномен уже давно изучен вдоль и поперек. Известны все проблемы во всех возможных и невозможных случаях. На каждую проблему асинхронности есть своя таблетка, которая зарекомендовала себя лет так за 50-60. В крайнем случае асинхронность можно не использовать, не будет никаких разрывов в логике – вот только пользователям Вашим это не понравится сильно.
Про проблему остатка специально ничего писать не буду, но как Вы понимаете, она тоже называется слегка по другому и про нее тоже все известно давно и с такой же степенью детализации, как Ньютоновская физика.
Вместо этого скажу, что архитектура не то, чтобы должна решать все перечисленные 3 проблемы. Для их решения есть свои собственные инструменты. А архитектура немножко для другого. (И, кстати, про цели архитектуры тоже неплохо бы подтянуть матчасть.) Вот например, из документации MVC имеет своей целью максимальную переиспользуемость кода. Цитата: "A goal of a well-designed MVC application should be to use as many objects as possible that are (theoretically, at least) reusable."
Но мы прям с нетерпением ждем, что же такое Вы нам покажете.
Разве в VIP ViewController знает о Presenter? В своей прошлой статье вы описали, что под «знает» подразумеваете «владение». Что-то порядок навести так и не вышло :)
В VIP не зря все стрелки направлены в одном лишь направлении. ViewController ничего не должен знать о Presenter. Наоборот, лишь Presenter знает о и говорит с ViewController на языке последнего.
Нет. Способ подходящий. Сам им активно пользуюсь, только не заморачиваюсь со списком :)
Просто мне кажется, что Вы ошибаетесь, когда говорите, что из-за одного неотвеченного хардварного вопроса Вам отказывают потому, что находится тот, кто отвечает и на этот вопрос.
Хардварные вопросы, кажется, уже давно не являются критерием приема во многих компаниях (ну, если не ищут супер-пупер-архитектора). Они, скорее, просто повод, чтобы о чем-то поговорить. Чтобы заполнить пустоту на собеседовании. С таким же успехом можно было бы поговорить и о Вашем хобби, но это бы у Вас еще большее недоумение вызвало и гневную статью о бренде на Хабре. Поэтому и принято говорить о том, что меньший стресс у человека вызывает. :)
А решение принимают все же по другим критериям. Иногда чисто по очень субъективным. Увы и ах, но да.
Поэтому и спросил про мягкие навыки. Без их упоминания и анализа делать глубокие выводы, которые делаете Вы, немножко некорректно. Нужно анализировать всю картину целиком. Возможно, Вы как раз проваливали мягкую часть и шутейки ^.^
В том-то и дело, что старая функция нужна. У нее есть ценность. Она покрыта тестами. Она работает. Она проверена временем. А вот для новой ситуации использования достаточно создать адаптер между этой функцией и новой ситуацией.
Да нет, я посмотрел. Вы считаете, что в обсуждаемом примере вместо того, чтобы добавить 1 функцию с новым контрактом, вызывающую старую, и покрыть ее 2мя тестами, лучше переписывать эту функцию под новый контракт и все тесты, которые на эту функцию завязаны?
Это не отменяет справедливости остальной части мысли ;-)
Об этом я и написал, да. Что это вряд ли будет быстрее. Скорее медленнее.
в интернетах пишут. раз. два - swiftui code is converted to uikit views behind the scenes. больше искать не стал. поищите, пожалуйста, сами.
возможность транслировать код из SwiftUI в UIKit и обратно тоже как бы намекает.
Ну и я собрал маленький пример. Скрины ниже.
Hidden text
Да, никто не запрещает Эплу полностью переписать внутреннюю реализацию без использования UIKit, но пока это не так. Планов по переписыванию я не встречал.
Да, на других платформах под SwiftUI будут другие фреймворки. Но смысл тот же - это всего лишь обертка.
Так что? Исправите статью под многочисленные комментарии к ней?
А пожалуйста.
Вы "быстродействие" обосновываете "более быстрым и эффективным развитие фреймворка", "лёгкостью, читабельностью и удобством в работе", "опытом программиста" и т.д. Это все, естественно, не связано.
Если оставить только связанное, то остаются только структуры против классов.
Отбросим тезис про то, что структуры быстрее, чем классы, т.к.это тоже очень холиварный вопрос (там все не так однозначно, как писали в рекламных статьях, продвигающих Swift).
Сконцентрируемся на том факте, что SwiftUI – это всего лишь обертка поверх UIKit. Т.е. все ваши структуры под капотом все равно создают соответствующие классы UIKit и работают с ними. Т.е. никакого выигрыша в производительности Вы не получите просто по одной причине: вместо того, чтобы работать только лишь с одними классами, вы еще создаете, модифицируете, гоняете по памяти, удаляете эти самые структуры-обертки-описания этих самых классов. Большее количество работы ну никак не может быть быстрее, чем меньшее количество работы. Согласны?
Теперь про "сборку мусора". Ее на iOS нет. Вместо нее используется механизм подсчета ссылок. Вопрос, который проясняют с каждым джуном на собеседовании. Этот механизм считается очень быстрым и имеющим нулевые затраты на управление памятью (на самом деле не нулевые, но близкие к нулю). При этом точно такой же механизм используется и для определения момента удаления структуры из стека. Поэтому этот аргумент в пользу быстродействия SwiftUI и структур тоже сомнителен.
Но да, спасибо за проделанную работу. Осталось ее подкорректировать и получится очень классная статья-сравнение. Можно будет ссылаться на нее и на Вас в моих дискуссиях про 2 технологии :)
Отличная работа проделана. Вы молодец. Но многие вещи все же подтягиваются под необходимый ответ. К комментариям выше добавлю следующие.
В корне неверно. SwiftUI полностью совместим с ObjC. У Элла есть документация, какие оберточки Вам нужно сделать, чтобы иметь возможность использовать SwiftUI в ObjC.
Про скорость верстки очень неоднозначный момент. Да, в простых синтетических примерах, где надо только фрейм поменять, тут SwiftUI нет конкурентов. Но как только мы переходим в область комплексного UI и UX, так сразу начинаются проблемки и преимущество в скорости верстки резко превращается в мощный такой минус, перекрывающий полученный до этого выигрыш.
В теории разработки информационных систем считается, что View-компонент должен быть платформенно зависимым. Попытки делать его платформенно независимым делают его тяжелым, сложным и не гибким в настройке и расширении.
Проще написать отдельный UI для TVOS, watchOS и iOS в горизонтальной и вертикальной ориентации, чем пытаться описать все это единым языком с лапшой условий.
По Modern Concurrency. Вам ничего не мешает добавить подобный синтаксис к ObjC и использовать его с ObjC.
Эта проблема давным давно решена. Разделяй и властвуй. Не нужно весь UI приложения пытаться запихнуть в 1 xml-файл. Этих файлов может быть много. Тогда вероятность, что 2 разработчика полезут в один xml-файл резко сократится. А практики установления владения над кодом эту вероятность вообще к нулю сводят. Никаких проблем. Проверено на практике.
Это не так. Подписка автоматически удалится, когда удалится соответствующий токен. Функция invalidate() вызывается автоматически при удалении токена, что произойдет при удалении удерживающего его объекта в вашем примере. Никаких дополнительных действий по отписке осуществлять в новом синтаксисе не надо. Раз, два.
Что касается остальных примеров, то они похожи на совет не пользоваться ножом для нарезки масла, потому что нож острый и можно порезаться. Да, можно порезаться. Но мазать масло на хлеб без ножа будет довольно сложно и не очень вкусно. Лучше на мой взгляд все же сделать над собой усилие и освоить нож так, чтобы им никогда не резаться. Но дело Ваше.
1.1 Все же это адаптер получится по факту, т.к. вы примените принципы разбиения на слои, как Вы написали. Верхний не будет взаимодействовать с нижним, их интерфейсы не совместимы. При этом между ними и будет некая часть, которая их соединяет. В чистом виде - адаптер. Правда, в этом случае там будет еще куча функционала и будет нарушен принцип единой ответственности. Но функционал адаптера там точно есть.
1.2 Понял, адаптером Вы его назвали только из-за функции адаптации данных.
Но поглядите, что медиатор тоже "адаптирует" сигналы от одного модуля к другому и обратно. Из-за этого он не становится адаптером. Медиатор от адаптера как раз расположением в слоях и зависимостью различаются (кто выше, кто ниже, кто от кого зависит). Блок1 -> Адаптер -> Блок2 против Блок1 <- Медиатор -> Блок2. Это ключевое и, кажется, единственное, отличие между ними.
Ну, кажется, подробности того, как вы это все настроили, как оно работает, какие проблемы, какие выгоды. Почему именно так, а не иначе. Какие вообще варианты рассматривали, какие критерии выбора и т.д. Скрипты, утилиты и т.д. Советы.
Жду следующую статью. Там обсудим предметно. Но пока мы вот наоборот от хореографии обратно в оркестровку предпочитаем все возвращать (на медиаторах, не на адаптерах, это важно), ибо проще. Даже в большом проекте. У хореографии единственный плюс – когда есть шина и общий формат общения. Возможно, это ваш случай. Но если это не ваш случай, то осветите, пожалуйста, этот момент в следующей статье очень детально. Возможно, откроете для себя ошибки.
Спасибо за подробные ответы.
про критический путь.
"Медиатор" же. "Адаптер" как раз в первом примере.
Последний вариант действительно очень мощный, но и неоправданно сложный. Особенно в больших проектах. При прочих равных его выбирать не стоит. Разница между вторым и третьим вариантом описывается разницей между оркестровкой и хореографией (это как раз из теории распределенных систем, о которых Вы в выводах упоминаете). Там вроде даже правило есть, что без особой необходимости надо предпочитать оркестровку (т.е.второй вариант из Вашей статьи).
Вот конкретно я бы хотел почитать про графы, артефакты сборки (не смотрели в сторону Nexus?) и все перечисленные Вами инструменты. Ссылки Вы дали (и спасибо за них), но хочется опыт и проблемы.
Какой, кстати, способ уменьшения критического пути выбрали? Я бы вот почитал еще и про сравнение второго и третьего пути. Оно пока интуитивное. Хоть я выше и дал некоторые ссылки, но однозначно утверждать пока не решаюсь. Эту статью бы тоже почитал, если у Вас есть информация.
Не функциональные зависимости как-то можно изолировать? Откуда эта градация? можно ссылку? Есть там что-то про то, как их влияние минимизировать? Те же адаптеры или что-то еще?
В заключение.
Статья – просто огонь. Давно не получал такого удовольствия от чтения материалов с Хабра. Настоящий инженерный труд. Спасибо за него. Ответить бы на мои вопросы выше – получится еще и отличный научный труд. ^.^ Ждем следующих статей.
Хороший коммент. Глубокий. Видно, что работу над ошибками Вы провели. Уважаю.
Вы правы про блокировку контекста полностью. Но глядите какая штука. Вы ведь не обязаны дочерний бекграунд поток делать от родительского main. Можно же и наоборот? Родительский у вас в бекграунде и работает напрямую с хранилищем, а вот дочерний от него работает на главном потоке и весь UI завязан на дочерний, а не на родительский контекст. С CoreData работал давно, но почему-то помню именно такую схему. Мне казалось, что как раз в книжке, на которую Вы ссылаетесь эту схему я и видел. Эта схема должна работать быстрее, потому что она отбирает ресурсы главного потока только на мёрдж изменений из родительского контекста в дочерний (без блокировки на запись в стор). Но это не точно :)
Вот как раз ответ из треда, на который Вы ссылаетесь, о том, что я и говорю.
В первом же куске кода у вас ошибка. Вы не имеете права вызывать замыкание в текущей очереди. Только в очереди контекста.
Отсюда.
Если бы Вы сделали правильно, то проблем бы не возникло:
Это заблуждение. Методы выше, как раз и сделаны для того, чтобы кордатой пользоваться потокобезопасно.
Вот примерно так нежелание читать документацию приводит к выполнению абсолютно бесполезной работы. Вы проделали все то, что уже есть у Apple из коробки. Только у Apple тот код более надежен и учитывает кучу различных специфических ситуаций.
Удачи в чтении документации и приведении своего кода к рекомендациям Эпла.
Чертовски верно определена причина. Поработайте над интуитивным подходом к масштабированнию и проблема решится. Почитайте, что ли, как теория рекомендует масштабировать системы в общем и фичи и код в частности? Ну, чтобы подход был научный, а не интуитивный.
Тоже шикарнейшее название. Но вот над теорией тоже надо поработать... Это называется асинхронностью. Сей феномен уже давно изучен вдоль и поперек. Известны все проблемы во всех возможных и невозможных случаях. На каждую проблему асинхронности есть своя таблетка, которая зарекомендовала себя лет так за 50-60. В крайнем случае асинхронность можно не использовать, не будет никаких разрывов в логике – вот только пользователям Вашим это не понравится сильно.
Про проблему остатка специально ничего писать не буду, но как Вы понимаете, она тоже называется слегка по другому и про нее тоже все известно давно и с такой же степенью детализации, как Ньютоновская физика.
Вместо этого скажу, что архитектура не то, чтобы должна решать все перечисленные 3 проблемы. Для их решения есть свои собственные инструменты. А архитектура немножко для другого. (И, кстати, про цели архитектуры тоже неплохо бы подтянуть матчасть.) Вот например, из документации MVC имеет своей целью максимальную переиспользуемость кода. Цитата: "A goal of a well-designed MVC application should be to use as many objects as possible that are (theoretically, at least) reusable."
Но мы прям с нетерпением ждем, что же такое Вы нам покажете.
В VIP не зря все стрелки направлены в одном лишь направлении. ViewController ничего не должен знать о Presenter. Наоборот, лишь Presenter знает о и говорит с ViewController на языке последнего.
Вот бы это все, да еще подробно и с примерами :)
А с Телеграмм? точно такой же конкурс объявляют раз в надцать месяцев.
Нет. Способ подходящий. Сам им активно пользуюсь, только не заморачиваюсь со списком :)
Просто мне кажется, что Вы ошибаетесь, когда говорите, что из-за одного неотвеченного хардварного вопроса Вам отказывают потому, что находится тот, кто отвечает и на этот вопрос.
Хардварные вопросы, кажется, уже давно не являются критерием приема во многих компаниях (ну, если не ищут супер-пупер-архитектора). Они, скорее, просто повод, чтобы о чем-то поговорить. Чтобы заполнить пустоту на собеседовании. С таким же успехом можно было бы поговорить и о Вашем хобби, но это бы у Вас еще большее недоумение вызвало и гневную статью о бренде на Хабре. Поэтому и принято говорить о том, что меньший стресс у человека вызывает. :)
А решение принимают все же по другим критериям. Иногда чисто по очень субъективным. Увы и ах, но да.
Поэтому и спросил про мягкие навыки. Без их упоминания и анализа делать глубокие выводы, которые делаете Вы, немножко некорректно. Нужно анализировать всю картину целиком. Возможно, Вы как раз проваливали мягкую часть и шутейки ^.^
А где же вопросы про мягкие навыки?
Какой ответ вызвал смех у вас обоих?
И устроились ли Вы в итоге, зазубрив ответы на самые популярные вопросы?
В том-то и дело, что старая функция нужна. У нее есть ценность. Она покрыта тестами. Она работает. Она проверена временем. А вот для новой ситуации использования достаточно создать адаптер между этой функцией и новой ситуацией.
Да нет, я посмотрел. Вы считаете, что в обсуждаемом примере вместо того, чтобы добавить 1 функцию с новым контрактом, вызывающую старую, и покрыть ее 2мя тестами, лучше переписывать эту функцию под новый контракт и все тесты, которые на эту функцию завязаны?
Вот прям необходимо?