聊聊程序员做编程设计--API设计

0x01 缘由

    最近,时间比较充裕,对几个行业和公司等相关进行了简短的思考。今天开始整理一些方法论。C/C++程序员如何做设计。以前在产品规划前也尝试过去做相关的设计,但很多场景是根据竞品进行需求提炼,然后编写需求规格说明书,然后做详细的设计,然后就把任务下发了,这样做的结果是下面的程序员和我都没有进行源码级相关设计。需求分析过程也不规范,大部分时间是领导的意图,然后按照领导的意图去实现某个功能。存在很多不规范的地方,导致积累了很多的技术债务,到最后就要面对重构或维护。最终的结果,团队解散。
    在偿还技术债务过程中,领导采用了两种方式:演进式、革命式。
    演进式:设计一个包含所有需求的系统,然后迭代重构现有系统直到满足要求。
    革命式:丢掉旧代码,然后从来开始设计,实现一个全新的系统。
    最终,我们的结果是,投入大量的人力和财力,采用演进式的系统越做越不稳定。采用革命式的,被一些老系统和产品新需求所拖累,导致无法专注设计。最终结果.......
    出现以上的原因:团队成员不断的变化,没有规范的设计和文档记录导致积累大量的技术债务。当技术债务达到一定程度无法偿还时,就出现了崩塌。

0x02 API设计

    好的API设计是确定一个稳定的能够解决问题的逻辑接口。设计良好的API的相关步骤如下:
    收集功能性需求;
    创建用例;
    梳理API设计元素;
    架构设计;
    类的设计;
    函数设计;

