16 апреля в 20:12

Получил 1.2K звезд на GitHub с ужасной архитектурой. Как? recovery mode

Хочу поделится довольно обычной, но показательной историей. Идея проекта появилась 3 месяца назад, за 1 месяц была реализована и вот уже два месяца как проект переодически висит в топе GitHub, попал в какие только можно профильные новостные ресурсы, и даже забрался в дайджест в статье “Топ 5 библиотек апреля”.

Вы могли подумать что я хвалюсь, но нет. Это предыстория нужна для более глубоко диссонанса. Я хочу поговорить об… архитектуре. Да, знаю-знаю, “сколько можно” и “что он себе позволяет”. Но я буду говорить не столько о паттернах, сколько о подходе к их использованию. Именно такие статьи я искал и люблю. Примеров синглтона и фабрики вы найдете больше, чем ошибок при выходе новой версии свифта, а мы поговорим об обобщенном подходе на примере моей библиотеки.

Перед погружением — прочтите инструкцию


Не сказал бы что я iOs-разработчик какого-то запредельного уровня, поэтому прошу отнестись к всему сказанному критично. Уверен есть люди опытнее меня, для них все очевидно. А вот для заблудшей души, вчера сортировавшей массивы, хорошо бы быть объективным. Я буду стараться.

Задраить люки! Погружаемся!


Проект упрощает работу с разрешениями. Помимо этого повышает конверсию на получение тех же нотификаций. Кому не нравится красивое диалоговое окно?)

Основные требования к проекту:

  • Простое внедрение
  • Простое использование
  • Удобная кастомизация и расширение (если вдруг захочется добавить новых разрешений или визуалок)

В остальном просто попытался сделать хорошо (к примеру, возможность сменить бизнес-логику не стояла приоритетной, но учитывалась)

А теперь давайте рассуждать. Это вообще штука полезная. Чтобы проект получился простым — нужно иметь простой интерфейс и не грузить программиста реализацией под капотом. В этом я вдохновлялся подходом от Appodeal. В общем, нужно иметь одну точку входа. Т.е. сконфигурировали объект 2-мя разрешениями, а далее запросили их. Должно быть так же просто, как это звучит!

Сразу дьявол на левом? плече шепчет: “Singleton…”. И первые дни мне казалось это прекрасным решением, в AppDelegate сконфигурировал, а показывай контролер где захочется.

Но проблем оказалось больше:


  • Крайне редко необходимо будет держать в памяти диалоговое окно
  • После получения всех разрешений точно не нужно держать его в памяти
  • Мало вероятно что будет нужно запрашивать одни и те же разрешения на разных экранах

В общем, паттерн имел больше минусов, чем плюсов. Тут я хочу обратить внимание на то что отталкивался именно от вариантов использования своего проекта. Уверен что и Singleton оправдан в использовании, но в других ситуациях. 


В переломный момент мою точку зрения подтвердил известный в определенных кругах iOS уже Android разработчик — Алексей Скутаренко, назвав паттерн “сомнительным”. То ли от нелюбви к этому паттерну, то ли от не лучший применимости его к моим потребностям — неизвестно. Но решение было принято — выбросить листов 20 макулатуры, достать новых. Маркер, собственно, тоже кончился.

Тогда было принято решение пойти от обратного. Как я бы хотел, чтобы использовали проект? Я это четко представлял:

class ViewController: UIViewController {

    var permissionAssistant = SPRequestPermissionAssistant.modules.dialog.interactive.create(with: [.Camera, .PhotoLibrary, .Notification])

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(true)
        self.permissionAssistant.present(on: self)
   }
}

Решение напросилось само собой: должен быть главный класс, его мы и назовем PermissionAssistant. А логику разделим на ключевые блоки, для удобства объединим их словом Manager. А что, логично, разные задачи — соответственно разные классы будут за них ответственные. 



Теперь давайте определимся с тем, какие функциональные части будут. Очевидно, одна из будет отвечать за запрос разрешений и получение информации о них. Назовем ее PermissionsManager. Так как подразумевается еще и визуальная часть, добавим PresenterManager (своруем именование у Viper, да будут в достатке его открыватели).


