Кращі практики та інструменти проекту iOS

З шаблоном проекту Xcode з відкритим кодом

Під час роботи над greenfield iOS проектами мені часто доводилося починати новий проект з нуля. Роблячи це, я та моя команда завжди витрачали багато часу на базові настройки проекту, такі як інтеграція інструментів, налаштування структури проекту, написання базових класів, інтеграція зовнішніх бібліотек тощо.

Я вирішив, що час, затрачений на запуск проекту, можна заощадити, і процес може бути в основному автоматизованим. Я записав усі звичайні найкращі практики та інструменти, які ми використовували, і підготував шаблон проекту, який я та моя команда могли використовувати при запуску нових проектів. Цей шаблон повинен заощадити час налаштування проекту, а також забезпечити загальну основу, до якої кожен член команди звикне, щоб вам не потрібно було думати та досліджувати структуру та основи проекту. Вони завжди будуть однаковими.

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

Какаоди

Я не думаю, що цьому потрібен вступ. Це бібліотека для управління зовнішніми залежностями для iOS-проектів. Це вже давно, і він є надійним і бойовим випробуванням у тисячах (якщо не мільйонах) проектів. Там є альтернативні менеджери залежностей, такі як Carthage, але я вирішив поїхати з Cocoapods, оскільки він має найширший спектр проектів з відкритим кодом, який він підтримує. Використовувати Cocoapods дуже просто, і він постачається з пошуковим індексом, який дозволяє легко знаходити пакунки, які вам можуть знадобитися.

Проект шаблону поставляється з простим Podfile, який включає Swiftlint та R.swift. Шаблон також включає Gemfile для управління версією Cocoapods, яка використовується для вирішення залежностей. Це часто недооцінене вдосконалення, яке запобігає виникненню проблем, коли розробники у вашій команді встановлюють залежності, використовуючи різні версії самого Cocoapods. Gemfile застосовує однакову версію Cocoapods для всієї команди.

Swiftlint

Swiftlint - дуже корисний інструмент для виконання певних правил та стилю кодування для кожного програміста в команді. Ви можете розглядати це як автоматизовану систему перегляду коду, яка попереджає програміста про небезпечні речі, такі як розгортання сили, примусові спроби тощо, але також застосовує загальний стиль кодування, переконуючись, що всі програмісти дотримуються однакових правил, пов'язаних із «стилем коду» як-от правила відступів або проміжків. Це має величезні переваги не лише економії часу на перегляд коду, роблячи ці основні перевірки, але й робить усі файли в проекті знайомими, що підвищує їх читабельність і, як результат, їх розуміння усіма розробниками. Список усіх правил ви можете знайти тут. У шаблоні Swiftlint встановлюється через Cocoapods і включається в етап Фази збірки, щоб він натякав і попереджав розробника при кожній збірці проекту.

R.swift

R.swift - це інструмент для отримання сильно набраних, автозавершених ресурсів, таких як зображення, шрифти та локалізації. Це робиться шляхом сканування вашого проекту та генерування швидких класів, необхідних для отримання ресурсів. Найбільша продажна точка цієї бібліотеки полягає в тому, що, використовуючи ресурси, вона робить ваш код:

  • Повністю набрано - менше кастингу та здогадок, який метод повернеться
  • Перевірено час компіляції - більше невірних рядків, які призводять до аварійного завершення роботи програми
  • Автозавершено - ніколи більше не вгадайте назву цього зображення / підказки / раскадровки

Розглянемо наступний код за допомогою офіційного API рядка:

нехай значок = UIImage (названий: "власна-ікона")

Якщо ви неправильно написали ім'я зображення, тут ви отримаєте нуль. Якщо хтось із членів вашої команди змінить назву ресурсу зображення, цей код поверне нульовий або вийде з ладу, якщо ви змусите знімати зображення. При використанні R.swift це стає:

нехай значок = R.image.customIcon ()

Тепер ви можете бути впевнені, що піктограма дійсно існує (компілятор попередить вас, якщо це не буде завдяки проверенню часу компіляції), і ви можете засудити, що не будете робити помилки в назві значка, оскільки ви будете використовувати автозаповнення.

R.swift встановлюється через Cocoapods та інтегрується в шаблон як фаза збірки і генерує класи обгортання Swift для кожної збірки. Це означає, що якщо ви додасте файл / зображення / локалізацію / шрифт / колір / nib тощо, він буде доступний вам за допомогою R.swift після складання проекту.

Окремий AppDelegate для тестів

Хороша недооцінена практика - мати окремий клас TestAppDelegate під час запуску тестів. Чому це гарна ідея? Ну, зазвичай клас AppDelegate робить багато роботи при запуску програми. Він може налаштувати вікно, створити основну структуру інтерфейсу програми, зареєструватись для сповіщень, створити базу даних і навіть іноді робити дзвінки API на якусь сервісну програму. Одиничні тести не повинні мати жодних побічних ефектів. Ви дійсно не хочете здійснювати випадкові дзвінки api та налаштовувати всю структуру інтерфейсу інтерфейсу програми лише для того, щоб виконати кілька тестів на одиницю?

