За свой опыт разработки на iOS я видел много чужого кода. Как новичков, так и более опытных разработчиков. И часто приходилось сталкиваться с плохим неймингом. В этой статье я хочу показать свое представление какими должны выглядеть названия переменных и функций.
Переменная — отображение абстракции
Начнем с переменных. Так, как iOS разработчики большинство своей работы взаимодействуют с UIKit, стоит обсудить его элементы.
Допустим, у нас есть элемент UITextView, который отображает описание. Правильное название переменной — descriptionTextView. Многие любят называть подобный элемент следующим образом: descriptionText.
Если бы я не видел тип этой переменной, то я бы подумал, что это String, это же текст, ну. Когда вы используете элементы UIKit — возьмите название вашего класса и уберите префикс UI — получившееся должно соответствовать названию вашей переменной.
Я даже написал функцию, которая это может сделать за вас. Вы можете понять как это работает, запуская ее в Playground (конечно, она вам не пригодится, показываю просто для примера):
func variableName(of type: AnyClass, for purpose: String) -> String {
let className = String(describing: type)
let postFix = className.replacingOccurrences(of: "UI", with: "")
let result = purpose + postFix
return result
}let textFieldClass = UITextField.self
let textFieldPurpose = "description"
variableName(of: textFieldClass, for: textFieldPurpose) // descriptionTextFieldlet labelClass = UILabel.self
let labelPurpose = "title"
variableName(of: labelClass, for: labelPurpose) // titleLabel
Приведу примеры неправильных названий:
@IBOutlet weak var descriptionTextView: UITextView! // Правильно!
@IBOutlet weak var descriptionText: UITextView! // Неправильно.
@IBOutlet weak var avatarImageView: UIImageView! // Правильно!
@IBOutlet weak var image: UIImageView! // Неправильно.
@IBOutlet weak var avatarIcon: UIImageView! // Неправильно.
@IBOutlet weak var titleLabel: UILabel! // Правильно!
@IBOutlet weak var labelTitle: UILabel! // Неправильно.
@IBOutlet weak var contentScrollView: UIScrollView! // Правильно!
@IBOutlet weak var contentView: UIScrollView! // Неправильно.
Если говорить о случае когда imageView называют image, то когда мы хотим получить image из него, то получается
image.image = ...
Выглядит — просто ужасно, поэтому так делать никак нельзя.
Это первая беда переменных. Вторая беда — регистр букв. Думаю, когда человек начинает учить Swift — в первых уроках ему расскажут, что переменные не должны начинаться с большой буквы. Думаю, на объяснение этого не стоит тратить время, но бывают и такие примеры: titleTextfield, backgroundcontentView. Многие забывают про Camel-case с первой буквой нижнего регистра. С этим думаю все понятно, правильные названия этих переменных: titleTextField, backgroundContentView.
С UIKit закончили, идем дальше. Допустим, у вас есть такой кусок кода:
import UIKitvar ages = [18, 45, 60, 2] // Массив возрастов
// Нужно найти сумму всех возрастов (будем использовать for вместо reduce)
var sum = 0
for i in 0..<ages.count {
sum += ages[i]
}print(sum) // 125
Что в нем не так? Переменная i. Мы со школьной скамьи привыкли к такому виду счетчика еще с C++. Но это довольно неправильно. У нас ведь могут быть вложенные циклы (а там пойдут j, k, t). Стоит избавляться от этого и назвать переменную indexInAges или хотя-бы index (хоть что-то).
Привыкайте, чтобы ваши количество символов в ваших переменных было больше или равно 3. Вам в помощь SwiftLint , который поможет адаптироваться под эти правила. Можете его настроить под себя, если боитесь 1000+ errors и в 5 раз больше warnings в вашем проекте.
Теперь поговорим про кастомные классы. Конечно, их может быть бесконечность, но я постараюсь рассмотреть самые частые примеры.
Очень часто я встречал в функциях роутера или в подобных, когда нужно передать свойства в UIViewController, допустим или запрезентить его, используется следующий код:
// Неправильно!
let vc = NewsViewController()
vc.isNeedToLoadAllNews = true
UIViewController().present(vc, animated: true, completion: nil)
Первым делом, я уже говорил о том, что нужно использовать больше трех символом в названии и вы помните о постфиксе в ваших переменных UIKit. vc — не подходит. Более того, здесь передаются проперти через точку. Более правильным было бы сделать передачу их через конструктор, так вы обезопасите целостность данных, самого UIViewController. Если же они у вас необязательны для передачи, то default аргументы в конструкторе никто не отменял. Правильной реализацией считалось бы следующее:
class NewsViewController: UIViewController {
private var isNeedToLoadAllNews: Bool = false
convenience init(isNeedToLoadAllNews: Bool = false) {
self.init()
self.isNeedToLoadAllNews = isNeedToLoadAllNews
}
}let newsViewController = NewsViewController(isNeedToLoadAllNews: true)
UIViewController().present(newsViewController, animated: true, completion: nil)
Еще один плюс данного подхода в том, что мы инкапсулировали значение isNeedToLoadAllNews и оно стало безопаснее.
Если говорить о моделях данных, то здесь все намного проще.
// Неправильно
let msg = Message()
let animal1 = Animal()// Правильно:
let firstAnimal = Animal() // Альтернатива animal1
let cat = Animal() // Модель называется животное, но кошка может им являться
let lastMessage = Message() // Здесь мы можем конкретизировать какое именно это сообщение
let message = Message() // Но можно и так
Поговорим еще немного о примитивных типах, например, Bool.
До Swift 3.2, в стандартных библиотеках Apple вы могли встретить такие названия:
- view.hidden
- element.expanded
- viewController.presented
После, Apple начала добавлять префикс is в булевых типах, и это очень хорошее решение, переменные начали выглядеть так:
- view.isHidden
- element.isExpanded
- viewController.isPresented
Читайте функции как предложения
Хотелось бы пару слов сказать о методах. Самое первое, что я хотел бы отметить — это слова перед аргументами, которые используются в функциях.
Говорю я про них:
fetchNews(with count: Int, and completion: () -> ())
Они невероятно важны и делают ваш код красивее и читабельнее. Но многие не используют их, а если даже и используют, до делают это следующим образом:
fetchNews(with: 5, and: {
print("News fetched.")
})
Это делает ваш код не читабельным. Непонятно, что такое 5 и к чему оно относится, но если мы вынесем их в константы, все станет намного приятнее:
let newsCompletion = {
print("News fetched.")
}let count = 5fetchNews(with: count, and: newsCompletion)
Не бойтесь выносить все в константы, Swift это очень любит. Теперь, когда мы попробуем прочитать функцию по-человечески, то получим предложение: “fetch news with count and news completion”, все максимально понятно. Такой подход к нам пришел еще из языка Smalltalk.
Но не со всеми функциями нужно поступать так. Иногда нам подобные слова вообще не нужны. Привожу пример:
func select(index: Int)
В данном случае у нас нет потребности во вспомогательных аргументах, то есть наша функция читается как “select index” — читабельно. Значит все ок.
На этом основные мысли насчет нейминга у меня заканчиваются, надеюсь статья была полезна для вас.
Ссылки на меня: