Как стать автором
Обновить
17
0
Кирилл @ws233

Руководитель мобильной разработки

Отправить сообщение

Значит, им там и место :)

А больше нигде и не нужно. И все попытки натянуть сову на глобус – неправильны в самой постановке реализации.

Либо пользуемся имеющимися контроллерами, либо создаем свой универсальный... Но мне сложно придумать такой универсальный контроллер, в котором мне бы пришлось добавлять поддержку работы с клавиатурой. Имеющихся двух вполне достаточно для решения проблемы, описанной в статье. Да и любой другой проблемы с клавиатурой.

Более того, это поведение зашито в UITableViewController и работает из коробки. Если поместить UITextField в ячейку таблички, то даже строчки кода писать не придется – все взлетит, как есть.

Могу ошибаться, но это же поведение зашито и в UIScrollView. UITextView содержит в себе UIScrollView, а значит, что и в нем это поведение должно быть из коробки. Но если его вдруг нет, то лучше вешать contentInset на keyboardLayoutGuide, а не позицию компонента на экране.

Профиты "зашитого" поведения:

  1. Не придется тратить время на написание того, что уже работает.

  2. Не придется писать тесты своих велосипедов.

  3. При последующих изменениях в ядре системы можно быть уверенным, что Apple о нас подумает и добавить поддержку старого кода и поведения.

Цикл статей о той же идее, но со слегка отличной реализацией.

В частности тут про источник данных. Но есть там статьи и про применение этой же идеи и к делегатам.

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

  1. Вы сделали жесткое соответствие типа вьюмодели и типа вьюхи, как один к одному. Этим Вы внесли зависимость вьюхи (представления) от вьюмодели (данных). И наоборот: вьюмодель должна знать о типе ячейки, где она будет отображаться (`$0.base`). Не зря все архитектуры стараются строить на трех элементах, где средний – это прослойка, необходимая для того, чтобы убрать зависимость как представления от данных, так и данных от представления. Углубляться, какие проблемы тут будут не стану, скажу лишь, что добавить такое разделение не сложно. В итоге вы получите связь между вью и вьюмоделью – многие ко многим, что гораздо гибче и удобнее в использовании.

  2. Вы явно не указали, что такое `itemRepresentation: { $0.base }`. Но я предположу, что это некое занесенное во вьюмодель знание о вьюхе, на которую эту вьюмодель надо смэппить. Это снова нарушение принципа из пункта 1. Сложно с этим будет и так лучше не делать. Вам это знание нужно из вьюмодели выносить. Вся информация и все алгоритмы, отвечающие за соответствие должны находиться в одном месте – мы этот класс назвали картой соответствия. Создавая разные карты, Вы можете реализовывать разные алгоритмы соответствия. Можно – класс на класс, можно объект – на класс, объект – на объект, класс – на объект, можно вешать сложную логику по выбору объекта вьюхи или ее класса через замыкания. И все это будет отдельно – менять ни вью, ни вьюмодель не придется. У вас же вся эта ответственность, которую Вы называете ViewRegistration, размазана по многим классам (при необходимости изменения логики соответствия придется менять все перечисленные классы, а их будет ооооочень много):

    1. регистрация – в источнике данных;

    2. идентификатор соответствия – во вьюмодели;

    3. замыкание выбора соответствия – вообще по коду непонятно где. Но я предположу, что в контроллере.

  3. Не смешивайте регистрацию типа ячейки в таблице и регистрацию вьюмодели на ячейку. Это снова нарушение п.1. И это вам не дает видеть и понимать ясно разные ответственности уровня вью, уровня вьюмодели и промежуточного уровня между ними, который осуществляет мэппинг одного в другое без жесткой связи между ними.
    Отсутствие жесткой связи в этом месте очень важно. Регистрируйте отдельно. Хоть это и лишний код, но Вы сможете переиспользовать одну таблицу со всеми зарегистрированными ячейками на всех своих экранах. Кажется, что экономия тут больше, чем в Вашем случае. Не настаиваю.
    При этом обратите внимание, что Вы чувствуете, что регистрация, это некая ответственность, которую необходимо инкапсулировать. Но инкапсулируете Вы 2 куска разных ответственностей, при этом оставляя куски одной из них размазанными по другим классам и другим ответственностям. Это отсылка к п.2.

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

Почему же... Пример.

Но ФСБ со своими законами - все же регламент. Поэтому и делаем.

Да и наши безопасники считают, что разобрать то, что написано в гугле не каждый сможет. Вон ниже ссылка про защиту SnapChat, если я правильно ее понял при беглом просмотре, то товарищу за 2 недели так и не удалось вскрыть SnapChat. Та самая неприемлемая стоимость вскрытия. А напихать сотни проверок - не такая уж и трудоемкая задача-то...

