NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

借助基于模块的软件工程方法征战物联网丛林

  • 2017-08-16
  • 本文字数:8545 字

    阅读完需:约 28 分钟

主要结论

  • 从软件工程的观点来看,物联网应用有两个特征。首先,包含大范围分布的处理节点;其次,处理节点以及通信协议存在极高异构性。
  • ThingML(Internet of Things Modeling Language,物联网建模语言)方法旨在促进服务开发者与平台专家之间的协作,帮助双方联手使用建模语言、一系列工具,以及相应的方法论开发基于物联网的增值服务。
  • ThingML 的主要目的是物联网软件建模,通过将现有代码融入 ThingML 模型,为复杂事件的处理和新传感器的发现提供支持,可简化这一过程的实现,同时还可针对异构平台生成代码。
  • 在商用医疗解决方案中运用 ThingML 已可证明其效果,但在部署和更新等方面,这种方法依然面临重要的挑战。

本文首发于 IEEE Software 杂志。 IEEE Software 针对当今世界的主要战略性技术问题提供了坚实的同行审阅信息。为了应对企业在可靠性、灵活性等方面提出的挑战,IT 经理和技术主管必须依赖 IT 专业人员才能获得最先进的解决方案。

在 UML 启发下诞生的 ThingML 方法解决了物联网在分布和异构两方面遇到的挑战。这种模块驱动的生成式方法还在不断演进,已在不同领域获得了广泛应用,包括商业化的数字医疗解决方案。

编写、部署、演化物联网软件的过程中面临的挑战往往被人们低估 [footnote1]。从软件工程的观点来看,物联网应用有两个特征。首先,包含大范围分布的处理节点;其次,处理节点以及通信协议存在极高异构性。对于上述每个特征,都有大量围绕软件工程的文献,然而很少有研究结果能同时解决这两个问题,进而会产生三个挑战。

首先,在大规模物联网应用中,往往包含大量异构节点,在距离数据源较近的位置处理数据,以及通过去中心化的方式做出响应的过程中,这些节点通常扮演了不同的角色。分布式系统、远程通信,甚至传感器网络领域的大量研究都专注于伸缩至极大数量的节点,但对于这些节点的类型和角色(例如客户端 - 服务器、对端追踪器、传感器网关服务器等)往往涉足甚少 [1] 。这种同质性的特征使得我们可以针对大量节点开发并部署类似的代码,确保软件不会变得过于复杂。但物联网软件的情况截然不同,物联网不仅需要对节点数量进行伸缩,而且需要对节点和平台的类型数量进行伸缩,例如从微控制器扩展至云端。

其次,为了让物联网系统发挥全部潜力,开发者必须充分利用异构节点锁提供的多样化资源和去中心化计算能力。很多工具和技术会隐藏这种异构性,借此帮助开发者编写能在不同平台(操作系统、Web 浏览器、移动设备等)上以相同方式执行的应用 [2] 。在物联网应用中,这种异构性从部分方面来说并非出于偶然,开发者必须明确这种特性并能加以利用。例如只有这样,开发者才能利用物联网节点的深度睡眠模式省电,而不同平台在这种模式的实现上往往存在差异。

第三,按照物联网的愿景,应用程序不再是相互隔离的专有设备和软件组成的“竖井” [3] ,而是在整个环境中相互结合唾手可得的真实物件:有共性,也有面向具体应用的个性,甚至可能还有遗留的物件。因此物联网应用必须能在共享的硬件上运行,开发者也需要密切注意,以避免应用之间产生不必要的交互。

因此工业化的物联网应用会在开发过程的不同阶段面临挑战,开发者团队需要在电子、微处理云计算,以及数据挖掘等领域有着全面的资质。ThingML(Internet of Things Modeling Language,物联网建模语言)方法旨在促进服务开发者与平台专家之间的协作,帮助双方联手使用建模语言、一系列工具,以及相应的方法论开发基于物联网的增值服务。过去六年来,这个方法在不断演进,已在不同领域获得了广泛应用,包括商业化的数字医疗解决方案。

ThingML 方法

ThingML 方法的发展历程

ThingML(Internet of Things Modeling Language)方法意在将学术界有关基于模型的软件开发技术带到相关行业内。

过去六年来,ThingML 语言和工具经历过三次重大变革。

