如何提升代码质量,重构并非“万能药”

2023-09-15 19:44:42 浏览数 (1)

随着编程技术的不断进步,编程语言变得越来越高级,功能封装也越来越完善。各种技术都在帮助程序员提高编写代码的效率。通过层层封装,程序员似乎不需要了解技术细节,只需逐行翻译需求内容即可。

许多程序员不了解如何组织代码、提升运行效率以及底层基于的原理是什么,但是他们编写的代码通过了编译、测试,并且在上线运行了一个月而没有出现问题,似乎并没有对他们的实际工作产生明显的负面影响。

尽管有“菜鸟”表达了对代码质量潜在问题的担忧,但这些担忧通常会被用“目前项目进展紧迫,等几个月后项目进度宽松后再进行代码重构”这样的说辞来安抚。

虽然我们不能否认,在某些(极其有限的)场景下,重构是解决问题的一种方法。但是,写了大量代码后,我们会发现,重构往往是程序开发过程中最复杂的任务之一。如果我们花了一个月的时间写了一堆糟糕的代码,那么要重构它可能需要更长的时间,也可能面临更高的风险。

过去我们经历了几次无法忍受的大规模重构。每一次重构之前,我们都会集合组内的专家,进行多次分析会议,暂停组内的需求,然后才开始重构。然而,在重构过程中,我们经常会遇到各种困难,几乎每天都会出现许多意想不到的问题。而且,上线时也几乎一定会出现一些问题。

在进行复杂代码重构时,从技术角度来看,需要执行三项任务:理解原有代码、将原有代码分解、构建新代码。然而,待重构的原有代码通常难以理解;模块之间过度耦合,一举一动可能影响整个系统,难以控制影响范围;原有代码不容易进行测试,无法确保新代码的正确性。

重构后会使效率提升多少?风险会降低多少?这个问题很难回答,因为低质量的代码本身并不能简单地标准化。

与写出质量差的代码不同的是,想写出好代码有很多前提:

✔ 理解要开发的功能需求。

✔ 了解程序的运行原理。

✔ 做出合理的抽象。

✔ 组织复杂的逻辑。

✔ 对自己开发效率的正确估算。

✔ 持续不断的练习。

因此随着技术的进步,终究能否实现快速交付和保证代码质量二者的世纪大和解?

以SoFlu软件机器人近日推出的专注AI生成Java函数的FuncGPT(慧函数)为代表的AI代码生成工具的出现,或许带来了新的希望。作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。同时FuncGPT(慧函数)采用代码编写最佳实践及大规模机器联合训练的方式,致力于通过AIGF(AI-Generated Function)赋能软件开发,为中国软件开发者提供全栈式全流程软件开发的最佳体验,让程序员告别996!

FuncGPT(慧函数)具备以下五大能力:

● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。

● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。

● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。

● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。

● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。

FuncGPT(慧函数)的代码质量如何?我们以一个Java函数实现BigDecimal的表达式运算需求为例,让FuncGPT与代码屎山一决高下。

代码屎山示例

