3

如何写出更好的程序二:尽可能减少代码的修改

 8 months ago
source link: https://muyuuuu.github.io/2023/11/17/minimize-code-modification/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

职场新人兼新手程序员斗胆开了新坑「如何写出更好的程序」,所见所得都是来自实际写代码时自己的思考,且已脱敏。这一系列不包含任何复杂的技术,也不包含任何难懂的代码。只是将核心问题暴露出来,针对这些场景,如何写出可维护性更高、更简洁优雅的代码。

目前仅包括 python 装饰器的使用,等某天遇到其他技术也可以减少代码的修改时,会追加到本文。

使用 Python 装饰器

一开始写代码的时候,都在想着要尽可能的支持全部功能,要获取各种信息并反馈给用户。于是我写了一大堆代码,创建了各种类、各种数据结构,以及实现了各种方法。

class A:
def func1(): ...
def func2(): ...
def func3(): ...


class B:
def func4(): ...
def func5(): ...
def func6(): ...

为了高效的获取信息,一些数据可以复用,一些逻辑可以跳过,这样写出来的代码也会错综复杂:

def main():
a = A()
a.func1()
b = B()

val = some_func()

if val < 100:
a.func3()
else:
b.func4()

某天忽然遇到一个新需求:需要增加一个轻量版的代码,只得到 3 个核心信息就好了,其他信息直接忽略掉。这时我回首我的代码发现:为了得到各种信息,之前的代码十分庞大,有很多类,也有很多方法,复杂的逻辑修改起来并不是件很容易的事。

  • 为了实现轻量版的代码,重写代码肯定是不值得的,毕竟一些代码逻辑和数据结构可以复用。重写代码势必会导致代码文件增加,冗余代码增多。
  • 如果复用代码,会发现这个类可以不用创建,这个逻辑可以跳过,一些类的成员方法可以不用执行。

如果在代码中手动添加 lite 这一轻量化参数,遇到不需要执行的代码就根据 liteif else 分支给代码加岔路口,代码结构会十分繁杂。比如有 lite 选项时,我们需要创建 A 这个类,根据临时结果判断是否需要执行 b.func4(),那么上述代码修改为:

def main():
lite = True
a = A()
if not lite:
a.func1()
b = B()

val = some_func()

if val < 100 and lite:
a.func3()
else:
b.func4()

对于 1000 多行更加复杂的代码,手动添加 lite 分支并修改逻辑,这是很累的工作,写出来的代码也不好看,通用性也随之变差。

装饰器优化

此时我们可以使用装饰器来完成这一工作,如果不知道装饰器是什么东西可以参考我之前的文章。在装饰器中首先传入 self 参数,如果检测到类的 lite 属性为 true,直接跳过这一函数不执行。此时我们只需要打开需要改动的类,增加 lite 属性。

如果确定这个方法可以不执行,给方法增加装饰器即可。而对于 main 函数中的代码,是不需要任何修改的,也不需要增加大量的 if else 分支,减少代码结构的修改和破坏。逻辑处理部分的代码如下所示,相比坏代码部分精简了很多,且 a.func1a.func3 都是不会执行的。

def use_lite(func):
def wrapper(self, *args, **kwargs):
if self.is_lite:
pass
else:
return func(self, *args, **kwargs)
return wrapper

class A:
def __init__(self, lite=False):
self.lite = True
@use_lite
def func1(): ...


def main():
a = A(True)
a.func1()
b = B()

val = some_func()

if val < 100:
a.func3()
else:
b.func4()

补充:@use_lite(self.lite) 是会报错的,因为装饰器是外部方法,并不是类的成员,也就无法捕捉类对象。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK