一、写作概述 |
最近比较平静,没有太多的思绪,为此不想多说一些话了。记录下这篇文章,完全是临时起意而有所感。
我曾做过应用端开发,也做过底层库相关的工作,甚至两者的角色也同时担任过。此篇文章可能会存在一种对底层库的工程师“不太友好”的评价,实际上我也只不过是在调侃工作上的不容易而已,并非针对某一个角色。请勿过多解读。
只是这些问题,也的的确确时常存在的。
二、对接项目的问题与分析 |
在开发过程中与底层库程序员的对接项目,他们往往做不到“专业”的水准:
底层库的接口跟应用不兼容 |
如果你曾经有遇到过这种情况:当你好不容易把该做的事情都做好了之后,结果到了对接底层库的关卡点,就出现了一堆问题。
或许你会发现底层库使用的环境以及提供的库版本,跟应用程序的有所不同。当然,如果你们所需的库版本号不相同也不是很大的问题,只要替换一个跟底层库相同的版本号,然后配置好环境就能很快解决掉。如果是对方的编程语言跟你不一样,人家用的是 C++ 编写的,而你使用 C# 写的,那问题也不是很大,幸好C# 也可以很好地处理 C++ 库。
但最糟糕的是,如果人家用的是 python 写的,而你用的是其他语言编写的,那么对语言的兼容性就加大了困难和工作量。因为你需要配置 python 环境,而有些第三方库也同样需要 python 支持的才行。其次,你还需要在中间层进行不同语言之间沟通的桥梁,并且在发布软件时还要打包好 python 依赖库。这时候,你会遇到更多的问题。
举例:
在开发一款图像处理的软件,张三负责开发图像处理的底层库,而李四负责把图像处理的功能运用在应用端。
张三和李四都确认好了功能需求之后,就各自埋头苦干。
等到了项目需要对接底层库的时候,张三和李四手里的工作也基本完成了。张三将自己的库发给了李四,李四将库被引用到了项目当中。
结果一运行,就报出了错误“缺少xxxx”。
经过排查,发现两者用的版本号不一致。于是李四就找了张三要了相同版本号的库替换了原来的。
李四再运行程序,结果直接干崩溃,没有任何提示。
这时李四很有可能以为环境没有配置好。于是仔细检查了一遍,经过确认环境并没有问题。
折腾了一段时间,李四发现张三提供的库是 Release 版本的,而自己是在 Debug 环境下运行的。
于是再向张三要了 Debug 版本的库。
李四再重新运行了一遍程序,结果又报错 “无法解析外部符号.....”。张三劝说李四应当再重新检查一下应用的环境有没有问题,
库有没有真正被引用到。当然这些都做了无用功,这一折腾就浪费了半天的时间。
实在没办法了,李四请求张三提供一个完整的 Demo 给他参考一下。当然张三的 Demo 能正常运行,而李四的应用还是报错。
李四又排查了半天时间,终于发现项目属性中多线程调试的选项跟张三的不一样。李四调整了之后,应用程序终于能正常运行了。
以上还只是最简单的问题,也是常有发生的情况。出现这种情况,一般就是你们在进行开发工作之前,各干各的,并没有确切地沟通确认好彼此所使用的开发工具和环境。等到需要提供接口的时候,你们才发现这些问题。
缺东缺西 |
他们或许是为了图方便,亦或者沉浸在自身所处的编码环境里走不出来而考虑欠缺。不过后者的可能性更大。于是他们提供的接口,要么缺少头文件,要么缺少系统库,缺少完整的接口文件。
缺少东西有两种:
1、缺头文件、缺系统库,缺少完整的接口文件。
在你第一次对接的时候,底层库工程师一般会给足你一些头文件。但是当底层库进行迭代修改之后,他们需要重新发一份给你时,却常常会忘记把更改的头文件给你。于是你运行之后,又报出了错误 “无法解析外部符号…”。
对于缺少系统库的问题,他会跟你一起去排查,然后哦了一声,说自己忘记提醒你还没有安装配置啥啥环境。于是让你先配置好,却又不说需要哪个版本的系统库。要是你不问问的话,光自己随意选用版本号的库来进行安装配置,结果应用提示你所引用的版本号不对,不受支持。
你再向张三询问原因,然后张三又”哦!“了一声,你就已经筋疲力尽了。
底层库工程师在这些方面做的不够“专业”的方式就是:你反馈缺少一个东西,他们就补发一个。你再提一个他再补一个。你不提的话,他们似乎永远都不会提供完整的东西出来。
2、缺少技术说明。
底层库需要依赖什么样的技术支持。有些细心的人,他会跟你好好讲讲应用端也要有哪些技术支持才能正常使用,并且会专门写一堆文字或者文档给你,需要注意些什么。但是现实中有太多“不够细心”的人了,二话不说马上给你提供接口,却不做任何解释,让你自己去摸索。所以需要一份技术说明实在太重要了。他不主动提出来,你作为应用端程序员,就更要主动跟他要点说明好。因为对接好项目,这是你的工作。
对外开放接口过于繁杂。 |
这方面取决于他们的处理方式,这种情况比较少见。但是如果你运气不好,碰到“不够专业”的接口封装方式,这将会长期影响到你的开发进度和代码质量。
他们提供的接口太混乱,设计代码结构很不合理。因为提供给外部头文件和外部实例类型太多了。一个功能模块,本就应当只提供一两个头文件和一种实例就足够了。由于应用端根本就没法清楚底层的实现逻辑,如果接口太多的话,反而用起来不方便,也容易出错。
举例:
编写一个视频显示接口,张三为此做了这样的接口设计:
显示视频接口:
Video.h
字幕接口:
Captions.h
特效接口:
SpecialEffects.h
清晰度接口:
Clarity.h
...
...
应用端使用时,需要:
创建 Video、Captions、SpecialEffects、Clarity...
初始化 Video->InitVideo、Captions->InitCaptions、SpecialEffects->InitSpecialEffects、Captions->InitClarity...
显示 Video->Show、Captions->Show、SpecialEffects->Show、Captions->Show
修改属性等 Video->SetVideo、Captions->SetCaptions、SpecialEffects->SetSpecialEffects、Captions->SetClarity...
释放资源 Video->close、Captions->close、SpecialEffects->close、Clarity->close...
...
...
从以上的例子看出来,应用端需要的工作太多了。使用一个显示视频接口,还要自己创建各种实例,分别对各实例进行出初始化修改等,然后逐一释放每一个实例。这样的方式不但增加了应用端的工作量,还会容易出现各种错误,比如可能会产生多个相同的实例,会被其他功能的代码逻辑干扰,难以管理显示接口的内存等等。
对于以上的设计,我们就要尽量控制住接口的头文件和实例的个数。假设以下做一个合理的接口设计:
显示视频接口容器:
VideoContainer.h
应用端使用时,需要:
创建一个容器 VideoContainer。如果指定某些实例创建:VideoContainer->Create(Model model);
初始化:VideoContainer->Init(Args args)。Args 需要修改的参数。
显示 VideoContainer->Show(Model models);
修改属性:VideoContainer->SetAttribute(AttributeType type,Value value),或者VideoContainer->SetCaptions(Args args);
释放资源
VideoContainer->close
特点:
全程只使用一个实例 VideoContainer 来管理显示视频的接口
转载请标明出处。。。请不要将我的文章 “标为原创” 来发表到自己的博客里,更不要把我之前辛辛苦苦所写的文章,以谋取推广费之类的利益。原创很费时间和精力,创作不易。
我只不过是很普通的打工人,希望跟大家一起进步。谢谢!