0x03 结合理论与实践中的情况阐述

    1、收集功能性需求

    收集功能性需求,维护功能性需求,管理功能性需求。
    理论情况:
    要实现好的软件设计,第一步就是理解软件真正需要做的是什么。收集业务需求、功能性需求、非功能性需求。
    功能性需求:我们要做什么
    收集功能需求的方式:直接与你客户合作完成。面谈、会议、调查问卷的形式向用户提一些问题。问题领域与领域思维模式,这个概念mark。
    非功能性需求:性能、平台兼容性、安全性、可伸缩性、灵活性、易用性、并发性、代价。
    功能性需求规定了API如何表现。
    实际情况:
    领导一个点子,开干,做竞品分析。结果......
    功能性需求文档:简单、易读、清晰、可验证、无开发术语。相当于一个完全不懂技术的人描述他自己想做的事情,

    2、创建用例

    用例基于API与用户或其他软件的交互来描述API的行为。用例本质上是功能性需求的一种形式,它明确地捕获了“谁出于什么目的使用API做了什么”这类问题,而不是简单地提供一些特性、行为或实现说明的列表。聚焦于用例有助于从客户的角度设计API。
    开发用例:识别系统所有的参与者以及他们扮演的角色、识别每个角色需要完成的所有目标。
    每个用例都应该使用问题域中的词汇用浅显的语言写出来。
    用户故事:用户故事是敏捷开发过程中一种从用户那获得最小需求的方法。
    用户故事模板:作为【某个角色】我想【什么事情】这样可以【获得什么好处】。
    INVEST: 独立性、可协商、有价值、可评估、短小、可测试。
    实际情况:此步跳过

    3、API设计元素

    对问题领域进行合理抽象,然后设计相应的对象与类的层次结构来表达抽象。
    (1)对象层次结构
        描述系统中不同的对象如何合作。
    (2)类层次结构
        描述共存于关联对象之间的公共结构和行为。它会处理对象属性的泛化与特化。
    实际情况:程序员自己爱咋干就咋干

    4、架构设计

    软件架构描述了一个完整系统的很粗糙的结构:API中顶层对象的集合以及他们彼此之间的关系。通过架构的开发,你会增加对系统中不同组件抽象的理解,也能更好地理解组件之间的通信和彼此合作。
    如何开发架构?
    (1)分析影响架构的功能性需求;
    (2)识别架构的约束并加以说明;
    (3)创造系统中的主要对象,并确认他们之间的关系;
    (4)架构的交流和文档;
    识别主要抽象?
    一旦完成了对系统的需求和约束的分析,就为开始构建高层对象模型做好准备了。本质上讲,这意味着识别问题域中的主要抽象,并将其分解成相互关联对象的层次结构。通过基于问题域中的实际概念来设计架构,你的设计应该对未来的需求变化保持一般性和健壮性。---参考优秀设计
    创建关键对象?
    API的关键对象并不容易识别,请尝试从不同的角度看待问题,并不断迭代和完善你的模型。
    自然语言:通常名词表示对象,动词表示函数,形容吃和所有格名词表示属性。
    属性:根据属性进行分类的技术,是将具有相似属性或特性的对象分为一组。
    行为:这一方法根据对象之间共同的动态行为来分类。
    原型:对于最初识别的对象,我们尝试通过这种方法识别其更一般的原型。
    领域(Shlaer-Mellor分类法):对系统进行水平划分,创建一些通用的领域,然后通过对每个领域的独立分析再对这些领域进行垂直划分。
    领域(Neighors分类法):发现问题领域中的所有应用共享的类和对象的技术。通过对问题领域中相关系统的分析。
    领域(Evans分类法):领域驱动设计。
    架构模式?
    架构模式对整个系统更大规模的结构和组织的描述:
    结构化模式:分层模式、管道与过滤器模式、黑板模式。
    交互式系统:模型-视图-控制器模式、模型-视图-表示器模式、表示-抽象-控制模式。
    分布式系统:C/S模式、三层模式、点对点模式、代理模式。
    自适应系统:微内核模式与反射模式。
    架构的交流?
    开发除架构后进行文档化,架构文档化都是将设计传达给工程师的重要因素。通过这种交流可以向工程师提供更多信息,让他们根据你的设想去实现系统,也能确保未来的改变能技术保持架构的原来的目标和完整性。如果开发团队规模很大,或开发人员分布在各处,那交流更为重要。
    在API的附属文档中要描述其高层架构并阐述其原理。
    类的设计?
    创建类时,我们需要考虑很多因素。正如Scott Meyers所言,创建一个新类涉及定义一个新类型。因此,你应该讲类设计当作类型设计来对待。设计类时,可以参考如下建议:
    继承的使用。将这个类添加到现有继承层次结构中是否合适?应用使用共有继承还是私有继承?应该支持多重继承吗?这会影响到哪些陈源函数应该设置为虚函数。 继承主要是代码复用和多态。
    组合的使用。相对于直接使用继承,将一个关联的对应用做数据成员是否更为合适?
    抽象接口的使用。打算将该类设计为抽象基类以使子类重写哥哥纯虚成员函数吗?
    标准设计模式的使用。能否在类的设计中使用众所周知的设计模式?使用设计模式能够从前人深思熟虑的、精妙的设计方法学中获益,也使设计更容易被其他工程师使用。
    初始化和析构模型:对象的创建与删除是让客户通过new和delete实现,还是用工厂方法管理?是否要为自己的类重载new和delete定制内存分配行为?要使用智能指针吗?
    定义复制构造函数和赋值操作符:如果这个类中分配了动态内存,那么这两个都需要定义。这会影响对象的复制和按值传递等行为。
    模板的使用:
    const与explicit的使用。尽可能将参数、返回值和方法定义为const。对于单参数构造函数使用explicit关键字以避免意外的类型转换。
    定义操作符。
    定义类型转换操作符。
    友元的使用。
    非功能性约束。
    几个设计原则:
    Liskov替换原则:如果S是T的子类,那么在行为上S类型的对象不需要修改即可替换T类型的对象。
    开放-封闭原则:类的目标应该是为扩展开放,为修改而关闭的。这意味着类的行为的修改可以在不改变现有源代码的情况下进行。
    迪米特法则:每个组件对其他组件都只有有限的知识,甚至只知道与其紧密相连的组件的知识。对类的设计指导为:
    调用同一个类的其他函数;
    在同一个类的数据成员上调用函数;
    在它创建的任何局部对象上调用函数;
    在全局对象上调用函数(但是你绝不应该有全部变量);
    迪米特法则指出,你应该只调用自己类或直接相关对象的函数。

0x03 总结

    有了这些理论做指导,希望在今后的工作中,能给自己一些方法的指引。
    
    
    
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值