Created
May 24, 2024 08:10
-
-
Save scott-lydon/3215db7abd1d92054b3cba028471aab4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Coding Guidelines | |
## Rules | |
1. **Omit the return keyword in one-line functions that return a value.** | |
2. **Use trailing closure syntax.** | |
3. **Remove the Google indentation guide rule due to lack of specific guidelines in the Google Swift style guide and because SwiftLint handles indentation.** | |
4. **Reevaluate the rule regarding DispatchQueue from inaction on the main thread for feasibility in static analysis.** | |
5. **Use higher-order functions when multiple properties call the same function.** | |
6. **Require every method to have a comment.** | |
7. **Remove one-line functions that do not return anything and call the code directly.** | |
8. **Avoid print statements; use a logging function instead (as a warning).** | |
9. **Avoid function declarations within other function bodies.** | |
10. **Use higher-order functions for processing arrays instead of loops.** | |
11. **Avoid using `[String: Any]`; use `Codable` instead.** | |
12. **Combine nested if-else statements into a single initialization statement.** | |
13. **Avoid empty files.** | |
14. **Inline constants or variables used only once.** | |
## Removed Rules and Reasons | |
1. **Google Indentation Guide:** Removed because there is no specific section on indentation in the Google Swift style guide, and SwiftLint already handles indentation. | |
2. **DispatchQueue from inaction is already on main thread:** Reevaluate the feasibility of enforcing this rule statically. Consider dynamic analysis or runtime checks to ensure code runs on the correct thread. | |
## Examples | |
### 1. Omit the return keyword in one-line functions that return a value. | |
**Non-triggering examples:** | |
```swift | |
func blocks() -> [Block] { | |
.all(with: .retained, times: 2) | |
} | |
``` | |
```swift | |
func fetchUser() -> User { | |
User(name: "John") | |
} | |
``` | |
```swift | |
func calculateSum(a: Int, b: Int) -> Int { | |
a + b | |
} | |
``` | |
**Triggering examples:** | |
```swift | |
func blocks() -> [Block] { return .all(with: .retained, times: 2) } | |
``` | |
```swift | |
func fetchUser() -> User { return User(name: "John") } | |
``` | |
```swift | |
func calculateSum(a: Int, b: Int) -> Int { return a + b } | |
``` | |
### 2. Use trailing closure syntax. | |
**Non-triggering examples:** | |
```swift | |
someFunction { value in | |
print(value) | |
} | |
``` | |
```swift | |
UIView.animate(withDuration: 0.3) { | |
self.view.alpha = 1.0 | |
} | |
``` | |
```swift | |
fetchData { result in | |
handle(result) | |
} | |
``` | |
**Triggering examples:** | |
```swift | |
someFunction(settingsAction: { value in | |
print(value) | |
}) | |
``` | |
```swift | |
UIView.animate(withDuration: 0.3, animations: { | |
self.view.alpha = 1.0 | |
}) | |
``` | |
```swift | |
fetchData(completion: { result in | |
handle(result) | |
}) | |
``` | |
### 4. Use higher-order functions when multiple properties call the same function. | |
**Non-triggering examples:** | |
```swift | |
[am6Btn, am7Btn].forEach { $0.titleLabel?.setAkinFont() } | |
``` | |
```swift | |
[btn1, btn2, btn3].forEach { $0.isEnabled = true } | |
``` | |
```swift | |
[view1, view2, view3].forEach { $0.isHidden = false } | |
``` | |
**Triggering examples:** | |
```swift | |
am6Btn.titleLabel?.setAkinFont() | |
am7Btn.titleLabel?.setAkinFont() | |
``` | |
```swift | |
btn1.isEnabled = true | |
btn2.isEnabled = true | |
btn3.isEnabled = true | |
``` | |
```swift | |
view1.isHidden = false | |
view2.isHidden = false | |
view3.isHidden = false | |
``` | |
**More examples:** | |
```swift | |
addButton.addTarget( | |
self, | |
action: #selector(addProfilePicPress), | |
for: .touchUpInside | |
) | |
addProfilePicButton.addTarget( | |
self, | |
action: #selector(addProfilePicPress), | |
for: .touchUpInside | |
) | |
``` | |
Should be: | |
```swift | |
[addButton, addProfilePicButton].forEach { | |
$0.addTarget(self, action: #selector(addProfilePicPress), for: .touchUpInside) | |
} | |
``` | |
```swift | |
logoutLabel.text = "Logout" | |
logoutLabel.textColor = .romanceRed | |
contentView.addSubview(logoutLabel) | |
logoutLabel.constraint(from: .centeredHorizontallyWith(contentView)) | |
logoutLabel.constraint(from: .centeredVerticallyTo(contentView)) | |
logoutLabel.constraint(from: .distanceToBottom(contentView.bottomAnchor, 36)) | |
logoutLabel.constraint(from: .distanceToTop(contentView.topAnchor, 36)) | |
``` | |
Should be: | |
```swift | |
logoutLabel.text = "Logout" | |
logoutLabel.textColor = .romanceRed | |
contentView.addSubview(logoutLabel) | |
[.centeredHorizontallyWith(contentView), .centeredVerticallyTo(contentView), | |
.distanceToBottom(contentView.bottomAnchor, 36), .distanceToTop(contentView.topAnchor, 36)].forEach { | |
logoutLabel.constraint(from: $0) | |
} | |
``` | |
```swift | |
rightAddButton.titleLabel?.setAkinFont() | |
scrollButton.titleLabel?.setAkinFont() | |
closeButton.titleLabel?.setAkinFont() | |
closeButtonBordered.titleLabel?.setAkinFont() | |
``` | |
Should be: | |
```swift | |
[rightAddButton, scrollButton, closeButton, closeButtonBordered].forEach { | |
$0.titleLabel?.setAkinFont() | |
} | |
``` | |
### 5. Require every method to have a comment. | |
**Non-triggering examples:** | |
```swift | |
/// Fetches data from the server. | |
func fetchData() { | |
// implementation | |
} | |
/// Handles user login. | |
func loginUser() { | |
// implementation | |
} | |
``` | |
**Triggering examples:** | |
```swift | |
func fetchData() { | |
// implementation | |
} | |
func loginUser() { | |
// implementation | |
} | |
``` | |
### 6. Remove one-line functions that do not return anything and call the code directly. | |
**Non-triggering examples:** | |
```swift | |
print("Hello, World!") | |
``` | |
**Triggering examples:** | |
```swift | |
func printHello() { | |
print("Hello, World!") | |
} | |
``` | |
```swift | |
func reset() { | |
value = 0 | |
} | |
``` | |
### 7. Avoid print statements; use a logging function instead. | |
**Non-triggering examples:** | |
```swift | |
logger.log("This is a log message") | |
``` | |
```swift | |
Log.info("User logged in successfully") | |
``` | |
```swift | |
debugPrint("Debugging information") | |
``` | |
**Triggering examples:** | |
```swift | |
print("This is a log message") | |
``` | |
```swift | |
print("User logged in successfully") | |
``` | |
```swift | |
print("Debugging information") | |
``` | |
### 8. Avoid function declarations within other function bodies. | |
**Non-triggering examples:** | |
```swift | |
func outerFunction() { | |
// code | |
} | |
func innerFunction() { | |
// code | |
} | |
``` | |
```swift | |
func calculate() { | |
let result = compute() | |
// other code | |
} | |
``` | |
```swift | |
func performAction() { | |
// action code | |
} | |
``` | |
**Triggering examples:** | |
```swift | |
func outerFunction() { | |
func innerFunction() { | |
// code | |
} | |
innerFunction() | |
} | |
``` | |
```swift | |
func calculate() { | |
func compute() -> Int { | |
return 5 | |
} | |
let result = compute() | |
} | |
``` | |
```swift | |
func performAction() { | |
func action() { | |
// action code | |
} | |
action() | |
} | |
``` | |
### 9. Use higher-order functions for processing arrays instead of loops. | |
**Non-triggering examples:** | |
```swift | |
let values = ["a", "b", "c"].map { $0.uppercased() } | |
``` | |
```swift | |
let filtered = numbers.filter { $0 > 10 } | |
``` | |
```swift | |
let sum = numbers.reduce(0, +) | |
``` | |
**Triggering examples:** | |
```swift | |
var values = [String]() | |
for item in ["a", "b", "c"] { | |
values.append(item.uppercased()) | |
} | |
``` | |
```swift | |
var filtered = [Int]() | |
for number in numbers { | |
if number > 10 { | |
filtered.append(number) | |
} | |
} | |
``` | |
```swift | |
var sum = 0 | |
for number in numbers { | |
sum += number | |
} | |
``` | |
### 10. Avoid using `[String: Any]`; use `Codable` instead. | |
**Non-triggering examples:** | |
```swift | |
struct MyData: Codable { | |
let name: String | |
let age: Int | |
} | |
``` | |
```swift | |
let jsonData = try? JSONEncoder().encode(myData) | |
``` | |
```swift | |
let myData = try? JSONDecoder().decode(MyData.self, from: jsonData) | |
``` | |
**Triggering examples:** | |
```swift | |
let data: [String: Any] = ["name": "John", "age": 30] | |
``` | |
```swift | |
let jsonData = try? JSONSerialization.data(withJSONObject: data) | |
``` | |
```swift | |
let data = try? JSONSerialization.jsonObject(with: jsonData) | |
``` | |
### 11. Combine nested if-else statements into a single initialization statement. | |
**Non-triggering examples:** | |
```swift | |
self.init( | |
presentation: enabled ? .enabled(importance ?? .irrelevant) : .disabled(importance), | |
auto | |
changedImportance: enabled && importance != nil | |
) | |
``` | |
**Triggering examples:** | |
```swift | |
if enabled { | |
if let importance = importance { | |
self.init(presentation: .enabled(importance), autoChangedImportance: false) | |
} else { | |
self.init(presentation: .enabled(.irrelevant), autoChangedImportance: true) | |
} | |
} else { | |
self.init(presentation: .disabled(importance), autoChangedImportance: false) | |
} | |
``` | |
### 12. Avoid empty files. | |
**Non-triggering examples:** | |
- Any file with content. | |
**Triggering examples:** | |
- Any file that is completely empty. | |
### 13. Inline constants or variables used only once. | |
**Non-triggering examples:** | |
```swift | |
alertViewController.styleCancelAlert( | |
regularContentsModel: RegularContentsView.Model( | |
title: "Are you sure?", | |
message: "If you close this greet, it can't be reopened." | |
), | |
models: UIButton.SimpleModel( | |
title: "Yes close it.", | |
action: { | |
self?.refuseGreetAndClose() | |
} | |
) | |
) | |
``` | |
**Triggering examples:** | |
```swift | |
let contents = RegularContentsView.Model( | |
title: "Are you sure?", | |
message: "If you close this greet, it can't be reopened." | |
) | |
let buttonModel = UIButton.SimpleModel( | |
title: "Yes close it.", | |
action: { | |
self?.refuseGreetAndClose() | |
} | |
) | |
alertViewController.styleCancelAlert( | |
regularContentsModel: contents, | |
models: buttonModel | |
) | |
``` | |
### 14. Inline constants or variables used only once. | |
**Non-triggering examples:** | |
```swift | |
alertViewController.styleCancelAlert( | |
regularContentsModel: RegularContentsView.Model( | |
title: "Are you sure?", | |
message: "If you close this greet, it can't be reopened." | |
), | |
models: UIButton.SimpleModel( | |
title: "Yes close it.", | |
action: { | |
self?.refuseGreetAndClose() | |
} | |
) | |
) | |
``` | |
**Triggering examples:** | |
```swift | |
let contents = RegularContentsView.Model( | |
title: "Are you sure?", | |
message: "If you close this greet, it can't be reopened." | |
) | |
let buttonModel = UIButton.SimpleModel( | |
title: "Yes close it.", | |
action: { | |
self?.refuseGreetAndClose() | |
} | |
) | |
alertViewController.styleCancelAlert( | |
regularContentsModel: contents, | |
models: buttonModel | |
) | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment