购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第3章
开发设计原则

在开发过程中,开发者需要遵守一些原则,以确保开发出高质量的应用,这些原则如下。

移植性:应用可以在不同的架构之间方便地迁移。

兼容性:应用和不同版本的系统之间需要保持兼容,避免产生不同系统之间的适配问题。

本章将介绍这些原则。

3.1 同源异构

Linux是开源的操作系统,源码的开放性使得不同的硬件架构都可以在Linux的基础上进行适配。在2020年之前,由于各自发展,x86、MIPS、ARM架构在市场上都有自己主推的发行版本,导致开发者在开发时的适配工作比较烦琐。基于减少操作系统厂商、硬件厂商和应用开发商的适配工作量的考虑,统信软件提出同源异构的工程实践,即在操作系统层进行兼容性处理,保证开发者在不同的硬件平台可以获得一致的API,也就是源码相同但硬件CPU架构不同。

3.1.1 内核适配

统信软件使用Linux 内核4.19作为长期维护内核。4.19版本的内核的主要功能特性如下。

(1)CPU:支持Intel Ice Lake,支持RISC-V,可提高NUMA模拟性能。

(2)图形系统:支持Qualcomm Adreno 600系列硬件,支持Intel Ice Lake“Gen 11”显卡。

(3)文件系统:支持EROFS(Enhanced Read-Only File System,超级只读文件系统),支持块I/O延迟控制。

(4)网络:支持CAKE队列算法,用于优化家庭网络问题。

操作系统需要保证实现不同架构下内核源码的同源,以减少内核/驱动的维护成本。

3.1.2 ABI兼容性

ABI(Application Binary Interface,应用程序二进制接口)定义了在计算机系统上使用机器码访问数据结构或者计算逻辑的方式。ABI是底层的接口,只保障使用机器码调用时的兼容性,这也意味着ABI是与架构相关的。对于不同的架构,其ABI是完全不相同的。在同一个架构上,不同的操作系统、编译器所定义的ABI也是不同的。这导致了不同系统上的程序、不同编译器编译的程序,甚至同一个编译器不同的版本所构建的二进制程序,都可能是无法兼容的。对于库开发者或者操作系统来说,需要保障系统的向后兼容性,即旧版本上运行的程序在新版本上是可以直接运行的。相对来说,应用开发者需要利用操作系统向后兼容的特性,在最低版本的系统上构建应用,这样才可能保障其在高版本系统上可以兼容运行。如果操作系统并不能保证ABI的兼容性,那么应用开发者需要做一些额外的工作来保障兼容性。在Linux发行版上,系统的开放性会导致很多发行版不能保障升级时ABI没有变化或者被删除,这时就需要应用来保障,主要手段有依赖打包和静态编译两种。

1.依赖打包

应用在发布时,通过ldd等分析应用运行时依赖的动态链接库分析工具,将应用运行需要的所有二进制文件都打包到一起,并通过LD_LIBRARY_PATH这一Linux系统环境变量来添加额外的运行依赖查找路径。也有一些开源项目能够用于对应用的依赖进行打包。例如,AppImage可以方便地对应用进行打包分发。

2.静态编译

在条件允许的情况下,可以通过静态编译来构建程序。

例如对构建的程序通过ldd来查看依赖,代码如下:

ldd dynamic-build-bin
    linux-vdso.so.1 (0x00007ffec371e000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa6f23c4000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa6f2203000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fa6f2414000)

如果使用静态编译来构建程序,那么使用ldd查看的结果如下:

ldd static-build-bin
    不是动态可执行文件

静态编译可以屏蔽依赖库导致的兼容问题,但是也无法处理所有问题。无法使用静态编译的情况:依赖库中有复杂的动态加载二进制插件的行为,操作系统的系统调用接口发生变化(由于Linux内核的系统调用非常稳定,该情况很难发生)。

3.1.3 接口兼容性

通过在不同的平台提供相同的内核以及相同的库版本,可以降低移植过程中接口变化的影响。即使开发者避免了ABI变化导致的运行问题,也还有更加复杂的接口兼容问题。在这里,接口是指不同进程直接调用的进程间通信(Interprocess Communication,IPC)接口,而不是指应用构建时的源码接口。源码接口的变化在应用构建时就可以被识别出来。IPC接口只有在程序运行时才能体现,这会导致应用的功能受到影响。

3.2 兼容性原则

兼容性具有“相互”的特点,即应用和操作系统应该相互兼容。作为应用开发者,我们应主要关心应用在不同版本操作系统上的运行情况,主要有以下两个方面的问题。