TestAppDelegate - це також чудове місце для коду, який потрібно запустити лише один раз під час виконання тестового набору. Він може містити код, який генерує макети, заглушки мережевих запитів тощо.

Шаблон містить файл main.swift, який є основною точкою входу для програми. У цьому файлі є методи, які перевіряють, у якому середовищі працює додаток, і якщо це тестове середовище, викликає TestAppDelegate.

Праполірування продуктивності компілятора

Swift - це чудова мова, простіший у використанні та набагато безпечніший, ніж Objective-C (IMO). Але коли він був вперше представлений, він мав один великий мінус - час складання. Ще 2 дні я працював над проектом, який мав близько 40 К рядків коду Swift (проект середнього розміру). Код був дуже важким із загальним висновком та типовим висновком, а для складання чистої збірки знадобилося майже 5 хвилин. Коли ви внесли навіть невелику зміну, проект буде перекомпільований і знадобиться приблизно дві хвилини, щоб побачити зміни. Це був один з найгірших досвіду розробника, який я коли-небудь мав, і я майже перестав використовувати Swift через це.

Єдиним рішенням тоді було спробувати проаналізувати час компіляції проекту та спробувати змінити свій код таким чином, що зробить компілятор швидше. Щоб допомогти у цьому, Apple представляє кілька неофіційних прапорів компілятора, які б попереджали вас під час компіляції методу або вирішення типу виразу зайняло занадто багато часу. Я додав ці прапори до шаблонного проекту, щоб вас з самого початку попередили про довгий час складання для вашої програми.

У наш час часи збірки значно покращилися, і вам дуже рідко потрібно налаштувати свій код, щоб покращити час збирання. Але все ж краще знати наперед, а потім спробувати вирішити проблему, коли проект стає занадто великим.

Конфігурації розробки / постановки / виробництва

Ще одна добра практика (або, можна сказати, необхідність) полягає в тому, щоб мати окремі конфігурації та змінні середовища для середовищ розробки, постановки та виробництва. Практично кожен додаток сьогодні має підключитися до якоїсь бекенд-сервісу, і зазвичай ці сервіси розгортаються в декількох середовищах. Середовище розробки використовується для щоденних розгортань та розробників для тестування свого коду. Постановочне середовище використовується для стабільних випусків для тестерів та клієнтів для тестування. Ми всі знаємо, що таке виробниче середовище.

Один із способів підтримки декількох середовищ у проекті iOS - додавання конфігурацій рівня проекту.

Конфігурації рівня проекту

Визначивши конфігурації, ви можете створити файл Configuration.plist, що містить змінні для кожного середовища.

Configuration.plist

Під час запуску проекту можна вказати, яку конфігурацію слід використовувати. Це можна зробити за схемою збірки.

Потім потрібно додати ще одну властивість у файл Info.plist проекту. Значення цього властивості буде динамічно вирішено під час виконання до назви поточної конфігурації.

Це все заздалегідь налаштоване для вас у шаблоні.

Залишилося лише написати клас, який може отримати ці змінні під час виконання, залежно від конфігурації, обраної у схемі збірки. Шаблон містить клас ConfigurationManager, який може отримати змінні для поточного середовища. Ви можете перевірити реалізацію цього класу на Github, щоб побачити, як він працює.

Readme

Кожен проект повинен мати базовий Readme, який має принаймні інструкції, як встановити залежності та запустити проект. Він також повинен містити описи архітектури та модулів проекту. На жаль, розробники не люблять писати документацію (readme є частиною цього), і я бачив проект, який розроблявся місяцями, і у них був навіть базовий Readme. Щоб зняти з себе тягар написання цього основного readme, шаблон містить стандартне readme, що охоплює установку та структуру проекту. Коли ви налаштуєте новий проект за допомогою шаблону, програма Readme буде автоматично включена.

Гітігноре

В даний час більшість проектів використовують GIT як свою систему управління версіями. Під час використання GIT зазвичай ви не хочете ігнорувати деякі файли чи папки в проекті, як-от папка збірки або похідна папка даних. Щоб заощадити проблеми пошуку файлу gitignore, який відповідає вашому проекту iOS, шаблон включає стандартний gitignore, наданий авторами Github.

Базові класи для обробки глибоких посилань та сповіщень

Практично кожен додаток сьогодні має обробляти посилання та сповіщення. Для цього розробник повинен записати деяку кількість кодового шаблону в клас AppDelegate. Цей шаблон охоплює, а також забезпечує базові класи, які спрощують роботу з перехідними посиланнями та повідомленнями.

Підсумок

Підводячи підсумок, шаблон намагається включити кращі практики та інтегрувати корисні інструменти сторонніх виробників. Це повинно заощадити вас та нашу команду, витрачені на нові налаштування проекту, а також забезпечити спільну та міцну основу для решти проекту. Нехай це вам добре послужить!

PS: Якщо у вас є якісь проблеми або запит на функцію шаблону, просто залиште мені проблему на Github. Я спробую це вирішити у вільний час.