蘭陵N梓記

一指流沙,程序年华


  • 首页

  • 归档

  • 关于

  • 搜索
close

飞哥讲代码7:消除重复,需要脚本模块化

时间: 2020-06-27   |   分类: 技术     |   阅读: 2936 字 ~6分钟

案例

这次就不上代码了。情况是这样的,我们某一新产品,采用微服务架构,每个微服务独立的源码仓:

  • 每个服务都要支持手工安装,DF部署,容器部署。
  • 每个服务都要支持修改密钥,密码等。
  • 每个服务都要支持容灾,WatchDog等

上面的功能实现都需要采用Shell脚本,当搞定一个服务时,只需要复制到其它的服务,是最为常见的做法。但这种做法也带来了大量的重复,导致维护极其困难。真是拷贝一时爽,维护成了火葬场。主要问题表现:

  • 服务内重复: 同一服务内脚本不同场景下复制粘贴,如手工安装与DF部署,都需要创建OS用户,没有抽取公共函数复用
  • 服务间重复: 不同服务间脚本复制粘贴,如同样是修改密码,只是配置文件路径不一样,配置项略有差别,没有抽取公共脚本复用。
  • 缺少封装性: 部分脚本从头到尾没有任何函数提取,大块脚本从顶写到尾,全局变量到处飞,阅读极其困难。
  • 健壮性不足: 脚本中的操作没有判断返回值或退出状态码,脚本没有太多的可靠性的防护。
阅读全文 »

飞哥讲代码6:消除重复,需要配置代码分离

时间: 2020-06-21   |   分类: 技术     |   阅读: 2198 字 ~5分钟

案例

下面的代码来自我们某一平台产品前端源码(Java语言)中:

private static Map<String, Map<String, String>> constructConstrainMap() {
    Map<String, Map<String, String>> typeConstrainMap = new HashMap<String, Map<String, String>>();
    Map<String, String> imageConstrainPatternMap = new HashMap<String, String>();
    imageConstrainPatternMap.put("allowdPatten", "^[a-zA-Z0-9_~.=@-]$");
    imageConstrainPatternMap.put("allowdMin", "1");
    imageConstrainPatternMap.put("allowdMax", "256");
    imageConstrainPatternMap.put("allowdValue", null);
    imageConstrainPatternMap.put("noEcho", "false");
    imageConstrainPatternMap.put("description", "com.huawei.....");
    typeConstrainMap.put(TPropType.IAA_S_IMAGE_ID.value(), imageConstrainPatternMap)

    Map<String, String> netWorkConstrainPatternMap = new HashMap<String, String>();
    // 省略 put ...

    Map<String, String> containerConstrainPatternMap = new HashMap<String, String>();
    // 省略 put ...

    // 省略 其它的Constrain代码 ...
}

上面的代码在一个方法中构造了16个Constrain,它是提供给BME控件用于输入框的校验。显然代码出现了重复(相似),也较容易想到采用外部配置文件方式来简化样板代码,但采用什么配置方式呢?

阅读全文 »

飞哥讲代码5:消除重复,需要搞点设计模式

时间: 2020-06-13   |   分类: 技术     |   阅读: 4367 字 ~9分钟

案例

下面的代码来自我们某一平台产品源码(Java语言)中:

public class RemoteExecuteHandler {
    public Future<RemoteExecuteResult> handleDownload() throws SspException {
        try {
            initSshClient();
            Future<RemoteExecuteResult> feture = downloadPackage();
            return feture;
        } catch (SspException e) {
            LOGGER.error("CMC download package failed", e);
            closeSshClient();
            throw e;
        }
    }

    public Future<RemoteExecuteResult> handleLoad() throws SspException {
        try {
            initSshClient();
            Future<RemoteExecuteResult> feture = loadPackage();
            return feture;
        } catch (SspException e) {
            LOGGER.error("Load site package failed", e);
            closeSshClient();
            throw e;
        }
    }

    // 下面还有几个类似的方法,不再一一列表
}

上面的代码较直观地出现重复(相似),除了执行具体的动作与日志不一样,都是样板代码。当然还存在其它问题:

阅读全文 »

飞哥讲代码4:消除重复,需要了解框架机制

时间: 2020-06-05   |   分类: 技术     |   阅读: 4224 字 ~9分钟

案例

下面的代码来自我们某一平台产品源码(Java语言)中(代码一):

public class ServiceFactory {
    private static ServiceFactory instance = new ServiceFactory();

    public static ServiceFactory getInstance() {
        return instance;
    }

    @Getter 
    @Setter
    @Autowired 
    private AppTemplateDesignServie appTemplateDesignServie;
   
    @Getter 
    @Setter
    @Autowired 
    private AppTemplateExportServie appTemplateExportServie;
    
    // 下面还有十多个Service对象注入,提供Getter与Setter,不再一一列出
}

再来看另一平台服务的代码(Java语言)(代码二):

阅读全文 »

飞哥讲代码3:简洁高效的线程安全

时间: 2020-05-31   |   分类: 技术     |   阅读: 3381 字 ~7分钟

案例

下面的代码来自我们某一中间件产品源码(Java语言)中(写法一):

// ConcurrentMap<String, AtomicLong> rejectMessageCounts = new ConcurrentHashMap<>();
private AtomicLong getRejectMessageCount(String serviceName) {
    AtomicLong rejectMessageCount = rejectMessageCounts.get(serviceName);
    if (null == rejectMessageCount) {
        rejectMessageCount = new AtomicLong();
        AtomicLong currentValue = rejectMessageCounts.putIfAbsent(serviceName, rejectMessageCount);
        if ( null != currentValue) {
            rejectMessageCount = currentValue;
        }
    }
    return rejectMessageCount;
}

上面的代码是线程安全的,但不够简洁,Java 1.8的ConcurrentMap提供computeIfAbsent()方法,可以简化为(写法二):

private AtomicLong getRejectMessageCount(String serviceName) {
    return rejectMessageCounts.computeIfAbsent(serviceName, (key)-> new AtomicLong());
}
阅读全文 »

飞哥讲代码2:把大象装进冰箱要几步

时间: 2020-05-23   |   分类: 技术     |   阅读: 1806 字 ~4分钟

案例

下面的代码来自我们某一老产品源码(C语言)中:

VOS_INT STARTER_Download(VOD_VOID) {
    VOS_UINT32 count, sleepTimeLen;
    VOS_CHAR ascExcuteFile[INSTALL_MAX_DIRNAME_LEN]={ 0 };
    VOS_BOOL enIsHaveUpdateOk = VOS_FALSE;
    VOS_INT siRet;

    BOOTTRACE(TRACE_TIP, "Checking and updating files...");

    if(LOAD_Init()==VOS_FALSE) {
        BOOTTRACE(TRACE_ERR, "The LOAD Init return error");
        return VOS_ERR;
    }

    siRet=LOAD_Begin(LD_STAGE_INSCHK, &g_downloadFileCount, g_pstFileListInfo, LD_ONLINE_UPDATE);
    if(siRet != VOS_OK) {
        LOAD_End();
        BOOTTRACE(TRACE_ERR, "The LOAD Begin return error");
        return VOS_ERR;
    }

    while(VOS_TRUE) {
        for(count=0;count<g_downloadFileCount;count++) {
            if (g_pstFileListInfo[count].enLoadCheckResult == LS_SUCESS_UPDATE ) {
                enIsHaveUpdateOk = VOS_TRUE;
            }
        }

        for(count=0;count<g_downloadFileCount;count++) {
            if (g_pstFileListInfo[count].enLoadCheckResult != LS_SUCESS_UPDATE &&
                (g_pstFileListInfo[count].enLoadCheckResult != LS_NOT_NEED_UPDATE) &&
                (g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &&
                (g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE)) {
                BOOTTRACE(TRACE_ERR, "update file %s error and result=%d",
                    g_pstFileListInfo[count].acFileName,
                    g_pstFileListInfo[count].enLoadCheckResult);
                break;
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &&
                (enIsHaveUpdateOk == VOS_TRUE) ) {
                BOOTTRACE(TRACE_ERR, "Not all files are updated,download these file again");
                break;    
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE) &&
                (enIsHaveUpdateOk == VOS_TRUE) ) {
                BOOTTRACE(TRACE_ERR, "Not all files version are consistent with inschk,download these file again");
                break;    
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_NORESPONSE) &&
                (g_pstFileListInfo[count].bLocalCheck = VOS_FALSE) ) {
                BOOTTRACE(TRACE_ERR, "Fail to connect witch OMU server and local file %s is uncertain, I will still download these files", g_pstFileListInfo[count].acFileName);
                break;    
            }

            if ((g_pstFileListInfo[count].enLoadCheckResult != LS_OMU_REFUSE) &&
                (g_pstFileListInfo[count].bLocalCheck = VOS_FALSE) ) {
                BOOTTRACE(TRACE_ERR, "OMU fesuse to update and %s local check result=%d or some file updated", g_pstFileListInfo[count].acFileName, g_pstFileListInfo[count].bLocalCheck);
                break;    
            }

            if (g_pstFileListInfo[count].ucFileType == PROG_FILE_TYPE ) {
                siRet = snprintf_s(ascExcuteFile, sizeof(ascExcuteFile),  sizeof(ascExcuteFile)-1,
                         "%s/%s", g_pstFileListInfo[count].acFileExecuteDir, g_pstFileListInfo[count].acFileName);
                if (siRet <= 0 ) {
                    BOOTTRACE(TRACE_ERR, "[%s:%d] snprintf_s failed,", __FUNCTION__, __LINE__);
                    break;
                }
                (void)chmod(ascExcuteFile, S_IRUSE | S_IXUSR);
            }
        }

        if (count == g_downloadFileCount) {
            BOOTTRACE(TRACE_TIP, "All %d files checked or updated OK.", g_downloadFileCount);
            for(count=0;count<g_downloadFileCount;count++) {
                BOOTTRACE(TRACE_LOD, "%d update result is %d and local check result is %d.",
                 g_pstFileListInfo[count].acFileName, g_pstFileListInfo[count].enLoadCheckResult,
                 g_pstFileListInfo[count].bLocalCheck);
            }
            break;
        } else {
            if (g_pstFileListInfo[count].enLoadCheckResult == LS_DISK_FULL){
                sleepTimeLen=INSTALL_DISK_FULL_AGAIN_TIMELEN;
            } else {
                sleepTimeLen=INSTALL_CONNECT_OMU_AGAIN_TIMELEN;
            }

            BOOTTRACE(TRACE_ERR, "Update file error so sleep for %d second and try again", sleepTimeLen);
            SLEEP(sleepTimeLen);

            siRet=LOAD_Begin(LD_STAGE_INSCHK, &g_downloadFileCount, g_pstFileListInfo, LD_ONLINE_UPDATE);
            if(siRet != VOS_OK) {
                LOAD_End();
                BOOTTRACE(TRACE_ERR, "The LOAD Begin return error");
                return VOS_ERR;
            }
        }
    }

    BOOTTRACE(TRACE_DBG, "Exit STARTER_Download");
    LOAD_End();
    return VOS_OK;
}