Презентер будет отвечать за презентацию контроллера, его конфигурирование… вообще за UI (если оно, конечно, будет). Кстати, обращаю внимание, что все части скрываем протоколами для большей гибкости в дальнейшем.

Гибкости?!

Да. Может не лучшее слово, но отражает суть. Представим что мы ремонтируем подводную лодку, крепление винта — 16-листовая резьба с 29 дюймами (только что выдумал). Не нужно каждый раз делать новую подводную лодку, достаточно будет сделать винт с известными требованиями и прикрутить его. Сделать и прикрутить.

Не мастер я алегорий, давайте к примеру с кодом. Разберём PermissionsManager, его сокрытие протоколом и реализацию. Для начала определим функционал менеджера. Нам хватит двух методов:

  • Запрос разрешения
  • Одобрено ли разрешение

По вкусу можно функционал расширить, но нам хватит. И так, протокол:

protocol PermissionManagerInterface {

   func requestPermission(_ type: PermissionType)

   func isAllowedPermission(_ type: PermissionType)
}

В нашем случае это требования к винту лодки.

Теперь имплементируем протокол. Получим реальный объект (винт). Его и прикручиваем. А вот наш главный класс Assistant (подводная лодка) не будет знать какая конкретно реализация (из какого метала, сколько дней ее лили и сколько работа стоила). Главный класс знает только что есть две функции. Захотели сменить реализацию — пожалуйста) Особенно полезно это будет в кастомизации визуальной части и DataSource. Вот о нем сейчас и поговорим.

Очевидно что визуальная часть куда сложнее, чем просто Presenter. По хорошему ее нужно делить на модули. Собственно разделим на две части: Controller и DataSource

Presenter держит контроллер, он будет разбираться с жестами, экраном и прочим, чем занимаются контроллеры. Конечно, возникает вопрос как контроллер будет сообщать о действиях. У особо пытливых возникнет вопрос «а ARC часом не уничтожит все к чертям?».


Если с первым вопросом все понятно — делегаты, то второй — проблема, которая остановила мою работу на неделю. Но чтобы вы понимали, я дополнил схему ссылками между объектами (надеемся все знают про сильные и слабые ссылки, вопросов возникнуть не должно).

Проблема очевидна (надеюсь) — контроллер держит исключительно объект Assistant (конечно, Presenter, но он держит Assistant, так что опустим звено). Если проблема еще не понятна, разъясняю: 



Представим что объект Assistant вышел из своей области видимости, и соответственно, был выкинут за борт ARC. Если не был презентован контроллер, то умирает весь объект целиком. Это корректное поведение. Но если контролер был презентован…

то он теперь весит в стеке — и соответственно на него имеется ссылка вне объекта. А вот Assistant, так как выйдет из зоны видимости — умрет. Продемонстрировать можно на простом примере



if true {
	let permissionAssistant = SPRequestPermissionAssistant.modules.dialog.interactive.create(with: [.Camera, .PhotoLibrary, .Notification])
	
permissionAssistant.present(on: self)
}



Получаем ситуацию, когда контроллер будет жив, а вот все классы окружения — умрут. И даже Presenter, который и держал контроллер.

Грустно


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

Сколько разговоров было о проблеме, на уши поднял даже своих матросов сотрудников. Все в один голос твердили — “Что за ужасная архитектура?!”, “Автору — яду” и “Контроллер должен все держать”. 

Да, контроллер я выносил в центр. Но проблема в том, что если контроллер держит Assistant и небыл презентован сразу при инициализации — умирает весь объект. В общем, перевернуть связи не получилось, а это означало что…

контроллер выносить как главный объект! Писать логику внутри контроллера — ну уж нет. 



Решение пришло само собой за чашечкой чая и было чем то вроде прозрения:

— “А почему нет?” 



Просто инициализировать Assistant как проверти контроллера — и все! Пока жив родитель, жив и Assistant. А так как все диалоговые контролеры подразумевались модальными, решение отлично влилось. Такое решение мне показалось оптимальным, хоть и педантичность внутри взгрустнула. Что ж, продолжим. Дух был поднят, снова набираем скорость!



