热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

如何摆脱烂项目的纠缠

有没有这样觉得,以前做过的,刚做完的,或者正在做的项目,简直就是狗屎,不想去维护,不想去看以前写的代码?如果有,那么我们可以继续下面的内容。分析一下原因,项目为什么会烂,从纯技术上去看无非有以下两个问题:项目架构烂,代码质量差。

有没有这样觉得,以前做过的,刚做完的,或者正在做的项目,简直就是狗屎,不想去维护,不想去看以前写的代码?如果有,那么我们可以继续下面的内容。

分析一下原因,项目为什么会烂,从纯技术上去看无非有以下两个问题:

  • 项目架构烂
  • 代码质量差

下面我们各个击破,分别说说我的一些愚见。项目架构往往是项目经理,架构师,团队中技术较好程序员,或者呆公司较久程序员的事,由于对架构的理解不同,做事方式不同,项目的周期不同,技术选型不同,所以架构也就形形色色,但以我看来较鲜明的也就是较为守旧的数据库先行,和时下流行的领域驱动。这两者有明显的区别,我觉得后者在架构上更有优势,前者在开发周期上更有优势,而且不需要很多前期设计,但是优雅程度远不及后者,但在外包公司或者遇到很急的预算不多的项目往往会选择前者。

数据库先行架构的一般流程:

  1. 需求分析
  2. 设计数据库
  3. 编写或使用工具生成实体类(DTO)
  4. 编写逻辑

领域模型架构的一般流程:

  1. 需求分析
  2. 分析业务,整理领域对象,划分对象之间关系(理出聚合根)
  3. 为领域对象写行为

两者共同点:都可以采用AOP,面向对象,设计模式来提升程序的可维护性,但后者面向对象的味道更浓,从架构上讲有先天的优势。

数据库先行给项目带来的问题

1. 由于依赖数据库,团队中多数人更喜欢写sql,写sql不是坏事,但是太多的sql,甚至逻辑都采用写sql去处理,势必造成可维护性降低,原因如下:

  • sql先天性决定,sql没有面向对象的概念,这意味着,它的抽象层次较低,流程式的代码很难做到高维护性,高封闭性,很多相同逻辑的代码需要重复写在不同的存储过程里面,虽然可以提炼到函数或者另外的存储过程中,但那是个不容易的事。
  • 既然很多逻辑写到数据层面,那比如时间的处理,数据的转换,验证,错误的处理,很大程度也都依赖数据库,很明显,数据库相对于面向对象的语言并不擅长。这样做几乎让项目的可维护性降到最低。
  • 缺少或薄弱的现代IDE的很多编码优势,如智能提示,编译期纠错,这一点使可测试性大大降低,你甚至很难做单元测试。

当然优点也有,那就是易于发布和性能会略高一筹。 

2. 较好的方式,是把逻辑写到代码里,数据库只用来持久化数据,这里又有两种风格

  • 使用ORM,sql为框架生成,这种方式普遍,好处是有成熟的ORM框架(如EF,NHibernate等)帮我们生成Sql,我们省去了在代码里写Sql造成如,可维护性低,被sql注入的风险,且能享受代码智能提示,编译期纠错等待遇。
  • 写存储过程,这里与上一点的不一样,这种方式只是将CRUD操作写成存储过程,逻辑写代码里,这种方式的优点是利于发布。缺点是要手动写实体类和存储过程,不过我们可以使用工具生成。

数据库先行的优点

  • 架构没什么复杂性,容易被团队成员理解,容易交流
  • 开发周期短,成本低

说说领域模型,它更像是一种思考问题的方式,它的出现就是为了为软件开发提供一个切实可行的指导思想,里面包含太多思想,包括软件开发原则,OO思想,解决问题的思路,如何易于测试,AOP,等,感兴趣的朋友可以去系统的学习一下,会有收获的。

以上是架构上的问题,如果你有空间和时间建议你的考虑了顺序为:

  1. 领域驱动
  2. 数据库驱动,采用ORM,逻辑写程序

其他方式慎用。

回到开篇,再来说说如何写出优雅的代码,其实这是一个累积的过程,当然前提是你在进步,进步是因为你意识到自己写的代码不够优雅打算改进而采取学习和重构的结果。所以当你觉得代码烂的时候,不要放弃,不要破罐子破摔,重构吧。既然要重构,就得找到需要重构的代码,我能想到的烂代码有:

1. 过长的方法

这里是指,方法内容太长,发生这种情况,往往是封装不好的结果,往往在一个方法里去实现一个业务,而这个业务其实可是拆开到不同的对象中去,也就是这个操作不够原子性,举个例子,人喝可乐这个需求,业务流程应该是这样:给人一瓶可乐,人需要打开瓶子然后喝到不渴为止。

伪代码如下:

public class Person
{
	pubic void Drink(Bottle bottle)
	{
		if(bottle == null)
			 bottle = new Bottle();
		if(cola.Capacity <=0)
			 throw new Exception("没有可乐");             
		
		if(!bottle.IsOpen)
		 {
	         this.LeftHand(bottle); //左手拿瓶子
	             this.RightHand(bottle.Kou);//右手拉环
			  this.pull();//拉开
		 }
		 var needCapactity = xx+yy-zz;  //
		  while(cola.Capacity <=needCapactity )
		  {
				cola.Capacity--;
				cola.Refresh();
				this.ColaCapacity++;
				this.Refresh();
	      Thread.Sleep(1000);
		  }
	}  
}