第一次迭代主要基于原有 UML 工具。我们开发了一种极简化语言,用来描述基于传感器的架构,实现了商用状态机工具生成的代码与现有 API 的集成。但大规模传感器网络的开发(与油气行业合作)受到了难用的图形规范(几个“玩具示例”除外)、资源有限的平台对代码要求严苛,以及重要的遗留和第三方组件等问题阻碍。

第二次迭代为状态机引入了一种文本语法(Textual syntax)以及以及一种一流的动作语言(Action language)。我们还分别针对微处理器、Posix C 和 Java 提供了三个独立的编译器。我们通过 CORBYS(Cognitive Control Framework for Robotic Systems:corbys.eu)项目开发了一种医疗康复机器人,并通过 Arrowhead 项目(arrowhead.eu)开发了一种智能家居网关,借此证明了这种文本语言的用途。同时也证明了固定的整体式编译器(Monolithic compiler)所存在的局限,必须对其进行必要的调整才能满足项目需求。

借此我们也意识到,真正重要的还是代码本身。基于模型的技术不应试图替代或隐藏实际代码,而是应该支持从业者以更系统化,也更有效的方式生成所需代码。

第三次迭代主要围绕 HEADS 项目(heads-project.eu),通过以往获得的经验,我们为医疗和数字健康领域提供了两个几乎完全实现的商用产品。该项目的主要贡献在于代码生成框架,并通过相关方法论让从业者可以全面控制代码,根据需求灵活定制编译器。第三次迭代同时还为 ThingML 语言扩展出更多概念,例如复杂事件处理以及动态会话(见下文)。

我们所提出的方法是与行业合作伙伴和从业者不断联手完善,根据反馈进行改进的产物。

ThingML 方法包含一个建模语言,一系列工具,以及一个方法论。该语言(ThingML)包含与 UML(状态图 [Statechart] 和组件)相符并获得证实的软件建模构造,一种必须采用的平台独立动作语言,以及围绕物联网应用制定的构造。工具包括编辑器、转换器(例如导出至 UML),以及一个可支持多种目标编程语言的高级多平台代码生成框架 [4] 。方法论规定了物联网服务开发者和平台专家的开发流程和所用工具。语言、工具、方法论,均以开源形式包含在 HEADS IDE 中发布。

物联网软件建模

ThingML 方法的首要目标是对异构平台和物联网设备进行抽象,借此为所需的物联网系统架构进行建模。在实践中,平台和设备,以及软件组件的最终分布通常在早期设计阶段是不确定的。架构模型可包含组件、端口、连接器,以及异步消息。

常规架构定义完毕后,我们的方法可以通过平台独立的方法使用状态图和动作语言确定组件的业务逻辑规范。ThingML 状态图包含合成器、并行区域,以及历史状态。状态机通常会对组件端口传入的消息所对应的事件做出响应。动作语言可以让开发者在组件中指定保护措施、动作、变量,以及函数,并让状态机通过组件端口收发消息。

促进应用程序的开发

ThingML 方法还集成了三个可以促进物联网应用开发的功能。首先是一种可以通过将 ThingML 代码融入目标代码,快速封装现有库的机制。其次是通过复杂事件处理(CEP)处理复杂反应模式的能力。第三是可以动态发现传感器的动态会话功能。

ThingML 与原生代码的融合。平台独立的规范有助于促进早期开发工作,以及不直接依赖底层系统或硬件功能的组件开发工作。然而一旦开发者选定了具体平台,必须以足够高效的方式实现某些组件,并且要能充分利用硬件功能以及任何可用的软件库。为提供所需灵活性,我们的方法可以自由地将模型动作与目标语言动作结合在一起。这种机制使得开发者可以轻松地双向共享变量并实现调用和回调。

图 1 展示了将一个组件链接至现有 JavaScript Z-Wave 库的实现。蓝色代码是纯粹的 JavaScript 代码,借此我们初始化了 Z-Wave 驱动并注册了回调。我们将 ThingML 代码融入这些回调中,借此可在调用回调时发出 ThingML 事件。通过这种方式,网关依然可以实现平台独立,只要针对 ThingML 事件做出回应即可。

(点击放大图像)

图1:ThingML 中平台独立和平台特定的组件。蓝色代码是纯粹的JavaScript 代码,借此我们初始化了Z-Wave 驱动并注册了回调。这些回调包含的ThingML 代码可在调用回调时发出ThingML 事件。

CEP。物联网业务逻辑通常需要对不同来源和设备的事件流做出回应。根据我们的经验,当时用传统状态机(或直接使用目标语言)实现这种逻辑时,会不必要地增加事件缓冲集地复杂度,并会将不同来源的事件混合在一起。CEP 语言以及诸如 ReactiveX 等库 [5] 提供了一种陈述式(Declarative)的方式,可以指定如何处理来自不同流的事件,并将其结合成一个新的事件流。

我们的方法在与状态机相同的层面上定义了 CEP 查询。与状态机类似,CEP 查询可处理一系列输入消息并生成输出消息。然而 CEP 查询的规范完全是陈述式的。ThingML CEP 包含的运算符可联接(Join)并合并(Merge)消息流,并可在通过时间或消息数量定义的窗口内处理消息。下文我们将通过之前提到的数字医疗应用介绍 CEP 查询。

会话。物联网网关组件可动态地处理连接,与通过网关网络往来的设备交互。此类动态环境的处理与 Web 应用中用户会话的处理极为类似。为了实现此类行为,我们本可使用即席(Ad hoc)解决方案,但为了提供系统化的解决方案并杜绝内存管理方面的问题,ThingML 状态机也使用了会话的概念。

“会话”是对并行区域(Parallel region)进行动态实例化的产物,会在初始化时包含其父项上下文(一组属性)在 Fork 时的副本。会话可执行自己的行为(状态机、CEP,或函数),并且只能访问和修改自己的上下文。与其他组件一样,父项和会话只能通过异步消息通信。会话到达最终状态后将会终止。下文将在数字医疗应用中展示会话的使用。

为异构平台生成代码

与从业者通过基于模型的方式进行开发,我们最大的收获是:代码真的很重要。尽管很多架构师与管理者通常更愿意使用模型和系统化的代码生成技术,但有经验的开发者往往更关注通过模型生成的代码的质量、可管理性,以及集成。所有重要项目对 ThingML 方法的成功运用都要求对代码生成器进行调整,不仅是为了满足目标平台的需求,同时也是为了满足整个项目对代码风格、库、API,以及遗留组件等方面的要求。

考虑到这些情况,ThingML 代码生成框架可以帮助开发者适应并扩展代码生成器,以满足自己领域和项目的独特需求。该框架包含一个抽象框架以及针对三种语言(C/C++、Java、JavaScript)现成可用的代码生成器,以及多个库和开放平台(Arduino、Raspberry Pi、Intel Edison、Linux 等)。在物联网应用中,ThingML 组件可分布在不同的异构平台中,因此需要使用不同的代码生成器。此外还可通过特定的代码生成器插件为不同平台上多个组件生成通信并交换消息。

为了能高效地定制所生成代码的任何内容,该框架还提供了大约 10 个扩展点,每个都可生成特定类型的源代码。例如用一个生成器发布 API,用另一个生成器实现组件。在物联网系统中,每个组件都可以用不同组合方式使用众多代码生成器插件。

在使用、扩展、定制代码生成器过程中,还有一个重要问题:必须确保它们都能为 ThingML 构造提供相同的执行语义。为了帮助开发者做到这一点,我们提供了一个包含上百种测试用例以及一系列测试装置(Test harness)的测试框架(还可针对新的目标平台进行扩展),借此可对任何代码生成器进行自动化的诊断。该测试框架可针对所有测试用例生成代码,在目标平台上执行代码,收集执行过程追踪信息,并将其与一系列参考记录进行对比。

实际运用中可定制的范围非常广泛,从现有生成器的简单调整,到针对新平台或目标编程语言开发全新的生成器,均可实现。下文将简单介绍三个例子以及大致的工作量。

首先,可对特定动作进行定制,例如让 ThingML 将输出结果保存到日志文件,而非在控制台中显示文字,这大约需要 5 行 -50 行代码。

另一个常见的定制是更改所生成项目的具体构造并进行构建,例如从默认的 Maven 改为 Gradle,以管理并构建 Java 项目,这大约需要 100 行代码。

最后说一个略微复杂的定制,该框架可通过构建插件处理不同平台上组件之间的消息交换。例如可以让任何 Java 组件与任何 C 组件通过 MQTT(Message Queuing Telemetry Transport)通信,这大约需要 800 行代码,其中 Java 需要约 400 行,C 也需要约 400 行。在这 400 行代码中,大约有一半负责消息的编组(Marshaling)和解组(Unmarshaling),另一半负责处理使用 MQTT 库进行的载荷传输。默认情况下,对于受支持的语言可以使用二进制序列化 [6] 和 JSON(JavaScript Object Notation)序列化,以及 MQTT、WebSocket,以及序列传输协议。

在不使用现有插件的情况下全新实现一个编译器,大约需要 10,000 行代码。这个过程较为困难,但对大部分开发者,至少企业中的开发者来说,依然是可行的。

打造数字医疗跌倒检测系统

挪威 IT 公司 Tellu 开发的 SmartTracker 是一种物联网平台,可以让用户注册传感器,存储数,并使用云服务器中运行的 JBoss Drools 定义业务规则。该公司适用于物品和人员的地理围栏和监视应用已正式商用。虽然这种集中化的方式在某些领域已有成功的先例,但 Tellu 发现在数字医疗服务的开发方面存在局限,因为这个领域对数据吞吐量、延迟、时间要求,以及可靠的反应等方面有更高要求。这种情况下,业务逻辑必须分布在整个物联网架构中,而所建立的系统必须能在不依赖互联网连接或云服务的情况下实现关键功能。

Tellu 数字健康解决方案的核心是一种基于气压的跌倒检测系统。该系统的表现远超竞争对手,并使用了可穿戴的惯性传感器。然而除了可穿戴传感器,该系统还要求环境中具备固定式压力传感器集群 [7] 。这个额外的基础架构同时可以充当精确的室内定位系统,可触发家庭范围内的各种自动化任务,如在无需运动传感器的情况下自动打开房间内的灯光。该应用的逻辑和软件必须针对具体的住宅、用户以及设备进行调整。

固定式传感器会以分布式的方法,通过处理可穿戴传感器借助 BLE(Bluetooth low energy,也叫做 Bluetooth Smart)发送的数据检测跌倒。固定式传感器需要连接至一个 Wi-Fi 网络,借此通过点对点通信检测跌倒,并使用 MQTT 代理(Broker)与网关通信。

Tellu 使用 ThingML 在传感器和网关处实现所需逻辑。图 2 展示了这种基础架构在家庭中部署后的概况,此外图中还展示了一个部署在网关上的状态机。

(点击放大图像)

图 2:Tellu 数字健康和家具自动化解决方案。(a) 基础架构和部署方式概况;(b) 网关所用状态机的部分内容,网关会使用动态会话实现设备的动态发现与管理工作。BLE 是指 Bluetooth low energy,MQTT 是指 Message Queuing Telemetry Transport。

该系统包含超过 25 个 ThingML 组件,共运行在四种类型的嵌入式节点上:

  • 基于 ARM Cortex M3 微处理器的可穿戴传感器,
  • 基于 Intel Edison 的固定式压力传感器节点,
  • 一个基于树莓派网关搭建的初代系统原型,以及
  • 一个基于 MIPS,适用于生产系统的专有网关。

在协议方面,该系统主要使用 BLE、MQTT(通过 Wi-Fi 和以太网)以及 Z-Wave。

为了实现动态的设备发现和管理,网关会使用会话(图 2)。当系统发现新设备(Z-Wave?nodeAdded)后,网关会 Fork 一个设备会话(fork device),并提供及时更新的 ID,借此处理与该设备有关的消息。

传感器会利用 CEP 以优雅的方式实现并轻松调整精确度量所需的压力补偿算法(图 3)。当系统同时收到未经处理的原始温度和压力数据后,会触发一个流。用户可通过输入注解的方式自定义可联接的两个事件间的时间间隔。这个流还可以将最后三个补偿压力合并在一起进行计算。为了计算最终的补偿压力,可通过 compensate 函数应用为缓冲区中最新的补偿值,以及当前压力和温度应用多项式函数。

(点击放大图像)

图3:以ThingML CEP(复杂事件处理)流的方式表示的压力补偿算法。压力传感器会利用CEP 实现并调整精确度量所需的压力补偿算法。

虽然Tellu 数字健康系统依然在开发中,但ThingML 方法已开始显现出四个重要收益。首先,ThingML 组件及其严格的异步消息传递通信语义使得系统能够发现组件之间的所有交互。这一点极大地简化了系统集成和测试工作,因为现在可以用更简单的方法模拟不同组件。

其次,用于处理缓冲区和计时器分配与管理的大部分代码已经可以通过ThingML 或其他目标语言来表达,因此可以直接从模型中移出,并在引入CEP 和会话后交给编译器处理。

第三,ThingML 方法大幅简化了从原型到生产系统的过度。正如上文所述,除了最初使用的,基于树莓派的家庭网关,这个系统现在还可以使用专有的MIPS 网关。虽然这样的网关包含与某些特定平台有关的组件(图1),但可以很简单地迁移至新平台,因为所有与特定平台有关的引用都可以在ThingML 模型中清楚明确地表达。对于Tellu 这样的软件公司来说,快速更改平台的能力很重要,可以避免自己被任何硬件解决方案锁定。

最后,开发者只要将现有库封装至ThingML,并使用ThingML 框架定制代码生成器,即可为自己的目标平台和协议提供支持,甚至可支持ARM Cortex M3 微处理器。

Tellu 数字健康系统的开发很好地诠释了商用物联网系统开发的流程和可能遇到的问题:异构、资源有限、分布式、可靠性、隐私需求,以及软硬件的代码开发。在这种情况下,ThingML 方法是应对系统复杂性以及在底层物联网平台的丛林中顺利发展的第一步。我们围绕数字健康、机器人、传感器网络、媒体,以及家具自动化等领域获得的经验也可以应用在更多领域,让更多从业人员获益。

然而软件工程领域的重要挑战依然存在,尤其是在软件部署和更新,以及以可靠可预测的方式在不同物联网应用之间共享计算资源和设备等方面更是如此。在云计算的环境中,诸如 Docker [8] 或 LXC(Linux 容器)等方法可将组件和应用程序实现容器化,借此应对共生(Mutualized)服务器上的部署和“沙箱”执行环境等需求。在物联网方面,Docker 和 LXC 已经可以移植到树莓派这样资源极为有限的平台 [9] ,使其可充当中介作用的物联网节点。然而规模更小的物联网节点需要不同的方式。对于资源有限的平台,可通过调度算法处理相互混合的关键性系统 [10] ,借此为计算工作执行过程建立可预测的基准线。模型所提供的抽象为行为分析提供了可行、有效的基础。

致谢

本次研究得到了 EU FP7 HEADS 项目(611337 项目)的支持。

关于本文作者

Brice Morin是芬兰奥斯陆 SINTEF 信息与通信技术中心的研究员,他的研究通过 ThingML 语言为物联网技术提供了强大、实用的建模功能。Morin 在法国雷恩大学(University of Rennes)获得了博士学位。他的联系方式:brice.morin@sintef.no。

Nicolas Harrand是芬兰奥斯陆 SINTEF 信息与通信技术中心的工程师,他的研究致力于通过模型驱动的工程技术打造异构分布式系统。Harrand 在法国圣马丹代雷研究生院(école Nationale Supérieure D’informatique et de Mathématiques Appliquées de Grenoble)获得工程学学士学位。他的联系方式:nicolas.harrand@sintef.no。

Franck Fleurey是芬兰奥斯陆 SINTEF 信息与通信技术中心的资深研究员,他的研究方向包括模型驱动的软件工程、嵌入式系统,以及动态自适应系统。Fleurey 在法国雷恩大学获得了计算机科学博士学位。他的联系方式:franck.fleurey@sintef.no。

作者 Brice Morin Nicolas Harrand Franck Fleurey 阅读英文原文 Model-Based Software Engineering to Tame the IoT Jungle


[1] I. Stoica et al., “Chord: A Scalable Peer-to-Peer Lookup Service for Internet Applications”, ACM SIGCOMM Computer Communication Rev., vol. 4, no. 31, 2001, pp. 149-160. [2] P. Grace, G. Blair, and S. Samuel, “A Reflective Framework for Discovery and Interaction in Heterogeneous Mobile Environments”, ACM SIGMOBILE Mobile Computing and Communications Rev., vol. 1, no. 9, 2005, pp. 2–14.

[3] A. Marinos and G. Briscoe, “Community Cloud Computing”, Cloud Computing, LNCS 5931, Springer, 2009, pp. 472-484.

[4] N. Harrand et al., “ThingML: A Language and Code Generation Framework for Heterogeneous Targets”, Proc. ACM/IEEE 19th Int’l Conf. Model-Driven Eng. Languages and Systems (MODELS 16), 2016, pp. 125–135.

[5] E. Meijer, “Reactive Extensions (Rx): Curing Your Asynchronous Programming Blues”, Proc. 2010 ACM SIGPLAN Workshop Commercial Users of Functional Programming (CUFP 10), 2010, article 11.

[6] F. Fleurey et al., “MDE to Manage Communications with and between Resource-Constrained Systems”, Model Driven Engineering Languages and Systems, LNCS 6981, Springer, 2011, pp. 349–363.

[7] A. Liverud, “ New Sensor Will Make Life Safer for the Elderly ”, Gemini, 9 Feb. 2016;

[8] F. Fouquet et al., “Dissemination of Reconfi guration Policies on Mesh Networks”, Distributed Applications and Interoperable Systems, LNCS 7272, Springer, 2016, pp. 16–30.

[9] F.P. Tso et al. “The Glasgow Raspberry Pi Cloud: A Scale Model for Cloud Computing Infrastructures”, Proc. 33rd Int’l Conf. Distributed Computing Systems Workshops, 2013, pp. 108–112.

[10] S. Baruah, H. Li, and L. Stougie, “Towards the Design of Certifi able Mixed-Criticality Systems”, Proc. 16th IEEE Real-Time and Embedded Technology and Applications Symp. (RTAS 10), 2010, pp. 13–22.

2017-08-16 17:241194
用户头像

发布了 283 篇内容, 共 102.1 次阅读, 收获喜欢 61 次。

关注

评论

发布
暂无评论
发现更多内容

CSS布局之display:flex(二)

Augus

CSS 11月日更

Nebula Graph 源码解读系列 | Vol.04 基于 RBO 的 Optimizer 实现

NebulaGraph

图数据库 源码解读

openGauss支持国密SM3和SM4算法

openGauss

#数据库

首次!统一调度系统规模化落地,全面支撑阿里巴巴双 11 全业务

阿里巴巴中间件

阿里云 云原生 中间件 双十一 统一调度

第一本 Compose 图书上市,联想大咖教你学会 Android 全新 UI 编程

图灵教育

Compose AndroidUI

我所理解的社群—社群本质

sec01张云龙

社群 11月日更 社群运营

不要再重复造轮子了,Hutool这款开源工具类库贼好使

沉默王二

Java

开源数据库风起云涌,openGauss 恰逢其时

openGauss

#数据库

【高并发】通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程

冰河

Java 并发编程 多线程 高并发 异步编程

短视频个性化Push工程精进之路

百度Geek说

后端 软件架构

极光笔记丨关于数据大屏一比一还原设计稿这件事

极光JIGUANG

大前端 数据可视化

手把手教你学Dapr - 1. .Net开发者的大时代

MASA技术团队

C# .net 微软 后端 dapr

模块三作业——外包学生管理系统架构设计

覃飞

前端的状态管理与时间旅行:San实践篇

百度开发者中心

大前端 san san-store 技术实践

浅谈 RDMA 与无损网络

青云技术社区

云计算 云原生 存储

Nginx中间件渗透总结

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

彻底搞懂Spring状态机原理,实现订单与物流解耦

Tom弹架构

月薪3万的大厂测试工程师裸辞3个月,送外卖谋生背后的真实感悟

六十七点五

程序员 程序人生 软件测试 软件自动化测试 测试工程师

我是一个程序员,总想引导亲朋好友走上编程的伟大航路......

图灵教育

程序员 App Inventor

手把手教你学Dapr - 2. 必须知道的概念

MASA技术团队

C# .net 微软 后端 dapr

如何穿透ToB客户生命周期的全链增长?

ToB行业头条

混合云的概念以及优势劣势简单介绍-行云管家

行云管家

云计算 混合云 多云 云管平台

Python代码阅读(第58篇):压缩列表

Felix

Python 编程 列表 阅读代码 Python初学者

企业如何选择合适的低代码平台?这6点不得不考虑!

J2PaaS低代码平台

低代码 低代码开发 低代码平台 企业数字化

项目管理常见问题系列(1)—资源不足

一叶而不知秋

项目管理

LevelDB Java&Go实践

FunTester

Java 自学 Go 语言 leveldb FunTester

拥抱智能,AI 视频编码技术的新探索

阿里云视频云

阿里云 视频编码 机器视觉 视频编解码 视频云

Web 用户体验设计提升实践

Shopee技术团队

大前端 web开发 用户体验 交互设计 可访问性

一招教你通过焱融 SaaS 数据服务平台+ELK 让日志帮你做决策

焱融科技

云计算 分布式 SaaS 公有云 文件存储

就是简单,全球100多万读者,一起跑通前端HTML5与CSS3知识!

图灵教育

大前端 HTML5, CSS3

速来!开源中国首届飞算SoFlu组件开发悬赏赛来袭

SoFlu软件机器人

Java

借助基于模块的软件工程方法征战物联网丛林_移动_Brice Morin_InfoQ精选文章