【面向实现】- 在快速交付背景下通过方法结构腐化代码

在代码开发当中,无论使用什么语言,在没有严格秩序的三层项目当中,往往都会重复着代码变屎山的过程,我们亲眼看到自己从0到1的项目随着代码堆叠慢慢变得臃肿,却很难有效的改变现状。

从历史规律来看,这似乎是人的问题,没有写好代码,但我们拉高视角,似乎这更是一个开发体系潜移默化的选择,选择了容忍臃肿和泛滥来换取所谓的开发迭代效率和需求功能产出。

这就像是盖楼少了一半的预算,工人不得从水泥钢筋削减成本,少了一半的工期,工人不得不简化设计一切只为尽快达成目的,而最后收尾复盘将所有一切项目质量的责任追究到工人头上,事实上是个笑话。

那么我们必须承认一个事实,优秀的代码往往需要更好的人力来实现,更长的时间来守序,这意味着更高的成本,从一开始这仅仅是一个简单的买单倾向问题。

抛开背景,我们从代码实现开始,一步一步开始看,我们的代码是怎么被腐化的。

一开始,有了一个需求,需要增删改查订单信息,于是张三写了如下方法:

// 添加订单
public bool addOrder(AddOrderInput input)
{
   if(_orderRepository.GetExist(input.OrderId)){ throw Exception("订单号已存在")};
   _orderRepository.AddOrder(new OrderMaster(){ ... });
}

后来,有个团队希望能够通过CRM生成订单,张三于是添加了方法:

// 添加Crm订单
public bool addCrmOrder(AddCrmOrderInput input)
{
   var order = new OrderMaster(){ ... };
   order = this.ConvertCrmOrder(input); // 转换CRM订单为后台订单模型
   this.addOrder(order); // 调用上方方法
}
// 转换模型
public AddOrderInput ConvertCrmOrder(AddCrmOrderInput input);

然后,产品修改需求,CRM的订单存在子单多插入,要求你针对这个来源不用卡控单号唯一。
于是,张三开始修改addOrder方法:

public bool addOrder(AddOrderInput input)
{
   if(input.Source != SourceEnum.Crm && _orderRepository.GetExist(input.OrderId))
   { 
   	  throw Exception("订单号已存在")
   };
   return _orderRepository.AddOrder(new OrderMaster(){ ... });
}

我们很容易看出,input.Source != SourceEnum.Crm 这行代码已经对addOrder构成逻辑侵入。
但现实这是高速实现需求的最快途径,因为产品要求让张三一分钟改完上线。

然后,我们又有了来自OA的订单,我们需要针对OA订单生成单号:

public bool addOrder(AddOrderInput input)
{
   if(input.Source == SourceEnum.OA)
   {
       input.OrderId = this.GeneratorOrderId();
   }
   else if(input.Source != SourceEnum.Crm && _orderRepository.GetExist(input.OrderId))
   { 
   	  throw Exception("订单号已存在")
   };
   return _orderRepository.AddOrder(new OrderMaster(){ ... });
}

然后,产品要求订单创建后,推送ESB消息到企业微信:
张三二话不说加了几行代码:

public bool addOrder(AddOrderInput input)
{
   if(input.Source == SourceEnum.OA)
   {
       input.OrderId = this.GeneratorOrderId();
   }
   else if(input.Source != SourceEnum.Crm && _orderRepository.GetExist(input.OrderId))
   { 
   	  throw Exception("订单号已存在")
   };
   var res = _orderRepository.AddOrder(new OrderMaster(){ ... });
   if (res) {
      _esb.PublishMsg(new MsgDto(){...});
   }
   return res;
}

时间慢慢推移,公司外购了一套订单系统,要求老旧系统并用一段时间。
由此张三需要同步新系统订单到老系统,但新系统订单已闭环,你不必推送消息。
此时,张三为了防止对老系统产生影响,于是就CV了一个新的方法出来:

public bool addOrder2(AddOrderInput input)
{
   if(input.Source == SourceEnum.OA)
   {
       input.OrderId = this.GeneratorOrderId();
   }
   else if(input.Source != SourceEnum.Crm && _orderRepository.GetExist(input.OrderId))
   { 
   	  throw Exception("订单号已存在")
   };
   var res = _orderRepository.AddOrder(new OrderMaster(){ ... });
   //if (res) {
      //_esb.PublishMsg(new MsgDto(){...});
   //} 注释大法YYDS
   return res;
}

