我正在考虑重构一些非常复杂的代码,这是我工作的项目的子系统。我对这段代码的部分检查是它非常复杂,并且包含许多输入,中间值和输出,具体取决于某些核心业务逻辑。
我想重新设计这个代码,以便更容易维护以及执行更快的地狱,所以首先我一直在尝试查看每个参数及其相互依赖关系。这导致了相当大的纠结图,我想要一种简化此图的机制。
前段时间我在一本关于SOA设计的书中遇到了一种称为“矩阵设计分解”的技术,它使用输出矩阵和它们对输入的依赖关系,应用某种形式的矩阵代数并生成业务流程图对于那些依赖。
我知道http://www.designdecomposition.com/有一个可用的网络工具,但它可以拥有的输入/输出依赖数量有限。我已经尝试过寻找这个工具的算法源(所以我可以尝试在没有大小限制的情况下自己实现它),但是我没有运气。
有人知道我可以使用的类似技术吗?目前我甚至考虑采用依赖矩阵并应用一些遗传算法来看看进化是否能够提出更简单的工作流程......
干杯,
Aidos
编辑:
我将解释动机:
原始代码是为每次用户执行操作(添加,删除或修改项目的某些属性)计算所有值(大约60)的系统编写的。这段代码是在十多年前编写的,并且肯定显示出年龄的迹象 - 其他人已经在系统中添加了更复杂的计算,现在我们得到了完全不合理的性能(在控制返回给用户之前最多2分钟)。已经决定从用户操作中分离计算并提供“重新计算”值的按钮。
我的问题出现了,因为有很多计算正在进行,它们基于所有必需数据都可用于计算的假设 - 现在当我尝试重新实现计算时,我一直遇到问题因为我没有得到这个计算所依赖的不同计算的结果。
这是我想要使用矩阵分解方法的地方。 MD方法允许我指定所有输入和输出,并为我提供“最简单”的工作流程,我可以用它来生成所有输出。
然后,我可以使用此“工作流程”来了解我需要执行的计算的优先级,以获得相同的结果,而不会产生任何异常。它还向我展示了我可以并行计算系统的哪些部分以及fork和join点的位置(我不会担心那部分)。目前,我所拥有的是一个非常大的矩阵,其中包含许多依赖关系,不知道从哪里开始。
我将从我的评论中再详述一下:
我不想在实际程序中使用EA流程的解决方案。我想采用依赖矩阵并将其分解为模块,然后我将手动编码 - 这纯粹是一种设计辅助 - 我只对这些模块的输入/输出感兴趣。基本上是这些计算之间复杂的相互依赖关系的表示,以及一些优先级的概念。
说我有A需要B和C.D需要A和E. F需要B,A和E,我想有效地将问题空间从一组复杂的依赖项划分为一个“工作流程”,我可以检查到得到更好的理解。一旦我理解了这一点,我就可以提出一个更好的设计/实现仍然是人类可读的,所以我知道我需要计算A,然后是C,然后是D,然后是F,
-
我知道这看起来有点奇怪,如果你在基于矩阵的分解之前看一下我链接的网站,那么应该让你对我的想法有所了解......
答案 0 :(得分:2)
kquinn,如果它是我认为他所指的那段代码(我曾经在那里工作),那它已经是一个人类无法理解的黑盒解决方案了。他并不打算让它变得更复杂,实际上更少。他想要实现的是一大堆相互关联的计算。
目前发生的事情是,无论何时发生任何变化,都会发生大量事件导致大量计算失效,从而导致更多事件继续发生,直到最终达到平衡状态。
我认为他想要做的是找到那些外围计算的依赖关系并从那里开始工作,这样就可以重写它们并找到计算方法,而不是因为它们需要。
我无法就简化图表提供太多建议,不幸的是,这并不是我经验丰富的事情。也就是说,我会开始寻找那些没有依赖关系的偏离计算,并且只是从那里。开始构建一个新框架,以最简单的方式包含每个计算的核心业务逻辑,并在整个过程中重构废话。
答案 1 :(得分:0)
如果这是,正如你所说的那样,“核心业务逻辑”,那么你真的不想用花哨的分解和进化算法来制造一个世界上没有人理解的“黑盒子”解决方案或能够修改。如果这些技术中的任何一种实际上产生了任何有用的结果,我会非常惊讶;在处理复杂的关系时,人类的大脑仍然比任何机器都难以理解。
您要做的是传统的重构:清理各个程序,简化它们并尽可能地合并它们。您的目标是使代码清晰,因此您的继任者不必经历相同的过程。
答案 2 :(得分:0)
您使用的是哪种语言? 使用Java Executors和Future<>建模您的问题应该非常容易。任务,但也可以在您选择的平台上提供类似的框架?
另外,如果我理解正确,你想为一大堆相互依赖的计算生成关键路径 - 是动态完成的,还是“只是”需要静态分析?
关于算法解决方案;拿起你的数值分析教科书的最接近的副本,并在奇异值分解和LU分解上刷新你的记忆;我从头顶猜测这就是你所链接的工具背后的原因。
编辑:由于您使用的是Java,我将简要介绍一下建议提案:
- >使用线程池执行器轻松并行化所有计算
- >用Future<>的对象图解决相互依赖性。或FutureTask<>:s,即如果变量是A,B和C,其中A = B + C,则执行以下操作:
static final Map<String, FutureTask<Integer>> mapping = ...
static final ThreadPoolExecutor threadpool = ...
FutureTask<Integer> a = new FutureTask<Integer>(new Callable<Integer>() {
public Integer call() {
Integer b = mapping.get("B").get();
Integer c = mapping.get("C").get();
return b + c;
}
}
);
FutureTask<Integer> b = new FutureTask<Integer>(...);
FutureTask<Integer> c = new FutureTask<Integer>(...);
map.put("A", a);
map.put("B", a);
map.put("C", a);
for ( FutureTask<Integer> task : map.values() )
threadpool.execute(task);
现在,如果我没有完全关闭(我可能很好,因为我在Java工作了一段时间),你应该能够通过调整线程池大小来解决明显的死锁问题,或者使用不断增长的线程池。 (你仍然需要确保没有相互依赖的任务,例如A = B + C,B = A + 1 ......)
答案 3 :(得分:0)
如果黑盒是线性的,您可以通过简单地连接许多输入向量和许多输出向量来发现所有系数。
你有输入 x[i] 和输出 y[i],然后你创建一个矩阵 Y,它的列是 y[0], y[1], ... y[n],和一个矩阵 X,它的列是 x[0], x[1], ..., x[n]。会有一个变换 Y = T * X,那么你可以确定 T = Y * inverse(X)。
但既然你说它很复杂,我敢打赌它不是线性的。那么如果你仍然想要一个通用的框架,你可以使用这个因子图
https://ieeexplore.ieee.org/document/910572
我很好奇你是否能做到这一点。
我认为更容易的是理解代码并使用最佳实践重写它。