Clean Code 规范
Clean Code 是由 Robert C. Martin 提出的编写高质量代码的原则。主要包括以下几点
有意义的命名:
- 命名要准确和清晰,让人一看就知道变量、函数或类的用途。
- 避免使用缩写和难以理解的名称
// 不好的命名
val d: Int = 5
// 好的命名
val daysUntilDeadline: Int = 5
函数要短小精悍:
- 一个函数只做一件事。
- 函数尽量短小,易于理解和测试。
// 不好的例子
fun processUserData(user: User) {
validateUser(user)
saveUserToDatabase(user)
sendWelcomeEmail(user)
}
// 好的例子
fun validateUser(user: User) { /* ... */ }
fun saveUserToDatabase(user: User) { /* ... */ }
fun sendWelcomeEmail(user: User) { /* ... */ }
减少嵌套层次:
- 使用早期返回来减少不必要的嵌套
// 不好的例子
fun isValidUser(user: User): Boolean {
if (user != null) {
if (user.isActive) {
if (user.hasPermission) {
return true
}
}
}
return false
}
// 好的例子
fun isValidUser(user: User?): Boolean {
if (user == null) return false
if (!user.isActive) return false
if (!user.hasPermission) return false
return true
}
注释要有意义:
- 仅在必要时添加注释,代码本身应该是最好的文档。
- 避免无意义的注释。
// 不好的例子
// 这个函数返回用户的年龄
fun getUserAge(user: User): Int {
return user.age
}
// 好的例子
// Only add comments if the code isn't clear enough by itself
安全编码规范
安全编码规范旨在防止常见的安全漏洞,提高代码的安全性。以下是一些关键原则:
-
输入验证:
- 确保所有外部输入都经过验证和清理,防止注入攻击。
fun validateInput(input: String): Boolean {
val pattern = Regex("^[a-zA-Z0-9_]+$")
return input.matches(pattern)
}
避免硬编码敏感信息:
- 不要在代码中硬编码密码、密钥等敏感信息。使用安全的存储机制,如 Android 的
Keystore
。
// 不好的例子
val apiKey = "12345"
// 好的例子
val apiKey = getApiKeyFromSecureStorage()
使用安全的库和算法:
- 使用经过验证的安全库和加密算法,避免自己实现加密算法。
// 不好的例子
fun encrypt(data: String): String {
// custom encryption logic
}
// 好的例子
fun encrypt(data: String): ByteArray {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
return cipher.doFinal(data.toByteArray())
}
避免泄露敏感信息:
- 在日志中避免打印敏感信息,如用户数据、密码等。
// 不好的例子
Log.d("UserData", "Password: $password")
// 好的例子
Log.d("UserData", "Password entered")
最小权限原则:
- 仅授予程序执行其任务所需的最小权限,避免使用不必要的权限。
<!-- 不好的例子 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 好的例子 -->
<uses-permission android:name="android.permission.INTERNET"/>
错误处理:
- 处理所有异常,避免程序崩溃,并给用户友好的提示。
- 不要暴露内部实现细节。
// 不好的例子
fun readFile(filename: String): String {
return File(filename).readText()
}
// 好的例子
fun readFile(filename: String): String {
return try {
File(filename).readText()
} catch (e: IOException) {
Log.e("FileRead", "Error reading file", e)
"Error reading file"
}
}
真实的例子和方案代码
结合 Clean Code 和安全编码规范,以下是一个例子:
示例:用户登录
import android.content.Context
import android.util.Log
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
class LoginManager(context: Context) {
private val keyAlias = "LoginKeyAlias"
private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
private val cipher = Cipher.getInstance("AES/GCM/NoPadding")
private val preferences = context.getSharedPreferences("login_prefs", Context.MODE_PRIVATE)
init {
if (!keyStore.containsAlias(keyAlias)) {
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
keyGenerator.init(KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build())
keyGenerator.generateKey()
}
}
private fun getSecretKey(): SecretKey {
return (keyStore.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry).secretKey
}
fun encrypt(data: String): ByteArray {
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey())
val iv = cipher.iv
val encryptedData = cipher.doFinal(data.toByteArray())
preferences.edit().putString("iv", iv.joinToString(",")).apply()
return encryptedData
}
fun decrypt(encryptedData: ByteArray): String {
val iv = preferences.getString("iv", "")!!.split(",").map { it.toByte() }.toByteArray()
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(), GCMParameterSpec(128, iv))
return String(cipher.doFinal(encryptedData))
}
fun login(username: String, password: String): Boolean {
if (!validateInput(username) || !validateInput(password)) {
Log.e("LoginManager", "Invalid input")
return false
}
val encryptedPassword = encrypt(password)
// 发送用户名和加密后的密码到服务器进行验证
return true
}
private fun validateInput(input: String): Boolean {
val pattern = Regex("^[a-zA-Z0-9_]+$")
return input.matches(pattern)
}
}
在这个例子中,我们创建了一个 LoginManager
类,遵循了 Clean Code 和安全编码规范,包括:
- 使用有意义的命名,如
LoginManager
、encrypt
、decrypt
。 - 函数短小且只做一件事,如
encrypt
和decrypt
。 - 安全处理用户输入,防止注入攻击。
- 使用
Android Keystore
存储和管理加密密钥,确保敏感信息安全。 - 使用日志记录错误信息,但避免泄露敏感信息。