运行依赖问题:应用运行时会依赖很多系统库,这些库在不同版本的操作系统上是不一样的。一般来说,操作系统会保证库升级时不删除接口,但这并不是绝对的。在这种情况下,应用的处理方式是使用自带依赖的方式,例如AppImage技术就会进行依赖打包。

功能依赖问题:如果应用需要使用操作系统上的特性,那么必须进行操作系统版本判断,在不同版本的操作系统上进行不同的操作。

3.3 目录权限规范

应用的全部安装文件必须在/opt/apps/${appid}/目录下。该目录所有者必须为root,建议目录权限为755。7表示当前文件所有者的权限,为可读可写可执行权限(7=4+2+1);第一个5表示当前文件的所属组(同组用户)权限,为可读可执行权限(5=4+1);第二个5表示当前文件的组外权限,为可读可执行权限(5=4+1)。所以755表示该文件所有者对该文件具有读、写、执行权限,该文件所有者所属组用户及其他用户对该文件具有读和执行权限。软件包不允许直接向$HOME目录中写入文件,后期系统将会使用沙箱技术 重新定向$HOME,任何依赖该特性的行为都可能失效。应用使用如下环境变量指示的目录写入应用数据和配置:

$XDG_DATA_HOME
$XDG_CONFIG_HOME
$XDG_CACHE_HOME

对于appid为com.deepin.demo的应用,其写入目录为:

$XDG_DATA_HOME/com.deepin.demo
$XDG_CONFIG_HOME/com.deepin.demo
$XDG_CACHE_HOME/com.deepin.demo

3.4 界面设计理念

界面设计是广义上的概念,其一般遵循简易性等原则。计算机中的界面设计一般指用户界面(User Interface,UI)设计。UI设计(或称界面设计)是指对软件的人机交互、操作逻辑、界面美观性的整体设计。

3.4.1 为用户而设计

通常来讲,用户使用计算机时都是带着一定的心智模型的,这些心智模型可能来自生活、自然界,也可能来自其他场景或操作系统等。好的产品设计既要尊重各类用户的心智模型,也要充分了解各类用户的心智模型。产品开发者应该为用户(或者潜在用户)设计产品,而不是为自己设计产品,不可以站在“上帝视角”或者以设计师的惯性思维来思考产品设计,个人的需求不能代表用户的需求,产品开发者使用产品的方式也不一定是用户使用产品的方式。只有在设计过程中时时站在用户的角度去考虑,才能做出符合用户需求的产品。如果你知道目标用户群体,并充分了解他们的情况和需求,能体会他们在使用相关产品的过程中遇到的痛点,并全力为解决他们的痛点而思考,那么你离好的产品设计就更进一步了。

3.4.2 设计解决的不是视觉问题

如果只是为了将产品做得好看或者漂亮,而忽略了用户真正的需求,偏离了产品真正的侧重点,那么产品再好看也只是空有其表。如果设计只是一味地堆控件,这样的产品设计也可以说是失败的。产品可以设计得很好看,让用户看着心里舒服,同时可以设计得简单、易用,并能满足用户的需求,这是关键。想一想,鸟儿为了飞翔,骨头必须要变成中空的,鲸为了能在海里遨游,必须要有鳍,自然界里的生物各种各样,它们的DNA为了它们自身能不断繁衍下去不断改进,且从不做无用的进化,千万年来,它们每一次改进,都有它们的意义。UI设计并非堆控件,只有满足了用户的需求,UI设计才有意义。

3.4.3 保持轻量

一般随着时间的推移,增加的功能必然会越来越多,功能的增多必然会导致系统或者应用“臃肿”。每个用户需要的功能大多数时候是恒定的,只不过不同的用户有不同的需求,如果只是一味地“吸收”所有功能,然后让用户各取所需,这样肯定是不行的,因为这意味着用户不常用的功能也很多。应用也是一样的道理。

即使按照上面所说的有选择性地根据用户需求做功能筛选,功能还是会慢慢增多。应该避免直接向用户展现其复杂性,即使系统或应用本身很复杂,也至少要让用户看起来不复杂。有了不复杂的直观感受之后,用户才有继续深入使用的耐心和勇气。轻量化是深度操作系统设计贯穿始终的一个原则,小到一个图标,大到整个系统,都需要遵循这个原则。轻量化的设计无论在视觉上还是功能上都能让用户更轻松地使用,不会让用户在视觉上产生很强烈的疲惫感,也不会让用户在操作上有很大的心理负担。 RYiEeKOAX/BP3MzPmlipPLys0BauJ4n5dU3xUSXA53gZWseZ8p3k9KRw1fahXriJ

点击中间区域
呼出菜单
上一章
目录
下一章
×