当然这段代码并不长,只是为了说明方式,看得出来,这里的问题有,验证逻辑,获取需要喝的容量,开盖的方式都写到里面。

2. 硬编码的字符串和数字

if(age>50)
if(city.ToLower()=="shengzhen")

3. 职责不分明的类

4. 重复的代码

其实提高代码的重用,有几个途径:

  • 继承
  • 工具方法
  • 使用委托

前两点都很容易理解,说一下这一点,举个DataContext事务的例子。

using(var cOntext= new DataContext())
{
     context .BeginTransaction();
     try
    {
      context.User.GetUser();
      context.User.add(new User{name="xian"}); 
      context.User.add(new User{name="hong"});
      context.Commit();
   }
  catch
  {
     context.Rollback();
  } 
}

以上代码很常见吧,是不是每个使用事务地方都需要这么写,其实这个时候我们可以利用委托来实现。

public class DbInvoker
{
	public void Transaction(Action aciton)
	{
		using (var cOntext= new DataContext())
		{
			context.BeginTransaction();
			try
			{
				aciton(context);
				context.Commit();
			}
			catch
			{
				context.Rollback();
			}
		}
	}
}

以后用到事务的地方这样调用就行了。

DbInvoker.Transaction(cOntext=>{
      context.User.Add(new User{name="xian"});
      context.User.Add(new User{name="hong"});
});

是不是方便了许多?

5. 意义不准确的命名

6. UI与逻辑隔离差

这个最典型的我觉得就是比如在做WEB时,用MVC框架,却在后端网前段输出js的引用,或者长篇js,客户端的东西了。

我就不一一举例子了,最后说一句,优秀的开源项目要多看,感谢你的阅读。

本文地址:http://www.nowamagic.net/librarys/veda/detail/2305,欢迎访问原出处。


推荐阅读
  • 前言无论是对于刚入行工作还是已经工作几年的java开发者来说,面试求职始终是你需要直面的一件事情。首先梳理自己的知识体系,针对性准备,会有事半功倍的效果。我们往往会把重点放在技术上 ... [详细]
  • 本文深入探讨了SQL数据库中常见的面试问题,包括如何获取自增字段的当前值、防止SQL注入的方法、游标的作用与使用、索引的形式及其优缺点,以及事务和存储过程的概念。通过详细的解答和示例,帮助读者更好地理解和应对这些技术问题。 ... [详细]
  • 本文详细介绍了MySQL数据库中的Bin Log和Redo Log,阐述了它们在日志记录机制、应用场景以及数据恢复方面的区别。通过对比分析,帮助读者更好地理解这两种日志文件的作用和特性。 ... [详细]
  • 本章详细介绍SP框架中的数据操作方法,包括数据查找、记录查询、新增、删除、更新、计数及字段增减等核心功能。通过具体示例和详细解析,帮助开发者更好地理解和使用这些方法。 ... [详细]
  • 本文介绍了一个基于 Java SpringMVC 和 SSM 框架的综合系统,涵盖了操作日志记录、文件管理、头像编辑、权限控制、以及多种技术集成如 Shiro、Redis 等,旨在提供一个高效且功能丰富的开发平台。 ... [详细]
  • SpringMVC RestTemplate的几种请求调用(转)
    SpringMVCRestTemplate的几种请求调用(转),Go语言社区,Golang程序员人脉社 ... [详细]
  • 配置PHPStudy环境并使用DVWA进行Web安全测试
    本文详细介绍了如何在PHPStudy环境下配置DVWA( Damn Vulnerable Web Application ),并利用该平台进行SQL注入和XSS攻击的练习。通过此过程,读者可以熟悉常见的Web漏洞及其利用方法。 ... [详细]
  • docker镜像重启_docker怎么启动镜像dock ... [详细]
  • 在寻找轻量级Ruby Web框架的过程中,您可能会遇到Sinatra和Ramaze。两者都以简洁、轻便著称,但它们之间存在一些关键区别。本文将探讨这些差异,并提供详细的分析,帮助您做出最佳选择。 ... [详细]
  • 本文详细介绍了MySQL中的存储过程,包括其定义、优势与劣势,并提供了创建、调用及删除存储过程的具体示例,旨在帮助开发者更好地利用这一数据库特性。 ... [详细]
  • 本文探讨如何利用Java反射技术来模拟Webwork框架中的URL解析过程。通过这一实践,读者可以更好地理解Webwork及其后续版本Struts2的工作原理,尤其是它们在MVC架构下的角色。 ... [详细]
  • 本文将详细介绍如何在ThinkPHP6框架中实现多数据库的部署,包括读写分离的策略,以及如何通过负载均衡和MySQL同步技术优化数据库性能。 ... [详细]
  • 掌握Spring MVC中自定义类型转换与格式化的技巧
    近期,在开发一款小程序的过程中遇到了几个Spring MVC接口需要传递时间参数的问题。本文将详细介绍如何利用Java 8 Time API在Spring MVC中实现时间参数的自定义类型转换和格式化。 ... [详细]
  • 本文详细列举了软件开发中常见的功能测试要点,涵盖输入框、搜索、添加/修改、删除、文件上传下载等多个方面,旨在帮助测试人员全面覆盖测试需求,确保软件质量。 ... [详细]
  • 本文介绍了Java语言开发的远程教学系统,包括源代码、MySQL数据库配置以及相关文档,适用于计算机专业的毕业设计。系统支持远程调试,采用B/S架构,适合现代教育需求。 ... [详细]
author-avatar
舞动青春的迪斯科舞厅
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有