对于软件开发管理来说,制订编码规范是一个历久弥新的话题。每一个大有为开发头目,都强调编码规范。或者程序员也互相攻讦(jie,第二声,阳平),说你写的代码很乱,不规范,很难看懂,很难维护。总之别人写的都不行,自己写的才是好的。

那么,怎么才算编码规范?按照我的经历,大家说编码规范,一般都是聚焦于命名规则,注释。命名现在可能普遍没啥问题了,驼峰命名,英文(而不是拼音缩写);注释,刚开始就一本正经地写上作者,创建时间,更新时间。其实时间一长,经手的人多了,就形同虚设,鸡肋得很。其实,在哪里注释、注释针对对象,注释内容比注释格式要重要得多。

下面我总结一下我自己认为的,编码规范需要注意的地方。

一、注释

1、要有个代码文件说明

项目级有个项目说明;如果项目内有多个子系统,每个子系统也要有个子系统说明。这不是写在代码里面,而是放在项目外面,严格来说不算注释,但这个说明真的很重要。如果是交接工作,后来者接手,或者隔了很长时间以后,自己看到,可以大致知道这份代码是做什么的。

编码规范之注释、条件语句中限制代码行数和避免硬编码_sed

2、代码文件注释

在文件头部,简要说明本文件的作用。

编码规范之注释、条件语句中限制代码行数和避免硬编码_代码可读性_02


编码规范之注释、条件语句中限制代码行数和避免硬编码_User_03

3、重要方法注释

对于一些重要的方法,说明一下

编码规范之注释、条件语句中限制代码行数和避免硬编码_User_04

4、重要或难懂的处理逻辑的注释

编码规范之注释、条件语句中限制代码行数和避免硬编码_User_05

5、小结

注释不是越多越好,太多容易分神。如果注释跟代码不同步,比如复制粘贴,或者代码改了,注释没改,甚至起反作用。只有重要、难懂的地方才需要写注释。

二、条件语句中的代码行数

每个条件判断,处理的代码行数非常多,需要不停地上下滚屏,甚至滚屏滚到手酸,才能看到 else 或结束符。然后想看看开头吧,好于是又一轮滚屏开始了。这样很难从总体上对这个条件判断进行理解。我今年接手的项目,很多这样的情况,简直是噩梦。一时找不到这些代码了,下面这个例子是AI给的,不算最夸张,只是嵌套多一点而已。

