V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
heavymetals
V2EX  ›  随想

今天发生了件挫败感很强的事

  •  
  •   heavymetals · 77 天前 · 2644 次点击
    这是一个创建于 77 天前的主题,其中的信息可能已经有所发展或是发生改变。

    因为 MacOs 端微信保存文件的路径是这种形式

    /Message/MessageTemp/一堆随机字符 /File(OpenData)/2022-09

    相对于 Win 端的File/2022-09 太过复杂,而且每个联系人的随机字符串都不同,查找起来不太方便,所以今天(2022 年 9 月 23 日)中午的时候我打算写一个能定期将微信文件备份到特定文件夹,并按月份归档的 python 小程序。

    刚开始我觉着很简单,不就是读取创建时间然后复制粘贴吗,然后我就开始了愉快地面向谷歌编程。

    写着写着我开始不断想着添加新功能,微信每收发一个文件不管文件是否一样,都会在本地保存一份 --> 所以想着根据文件名去重 --> 又想到可能会有不同内容的同名文件 --> 不如根据 MD5+文件名去重 -- > 全查 MD5 太慢 --> 先看名字再检查 MD5

    然后我自己就乱了,前面写了一大堆 if else break ,也没怎么写注释,出错以后往上查自己也看不懂了......

    当时真是气死我了

    大概就是这样:

    for path, dir_list, source_file_list in g:
        for source_file_list in source_file_list:
            riqi = get_change_time(str(path) + '/' + str(source_file_list))
            target_path = '' + riqi
            target_path_file_name = return_target_file_name(target_path)
            for i in target_path_file_name:
                if i == source_file_list:
                    md5_target = return_md5(target_path + '/' + i)
                    md5_source = return_md5(path + '/' + source_file_list)
                    if md5_target==md5_source:
                        status=2
                        break
                    else:
                        print(i)
                        target_path_file_name.remove(i)
                        for uu in target_path_file_name:
                            md5_target = return_md5(target_path + '/' + uu)
                            md5_source = return_md5(path + '/' + source_file_list)
                            if uu == target_path_file_name:
                                status=1
                                break
                            else:
                                status=2
                        break
    
                else:
                    status=3
    

    现在我也没理清楚计算 md5 那段是怎么个逻辑

    还好经过我的不懈努力,程序能正常工作了,上面想的几个功能也都实现了。从下午两点一直搞到晚上八点,晚饭也烦的没有吃,一个下午全耗在这了,啥正事也没干,就为了这个小功能(责任全在微信)。为什么说是挫败感呢?因为我感觉这个真是个挺简单的程序,而且晚上写完回看确实感觉很简单,但是耗费了我这么长的时间,而且感觉自己好菜....我不是科班出身,写代码全是个人爱好,我一直认为自己有点写代码的天赋,现在看来我应该去重新系统的学习一下如何写代码。

    晚上睡不着,写出来感觉舒服多了,晚安兄弟们

    15 条回复    2022-09-24 21:14:30 +08:00
    Aloento
        1
    Aloento  
       77 天前   ❤️ 1
    加油加油,我写代码推翻重来的次数可多了,根本不担心的
    kkeep
        2
    kkeep  
       77 天前 via Android   ❤️ 1
    想想
    agagega
        3
    agagega  
       77 天前 via iPhone   ❤️ 1
    挺正常的,不要太在意,科班出身的人代码如果写得不多也容易这样。把思路转换成代码是一种需要训练的能力,所谓 LeetCode 考的并不只是对算法 /数据结构的理解,更重要的就是这个把思路转换成代码的能力
    levelworm
        4
    levelworm  
       76 天前 via Android   ❤️ 1
    我觉得得先设计清楚了再写,就能一次成功了。
    swulling
        5
    swulling  
       76 天前   ❤️ 1
    工程经验问题,不要写嵌套层级超过 3 的 if
    wzzzx
        6
    wzzzx  
       76 天前   ❤️ 3
    这里最最最主要的问题是 “写着写着我开始不断想着添加新功能”
    winglight2016
        7
    winglight2016  
       76 天前   ❤️ 1
    套了三层 for 循环不提,这么多 ifelse ,都没想过画个流程图吗?
    ilcn
        8
    ilcn  
       76 天前   ❤️ 1
    教你个简单易行的办法。用 IDE ,比如我用 jetbrains ,每写一个 if condition 就用 Ctrl+Alt+M 换成一个易理解的名字。

    比如:
    if line_number_is_1:
    if column_count_is_5:
    ...
    Kiriya
        9
    Kiriya  
       76 天前   ❤️ 1
    你写代码解析一堆屎山=你写了屎山代码🐶
    ma836323493
        10
    ma836323493  
       76 天前   ❤️ 1
    三层 for 循环 , 里面的 for 循环改成 函数, 特殊的 if 条件写在前面
    msg7086
        11
    msg7086  
       76 天前   ❤️ 1
    这种一大段 for 循环嵌套的写法挺不好的。
    写代码要先分割功能,把一个大功能分割成多个小功能的组合,分而治之。
    比如你这里至少会有( 1 )在目录下遍历文件列表( 2 )对比源和目标文件列表找出新增的文件( 3 )对比相同文件的 hash ( 4 )备份文件。那你分别实现这 4 个功能,再组合起来就好了。

    用伪代码来说就是:
    src_file_list = 某函数
    dst_file_list = 某函数
    new_file_list = src 中不在 dst 的文件集合
    common_file_list = src 与 dst 的交集
    changed_common_file_list = 交集里 MD5 不相同的文件集合
    backup(new_file_list)
    backup(changed_common_file_list)

    最后把伪代码里没实现的函数实现了就行。
    acehinnnqru
        12
    acehinnnqru  
       76 天前 via iPhone   ❤️ 1
    先确定思路和架构挺好的,返回来看的时候也没那么挫败
    THESDZ
        13
    THESDZ  
       76 天前   ❤️ 1
    仅从你的描述来看:
    虽然确定思路和架构,但是好像没有封装.
    那就导致了,你虽然设计了层次,但是从你的实现中看不出层次,而阅读代码的人(不管是你还是其他人)是不可能看设计的去推导代码的.

    我一般这么做:
    设计好思路,然后抽象出接口(或者方法),哪些做为主干,哪些作为分支.
    主干中的状态如何传递,是走上下文还是传入传出?
    枝干部分如何调用(写个代理类统一触发,还是作为回调外部传入)?

    写好每一个变量名,每一个方法名,减少非代码注释(避免后续注释没有随着代码变更导致更加难以理解)

    实现的代码条理清晰: 主干很简练,一上来就能读懂在干嘛,子模块通过方法名就可以猜测出在干嘛.
    拓展性也不错: 封装后只需要改封装部分,枝干部分直接增加回调或代理类中修改.


    举个例子,根据 op 的描述:
    主干部分为:
    1.读取微信的文件列表
    2.判断哪些要备份
    3.判断重复
    4.备份

    那就 main

    var context = make(map[string]interface{})
    func BackupWechatFile(rootPath,backPath string){
    files ,err := getFilesByRootpath(rootPath)
    if err!=nil {
    ...
    }
    for _,file := range files{
    isRepeated := judgeFileIfRepeated(file)
    if !isRepeated {
    err := backUp(file)
    if err!=nil{
    ...
    }
    }
    }
    }
    heavymetals
        14
    heavymetals  
    OP
       76 天前   ❤️ 1
    @THESDZ
    @acehinnnqru
    @msg7086
    @ma836323493
    @ilcn
    @swulling
    @agagega
    @Aloento
    @levelworm
    谢谢老哥们的悉心指导,感觉又学到了很多东西
    christin
        15
    christin  
       76 天前 via iPhone   ❤️ 1
    哈哈 比我这个科班出身的好多啦,我可能想想功能麻烦就不想做了。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1518 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 45ms · UTC 18:35 · PVG 02:35 · LAX 10:35 · JFK 13:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.