然后这样对外服务:

public bool addOrder(AddOrderInput input){
	if(input.Mode == OrderMode.NewSys){
	   this.addOrder2(input);
	} else {
	   this.addOrder(input);
	}
}

张三心里乐开了花,两个理由:
我没有修改addOrder一行代码,对老系统逻辑0修改
我新系统用的全新的addOrder2方法,完全新代码

后台,因为外购系统同步订单是定时批量,并发太大,张三立马针对外购订单加上了操作锁:

public bool addOrderMain(AddOrderInput input){
	if(input.Mode == OrderMode.NewSys){
	   if (_redis.Lock(input.orderId)) {
	      try{
	      	this.addOrder2(input);
		  } finally {
		  	_redis.releaseLock(input.orderId);
		  }
	   } else { 
	   	 throw new Expeption($"订单{input.orderId}正在添加")
	   }
	} else {
	   this.addOrder(input);
	}
}

然后,外购系统要求张三提供一个add接口供他们调用,外部提供的信息里并没有mode信息,张三于是又开始了新的创造:

public bool addOrderMain2(AddOrderInput input){
	 if (_redis.Lock(input.orderId)) {
	      try{
	      	this.addOrder2(input);
		  } finally {
		  	_redis.releaseLock(input.orderId);
		  }
	 } else { 
	   	 throw new Expeption($"订单{input.orderId}正在添加")
	 }
}

随即,产品觉得需要在添加订单时有一条日志,张三于是在addOrder3加了日志:

public bool addOrderMain2(AddOrderInput input){
	 if (_redis.Lock(input.orderId)) {
	      try{
	      	this.addOrder2(input);
	      	this.addOrderLog(input);
		  } finally {
		  	_redis.releaseLock(input.orderId);
		  }
	 } else { 
	   	 throw new Expeption($"订单{input.orderId}正在添加")
	 }
}

随后,张三被提了bug,因为发现同步订单addOrderMain没有加日志
张三于是干脆直接手起刀落,直接在addOrder2里加了日志:

public bool addOrder2(AddOrderInput input)
{
   if(input.Source == SourceEnum.OA)
   {
       input.OrderId = this.GeneratorOrderId();
   }
   else if(input.Source != SourceEnum.Crm && _orderRepository.GetExist(input.OrderId))
   { 
   	  throw Exception("订单号已存在")
   };
   var res = _orderRepository.AddOrder(new OrderMaster(){ ... });
   if (res) {
      //_esb.PublishMsg(new MsgDto(){...});
      this.addOrderLog(input);
   }
   
   return res;
}

然后,测试又提了bug,来自外部调用的订单日志重复了
张三一看,addOrderMain2和addOrder2似乎重复写了日志,蓝瘦香菇。
于是,张三干脆加了个判断:

public bool addOrder2(AddOrderInput input, bool isMain2)
{
   if(input.Source == SourceEnum.OA)
   {
       input.OrderId = this.GeneratorOrderId();
   }
   else if(input.Source != SourceEnum.Crm && _orderRepository.GetExist(input.OrderId))
   { 
   	  throw Exception("订单号已存在")
   };
   var res = _orderRepository.AddOrder(new OrderMaster(){ ... });
   if (res) {
      //_esb.PublishMsg(new MsgDto(){...});
      // 如果不来自addOrderMain2就不加日志防止重复加
      if(isMain2){
      	this.addOrderLog(input);
      }
   }
   
   return res;
}

然后:

public bool addOrderMain2(AddOrderInput input){
	 if (_redis.Lock(input.orderId)) {
	      try{
	        // 外部订单,加日志
	      	this.addOrder2(input, true);
	      	// this.addOrderLog(input);
		  } finally {
		  	_redis.releaseLock(input.orderId);
		  }
	 } else { 
	   	 throw new Expeption($"订单{input.orderId}正在添加")
	 }
}

再然后:

// 同步订单,不加日志
public bool addOrder(AddOrderInput input){
	if(input.Mode == OrderMode.NewSys){
	   this.addOrder2(input, false);
	} else {
	   this.addOrder(input);
	}
}

故事还没走完,我们向上看代码,此时添加订单的逻辑已经变得异常臃肿,通过不断的嵌套调用,内外参数传值分流逻辑已经变得难以维护。

然而张三不服,他说他的方法通俗易懂,像流水账一样从上到下往下看就行了,没有任何结构性理解成本。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值