# 代码质量最佳实践

代码质量是Android应用开发的核心要素，直接影响应用的稳定性、可维护性和团队协作效率。本文档介绍Android开发中的代码质量最佳实践。

## 目录

- [代码规范](#代码规范)
- [代码审查](#代码审查)
- [代码重构](#代码重构)
- [代码测试](#代码测试)
- [文档编写](#文档编写)

---

## 代码规范

### 命名规范

#### 类命名

```java
// ✅ 好的命名：清晰、有意义、遵循Android约定
public class MainActivity extends AppCompatActivity { }
public class UserRepository { }
public class LoginViewModel extends ViewModel { }
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> { }

// ❌ 不好的命名：模糊、无意义、不符合规范
public class Activity1 { }
public class Manager { }
public class Repo { }
public class Adapter1 { }
```

**Android命名约定：**
- Activity：以`Activity`结尾，如`LoginActivity`
- Fragment：以`Fragment`结尾，如`UserListFragment`
- Service：以`Service`结尾，如`DownloadService`
- ViewModel：以`ViewModel`结尾，如`UserViewModel`
- Repository：以`Repository`结尾，如`UserRepository`
- Adapter：以`Adapter`结尾，如`UserAdapter`

#### 方法命名

```java
// ✅ 好的命名：动词开头，清晰表达意图
public void loadUserData() { }
public boolean isValidEmail(String email) { }
public User getUserById(String id) { }
public void showErrorMessage(String message) { }

// ❌ 不好的命名：模糊、无意义
public void load() { }
public boolean check(String str) { }
public User get(String id) { }
public void show(String msg) { }
```

#### 变量命名

```java
// ✅ 好的命名：清晰、有意义、遵循驼峰命名
private String userName;
private int userCount;
private List<User> userList;
private boolean isLoggedIn;
private static final String TAG = "MainActivity";
private static final int REQUEST_CODE_LOGIN = 1001;

// ❌ 不好的命名：缩写、无意义、不符合规范
private String un;
private int uc;
private List<User> ul;
private boolean logged; // 布尔值应使用is/has/can前缀
```

#### 资源命名

```xml
<!-- ✅ 好的命名：使用下划线，清晰表达用途 -->
<TextView
    android:id="@+id/tv_user_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<Button
    android:id="@+id/btn_login"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<!-- ❌ 不好的命名：无意义、不符合规范 -->
<TextView
    android:id="@+id/text1" />
<Button
    android:id="@+id/button1" />
```

**资源命名约定：**
- Layout：`activity_xxx.xml`、`fragment_xxx.xml`、`item_xxx.xml`
- ID：`tv_xxx`（TextView）、`btn_xxx`（Button）、`iv_xxx`（ImageView）
- String：`app_name`、`login_title`、`error_message`
- Color：`color_primary`、`color_text_primary`
- Dimension：`sp_12`、`dp_16`

### 代码格式

#### 缩进和空格

```java
// ✅ 好的格式：统一缩进（4个空格），适当空格
public class UserManager {
    private String userName;
    private UserRepository repository;
    
    public UserManager(UserRepository repository) {
        this.repository = repository;
    }
    
    public void setUserName(String name) {
        if (name != null && !name.isEmpty()) {
            this.userName = name;
        }
    }
}

// ❌ 不好的格式：缩进不一致，空格混乱
public class UserManager{
private String userName;
public void setUserName(String name){
if(name!=null){
this.userName=name;
}
}
}
```

#### 代码组织

```java
// ✅ 好的组织：按逻辑分组，清晰的结构
public class MainActivity extends AppCompatActivity {
    // 1. 常量
    private static final String TAG = "MainActivity";
    private static final int REQUEST_CODE = 1001;
    
    // 2. 成员变量
    private TextView tvUserName;
    private Button btnLogin;
    private UserViewModel viewModel;
    
    // 3. 生命周期方法
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        initViewModel();
        observeData();
    }
    
    // 4. 初始化方法
    private void initViews() { }
    private void initViewModel() { }
    private void observeData() { }
    
    // 5. 业务方法
    private void handleLogin() { }
    private void showError(String message) { }
}
```

#### 注释规范

```java
// ✅ 好的注释：清晰、有用、及时更新
/**
 * 获取用户信息
 * 
 * @param userId 用户ID，不能为空
 * @return 用户信息，如果用户不存在返回null
 * @throws IllegalArgumentException 如果userId为空或无效
 */
public User getUserInfo(String userId) {
    if (userId == null || userId.isEmpty()) {
        throw new IllegalArgumentException("userId cannot be null or empty");
    }
    // 从数据库查询用户信息
    return userRepository.getUserById(userId);
}

// 复杂逻辑需要注释说明
private void calculatePrice() {
    // 计算基础价格
    double basePrice = getBasePrice();
    
    // 应用折扣（如果满足条件）
    if (isEligibleForDiscount()) {
        basePrice *= DISCOUNT_RATE;
    }
    
    // 添加税费
    double finalPrice = basePrice * (1 + TAX_RATE);
    this.price = finalPrice;
}

// ❌ 不好的注释：无用、冗余、过时
// 获取用户信息
public User getUserInfo(String userId) {
    // 获取用户信息
    return userRepository.getUserById(userId);
}
```

### 代码规范工具

#### Android Lint

```gradle
// build.gradle
android {
    lintOptions {
        // 检查所有问题
        checkAllWarnings true
        // 将警告视为错误
        warningsAsErrors true
        // 生成HTML报告
        htmlReport true
        htmlOutput file("$project.buildDir/reports/lint/lint-results.html")
    }
}

// 运行Lint检查
// ./gradlew lint
```

#### Checkstyle

```gradle
// build.gradle
plugins {
    id 'checkstyle'
}

checkstyle {
    toolVersion = '10.3.4'
    configFile = file("checkstyle.xml")
    ignoreFailures = false
}

// checkstyle.xml配置示例
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
    "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
    "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
    <module name="TreeWalker">
        <module name="MethodName"/>
        <module name="ConstantName"/>
        <module name="LocalVariableName"/>
    </module>
</module>
```

#### Ktlint（Kotlin代码规范）

```gradle
// build.gradle.kts
plugins {
    id("org.jlleitschuh.gradle.ktlint") version "11.0.0"
}

ktlint {
    version.set("0.48.2")
    debug.set(true)
    verbose.set(true)
    android.set(true)
}

// 运行Ktlint检查
// ./gradlew ktlintCheck
```

---

## 代码审查

### 代码审查流程

```java
// 1. 创建功能分支
git checkout -b feature/user-login
git add .
git commit -m "feat: 添加用户登录功能"

// 2. 推送分支
git push origin feature/user-login

// 3. 创建Pull Request/Merge Request
// - 填写清晰的PR描述
// - 添加相关Issue链接
// - 添加审查者
// - 添加标签

// 4. 代码审查
// - 审查者检查代码
// - 提出修改建议
// - 讨论技术方案

// 5. 修改代码
// - 根据审查意见修改
// - 重新提交代码
// - 更新PR

// 6. 合并代码
// - 审查通过后合并
// - 删除功能分支
```

### 代码审查清单

#### 1. 代码质量

```java
// ✅ 好的代码：清晰、简洁、易读
public User getUserById(String userId) {
    if (userId == null || userId.isEmpty()) {
        return null;
    }
    return userRepository.getUserById(userId);
}

// ❌ 不好的代码：复杂、难以理解
public User getUserById(String userId) {
    if (userId != null) {
        if (!userId.isEmpty()) {
            User user = userRepository.getUserById(userId);
            if (user != null) {
                return user;
            } else {
                return null;
            }
        } else {
            return null;
        }
    } else {
        return null;
    }
}
```

**检查要点：**
- 代码是否清晰易读？
- 是否有重复代码？
- 方法是否过长（建议不超过50行）？
- 是否有深层嵌套（建议不超过3层）？

#### 2. 性能问题

```java
// ✅ 好的代码：性能优化
// 使用StringBuilder拼接字符串
StringBuilder sb = new StringBuilder();
for (String item : items) {
    sb.append(item);
}
String result = sb.toString();

// 使用增强for循环
for (User user : users) {
    processUser(user);
}

// ❌ 不好的代码：性能问题
// 字符串拼接性能差
String result = "";
for (String item : items) {
    result += item; // 每次拼接都创建新对象
}

// 不必要的循环
for (int i = 0; i < users.size(); i++) {
    User user = users.get(i);
    processUser(user);
}
```

**检查要点：**
- 是否有性能瓶颈？
- 是否有内存泄漏风险？
- 是否有不必要的对象创建？
- 是否有低效的算法？

#### 3. 安全问题

```java
// ✅ 好的代码：安全处理
// 验证输入
if (password != null && password.length() >= 8) {
    // 处理密码
    String hashedPassword = hashPassword(password);
}

// 使用HTTPS
OkHttpClient client = new OkHttpClient.Builder()
    .certificatePinner(CertificatePinner.DEFAULT)
    .build();

// ❌ 不好的代码：安全问题
// 未验证输入
if (password.length() >= 8) { // 可能NullPointerException
    // 处理密码
}

// 硬编码敏感信息
String apiKey = "sk-1234567890abcdef"; // 不应该硬编码
```

**检查要点：**
- 是否有安全漏洞？
- 是否验证了用户输入？
- 是否保护了敏感数据？
- 是否使用了安全的网络通信？

#### 4. 可维护性

```java
// ✅ 好的代码：易于维护
// 使用常量
private static final int MIN_PASSWORD_LENGTH = 8;
private static final String ERROR_MESSAGE = "密码长度至少8位";

if (password.length() < MIN_PASSWORD_LENGTH) {
    showError(ERROR_MESSAGE);
    return;
}

// 提取方法
private void validatePassword(String password) {
    if (password == null || password.isEmpty()) {
        throw new IllegalArgumentException("密码不能为空");
    }
    if (password.length() < MIN_PASSWORD_LENGTH) {
        throw new IllegalArgumentException(ERROR_MESSAGE);
    }
}

// ❌ 不好的代码：难以维护
// 魔法数字
if (password.length() < 8) {
    showError("密码长度至少8位");
    return;
}

// 重复代码
if (password1.length() < 8) {
    showError("密码长度至少8位");
}
if (password2.length() < 8) {
    showError("密码长度至少8位");
}
```

**检查要点：**
- 代码是否易于理解和修改？
- 是否有重复代码？
- 是否使用了合适的抽象？
- 是否遵循了SOLID原则？

### 代码审查工具

#### GitHub Pull Request

```markdown
## PR模板示例

### 变更描述
- 添加用户登录功能
- 实现记住密码功能

### 测试说明
- [x] 单元测试通过
- [x] UI测试通过
- [x] 手动测试通过

### 截图
[添加相关截图]

### 相关Issue
Closes #123
```

#### Gerrit

```bash
# 提交代码审查
git push origin HEAD:refs/for/master

# 查看审查意见
# 在Gerrit Web界面查看

# 修改代码后重新提交
git commit --amend
git push origin HEAD:refs/for/master
```

---

## 代码重构

### 重构原则

#### 1. 小步重构

```java
// ✅ 好的重构：小步进行，每次只改一点
// 第一步：提取方法
public void processOrder(Order order) {
    validateOrder(order);
    calculatePrice(order);
    saveOrder(order);
}

// 第二步：提取类
public class OrderProcessor {
    public void process(Order order) {
        validateOrder(order);
        calculatePrice(order);
        saveOrder(order);
    }
}

// ❌ 不好的重构：一次性大改
// 一次性重构整个模块，风险大，难以测试
```

#### 2. 保持测试通过

```java
// ✅ 好的重构：先写测试，再重构
@Test
public void testProcessOrder() {
    Order order = new Order();
    OrderProcessor processor = new OrderProcessor();
    processor.process(order);
    assertNotNull(order.getId());
}

// 重构时保持测试通过
public class OrderProcessor {
    public void process(Order order) {
        // 重构代码，但保持行为不变
    }
}
```

#### 3. 识别代码坏味道

```java
// 1. 长方法（Long Method）
// ❌ 坏味道：方法过长
public void processUserData() {
    // 100行代码...
}

// ✅ 重构：拆分为多个小方法
public void processUserData() {
    validateUserData();
    transformUserData();
    saveUserData();
}

// 2. 重复代码（Duplicated Code）
// ❌ 坏味道：重复代码
public void processUser1() {
    if (user1 != null) {
        user1.setStatus("active");
        saveUser(user1);
    }
}
public void processUser2() {
    if (user2 != null) {
        user2.setStatus("active");
        saveUser(user2);
    }
}

// ✅ 重构：提取公共方法
public void processUser(User user) {
    if (user != null) {
        user.setStatus("active");
        saveUser(user);
    }
}

// 3. 大类（Large Class）
// ❌ 坏味道：类职责过多
public class UserManager {
    // 用户管理
    // 订单管理
    // 支付管理
    // ...
}

// ✅ 重构：拆分职责
public class UserManager { }
public class OrderManager { }
public class PaymentManager { }
```

### 常见重构技巧

#### 1. 提取方法（Extract Method）

```java
// 重构前
public void printUserInfo(User user) {
    System.out.println("Name: " + user.getName());
    System.out.println("Email: " + user.getEmail());
    System.out.println("Age: " + user.getAge());
}

// 重构后
public void printUserInfo(User user) {
    printName(user);
    printEmail(user);
    printAge(user);
}

private void printName(User user) {
    System.out.println("Name: " + user.getName());
}

private void printEmail(User user) {
    System.out.println("Email: " + user.getEmail());
}

private void printAge(User user) {
    System.out.println("Age: " + user.getAge());
}
```

#### 2. 提取类（Extract Class）

```java
// 重构前
public class User {
    private String name;
    private String email;
    private String street;
    private String city;
    private String zipCode;
}

// 重构后
public class User {
    private String name;
    private String email;
    private Address address;
}

public class Address {
    private String street;
    private String city;
    private String zipCode;
}
```

#### 3. 引入参数对象（Introduce Parameter Object）

```java
// 重构前
public void createUser(String name, String email, String phone, String address) {
    // ...
}

// 重构后
public void createUser(UserInfo userInfo) {
    // ...
}

public class UserInfo {
    private String name;
    private String email;
    private String phone;
    private String address;
}
```

### 重构工具

#### Android Studio重构功能

```java
// 右键菜单 -> Refactor
// - Rename：重命名
// - Extract Method：提取方法
// - Extract Variable：提取变量
// - Extract Field：提取字段
// - Extract Interface：提取接口
// - Extract Superclass：提取父类
// - Inline：内联
// - Move：移动
// - Safe Delete：安全删除
```

---

## 代码测试

### 测试金字塔

```
        /\
       /  \
      /集成测试\
     /----------\
    /  单元测试   \
   /--------------\
```

- **单元测试**（70%）：快速、隔离、覆盖核心逻辑
- **集成测试**（20%）：测试组件间交互
- **UI测试**（10%）：测试用户界面

### 单元测试

#### JUnit测试

```java
// UserRepositoryTest.java
@RunWith(MockitoJUnitRunner.class)
public class UserRepositoryTest {
    
    @Mock
    private UserDao userDao;
    
    @InjectMocks
    private UserRepository repository;
    
    @Test
    public void getUserById_shouldReturnUser_whenUserExists() {
        // Given
        String userId = "123";
        User expectedUser = new User(userId, "John");
        when(userDao.getUserById(userId)).thenReturn(expectedUser);
        
        // When
        User result = repository.getUserById(userId);
        
        // Then
        assertNotNull(result);
        assertEquals("John", result.getName());
        verify(userDao).getUserById(userId);
    }
    
    @Test
    public void getUserById_shouldReturnNull_whenUserNotExists() {
        // Given
        String userId = "999";
        when(userDao.getUserById(userId)).thenReturn(null);
        
        // When
        User result = repository.getUserById(userId);
        
        // Then
        assertNull(result);
    }
}
```

#### Mockito使用

```java
// Mock对象
@Mock
private UserService userService;

// Stub方法
when(userService.getUser("123")).thenReturn(new User("123", "John"));

// 验证调用
verify(userService).getUser("123");
verify(userService, times(2)).getUser("123");
verify(userService, never()).deleteUser("123");

// 参数匹配
verify(userService).getUser(anyString());
verify(userService).getUser(eq("123"));
```

### UI测试

#### Espresso测试

```java
@RunWith(AndroidJUnit4.class)
public class LoginActivityTest {
    
    @Rule
    public ActivityScenarioRule<LoginActivity> activityRule =
        new ActivityScenarioRule<>(LoginActivity.class);
    
    @Test
    public void testLogin_success() {
        // 输入用户名
        onView(withId(R.id.et_username))
            .perform(typeText("testuser"));
        
        // 输入密码
        onView(withId(R.id.et_password))
            .perform(typeText("password123"));
        
        // 点击登录按钮
        onView(withId(R.id.btn_login))
            .perform(click());
        
        // 验证跳转到主页面
        intended(hasComponent(MainActivity.class.getName()));
    }
    
    @Test
    public void testLogin_failure() {
        // 输入错误的用户名和密码
        onView(withId(R.id.et_username))
            .perform(typeText("wronguser"));
        onView(withId(R.id.et_password))
            .perform(typeText("wrongpass"));
        
        // 点击登录按钮
        onView(withId(R.id.btn_login))
            .perform(click());
        
        // 验证显示错误消息
        onView(withId(R.id.tv_error))
            .check(matches(isDisplayed()));
    }
}
```

### 测试覆盖率

```gradle
// build.gradle
android {
    buildTypes {
        debug {
            testCoverageEnabled = true
        }
    }
}

// 生成测试覆盖率报告
// ./gradlew createDebugCoverageReport
// 报告位置：build/reports/coverage/debug/index.html
```

### 测试最佳实践

```java
// ✅ 好的测试：清晰、独立、快速
@Test
public void calculateTotalPrice_shouldReturnCorrectSum() {
    // Arrange
    List<Item> items = Arrays.asList(
        new Item("A", 10.0),
        new Item("B", 20.0)
    );
    PriceCalculator calculator = new PriceCalculator();
    
    // Act
    double total = calculator.calculateTotal(items);
    
    // Assert
    assertEquals(30.0, total, 0.01);
}

// ❌ 不好的测试：依赖外部、慢、不清晰
@Test
public void test() {
    // 测试代码混乱，依赖网络、数据库等
}
```

---

## 文档编写

### 代码文档

#### JavaDoc注释

```java
/**
 * 用户管理类，提供用户的增删改查功能
 * 
 * <p>使用示例：
 * <pre>{@code
 * UserManager manager = new UserManager();
 * User user = manager.getUserById("123");
 * }</pre>
 * 
 * @author John Doe
 * @version 1.0
 * @since 1.0
 */
public class UserManager {
    
    /**
     * 根据用户ID获取用户信息
     * 
     * @param userId 用户ID，不能为空
     * @return 用户信息，如果用户不存在返回null
     * @throws IllegalArgumentException 如果userId为空
     * @see User
     */
    public User getUserById(String userId) {
        if (userId == null || userId.isEmpty()) {
            throw new IllegalArgumentException("userId cannot be null or empty");
        }
        return userRepository.getUserById(userId);
    }
}
```

#### README文档

```markdown
# 项目名称

项目简要描述

## 功能特性

- 功能1
- 功能2
- 功能3

## 快速开始

### 环境要求

- Android Studio Arctic Fox+
- JDK 8+
- Android SDK API 21+

### 安装步骤

1. 克隆项目
```bash
git clone https://github.com/example/project.git
```

2. 打开项目
```bash
cd project
./gradlew build
```

3. 运行项目

## 项目结构

```
app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   ├── res/
│   │   └── AndroidManifest.xml
│   └── test/
└── build.gradle
```

## API文档

[API文档链接]

## 贡献指南

[贡献指南内容]

## 许可证

[许可证信息]
```

### 技术文档

#### 架构文档

```markdown
# 应用架构文档

## 架构概览

应用采用MVVM架构模式

## 模块划分

### 1. UI层
- Activity/Fragment
- ViewModel
- Adapter

### 2. 业务层
- UseCase
- Repository

### 3. 数据层
- DataSource
- API Service
- Database

## 数据流

[数据流图]

## 技术选型

- 架构：MVVM
- 依赖注入：Dagger/Hilt
- 网络：Retrofit + OkHttp
- 数据库：Room
```

#### API文档

```markdown
# API文档

## 用户相关API

### 获取用户信息

**请求**
```
GET /api/user/{userId}
```

**响应**
```json
{
  "id": "123",
  "name": "John Doe",
  "email": "john@example.com"
}
```

### 更新用户信息

**请求**
```
PUT /api/user/{userId}
Content-Type: application/json

{
  "name": "Jane Doe",
  "email": "jane@example.com"
}
```
```

### 文档维护

```markdown
## 文档维护清单

- [ ] 代码变更时更新相关文档
- [ ] 定期检查文档准确性
- [ ] 保持文档与代码同步
- [ ] 添加必要的示例代码
- [ ] 更新版本号和日期
```

---

## 总结

代码质量是Android应用开发的核心要素。通过遵循代码规范、进行代码审查、定期重构、编写测试和完善文档，可以显著提升代码质量和团队协作效率。

### 关键要点

1. **代码规范**：统一的命名、格式和注释规范
2. **代码审查**：建立审查流程，关注质量、性能和安全
3. **代码重构**：小步重构，保持测试通过
4. **代码测试**：编写单元测试和UI测试，提高覆盖率
5. **文档编写**：完善代码文档和技术文档

### 相关资源

- [Android代码规范指南](https://developer.android.com/kotlin/style-guide)
- [Android测试指南](https://developer.android.com/training/testing)
- [Android架构指南](https://developer.android.com/topic/architecture)

---

*最后更新：2024年*