Теперь хорошо бы разделить UI и PermissionManager. Тут все тривиально — делаем протокол PermissionInterface, который выглядит так:


protocol PermissionInterface {
    
    func isAuthorized() -> Bool
    
    func request(withComlectionHandler complectionHandler: @escaping ()->()?)
}

И для каждого нового пермишина (Location, Notification, Camera…) реализовываем его. А в PermissionManager создаем необходимый класс Permission и дергаем нужные функции. 



Обновим схему:


Теперь мы видим всю картину. И как видно, любой кирпич мы можем заменить. Что лично я считаю — прекрасно. Чем ниже по лестнице блок — тем меньше придется переписывать. Для того, чтобы реализовать новый контроллер, нужно реализовать его интерфейс и внедрить в текущую систему (каким способом — ваше дело). Хотите поменять текста и цвета? Реализуйте протокол DataSource. Особенно мне нравится идея наличия нескольких PresenterManager. Сейчас вам хочется диалоговое окно, а на другом экране — всплывающий банер сверху (уже в разработке)


Время попсы


Прекрасно понимаю что кол-во звезд слабо коррелирует с качеством кода, надеюсь очевидно что текст совсем не про это.

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

Не считаю себя разработчиком, который может позволить себе давать советы. Но расскажу маленькую историю:

 когда я начинал только думать над проектом, мой хороший товарищ Геннадий (имя изменим) работал над одноэкранным приложением. Делал его на VIPER, и особо не вникал почему и зачем его использует. На мои аргументы:

— “Отпусти проблему, зачем тебе тяжелый паттерн на супер-простом приложении

он был непреклонен. Прошло несколько месяцев, я релизнул мелкие проекты, убрал в квартире и купил велик, сдал заказчику работу и видел как наступает весна. Геннадий продолжает писать приложение…

Паттерны не таблетка от всех болезней. Не используйте его как показатель профессионализма или потому что "так делают гуру". Не отсохнут руки, если из MVC сделаете “не эпловский MVC”. Используйте паттерны, когда понимаете что это необходимо. 

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

Я не призываю отказаться от паттернов, писать все в контроллере и вообще от VIPER отстреливаться магнитной пушкой. Используйте, но обдумано! Ставьте конкретные требования к архитектуре и экспериментируйте — узнавайте что лучше решит поставленные задачи. Если идеально подходит VIPER, но вот PRESENTER вам кажется лишним — выбросьте его, почему нет? Именно эмпирическая работа с архитектурой даст лучший, пускай и не классический результат.

Я не знаю как называется мой паттерн (компот?) — но я остался доволен тем, как он решает поставленные перед ним задачи. Именно такой результат должно приносить использование паттерна.

— "Даже профессионалы используют сториборды" — неизвестный автор.



Всем успешных билдов и православного CTR!
Ivan Vorobei @IvanVorobei
карма
9,7
рейтинг 17,7
Project Manager, iOS Developer, UI and UX
Похожие публикации
Самое читаемое Разработка