public void processUser(User user) {
    if (user != null) {
        if (user.getRole() != null && user.getRole().equals("ADMIN")) {
            if (user.getAge() > 18) {
                if (user.getStatus() != null && user.getStatus().equals("ACTIVE")) {
                    // 处理活跃管理员逻辑,包含大量冗长业务逻辑
                    log("Processing admin user...");
                    
                    performAdminTask1(user);
                    performAdminTask2(user);
                    performAdminTask3(user);

                    // 大量的日志记录和数据处理逻辑
                    for (int i = 0; i < 100; i++) {
                        log("Processing batch task: " + i);
                        performBatchOperation(user, i);
                    }

                    // 更加夸张的文件处理操作
                    for (File file : getAdminFiles(user)) {
                        try {
                            readAndProcessFile(file);
                            log("File processed: " + file.getName());
                            updateFileStatus(file);
                            archiveProcessedFile(file);
                            validateFileIntegrity(file);
                            synchronizeFileWithDatabase(file);
                        } catch (Exception e) {
                            log("Error processing file: " + file.getName() + " - " + e.getMessage());
                        }
                    }

                    // 各种同步任务
                    for (int i = 0; i < 50; i++) {
                        syncTaskWithServer(user, i);
                        log("Sync task with server " + i + " completed.");
                    }

                    // 模拟数据同步和备份逻辑
                    backupAdminData(user);
                    syncAdminDataAcrossServers(user);
                    log("Admin data backup and sync completed.");
                    
                    // 大量的系统调用和日志记录
                    for (int i = 0; i < 200; i++) {
                        systemCallOperation(user, i);
                        log("System call " + i + " executed.");
                    }

                    // 结束逻辑
                    updateLoginRecord(user);
                    log("Finished processing admin user: " + user.getUsername());

                } else {
                    // 处理非活跃管理员
                    log("Admin user is not active. Running inactive admin process...");
                    performInactiveAdminTask1(user);
                    performInactiveAdminTask2(user);
                    sendNotification(user, "Your admin account is not active.");

                    // 更加夸张的日志和数据库清理操作
                    for (int i = 0; i < 1000; i++) {
                        log("Cleaning up inactive admin record " + i);
                        performDatabaseCleanup(user, i);
                    }

                    // 文件操作和数据恢复
                    for (File file : getInactiveAdminFiles(user)) {
                        restoreFileFromBackup(file);
                        validateFileAfterRestore(file);
                        log("Restored and validated file: " + file.getName());
                    }

                    log("Inactive admin cleanup and restoration complete for user: " + user.getUsername());
                }
            } else {
                // 处理未成年人管理员
                log("Admin user is underage. Starting verification process...");
                sendVerificationEmail(user);
                log("Verification email sent.");

                // 冗长的家庭联系操作
                for (int i = 0; i < 10; i++) {
                    updateParentContact(user, i);
                    log("Updated parental contact for underage admin: " + i);
                    generateParentalConsentDocument(user, i);
                    sendParentalConsentRequest(user);
                    log("Parental consent request sent for attempt: " + i);
                }

                // 模拟更多的业务逻辑
                for (int i = 0; i < 50; i++) {
                    performUnderageAdminTask(user, i);
                    log("Underage admin task " + i + " completed.");
                }

                // 最后的日志记录
                log("Underage admin process complete for user: " + user.getUsername());
            }
        } else if (user.getRole() != null && user.getRole().equals("USER")) {
            if (user.getAccountStatus() != null && user.getAccountStatus().equals("ACTIVE")) {
                // 处理普通用户,添加更多的冗长处理逻辑
                log("Processing active user...");
                sendDiscountOffer(user);
                sendPromotionalEmails(user);

                // 模拟复杂的业务操作
                for (int i = 0; i < 500; i++) {
                    performUserActivityLogging(user, i);
                    performUserPreferencesUpdate(user, i);
                    generateUserReport(user, i);
                    log("Processed user activity for batch: " + i);
                }

                // 文件操作
                for (File file : getUserActivityFiles(user)) {
                    processUserActivityFile(file);
                    log("Processed activity file: " + file.getName());
                    archiveUserFile(file);
                    synchronizeUserFileWithCloud(file);
                    validateUserFile(file);
                }

                log("Finished processing active user: " + user.getUsername());

            } else {
                // 处理非活动用户
                log("Inactive user detected. Processing account cleanup...");
                
                for (int i = 0; i < 300; i++) {
                    performAccountDeactivation(user, i);
                    log("Deactivated user account batch: " + i);
                }

                // 数据删除操作
                for (int i = 0; i < 100; i++) {
                    deleteUserData(user, i);
                    log("User data batch " + i + " deleted.");
                }

                log("Inactive user cleanup complete for user: " + user.getUsername());
            }
        } else {
            // 未知角色用户的处理
            log("Unrecognized user role. Handling unknown user...");
            
            for (int i = 0; i < 50; i++) {
                performUnknownRoleTask(user, i);
                log("Processed unknown role task " + i);
            }

            // 结束未知角色处理
            log("Finished processing user with unrecognized role: " + user.getUsername());
        }
    } else {
        // 用户为空的处理逻辑
        log("User object is null. Skipping processing...");
        
        for (int i = 0; i < 10; i++) {
            handleNullUserRecord(i);
            log("Handled null user record " + i);
        }

        // 日志记录
        log("Null user handling completed.");
    }
}

对应这种情况,可以使用函数,将每个条件判断的处理逻辑,放到函数里。一般我们写一个函数,最大的作用是复用;但为了可读性,就算不需要复用,也可以写成函数。比如我将之前的一些代码改写成这样:

编码规范之注释、条件语句中限制代码行数和避免硬编码_i++_06


这样利于从整体上观察处理逻辑。

三、避免硬编码

硬编码就是将一些写死到代码里,后期很难修改。常见的如:

1、将地址写到代码里

编码规范之注释、条件语句中限制代码行数和避免硬编码_代码可读性_07

解决之道是将地址写到配置文件里

2、使用数字作为条件判断的依据

比如 if(type === 1) 之类,大家一定不会陌生,可读性很差,尤其是对接手的人,或者时间久远的项目。解决办法众所周知,后台可以用枚举,前端也可以定义常量来代替。如

// 定义常量
const MAX_LOGIN_ATTEMPTS = 5;
const USER_ROLE_ADMIN = 1;
const USER_ROLE_EDITOR = 2;
const USER_ROLE_VIEWER = 3;
const PASSWORD_MIN_LENGTH = 8;

// 函数用于检查用户登录尝试
function checkLoginAttempts(attempts) {
    if (attempts > MAX_LOGIN_ATTEMPTS) {
        console.log("Too many login attempts. Please try again later.");
    } else {
        console.log("Login attempt successful.");
    }
}

// 函数用于用户权限检查
function checkUserRole(role) {
    switch (role) {
        case USER_ROLE_ADMIN:
            console.log("User has admin privileges.");
            break;
        case USER_ROLE_EDITOR:
            console.log("User has editor privileges.");
            break;
        case USER_ROLE_VIEWER:
            console.log("User has viewer privileges.");
            break;
        default:
            console.log("Unknown user role.");
            break;
    }
}

// 函数用于验证密码长度
function validatePassword(password) {
    if (password.length < PASSWORD_MIN_LENGTH) {
        console.log(`Password must be at least ${PASSWORD_MIN_LENGTH} characters long.`);
    } else {
        console.log("Password is valid.");
    }
}

// 示例调用
checkLoginAttempts(6);
checkUserRole(2);
validatePassword("short");