上面的代码我已是删除了每个条件判断的注释,但是代码看起还是有点长。如果不仔细读,还真不看出不函数完成的功能。再来看优化重构之后的代码:

阅读全文 »

飞哥讲代码1:确保资源被释放

时间: 2020-05-16   |   分类: 技术     |   阅读: 2345 字 ~5分钟

案例

下面的代码来自我们某一工具源码(Python语言)中:

file_gz = gzip.GzipFile(file_name)
src_path, src_file = os.path.split(file_name)
tmp_file_name = os.path.join(path_name, src_file).strip('gz').strip('.')
tmp_file = open(tmp_file_name, 'wb')
tmp_file.writeline(file_gz.realines())
file_gz.close()
tmp_file.close()
os.remove(file_name)

从代码健壮角度来看,存在如下两个问题:

  • 缺少捕获异常,在GzipFile打开文件,open打开文件之后的操作都可能抛出异常
  • 当抛出异常时,file_gz与tmp_file就会出现未正常close,存在文件句柄的泄露问题

能正确释放资源的建议写法是:

阅读全文 »

阅读

时间: 2020-03-29   |   分类: 感想     |   阅读: 850 字 ~2分钟

生于80后,长相70后的我们,不知不觉已将跨入不惑不年。但还是为了房子、孩子、票子日复一日地忙碌工作,曾经年少的理想也慢慢被岁月磨平,也根本没有精力抽出一丁点的时间来读一本书,仰望一下星空。有人说:一日不读书,无人看得出;一周不读书,开始会爆粗;一月不读书,智商输给猪。当停下手中的工作工作,才发现自己知识结构那么地匮乏。

曾经梦想把阅读当成生活的重要组成部分,把阅读当作精神升华的方式。有自己一个独立的书房,书柜上摆上经典的、实用的、消遣的书籍,在空闲的时间里抱上一本细细咀嚼,娴静地阅读,享受书的世界,感受书的力量。

有些事,我们明知道是错的,也要去坚持,因为不甘心;有时候,我们明知道没有路了,却还在前行,因为习惯了。没有正确的方向,再多报努力也可能没有结果。阅读才能使自己的内心强大,也不会陷入死胡同,走正确的路,即时放弃错误的持着。

阅读全文 »
1 2 3 4 5 6 7 8 9
兰陵子

兰陵子

Programmer & Architect

162 日志
4 分类
57 标签
RSS 订阅
GitHub 知乎
© 2009 - 2022 蘭陵N梓記
Powered by - Hugo v0.98.0
Theme by - NexT
0%