• 系统设计之编码概述


    2017-2-14

    一、编码概述
    “编码”是企业应用中很重要、也很常见的一个概念。在业务系统中,对几乎所有的处理对象,都赋予一个唯一的代号,就像人的身份证号一样,表示唯一的一个业务对象。具体讲,比如公司代码,部门代码,员工代码,物资代码,科目代码,运输方式代码,发票编号,订单编号,报表编号,功能编号。等等。上面说了很多,几乎涵盖了业务系统中的从基础数据、到业务单证,到系统管理的方方面面,可见,在系统的每个层次、每种角色,都要与编码打交道。
    同上,以上也提到了常见的业务对象,如公司,部门,科目,发票,报表等等。每个业务对象的属性都很多。业务对象存放在数据库中,属性以列的方式存在(一般关系型数据库),当然,编码(以后我们统一称为编码,不使用代码这个名词了,这个名词有歧义,有更广泛的含义和用途)也是业务对象的一个属性,而且是很重要的一个属性。根据编码,我们可以唯一定位一个业务对象。编码就是业务对象的身份证,标签。
    二、如何编码
    如何编码包括,编码格式(使用数字,还是字母,还是允许特殊符号),编码长度,编码码段的含义。具体如何编码需要考虑实际的业务场景。这里就几个原则进行说明。
    1. 编码符号。可以使用 数字,字母 以及数字字母的组合。如果使用字母的话,最好不要区分大小写。采取字母的一个缺点就是数据库检索的时候,要考虑字母的大小写的问题,否则可能检索失败。编码也可以采用除数字字母这之外的其他符号,比如减号(-),下划线(_)。其他特殊符号、汉字就极少采用了。
    采用哪些符号,主要是考虑输入方便的问题,如果代码不需要输入或者很少输入(比如订单编号,极少人会根据订单编号去查找一个订单),就可以采用字母或者特殊符号。数字是最容易是输入的符号,因为数字不区分大小写,而且键盘上一般有专门的数字小键盘。熟练后,可以很快输入。
    2. 关于长度,考虑实际的编码的容量。容量是只编码允许的最大数量。比如2位的纯数字编码,最多容纳100个,00-99。在满足编码容量的基础上行,不要太长,否则不容易记忆,尤其是一些经常需要输入的编码,比如物资编码,部门编码等等。
    3,对一些系统自动生成、不需要输入的代码,可以适当长一些,比如guid就很长,可以作为唯一的代码来使用。
    4,编码不要使用 0 打头 ,因为在excel中,如果数据格式设置不对的话,0很可能给自动去掉了。因为excel会将纯数字串,自动作为数字来处理,0自然就给去掉了。
    5,编码是否需要体现业务含义。
    一般不建议。有时候,用户希望能将业务u对象的某些属性体现在编码中,这样通过编码就可以知晓对象的某些属性,比如我经手的一个收费项目,在确定住户编码规则时,业务组强烈要求在住户编码中将小区编号,楼栋号和门牌号放到编码中,比如 10小区的9栋楼1单元12号的编码为10090112。因为他们希望通过编码就能看出住户的地址,并且他们老系统就是这样编码的。技术组采纳了这个建议,但是后来带来一系列的麻烦,就是一旦创建了住户,那么住户的楼栋号就不能修改了,否则编码和楼栋号就不一致了。再上线初期,由于基础数据准备的有缺陷,导致大量的用户需要删除重建,就是因为地址搞错了。因此这里建议,编码最好是无意义的,不要包含任意的业务属性在里边。(注,GRG,20190428:纠正下,在上面的场景中,在编码中包含楼栋号是有意义的,首先好记,其实最重要的是,楼号,小区号是稳定的,基本上是不变的,之所以提到的数据错误,是另外一码事情,要解决这个问题,系统可以提供编码变更的功能)。业务含义可以通过对象的属性来表示。比如物资对象有物资名称,规格型号,分类,厂商等。这些属性放在物资编码中就不合适。因为这些属性是易变的。如果非要坚持,也只能考虑那些不变的属性。否则属性发生了变化,编码就要变。
    还有一种表单编码,很多客户希望能体现表单类型,日期等属性,比如订单,DJ202101100001,表示2020年1月份10号的订单。这个可以理解,但是一定不要用这个编码做关键的业务判断(比如根据订单编码来确定订单生效日期),只可以作为“大概”,“差不多”的视觉视觉就OK了,或者用在不是很严谨的查询中(根据订单号,查询每天的订单量)

    6,编码的自动生成与其他规则。
    在系统实现时,一旦定义好了编码规则,系统最好能根据编码规则自动生成编码,而不是让用户手工去输入。当然数据迁移类项目例外,因为这种项目需要保持新老系统的编码的一致性。一般自动生成使用流水号。系统自动记录某类业务对象的最大流水号,在创建时,自动加1。
    有时候用户可能希望编码中体现日期属性,这一般出现在业务单据编码上,比如订单编码,用户一般希望能以一下格式自动生成:YYYYMM+流水号。对这种稳定不变的编码可以采用这种方式。
    7,编码是否可以重复
    前面讲过了,编码作为业务对象的唯一标示,自然不允许重复,否则,两个对象具有同样的编码,怎么区分呢。如果编码容量足够大,这不是问题。但是凡事都有例外,如果编码容量有限,而系统的生命周期又很长的话,多达几年甚至更长,编码容量可能会用尽,就像千年虫一样,本质上就是编码容量不够了,怎么处理了。编码唯一值相对的,是相对与一定的时间期间,比如我们可以定义一年内编码不能重复,这样通过将编码+年度两个属相一起也能唯一确定一个业务对象。比如sap的凭证编号就是这样的处理机制,一年一循环,今年的凭证编号与去年的肯定有重复的。但是这种处理方法,只使用与动态业务数据,对生命周期比较长的,比如物资编码类的,在系统生命周期之内,必须保持编码的唯一性。
    8,组织机构编码
    特别拿出组织结构编码来讨论下,组织机构编码在企业信息化系统中是最重要的一个编码之一,因为任何一个企业都有组织机构,人都属于组织机构,业务的发生也是隶属于每个组织机构的。组织机构往往是分级的。这样组织机构的编码就要体现处分级,这里只是简单印出来,组织机构的进一步讨论有专门的章节。
    9,登录账号编码
    这个也是每个系统都有的。登录账号编码可以使用多种方式,一般村数值的用的比较多,固定一个长度,比如5位,10001.10002,这样一次编码。另外一个思路是,使用用户的姓名缩写,这样的有点是好记。使用姓名缩写的一个弊端就是,有可能存在重名的用户。尤其是企业很大的,员工很多的集团新企业,存在重名的可能性太大了,解决方法,1是使用 姓全拼,名简拼,比如诸葛亮的账号就是 zhugl,张飞的就是zhangf。再就是使用姓名全拼,zhugeliang,zhangfei,但是这样也不可避免同音重名,这样只能通过在后边加上序号了,比如张飞,张峰,分别编码为 zhangf,zhangf2。也可以加上身份证后4位来区分。根据个人身份(姓名和身份证)创建账号的方式的优点是,用户本人很容易知道自己的账号,而不需要特别通知。原则就是容易记忆,也能处理重名的问题。
    三,编码的生成
    一旦定义好了编码规则,系统最好能根据编码规则自动生成编码。一般编码中会有流水号,这样系统可以记住每个业务对象的最大流水号,自动加1,形成最终的数据编码。一般来讲,不同的业务对象采用独立的编码规则和流水号,这样能确保不同对象的编码不会重复。当然这不是必须的。
    前面讲过了,既然编码作为业务对象的唯一标识,编码就要唯一,不能重复。另一个角度讲,考虑到编码容量,尽量也不要浪费编码,就是不要有空着不用的编码。编码最好做到连续。
    不重复,可以通过全局流水号来控制,系统在生成编码是首先取最大流水号,然后加1,形成新的流水号。
    形成流水号的时机。通俗讲,就是说核实形成流水号的,是在界面上创建的时候,还是在确确实实保存到数据库的时候呢。如果在界面上的时候,就存在浪费流水码的问题,比如占用了一个号码,但是最后没有保存,保存时再形成就没有这个问题。其实怎么做都半斤八两,即便在新建时做到了不浪费流水号,创建的数据删除后,这个号也就空出来了。还有一个方式是插号,就是形成流水号时,检查前面时候有空的号,如果有,就直接拿过来用,否则,按照流水号的形成规则重新形成。这样做有点复杂了,如果码的容量没有这么紧张,就没必要了。这种插号的方式在实际业务中也碰到过,一个是前几年做的一个sap的接口的系统,sap的实施方中对订单号的形成做了很变态的规定,每一位的含义都给规定好了,他们为了方便出报表(根据订单号出报表),留给流水码的宽度只有3位,也就是如果只是用数字的话,最多就是1000个订单,这远远不够。后来果然出现了编码溢出的情况。这是sap实施方甩屁股走人了,留下客户傻眼了,后来找到我们,我们采取了两种措施:(1)插空,就是上面的方式,因为订单号,存在空的情况。(2)流水号,不仅仅使用数字,还可以使用英文字母,这样流水码就从10进制进化成了36进制,编码容量从1000扩充到36*36*36 = 46656,足足扩了46倍之多,完美解决了这个问题。
    最后的建议,不用考虑号码的连续性(如果没有特别要求)。

    四,编码允许修改吗
    最后一个头疼的问题,一旦编码创建后,还允许修改吗?
    这却是个难缠的问题,尽管经历过这么多项目,但是我现在还没想清楚怎么来回答这个问题。该吃饭了,我们吃完饭慢慢分析这个问题。
    为什么这是个问题?因为编码是对象的唯一标示,如果修改了,会有一下问题:
    1,已经被引用了。如果修改的话,导致引用无效
    如果考虑第一个原因,只要编码没有被使用,就可以修改。如何判断是否被引用,参见代码引用关系一节。
    还有一个变通的方法是,重新创建一个新编码,然后将原编码的状态数据(如余额数据)转到新编码。就像SAP一样,资产编码不能随便修改,因为资产编码中包含类别信息,他的做法就是重新创建一个新资产号,把资产价值等余额数据通过价值转储转到新资产上。
    2,如果没有被使用,可以修改。
    我搞错了,总不能不让改吧。尤其是系统开始使用,初始化数据的时候,这种情况尤其常见。
    3,修改后,同步修改被引用的数据。
    比如部门编码,人力资源部原本的编码是101,后来修改为1101,那么就把所有引用人力资源部编码101 的表中的字段的值,修改为 1101。

    六,内码
    对上一个问题,另外一个解决方法就是,对象除了编码之外,系统再分配一个内部编码给它,这个内部编码(简称内码)保持终生不变。内码对用户不可见,仅供系统使用。编码是可见的,可以修改,对对象的引用使用内码。这样就解决了编码调整的问题(编码想怎么该就怎么改,内码始终保持不变)。凡事有利必有弊,这样也带来了另外的一个麻烦,就是通过内码引用时,在查询时显示编码还需要根据内码关联查找,使程序变得复杂。同时也影响效率。关于内码,还有个传说,在我服务的一家公司(不妨称之为G公司吧)的时候,G公司在投标的时候,就是这个内码的概念,打败了IBM。因为当时用户就提出了一个问题,如果我的编码在使用过后变化了怎么办。IBM给出的方案就是不能变,如果确实箱变,就新建一个编码。G公司祭出内码的概念,立马忽悠住了客户。
    其实这个问题的本质就是,如何看待 内码 和 编码的关系,各是什么含义。
    如果你非要给编码附上特别的含义,那编码才有可能创建后修改的可能,否则如果仅仅是作为对象的标识,不包含任何意义,根本就不需要改,所以就没有内码和编码之争了。入库过非要加上业务含义,那我们将编码称之为“唯一特征码”,明确它的用法,这就能消除很多误会;内码恢复为id的本来面目。

    七,编码允许删除吗
    与是否允许修改类似,一旦编码使用过了,删除会带来很大的麻烦,引用的地方就找不到这个编码了,查询时, 就没法根据编码查询处编码代表的对象的其他属性(比如物资的描述)。一般的做法是将编码打上“停用标记”,停用标记后的编码,一般不可以发生任何交易,只能在查询历史数据时可以使用,在创建新的业务时则需要过滤掉,不允许使用。尚未使用的编码就没有以上的限制了,尤其是系统上线初期,经常为调整或者删除编码。有时候根据实际业务需要可以使用其他手段“停用”某个编码,如我们做的收费系统就有销户操作,这也是停用编码的一种方式。

    八,如何检查编码是否被使用
    上面说过了,如果编码被使用了就不能被删除,只能通过不使用标志来停用它。那么怎么检查是否被使用过呢?
    这个很简单了,在系统中定义编码引用关系(比如 员工表的所属部门列 引用了 部门表),通过这个关系就能检查某个编码被谁引用过。

    既然编码如此重要,在系统设计时,和实施上线时,需要对编码做好规划,编码的长度,编码的分级,编码允许的符号等等,否则上线后再调整是个大麻烦。很多系统由于前期规划不足,往往病并上线,给后来的系统维护和技术支持带来了很大工作量,也给用户带来了使用上的不便,从而导致系统实施和应用质量下降。

  • 相关阅读:
    Oracle 11g R2 常用配置与日志的文件位置
    DBA常用SQL之会话与等待事件
    SSH框架之Spring第三篇
    SSH框架之Spring第二篇
    SSH框架之Spring第一篇
    SSH框架之Struts2第三篇
    SSH框架之Struts2第一篇
    SSH框架之Struts2第二篇
    SSH框架之Hibernate第四篇
    SSH框架之Hibernate第三篇
  • 原文地址:https://www.cnblogs.com/senline/p/15420978.html
Copyright © 2020-2023  润新知