代码实例说明:关于建立“代码管理监控机制”的思路

举报
yd_234468518 发表于 2026/02/27 16:30:03 2026/02/27
【摘要】 代码实例说明:关于建立“代码管理监控机制”的思路

经过年复一年的开发积累,企业的代码仓逐渐变得臃肿,甚至变成屎山代码。

这些屎山代码,往往经过N个程序员之手,他们水平参差不起,风格不一。

如何对这些屎山代码进行统一的管理,让它们可以被监控、评价和批量改造?

建立“代码管理系统”的第一个难点在于,如何在庞大的代码仓中,快速的查找出具有某些特征的代码段。

由于我们需要查找的是代码段,而不是代码行,用传统的正则表达式难以实现,需要通过语法解析器进行自定义语法配置,然后进行代码查找。

以小实例说明 :

### 实例1: 找出JAVA代码中,入参数量超过4个的函数:

# 配置查找规则(Code_manage.syn)如下所示:

__DEF_CASE_SENSITIVE__    Y
__DEF_FUZZY__             Y 
__DEF_DEBUG__             N

__DEF_LINE_COMMENT__     //
__DEF_LINES_COMMENT__    /*  */


__DEF_STR__   __NAME__  
<1,200>
[1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$??
[0,199]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_??
[NO] import if else for while break continue class return try except finally final static public private


__DEF_PATH__    __FUNCTION_DEF__
0101          : x1         @              | public
              : x2         @              + private
0 0           : x3         @ CAN_SKIP     | static
1 1           : x4         @              | __NAME__
              : x5         @              | __NAME__
              : x6         @              | (
1111          : p1         @ CAN_SKIP     | final
              : p11        @              | __NAME__
              : p111       @              | __NAME__
              : p2         @              | ,
              : p22        @ CAN_SKIP     | final
              : p222       @              | __NAME__
              : p2222      @              | __NAME__
              : p3         @              | ,
              : p33        @ CAN_SKIP     | final
              : p333       @              | __NAME__
              : p3333      @              | __NAME__
NNNN          : p4         @              | ,
              : p44        @ CAN_SKIP     | final
              : x444       @              | __NAME__
              : x4444      @              | __NAME__
1111          : xx         @              | )

# 假设java代码(MyCode.java) 如下所示:

private int alreadyBufferedSize = 0;

// The index in the byte[] found at buffers.getLast() to be written next
private int index = 0;

// Is the stream closed?
private boolean closed = false;

public FastByteArrayOutputStream(int initialBlockSize) {
	Assert.isTrue(initialBlockSize > 0, "Initial block size must be greater than 0");
	this.initialBlockSize = initialBlockSize;
	this.nextBlockSize = initialBlockSize;
}

@Override
public void applyBeanPropertyValues(Object existingBean, String beanName, int autowireMode, boolean dependencyCheck, int initSize) 
throws BeansException {
	markBeanAsCreated(beanName);
	BeanDefinition bd = getMergedBeanDefinition(beanName);
	BeanWrapper bw = new BeanWrapperImpl(existingBean);
	initBeanWrapper(bw);
	applyPropertyValues(beanName, bd, bw, bd.getPropertyValues());
}

@Override
public Object initializeBean(Object existingBean, String beanName) {
	return initializeBean(beanName, existingBean, null);
}

根据配置规则,执行查找命令: ZGLanguage -e Code_manage.syn -f MyCode.java

可以得到结果:

C:\>ZGLanguage -e Code_manage.syn -f MyCode.java
Run type : Find
Syntax file : Code_manage.syn
code file : MyCode.java
Output file : out.zgl

--------------------------------------------------------------------
### Found code by : __FUNCTION_DEF__ | Lines : 17 ~ 17 :
--------------------------------------------------------------------
public void applyBeanPropertyValues(Object existingBean, String beanName, int autowireMode, boolean dependencyCheck, int initSize)

可以看出,查找结果只输出了函数 applyBeanPropertyValues,它的入参数量为5个,其他2个函数的入参均不超过4个,因此被忽略。

### 实例2: 提取SQL代码中的关联(on)和筛选(where)代码段:

# 配置查找规则(Code_manage.syn)如下所示:

__DEF_DEBUG__             N
__DEF_FUZZY__             Y
__DEF_CASE_SENSITIVE__    N

__DEF_LINE_COMMENT__      --
__DEF_LINES_COMMENT__     /*     */


__DEF_PATH__    __WHERE__
1         : x1  | where
          : x2  | __PATH_4_EXPR__


__DEF_PATH__    __ON__
1             : x1        | __\b__
              : x2        + __\t__
              : x3        + __\n__
              : x4        | on
              : x5        | __PATH_4_EXPR__


__DEF_SUB_PATH__     __PATH_4_EXPR__
1             : x1        | __SUB_PATH_EXPR__
              : x2        + __ONE_PATH_EXPR__


__DEF_SUB_PATH__     __SUB_PATH_EXPR__
1             : x1        | (
              : x2        | __ONE_PATH_EXPR__
              : x3        | )


__DEF_SUB_PATH__     __ONE_PATH_EXPR__
NN         :       @          | __NAME__
           :       @          + __INT__
           :       @          + __FLOAT__
           :       @          + __CASE_WHEN__
           :       @          + __STRING__
           :       @          + __CAST_AS__
           :       @          + __FUNCTION__
           :       @          + __SUB_PATH_EXPR__
           :       @          + = 
           :       @          + <>
           :       @          + !=
           :       @          + > 
           :       @          + >=
           :       @          + < 
           :       @          + <=
           :       @          + . 
           :       @          + ,
           :       @          + + 
           :       @          + - 
           :       @          + * 
           :       @          + / 
           :       @          + ||
           :       @          + null
           :       @          + between
           :       @          + and
           :       @          + or
           :       @          + like
           :       @          + in
           :       @ STRING   + not in 
           :       @ STRING   + is null
           :       @ STRING   + is not null


__DEF_STR__   __NAME__
<1,100>
[1,1]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_??
[0,100]ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_??
[NO] select inner left join on from where group order by having union all with as table date time


__DEF_STR__   __FLOAT__
<1,100>
[1,50]0123456789
[1,1].
[1,50]0123456789


__DEF_STR__   __INT__
<1,100>
[1,100]0123456789


__DEF_SUB_PATH__   __STRING__
1       : x1                         | '
        : x2                         | __ANY__
        : x3                         | '


__DEF_SUB_PATH__   __DECIMAL__
111       : x1 | decimal
0         : x2 | (
01        : x3 | __INT__
00        : x4 | ,
00        : x5 | __INT__
01        : x6 | )


__DEF_SUB_PATH__   __VAR_NAME__
1       : x1 | $
        : x2 | {
        : x3 | __NAME__
        : x4 | }


__DEF_SUB_PATH__   __CASE_WHEN__
1          : x1        @          | case
N          : x2        @          | when
           : x3        @          | __PATH_4_EXPR__
           : x4        @          | then
           : x5        @          | __PATH_4_EXPR__
1          : x6        @ CAN_SKIP | else
           : x7        @ CAN_SKIP | __PATH_4_EXPR__
           : x8        @          | end


__DEF_SUB_PATH__   __CAST_AS__
1       : x1 | cast
        : x2 | (
1       : x3 | __PATH_4_EXPR__
        : x4 | as
        : x5 | date
        : x6 + int
        : n1 + double
        : n2 + float
        : n3 + bigint
        : x8 + __DECIMAL__
1       : xx | )


__DEF_SUB_PATH__   __FUNCTION__      
1          : x1       @             | __NAME__
           : x2       @             | (      
N          : x3       @ CAN_SKIP    | __PATH_4_EXPR__
e          : x4       @ CAN_SKIP    | ,      
1          : x5       @             | )

# 假设SQL代码(myproc.sql) 如下所示:

CREATE OR REPLACE PROCEDURE PROC_F_CWWS_LOAN
(
    P_AS_OF_DATE IN  DATE,
    RET_FLG      OUT VARCHAR2,
    RET_MSG      OUT VARCHAR2
) IS

  -- 声明变量并初始化
  V_COUNT NUMBER := 0;
  V_PROC_NAME VARCHAR2(200) := 'PROC_F_CWWS_LOAN';
  V_PROC_DESC VARCHAR2(100) := 'xxxx业务数据ETL处理';
  V_P_FREQ VARCHAR2(4) := '';

BEGIN

  --写入初始日志
  INSERT INTO M_RUNLOG VALUES (SYSDATE, V_PROC_NAME, 'it is 1');
  COMMIT;


  --设置会话日期格式
  EXECUTE IMMEDIATE ' ALTER SESSION SET NLS_DATE_FORMAT = ''YYYY-MM-DD''';
  --查询参数表中,该程序对应的频率值
  SELECT P_FREQ
    INTO V_P_FREQ
    FROM ETL_PROC_STATUS_DEF
   WHERE PROC_NAME = V_PROC_NAME;
  --判断是调度频率

    ETL.ETL_ADD_PARTITION('MA_F_LOAN', P_AS_OF_DATE, 'ETL');

    --从还款计划表中取每笔账户最近一次小于等于数据日期还款日,作为上次还款日
    INSERT INTO ETL.TMP_XD_LAST_PAYDATE
      (OBJECTNO, LAST_PAYDATE)
      SELECT OBJECTNO, LAST_PAYDATE
        FROM (SELECT T.OBJECTNO,
                     MAX(TO_DATE(PAYDATE, 'YYYY-MM-DD')) LAST_PAYDATE
                FROM NYBDP.O_CWWS_ACCT_PAYMENT_SCHEDULE T
               WHERE T.AS_OF_DATE = P_AS_OF_DATE
                 AND T.SEQID <> '999'
                 AND TO_DATE(T.PAYDATE, 'YYYY-MM-DD') < P_AS_OF_DATE
               GROUP BY T.OBJECTNO);
    INSERT INTO M_RUNLOG VALUES (SYSDATE, V_PROC_NAME, 'it is 3');
    COMMIT;


    MERGE INTO ETL.MA_F_LOAN A
    USING (SELECT /*+PARALLEL(8)*/
            T.ACCOUNT_NUMBER, T.GL_ACCOUNT_ID, T.INT_GL_ACCOUNT_ID
             FROM ETL.MA_F_LOAN T
            INNER JOIN ETL.MA_D_GL_SUBJECT T1
               ON T.INT_GL_ACCOUNT_ID = T1.SUBJECT_NO3
              AND T1.SUBJECT_NAME3 LIKE '%已减值%'
              AND T1.AS_OF_DATE = P_AS_OF_DATE
            WHERE T.AS_OF_DATE = P_AS_OF_DATE
              AND T.ACCOUNT_NUMBER IN
                  (SELECT ACCOUNT_NUMBER
                     FROM (SELECT /*+PARALLEL(8)*/
                            T2.ACCOUNT_NUMBER, COUNT(1)
                             FROM ETL.MA_F_LOAN T2
                            WHERE T2.AS_OF_DATE = P_AS_OF_DATE
                            GROUP BY T2.ACCOUNT_NUMBER
                           HAVING COUNT(1) > 1))) B
    ON (A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.AS_OF_DATE = P_AS_OF_DATE AND A.GL_ACCOUNT_ID = B.GL_ACCOUNT_ID AND A.INT_GL_ACCOUNT_ID = B.INT_GL_ACCOUNT_ID)
    WHEN MATCHED THEN
      UPDATE SET A.CUR_BOOK_BAL = 0, A.OVERDUE_BAL = 0;
    COMMIT;


  RET_FLG := '0';
  RET_MSG := '执行成功';

EXCEPTION
  WHEN OTHERS THEN
    --写入异常日志
    ETL.PROC_ETL_LOG(P_AS_OF_DATE,V_PROC_NAME,V_PROC_DESC,V_COUNT,-1,SQLCODE,SQLERRM);
    RET_MSG := SQLCODE || ':' || SQLERRM;

END;
/

根据配置规则,执行查找命令: ZGLanguage -e Code_manage.syn -f myproc.sql

可以得到结果:

C:\>ZGLanguage -e Code_manage.syn -f myproc.sql
Run type : Find
Syntax file : Code_manage.syn
code file : myproc.sql
Output file : out.zgl

--------------------------------------------------------------------
### Found code by : __WHERE__ | Lines : 27 ~ 27 :
--------------------------------------------------------------------
WHERE PROC_NAME = V_PROC_NAME

--------------------------------------------------------------------
### Found code by : __WHERE__ | Lines : 39 ~ 41 :
--------------------------------------------------------------------
WHERE T.AS_OF_DATE = P_AS_OF_DATE
                 AND T.SEQID <> '999'
                 AND TO_DATE(T.PAYDATE, 'YYYY-MM-DD') < P_AS_OF_DATE

--------------------------------------------------------------------
### Found code by : __ON__ | Lines : 52 ~ 54 :
--------------------------------------------------------------------
               ON T.INT_GL_ACCOUNT_ID = T1.SUBJECT_NO3
              AND T1.SUBJECT_NAME3 LIKE '%宸插噺鍊?'
              AND T1.AS_OF_DATE = P_AS_OF_DATE

--------------------------------------------------------------------
### Found code by : __WHERE__ | Lines : 55 ~ 56 :
--------------------------------------------------------------------
WHERE T.AS_OF_DATE = P_AS_OF_DATE
              AND T.ACCOUNT_NUMBER IN

--------------------------------------------------------------------
### Found code by : __WHERE__ | Lines : 61 ~ 61 :
--------------------------------------------------------------------
WHERE T2.AS_OF_DATE = P_AS_OF_DATE

--------------------------------------------------------------------
### Found code by : __ON__ | Lines : 64 ~ 66 :
--------------------------------------------------------------------
    ON (A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER AND A.AS_OF_DATE = P_AS_OF_DATE AND A.GL_ACCOUNT_ID = B.GL_ACCOUNT_ID AND A.INT_GL_ACCOUNT_ID = B.INT_GL_ACCOUNT_ID)
    WHEN MATCHED THEN
      UPDATE SET A.CUR_BOOK_BAL = 0, A.OVERDUE_BAL = 0

可以看出,查找结果将 myproc.sql 代码中的 where 和 on 代码块及其所在行号提取出来。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。