Так знаем же. И защищаемся и от дебага тоже. Еще раз – полностью защититься нельзя. Можно лишь поднять стоимость взлома до неинтересных значений.

Или Вы предлагаете и стоимость взлома не повышать на одном лишь утверждении, что защититься нельзя? – пусть ломают простые смертные в 2 клика мышкой?

Что Вы-то предлагаете?

Так "прикладники" все прекрасно понимают. Взломать можно все. Защититься невозможно. Но можно сделать взлом экономически нецелесообразным. Это прикладникам доступно или тоже нет?

Ковырять приложение из под OS существенно дороже, чем напрямую само приложение. Поэтому и ковыряют приложение. И это надо сделать экономически нецелесообразным, чтобы сваливались на уровень OS, и пусть там творят, че хотят. На это мы-"прикладники" уже повлиять не можем. Но на свою часть повлиять можем. И будем.

Или у Вас другое мнение?

Тоже добавлю, что результат перечисленных проверок на взломанном устройстве тупо подменится злоумышленником на необходимый. И приложение, получив ожидаемый результат, даже не увидит, что запущено на взломанном устройстве, и продолжит работать, как в безопасной среде со всеми вытекающими.

Этих проверок мало, нужна еще как минимум защита от дебага.

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

Если взять во внимание этот простой тезис, то становится вообще непонятно, почему люди публикуют проверки безопасности под тезисом: "Мы настолько уверены в своей защите, что готовы показать ее всем!". Кто-то сможет пояснить о чем, кроме пиара думают эти люди?

Автор – молодец! Копай глубже!

А к Qiwi теперь вопросики...

Спасибо за статью. Качественно и полезно.

Ждем "отдельный доклад или статью" о том, как фильтровать и группировать результаты производительности запуска экранов. Без них данная статья выглядит неполной.

Тестовый стенд один.

Разработческих – много.

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

Тестовый стенд подключается к делу на этапе, когда разработка уже закончена, весь код разных команд собран вместе. Этот стенд – как раз для проверки интеграций и взаимовлияний.

Такой подход позволяет упростить тестирование и поиск ошибок.

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

Зная, общее число ошибок, мы можем проверить, реагирует ли хоть один тест на каждую из имеющихся ошибок. Если реагирует, то мы защищены от такой ошибки. Отношение ошибок, от которых мы защищены, к общему числу ошибок и дает нам качественный показатель нашего ПО.

Было бы гораздо лучше, если бы Вы ничего не придумывали, а просто вникли в теорию чуть глубже.

Вы же сами пишите, что "минимальное число тестов, обеспечивающих выполнение всего кода, будет равно цикломатической сложности."

До этого вы писали, что на тестах лучше экономить и сокращать их число.

Из этих двух тезисов без всяких выдумываний "прямолинейности кода" выходит, что циклометрическую сложность надо снижать. Для этого есть вполне себе известные инструменты. Некоторые из них Вы перечислили. Применяем (но не доводя до абсурда), и получаем уменьшение стоимости тестирования системы. Точка.

Apple ведь просто советует завести Swift-потомка от Obj-C родителя. Такой потомок получит область видимости всех свойств и методов, как у родителя. Его и выставляйте наружу своего фреймворка. Такой подход не пробовали?

Да, вам придется переименовать родителя, добавив ему префикс или постфикс, т.к.Swift-потомок должен иметь то же оригинальное имя родителя. Но это не проблема.

А не проще ли было просто использовать Set вместо массива и сравнивать Set?

Очень хорошо про это написано в трилогии у Юваля Харари.

Цель, конечно же, всегда благая. Например, собирательство требовало меньше времени на получение того же числа калорий, но зависело от очень многих причин. Была проблема – необходимы запасы, чтобы в неблагоприятное время не умереть с голоду. А делать запасы с собирательством не очень просто.

Поэтому научились выращивать сами – перешли на сельское хозяйство. Это очень быстро привело к избытку запасов и получаемых калорий. Лишние запасы и калории привели к взрывному росту населения. И вот мы получили ситуация, когда просто для того, чтобы прокормить себя, все имеющееся население вынуждено работать по 12/7, т.к. имеющаяся производительность и труда, и выхлоп урожая конечны, а рост населения продолжается.

Пришлось придумывать промышленную революцию, которая привела к аналогичному результату. Сначала производство благ стремительно выросло, что привело к еще более взрывному росту населения, которое сново уперлось в невозможность обеспечить всех благами – снова всем пришлось работать по 12/7...