代码语言:javascript复制
@MethodDesc(desc="BigDecimal按公式运算,结果四舍五入取N位小数",params= {
            @ParamDesc(name="scaleLen",desc="结果小数位"),
            @ParamDesc(name="middleScaleLen",desc="中间运算除法小数位(传0默认为6位)"),
            @ParamDesc(name="formualText",desc="计算公式(如:A B/C),如果出现负数请用下划线代替(例:A B*-1写成A B*_1"),
            @ParamDesc(name="varArr",desc="变量名和变量值列表(如:A:90,B:89)"),
    })
    public static BigDecimal bigDecimalFormualCalc(int scaleLen, int middleScaleLen, String formualText, Map<String, Object> varArr) {
        int iMiddleScaleLen=6;
        if(middleScaleLen>0){
            iMiddleScaleLen=middleScaleLen;
        }
        Set<String> keySet = varArr.keySet();
        for (String key : keySet) {
            varArr.put(key, varArr.get(key).toString().replace("-", "_"));
        }

        BigDecimal result=null;
        String formualTextStr=formualText;
        String sFormual="";
        String valueTemp="";
        int iLeftBracketIndex=formualTextStr.lastIndexOf(LEFT);
        int iRightBracketIndex=0;
        if(iLeftBracketIndex>=0){
            while (iLeftBracketIndex>=0){
                iRightBracketIndex=formualTextStr.indexOf(RIGHT,iLeftBracketIndex);
                sFormual=formualTextStr.substring(iLeftBracketIndex,iRightBracketIndex 1);
                sFormual=sFormual.replace(LEFT, REPLACEMENT);
                sFormual=sFormual.replace(RIGHT,REPLACEMENT);
                result= FloatUtils.oneBigDecimalFormualCalc(middleScaleLen,iMiddleScaleLen,sFormual,varArr);
                valueTemp=result.toString().replace("-","_");
                formualTextStr=formualTextStr.replace(LEFT.concat(sFormual).concat(RIGHT),valueTemp);
                iLeftBracketIndex=formualTextStr.lastIndexOf(LEFT);
            }
        }

        result=FloatUtils.oneBigDecimalFormualCalc(scaleLen,iMiddleScaleLen,formualTextStr,varArr);
        return  result;
    }
	
	
	public class FloatUtils {
    private FloatUtils(){}
    public static BigDecimal oneBigDecimalFormualCalc(int scaleLen, int middleScaleLen,
                                                      String oneFormualText, Map<String, Object> varArr) {

        BigDecimal result=null;
        String formualTextStr=oneFormualText;
        String linkStr="";

        Set<String> keySet = varArr.keySet();
        for (String key : keySet) {
            formualTextStr = formualTextStr.replace(key, varArr.get(key).toString());
        }
        char c ;
        List<Character> chars = new ArrayList<>();
        List<String> valueList = new ArrayList<>();
        String oneValue="";
        chars.add(' ');
        chars.add('-');
        chars.add('*');
        chars.add('/');
        boolean isFindedLink=false;
        while (formualTextStr.length()>0) {
            isFindedLink=false;
            for (int i = 0; i < formualTextStr.length(); i  ) {
                c = formualTextStr.charAt(i);
                if (chars.contains(c)) {
                    linkStr = linkStr.concat(String.valueOf(c));
                    oneValue = formualTextStr.substring(0, i);
                    oneValue=oneValue.replace("_","-");
                    formualTextStr = formualTextStr.substring(i 1, formualTextStr.length());
                    valueList.add(oneValue);
                    isFindedLink=true;
                    break;
                }
            }
            if(!isFindedLink){
                formualTextStr=formualTextStr.replace("_","-");
                valueList.add(formualTextStr);
                formualTextStr="";
            }
        }
        BigDecimal[] valueArr=new BigDecimal[valueList.size()];
        for(int i=0;i<valueList.size();i  ){
            valueArr[i]=new BigDecimal(valueList.get(i).toString());
        }

        result= FloatFunction.bigDecimalValueCalc2(scaleLen,middleScaleLen,linkStr,valueArr);
        return  result;
    }


}


@MethodDesc(desc="BigDecimal按值列表运算(中间除法小数位入参控制),结果四舍五入取N位小数",params= {
            @ParamDesc(name="scaleLen",desc="小数位个数"),
            @ParamDesc(name="middleScaleLen",desc="中间运算除法小数位(传0默认为6位)"),
            @ParamDesc(name="linkArr",desc="运算符列表(如:A B/C,则传 /)"),
            @ParamDesc(name="valueArr",desc="String值列表(如:A B/C,则传ABC的3个值)"),})
    public static BigDecimal bigDecimalValueCalc2(int scaleLen, int middleScaleLen,String linkArr,Object[] valueArr) {
        BigDecimal result;
        int iMiddleScaleLen=6;
        if(middleScaleLen>0){
            iMiddleScaleLen=middleScaleLen;
        }
        ArrayList<BigDecimal> valueList=new ArrayList();
        ArrayList linkList=new ArrayList();
        for (int i=0;i<valueArr.length;i  ){
            if (valueArr[i] instanceof BigDecimal){
                valueList.add((BigDecimal)valueArr[i]);
            }else if (valueArr[i] instanceof Double){
                valueList.add(BigDecimal.valueOf((double)valueArr[i]));
            }else if (valueArr[i] instanceof Integer){
                valueList.add(BigDecimal.valueOf((int)valueArr[i]));
            }else {
                valueList.add(new BigDecimal(valueArr[i].toString()));
            }
        }
        for (int i=0;i<linkArr.length();i  ){
            linkList.add(linkArr.charAt(i));
        }
        String linkStr="";
        BigDecimal valueOne=null;
        BigDecimal valueTwo=null;
        int iIndex=0;
        int multiplyDivideIndex=-1;
        BigDecimal tempValue= BigDecimal.ZERO;
        while (linkList.size()>0){
            multiplyDivideIndex=-1;
            for (int i=0;i<linkList.size();i  ) {
                linkStr=linkList.get(i).toString();
                if ("*".equals(linkStr)|| "/".equals(linkStr)) {
                    multiplyDivideIndex = i;
                    break;
                }
            }
            if(multiplyDivideIndex<0) {
                iIndex=0;
            }
            else {
                iIndex=multiplyDivideIndex;
            }
            linkStr=linkList.get(iIndex).toString();
            valueOne=valueList.get(iIndex);
            valueTwo=valueList.get(iIndex 1);
            switch (linkStr) {
                case " ":
                    tempValue=valueOne.add(valueTwo);
                    break;
                case "-":
                    tempValue=valueOne.subtract(valueTwo);
                    break;
                case "*":
                    tempValue=valueOne.multiply(valueTwo);
                    break;
                case "/":
                    tempValue=valueOne.divide(valueTwo,iMiddleScaleLen,BigDecimal.ROUND_HALF_UP);
                    break;
                default:
                    break;
            }
            valueList.remove(iIndex);
            valueList.remove(iIndex);
            valueList.add(iIndex,tempValue);
            linkList.remove(iIndex);
        }
        if (scaleLen<0){
            result=valueList.get(0);
        } else {
            result=valueList.get(0).setScale(scaleLen,BigDecimal.ROUND_HALF_UP);
        }
        return  result;
    }

