霞弹式修改

如果要直接地认识某种或某些事物,便只有亲身参加于变革现实、变革某种或某些事物的实践的斗争中,才能触到那种或那些事物的现象,也只有在亲身参加变革现实的实践的斗争中,才能暴露那种或那些事物的本质而理解它们。

—— 实践论,论认识和实践的关系——知和行的关系(一九三七年七月)

Fowler M. 重构: 改善既有代码的设计[M].

简介

霞弹式修改(Shotgun Surgery)指的是每遇到某种变化,都必须在许多不同的类内做出许多小修改。需要修改的代码散布四处,不但很难找到他们,而且很容易错过某个重要的修改。

修改策略

这种情况下,你应该使用搬移函数和搬移字段把所有需要修改的代码放进同一个模块里。

如果有很多函数都在操作相似的数据,可以使用函数组合成类。

如果有些函数的功能是转化或者充实数据结构,可以使用 函数组合成变换。

如果一些函数的输出可以组合后提供给一段专门使用这些计算结果的逻辑,这种时候常常用得上拆分阶段。

面对霰弹式修改,一个常用的策略就是使用与内联(inline)相关的重构—— 如内联函数或是内联类——把本不该分散的逻辑拽回一处。

完成内联之后,你可能会闻到过长函数或者过大的类的味道,不过你总可以用与提炼相关的重构手法将其拆解成更合理的小块。即便如此钟爱小型的函数和类,我们也并不担心在重构的过程中暂时创建一些较大的程序单元。

蒙特卡洛模拟程序重构

在声子蒙特卡洛模拟中,有三个地方需要根据不同的权重抽样声子的性质,内热源发射、散射、边界热流发射。但是不论是哪一类抽样,返回的都是同样的声子属性,比如群速度、频率等等,然后赋值给当前运动的声子。在我最开始的实现过程中,只返回了群速度大小和弛豫时间,然后不同的地方直接用赋值语句更改声子属性,

1
2
3
4
5
......
phonon.vg, phonon.tau = heatsource.sample_property(block, phonon.position)
......
phonon.vg, phonon.tau = block.material.sample_scatter_property(temperature)
......

现在为了把晶格动力学的全带界面穿透谱扩充进来,不得不

在声子类中新建一个更新声子属性的函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Phonon(object):
def __init__(self):
pass

def update_property(self, q_point: int, branch: int, vg_vector: NDArray[np.float64], tau: float):
"""更新声子的属性.

Args:
q_point (int): 声子所处的q点.
branch (int): 声子的支序号.
vg_vector (numpy.ndarray[3, numpy.float64]): 声子的群速度向量.
tau (float): 声子的弛豫时间.
"""
self.q_point = q_point
self.branch = branch
self.vg_vector = vg_vector
self.tau = tau