Впереди очередная революция...

Добрый день. Подскажите, как продвигается работа по следующей статье? Очень хочется ее увидеть...

Если Сбер завел 70 вакансий иосника, чтобы забить им ленту hh, но нанял 1, то в вашей статистике учитывается 70.

Если другой банк завел 1 вакансию, но нанял 10 человек, то в вашей статистике все равно будет 1.

Кажется, по Вашей методике можно лишь считать компании, которые ищут людей и спамят в ленту hh, но никак не число вакансий на рынке...

А есть более точная методика подсчета?

Так ведь:

  1. xib – это файл для разработки и хранения в человекочитаемом виде. В bundle приложения он не складывается. В bundle приложения складывается скомпилированная версия в формате nib. Это по сути сериализованная версия объектов, на парсинг которой особо времени и не нужно. Ну, не больше, чем на сериализацию/десериализацию. Это гораздо быстрее, чем парсить человекочитаемый код. Ну, и это не намного дольше, чем создавать объекты из кода. Есть цифры, подтверждающие, что одно дольше другого? А насколько?

  2. Xcode дает ворнинги при компиляции xib-файлов. По умолчанию это ворнинги и они не останавливают процесс билда. Но, кажется, что этот параметр можно менять и сделать ворнинги в xib-файлах ошибками, останавливающими процесс билда. Так что проверки на этапе компиляции все же есть.
    Что касается вызова событий, то для этого есть Responder Chain и first responder. Этот механизм не вызывает исключений и не роняет приложение, если не находит в цепочке указанный селектор. Добавляем сюда интеграционные тесты на корректность дерева вьюх и контроллеров и проблема уходит. Ошибки в переходах тоже прекрасно закрываются интеграционными тестами.
    С другой стороны, краши при вызове селектора, который не привязали в коде никак от IB не зависит. Это вообще не проблема IB. Это проблема отсутствия связи, которую и в коде можно неверно проставить или вообще не проставить. Полагаю, что и с переходами на экраны аналогично. И обе проблемы лечатся не переходом с IB на код, а интеграционными тестами.

Спасибо, что напомнили еще про 2 мифа, не имеющих отношения к реальности ^.^.

Идеально покрыть тестами сложный код - просто математически невозможно.

Математика очень не любит, когда ей приписывают слова, которых она не говорила. :)

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

Да, религию делать не надо, но получить вполне себе однозначную качественную оценку вашей сколь угодно сложной системы вполне возможно. И математика Вам в этом поможет.

Юнит-тесты очень просты и состоят обычно из трех строчек кода:

  1. assign

  2. act

  3. assert

К тому же в 80% случаев Ваши тесты будут копиями друг друга, но имеющими лишь отличия в третьей строчке, т.е.в том условии, которое Вы проверяете.

Согласитесь, что написать 5 функций, состоящие из 3-х строчек в день вполне возможно. Я даже удивляюсь, что написано всего 5 тестов в день, а не существенно больше.

Да, интеграционные тесты будет написать чутка сложнее, но и они должны состоять лишь из 4-х строчек (в первом пункте будет 2 строки, вместо одной, т.к. нужно создать 2 объекта и проверить их интеграцию). Тоже, кажется, что можно писать существенно больше 5 тестов в день.

e2e-тесты еще сложнее, но и они пишутся из заготовок и уже не проверяют то, что было проверено в двух абзацах выше. В итоге, даже тут 5 тестов в день выглядят прям скромным результатом.

Если у Вас так не выходит, задумайтесь, где Вы ошибаетесь.

  1. Тесты – это не просто документация. Это 100% копия технического задания, переведенная с человеческого на язык машинных кодов. Если у вас есть тест, но нет соответствующего описания на человеческом языке в ТЗ, то стоит это описание туда добавить. И наоборот. Любое изменение в ТЗ приводит к гарантированному изменению в тестов. В итоге у вас 1 и тот же документ записан на двух языках: человеческом (ТЗ) и машинном (тесты) – и оба перевода должны постоянно синхронизироваться в обе стороны.

  2. Проблемы с покрытием у Вас из-за отсутствия изоляции. Изоляция – необходимое условие юнит-тестов (принципы FIRST). Если вернете им изоляцию, то проблем с подсчетом покрытия для них не будет. С интеграционными и e2e-тестами это не сработает. Там изоляция быть не может, а значит, что и покрытие для этих тестов как метрика быть использована не может. Другими словами – покрытие можно считать ТОЛЬКО для юнит-тестов (которые являются копией ТЗ, помните?), для всех других тестов эту метрики использовать нельзя.

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Работает в
Дата рождения
Зарегистрирован
Активность