FuncGPT(慧函数)

代码语言:javascript复制
// 类名:BigDecimalCalculator
// 函数名:calculateExpression
// 函数功能:使用BigDecimal计算表达式的结果
// POM依赖包:
// <dependency>
//     <groupId>org.apache.commons</groupId>
//     <artifactId>commons-lang3</artifactId>
//     <version>3.12.0</version>
// </dependency>

import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Stack;

public class BigDecimalCalculator {
    /**
     * 使用BigDecimal计算表达式的结果
     * @param expression 要计算的表达式
     * @return 计算结果
     */
    public static BigDecimal calculateExpression(String expression) {
        if (StringUtils.isBlank(expression)) {
            throw new IllegalArgumentException("Expression cannot be blank");
        }

        Stack<BigDecimal> numberStack = new Stack<>();
        Stack<Character> operatorStack = new Stack<>();

        for (int i = 0; i < expression.length(); i  ) {
            char ch = expression.charAt(i);
            if (Character.isDigit(ch)) {
                StringBuilder sb = new StringBuilder();
                while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
                    sb.append(expression.charAt(i));
                    i  ;
                }
                i--;

                BigDecimal number = new BigDecimal(sb.toString());
                numberStack.push(number);
            } else if (ch == '(') {
                operatorStack.push(ch);
            } else if (ch == ')') {
                while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
                    BigDecimal result = performOperation(numberStack, operatorStack);
                    numberStack.push(result);
                }
                if (!operatorStack.isEmpty() && operatorStack.peek() == '(') {
                    operatorStack.pop();
                }
            } else if (isOperator(ch)) {
                while (!operatorStack.isEmpty() && hasHigherPrecedence(ch, operatorStack.peek())) {
                    BigDecimal result = performOperation(numberStack, operatorStack);
                    numberStack.push(result);
                }
                operatorStack.push(ch);
            }
        }

        while (!operatorStack.isEmpty()) {
            BigDecimal result = performOperation(numberStack, operatorStack);
            numberStack.push(result);
        }

        return numberStack.pop();
    }

    private static boolean isOperator(char ch) {
        return ch == ' ' || ch == '-' || ch == '*' || ch == '/';
    }

    private static boolean hasHigherPrecedence(char op1, char op2) {
        if ((op1 == '*' || op1 == '/') && (op2 == ' ' || op2 == '-')) {
            return true;
        }
        return false;
    }

    private static BigDecimal performOperation(Stack<BigDecimal> numberStack, Stack<Character> operatorStack) {
        BigDecimal num2 = numberStack.pop();
        BigDecimal num1 = numberStack.pop();
        char operator = operatorStack.pop();

        BigDecimal result;
        switch (operator) {
            case ' ':
                result = num1.add(num2);
                break;
            case '-':
                result = num1.subtract(num2);
                break;
            case '*':
                result = num1.multiply(num2);
                break;
            case '/':
                result = num1.divide(num2, 2, RoundingMode.HALF_UP);
                break;
            default:
                throw new IllegalArgumentException("Invalid operator");
        }

        return result;
    }
}

// 函数示例
// 使用BigDecimal计算表达式的结果示例
// 入参:expression,要计算的表达式
// 出参:result,计算结果
// 调用示例:
// String expression = "2.5   3 * (4 - 1)";
// BigDecimal result = BigDecimalCalculator.calculateExpression(expression);
// System.out.println(result);
// 输出结果:例如,计算表达式"2.5   3 * (4 - 1)"的结果为:11.5
// 则输出结果为:11.5

经过对比分析,不难发现:

可读性上:

人工代码命名存在截断和不规范,注释不够简洁清晰,代码可读性差;

FuncGPT使用了合理的命名和注释,函数和变量的命名清晰明了,注释对函数的功能和参数进行了说明,提高了代码的可读性。

可维护性上:

人工代码代码层层嵌套,方法繁琐,不利于后期维护修改;

FuncGPT使用了合适的数据结构和算法。它使用两个栈来处理运算符和操作数,通过遍历表达式字符并根据优先级进行计算,避免了复杂的嵌套逻辑和多重判断。

安全性上:

人工代码没有判断空值,存在漏洞,健壮性差;

FuncGPT引入了Apache Commons Lang库,利用StringUtils类的isBlank方法判断表达式是否为空,提高了代码的健壮性和可靠性。

综上,FuncGPT(慧函数)生成的代码具有更好的可读性、可维护性和异常处理,并且使用了逆波兰表达式计算和第三方库来提供更强大的功能。

FuncGPT(慧函数)免费使用,链接https://c.suo.nz/74U0Y

0 人点赞