Комментарии (36)

  • +8
    Используйте паттерны, когда понимаете что это нужно.

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


    Скажем если мы хотим чтобы код легко находился в проекте, повышаем coheasion. Что бы было проще определить насколько модуль кохизив, смотрим на него с точки зрения SRP. Хотим увеличить гибкость и избежать лавинообразных изменений между модулями — нужно снижать coupling, применять dependency inversion и т.д.


    Нужно изолировать презентационную логику от логики обработки данных — не вопрос, формируем отдельно слой обработки данных и сверху лепим контроллеры и вьюхи которые будут заниматься отображением готовых данных. Если у нас есть необходимость как-то изолировать обработку данных в отдельном треде, можно попробовать реализовать все таким образом, чтобы один слой лежал в одном треде и только выставлял бы нужное состояние некому view model а в другом слое мы бы отслеживали изменение состояния и перерисовывали вьюху.


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

    • +2
      Вам нужно было писать эту статью) Но насколько я понял — вы со мной солидарны
      • +3

        Я не iOS разработчик, я мельком знаком с проблемами в вашем комьюнити. Скажем мои мобильщики частенько жалуются что мол подавляющее большинство не замарачиваются и размазывают логику по контроллеру. То есть до смешного доходит когда на одном проекте из 10 скринов можно найти 6 реализаций обработки пагинации.


        Знакомый сделал интересное наблюдение, что начинающим Андроидщикам к примеру приходится потратить где-то год на осознание того что паттерны не составляют архитектуру приложения, что это просто инструменты которые нужно знать когда и зачем применять. А до этого момента есть две стадии:


        • Паттерны офигенны! Как я раньше без них жил! Куда бы еще запихнуть...
        • От этих паттернов только одни проблемы… Как мне теперь код мэйнтейнить...

        Как по мне тратить на подобное целый год слишком долго. И грустно от того что я сам проходил через подобные этапы. Грустно от того что про концепции вроде связанности или принципы/паттерны GRASP я узнал через года 3 после того как начал путь в коммерческой разработке. А многие и через 5 лет не знают об этом. Люди через какое-то время просто находят свою зону комфорта. Кто-то просто не парится и не повышает сложность проекта. Кто-то раз в год меняет работу чтобы сбежать от ужаса поддержки своих решений...


        Что до проектов с кривой архитектурой и кучей звезд — увы и ах… так везде. Многие хорошие разработчики которые выкладывают неплохие решения просто не парятся о продвижении своих библиотек.

        • +1
          Свою не продвигал, считаю что визуалка вытащила. Хотя для громкого заглавия использовал «плохую архитектуру». Проблемы она решает, я ей доволен — считаю что хороший выбор сделал.

          История скорее о том, «сидя в зонах комфорта» юзают один паттерн под все случаи жизни.

          Грустно когда смотрю код подчиненых, и вижу VIPER где только можно и нельзя. Тренды…
          • +2
            юзают один паттерн под все случаи жизни.

            тут скорее культ карго нежели зона комфорта. Ну мол кто-то рассказал что если будете применять viper то железные птицы вернутся все будет всегда хорошо. И скорее всего либо было лень разбираться что это такое либо авторитет шамана главного разработчика на проекте высок и ему лучше знать.


            вижу VIPER где только можно и нельзя.

            Я могу сказать так, из моего опыта общения с нашими мобильщиками которые практиковали viper на нескольких проектах, чаще проблема кроется еще и в неверной интерпретации этого паттерна. Поскольку паттерн этот основан на идеях Дяди Боба, нужно хорошо понимать такие принципы как SRP (который кажется обманчиво простым но на деле его весьма сложно соблюдать).


            Так же у нас там есть ограничение в духе "сущности никогда не должны покидать интерактор и попадать в presenter" что есть просто соблюдение закона деметры и инкапсуляции. Опять же за последние 6 лет мне попадались только 2-3 проекта где на клиенте было достаточно логики что бы можно было выстраивать интеракторы. И да, те самые интеракторы подразумевается использовать только для операций записи, операции чтения можно делать проще. Более того, использование одних и тех же сущностей как для записи так и для чтения может приводить к нарушению SRP ради которого весь viper и задуман.


            Ну то есть как по мне опять же проблема не в viper а в том что во всех описаниях этого паттерна которые мне удалось нагуглить вообще не говорится о том какие проблемы он решает. Как правило в качестве аргумента используют "юзают на больших проектах" и людям этого хватает.

            • +1
              Именно! Проблем с Viper нет никаких, есть вопросы «зачем», на которые часто ответ «ну так делают»

              А то что поддержка сложным паттернов обходится в 2x-5x времени, или что есть другие, лучшие варианты (или вообще плюнуть и написать это одностраничное приложение все в контроллере) — боятся будто нечесть серебряных пуль)
              • 0

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

                • 0
                  Еще раз, и VIPER — прекрасный паттерн. Но стоит перед вами задача реализовать экран, который выводит «Хабрахбр, дай мне кармы»

                  Вы будете подтягивать VIPER? Я — нет.

                  И вся статья о том, что нужно использовать VIPER не потому что «на больших проектах используют, значит надо», а понять что паттерн решит вашу проблему. И, возможно, кастомизировать / комбинировать уже существующие паттерны для этой цели. А может и свой сделать.

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

                  тут нет цели


                  При его использовании, у разработчика появляется привычка писать тестируемый, разбитый на простые объекты код.

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


                  Другое дело что вайпер налагает сэт весьма простых ограничений вида "такой-то код ложи сюда", что немного позволят дисциплинировать команду. Но все же что мне не нравится в этом паттерне что он как бы и прославляет SRP и как бы сам по себе отвечает за слишком многое. Скажем почему бы не воспринимать интеракторы как модель в контексте привычных многим MV* а все эти вайрфреймы/сущности сделать лишь деталью их реализации. Как бы при таком варианте вся та же идея сохраняется, но проще маневрировать.


                  Но имхо, все высказавшиеся правы в том, что времени на написание кода с этим паттернов уходит не мало.

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

  • +5
    Для чего используется вот эта конструкция?

    let permissionAssistant = SPRequestPermissionAssistant.modules.dialog.interactive.create(with: [.Camera, .PhotoLibrary, .Notification]
    


    Никому не нужны подробности реализации, должно быть просто:

    let permissionAssistant = SPRequestPermissionAssistant.create(with: [.Camera, .PhotoLibrary, .Notification]
    


    То что вы выставляете наружу кишки — это феил.
    • +1
      Для чего используется вот эта конструкция?

      Это сборка модуля. Если не ошибаюсь, прием называется Dependency Injection и очень близко идет с протокольным подходом.

      Никому не нужны подробности реализации, должно быть просто:

      Никаких подробностей реализации. Это просто выбор одного из модулей. Хотите банер сверху? Будет:

      SPRequestPermissionAssistant.modules.banner


      Хотите диалоговое окно, но не интерактивное, а с блюром:

      SPRequestPermissionAssistant.modules.dialog.blur
  • +8
    Какая связь между звёздами и качеством кода? Компонент нравится — потому и звездят, качество кода тут вообще побоку. Гитхаб это не кодревью.
    • 0
      В этом и смысл — нужно оправдано применять паттерны и не забывать о цели, которая ставится. Паттерны — не панацея.

      На примере проекта я показал как забить на традиционные паттерны и сделать такую архитектуру, которая будет решать необходимую мне проблему (я не говорю что изобрел ее, просто скомбинировал разные подходы).

      Я не говорю что есть связь между звёздами и качеством кода, скорее говорю что некачественный код может быть объективно лучше, нежели 5x сил, затраченных на реализацию паттерна (или "используем VIPER потому что промышленный стек")
      • +1
        Как мне кажется, похожие взгляды высказывались на хабре в статье про "выпекание хлеба".

        Ну и Оккам со своей бритвой плохого не посоветует.
        • 0
          Ну и Оккам со своей бритвой плохого не посоветует.

          бритва Хэнлона тож ничаго.

        • 0
          Суперская статья!
          Да, взгляды и призывы очень похожее
  • +1
    Я не говорю что есть связь между звёздами и качеством кода, скорее говорю что некачественный код может быть объективно лучше, нежели 5x сил на реализацию паттерна
    • +2
      Это уж конечно, программирование ради программирование вообще в последнее время как-то начинает напрягать.
  • –1
    По-моему эта либо нарушает гайдлайны эппла, разрешения должны запрашиваться в момент, когда они нужны, надо объяснить, зачем они нужны и приложение должно уметь работать при отсутствии разрешений.

    Рано или поздно заблочат в аппсторе
    • 0
      Вы правы. Но гидлайнов либа не нарушает и вопросов не возникало (лично у меня 20+ ревью уже было).

      Если капнуть глубже — завязано вообще приложение на выборе фотографии. Как вы без разрешения камеры и фото? Или те же пуши… они не влияют на функционал, но хотелось бы чтобы пользователи давали добро. По гидлайнам их нужно запрашивать… при первом запуске? Это ужасный подход, и конверсия будет на нуле.

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

      В остальном у ревьюеров вопросов ни разу небыло, блокировок тоже.
      • –1
        То, что у ревьюверов не было вопросов — это, как известно, не ваша заслуга, а их недоработка )
        Механизм разрешений у эппла не спроста же спроектирован так, что спрашивать пользователя можно один раз и потому желательно вовремя. Обходить это ограничение и в качестве побочного эффекта заставлять пользователя дважды подтверждать разрешение — как минимум плохой тон, а по факту — нарушение принципа заботы о пользователях. Популярность компонента обусловлена как ленью и низкой квалификацией разработчиков (не разработчиков компонента, а тех, кто его использует), так и пресловутыми задачами бизнеса.
        • 0
          В одном сообщении объяснили все в духе конспирологии:
          1) ревьюеры потеряли зрение
          2) все разработчики, которые внедрили проект, не знают гидлайнов
          3) все разработчики, которые внедрили проект, не думают о пользователях
          4) автор заработал на этом миллионы

          Ну серьезно?)

          Давайте еще раз, к примеру проект — перископ. Для корректной работы нужна камера, микрофон и локация. Выкиньте все 3 окна на пользователя? Мне кажется именно это и будет «низкой квалификацией». А так покажете диалоговое окно с тремя разрешениями (можно и пуши еще предложить, заодно, у пушей нет конкретной «правильной» точки запроса)

          Вы можете сказать что ситуация единственная, и скорее исключение. Но возьмем популярный вариант — вам нужно выбрать фотографию, или сделать ее. Два разрешения, так? Тоже выкиньте пачкой разрешения? Мне лично понравится диалоговое окно с приятной UI, а не N-ое количество алертов поверх

          Мне кажется вы просто поверхностно осмыслили способы использования, и надеюсь примеры смогли быть для вас показательными.

          А вообще грустно что вы аудиторию заочно назвали «низкоквалифицированной»
          • 0
            Перископ… вы же именно оттуда взяли идею, правильно я понимаю? Чтобы сделать фотографию мы запрашиваем доступ к камере, совсем не обязательно её нужно будет сохранять. Если только после фотографирования пользователь запросил сохранение, уже тогда запрашиваем доступ к галерее. Сравните сценарии:
            А) Пользователь запускает приложение, знакомится и интерфейсом, нажимает кнопку «сфотографировать», разрешает доступ к камере, играется с фильтрами, пересылает фотографию, отказывает в доступе к галерее.
            Б) Пользователь запускает приложение, получает окно с запросом кучи прав, нажимает «разрешить доступ к камере», получает уже системный запрос на разрешение доступа к камере, повторно разрешает доступ к камере, видит «вы не можете продолжить, пока не дадите все разрешения». Дальше лично я бы ругаясь прошел только при условии, что приложение уровня перископа. Давайте оставим такой ущербный подход к управлению правами доступа андроиду, ок?

            По вашим пунктам, на самом деле, никакой конспирологии:
            1) К сожалению, ревьюверы у эппла — индусы на аутсорсе, которые очень часто ошибаются;
            2 и 3) Если не все, то из разработчиков, использующих ваш компонент таких точно большинство;
            4) Про задчи бизнеса я имел ввиду то, что часто разработчику нужно просто быстро реализовать функциональность не думая качестве. Про автора и миллионы — это уже какие-то ваши мечты, ничего такого я не говорил.
            • 0
              Взял именно оттуда, когда перископ выкинул на меня подряд 3 запроса с разрешениями. Потом они поправили, и сделали удобненько)

              Согласен, с изображением вы правы. Но если сложнее сценарии, когда для функционирования приложения нужно сразу несколько разрешений. Я именно к этому аргументирую!

              Более того, я против если приложение где-то глубоко использует галерею, запрашивать ее при запуске. Еще раз вернемся к перископу (это прекрасный пример) — как иначе организовать, чтобы не убить лояльность? Да никак.

              А теперь, представим, вы запрашиваете пуши. Только пуши. Вместо того, чтобы выбросить на пользователя системный запрос, вы показываете ему окно, пытаясь убедить в том, что пуши ему будут полезны. Если что, конверсия реально оказалась выше.

              Главный вывод: есть сложные сценарии, когда необходимо запросить много пушей. Есть сценарии, когда непонятно зачем запрашивается разрешение: тогда можно и текста прикрепить, и интуитивное изображение. Запрашивать при старте все подряд — это ужасно

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

    Сразу дьявол на левом? плече шепчет: “Singltone…”. И первые дни мне казалось это прекрасным решением, в AppDelegate сконфигурировал, а показывай контролер где захочется.

    Presenter держит контроллер, он будет разбираться с жестами, экраном и прочим, чем занимаются контроллеры. Конечно, возникает вопрос как контроллер будет сообщать о действиях. У особо пытливых возникнет вопрос «а ARC часом не уничтожит все к чертям?».


    Я думаю вы ставили перед собой цель: Написать легко используемый, закрытый функционал. Но почему вы так далеко пошли? Вы ведь не храните ссылку на UIAlertController? Вроде как красивое решение, где легко добавляется и хендлится выбор элемента. Почему не покапали в эту сторону?
    Да и проблема с ARC решается retain циклом с последующим его освобождением, вы ведь знаете жизненней цикл вашей реализации.

    По поводу звезд — тут скорее заслуга не решения, а вашего маркетингового хода, я думаю вы потратили достаточно времени, чтобы написать во все возможные комьюнити.
    • 0
      Функционал не закрытый, скорее скрытый протоколом. Мне кажется (и не просто так) в таком проекте это отличная практика.

      По поводу маркетинга — я самый ужасный маркетолог. Ни одной статьи не найдете, потому что никто их не писал) Но погуглив найдете кучу рекомендаций на профильных ресурсах. Вообще все было просто, я попал в дно топа, после попал в выбору awesome-ios. А дальше понеслось…

      P.S. Даже грустно что сразу видите маркетинг, а не «лояльно воспринятый проект», тем более что предпосылок так думать вроде как и нет.
      • 0
        Функционал не закрытый, скорее скрытый протоколом. Мне кажется (и не просто так) в таком проекте это отличная практика.

        Речь шла про понятный и простой interface (как в UIAlertController, как я писал выше), а не property + SPRequestPermissionAssistant.modules.dialog.interactive.create.
        Жаль, что игнорите советы или у вас мнение о UIAlertController?
        P.S. Даже грустно что сразу видите маркетинг, а не «лояльно воспринятый проект», тем более что предпосылок так думать вроде как и нет.

        Серьезно? Я состою во множестве чатиках, группах, да и на всяких cocoacontrols, и во всех сиял ваш профиль с ссылкой на это чудо.
        • 0
          Жаль, что игнорите советы или у вас мнение о UIAlertController?

          Простите, перечитал раз 5 и не понял, торможу) Если у вас есть предложение — отпишитесь мне чуть подробнее. Всегда рад взгляду со стороны

          Серьезно?

          А да, на cocoacontrols действительно кидал, общаемся с автором проекта — он немного подержал в топе(очень понравился ему проект). Но максимум оттуда выжать ну 100 звезд) Было еще два момента, в группе iOS dev (проект уже имел больше 1к звезд), и в чате iOsNinja — тоже самое.

          Больше нет, я не вижу тут маркетинга. В iOS dev поделился успехом (мне много помогали резиденты, и даже Скутаренко), а в iOsNinja — 100 человек в чате)

          А где еще? Честн слово, органика) Так что я серьезно — маркетинга небыло
  • 0
    Исправьте в начале текста в слове «Singltone» две ошибки.
    • 0
      Поправил, спасибо!
  • +1
    Ну как бы в тему — http://local.joelonsoftware.com/wiki/Не_дайте_Астронавтам_Архитектуры_вас_запугать
    • 0
      Сколько раз себя ловил на этом

      Когда вы поднимаетесь слишком высоко, наполненный абстракциями, вы задыхаетесь из-за отсутствия кислорода. Иногда мыслители просто не знают, когда остановиться, и они создают абсурдные, всеобъемлющие, высокоуровневые картины устройства вселенной, которые являются хорошими и изящными, но фактически не означают вообще ничего.


      Отличная, ироничная статья
  • +1
    Использовал это расширение в своем приложении, очень понравилась тонкая настройка окошка уведомлений. Могу сказать, что количество пользователей, включающих-таки уведомления, увеличилось очень сильно, это следует из статистики «возвращений» пользователей в приложение на следующий день. Респект автору :)
    • 0
      Спасибо!

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.