速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

基于模式的架构评审

  • 2012-05-21
  • 本文字数:8217 字

    阅读完需:约 27 分钟

本文首次发表在 IEEE Software ,并由 InfoQ 和 IEEE 计算机协会为您引进

质量属性描述的是系统的易用性、可维护性、性能以及可靠性(虽然不是功能性的)。这些内容可以提高客户满意度,并更好地与类似产品区分。

质量属性是全系统级的,所以架构必将对这些属性造成巨大的影响。保罗•克莱门茨(Paul Clements)和他的同事曾这样描述,“一旦架构成型,可变性、性能、安全性、可用性、可靠性也就固定了。如果系统早期架构拙劣,即使再多的后期优化和奇技淫巧也无法对质量做出补救”[1] 不幸的是,这意味着,只有到系统基本开发完成并可以做系统级验收的时候,这些质量才能够得到充分的验证。然而,在系统验收之前,鉴定有关质量问题是非常重要的。

架构评审将是一种可行的解决方案:它将能找出潜在的问题,[2], [3], [4] 特别是针对那些相关质量属性的问题。然而,尽管已经证实,这样做很有价值,但很多项目还是不会或不愿意去实施评审。这些项目具有以下特征:

  • 时间表很短,还可能包括一系列短周期的迭代开发;
  • 项目期限非常紧张,除了生产之外几乎没有空闲时间;
  • 忽视文档,特别是像架构文档这样的内部文档;
  • 频繁的更改技术或用户需求;
  • 小团队;

这些特征导致团队关注生产一个仅仅“可工作的”软件,或“只要做出产品”——其他的活动的优先级都很低。由于没有更好的说法,我们用专注生产式来描述这些项目。很多这样的项目(尽管不是全部)遵循敏捷和精益软件开发方法论中的实践。[5], [6], [7]

我们创建了一种轻量级的适合专注生产式项目的架构评审过程。它可以确认架构模式并检查这些模式给质量属性带来的作用效果。我们曾使用它评审过九个项目;它并不仅仅可以用来发现重要的架构问题,同时也提高了开发团队对架构的理解。

架构评审和专注生产式项目

在很多软件架构评审实践中,我们都可以全面地检查架构中的质量属性。[8] 然而,它们在针对专注生产式项目进行架构评审时非常不协调,这体现在以下几个方面:

  • 人力资源。 专注生产的项目通常仅有满足简单编写软件的人力资源。即使对小项目进行基于构架权衡分析方法(ATAM-based)的架构评估的近似成本也需要 32 个员工日(staff day)。[9] 在 AT&T,一次架构评审的平均成本是 70 个员工日(staff day)。[10]
  • 成本。已发布推行中的架构评审方法一般都很昂贵。
  • 架构文档。 即使很多的架构评审方法都基于对文档的分析,[11] 专注生产式的项目却几乎没有架构文档——这是一个被广泛意识到的问题。[12]
  • 需求。 架构评审方法需要详细的需求说明书和相应需求的稳定性——一个过程会需要 2 到 6 个星期。 [13] 需求变更带来的大量准备工作会阻碍评审的执行。

这些不协调情况致使项目经理们无法评审他们的架构,从而放弃了评审带来的应有的好处。然而,轻量级的评审过程将解决这些不协调情况,同时让这些项目重新受益于架构评审。

基于模式的架构评审

软件架构模式是指那些处理频繁出现的设计问题的通用解决方案。基于模式的架构评审(PBAR)是一种轻量级的基于软件架构模式的评估方法。这种评审方法提供了一种已被验证的使用模式解决方案的方式,以及如何适应解决方案的效果。[14] 虽然最著名的软件模式是面向对象的设计模式,但在这里我们更关心的是那些涉及系统架构的模式。[15]

架构模式关注整个软件系统的设计以及高层次的模块化拆分。[16], [17], [18] 应用现有的架构模式可能使实现某些质量属性更容易或更困难。举个例子,分层模式将系统划分为不同的层次,使得每一层都向它的上一层提供一系列的服务,同时又使用下一层提供的服务。[19] 这种结构对故障容错提供了支持,你可以使用分层,从而在出现错误时方便地回滚以实现事务。可是,这种模式需要所有的请求都经历多个层次到达目的地,这使得性能受到了损失。

PBAR(基于模式的架构评审)平衡了模式与质量属性的关系,同时产生了一种适用于专注生产式项目的评审。它解决了这些项目与传统架构评审之间的不协调情况:

  • PBAR 仅仅需要很少的时间和精力。这非常适合于让小项目专注于编写产品代码。
  • PBAR 不需要架构文档。取而代之的是,它总结了正在使用中的架构模式与任何已存在的项目文档,从而推断在这样的情况下,质量属性将如何实现。
  • 专注生产式项目允许需求变更。PBAR 只需要简短的准备时间,一次简短的评审就可以在 1 到 2 天内给项目作出反馈。这使得它可以迅速对需求变更做出响应。

此类评审的基本元素与重量级的架构评审并无二致,但是显得更简单,并且更专注。

要素和计划

评审者需要具备架构,架构模式,质量属性等专业知识和一般的领域常识。评审者应该来自团队之外,这样才能在系统架构设计方面带来新颖的观点——这项工作与其说是内部回顾,更大程度上不如说是一次审核。

规划评审

在开发周期的早期,一旦确定了系统的基础结构,那么就应该准备规划架构评审了。所有开发人员以及对项目感兴趣的利益相关者都应该被邀请参加评审。参加者不需要做什么正式的准备,但是评审者需要提前掌握好所有相关的架构和需求文档,比如用户故事(user stories)和用例。

评审会议及跟踪

评审是一次面对面的会议,在其间以下几步将会迭代执行:

  1. 确定系统中最重要的质量属性并加以讨论。梳理用户故事(user stories)并浏览一遍相关质量属性对应的场景。
  2. 讨论系统架构(甚至将它画在白板上)。
  3. 确定出要使用的架构模式。(由评审者完成这个任务,但是其他懂架构模式的参与者可以帮忙)主要的技术是将系统结构与模式结构进行匹配。你希望找到一种成熟的模式,而不是一种新模式,因为我们已经了解这些成熟的模式将对质量属性有何影响,而后者则不然。
  4. 综合检查架构与质量属性,以确定每种模式对系统的质量属性的作用。评审过去的场景、实现方式以及在架构实现过程中发生的情况。用现有的模式文档去发现模式与质量属性之间的匹配之处(或不匹配的地方)。
  5. 找出并讨论质量属性的议题,包括哪些质量属性没有被处理,或哪些被充分满足了,哪些模式没有用到但是会带来帮助,以及在模式与质量属性之间存在的冲突。举个例子,分层的架构往往无法符合高性能的需求。

在评审结束后,评审者需要向整个团队做出总结。这应该可以进行的很快,因为多数问题已经在评审期间讨论或得到解决。(会议的全部过程可以在一个小时内结束)

评审和专注生产式实践

表格 1 展示了专注生产式项目的典型实践以及 PBAR 和传统重量级评审将如何适应它们。这些实践也可以在很多敏捷和精益方法论中看到。请注意,并不是所有的专注生产式项目都支持敏捷方法论,反之,也并不是所有的敏捷项目都是专注生产式的。

专注生产式项目的通用实践和架构评审

专注生产式实践

PBAR

传统评审

频繁发布 [5], [6], [7]

在早期的多次发布中进行规划,简短的评审反馈周期可以很好的适应较小的发布窗口

在多次发布间没有实际意义;较长的计划 - 评审 - 反馈时间会跨越多次发布

随用户需求而变 [5], [7]

专注于质量属性(稳定更胜于功能性需求);允许功能发生改变

需要保持需求的稳定性,包括功能性需求

轻量级文档 [5], [6]

不需要特定的文档;可以平衡好模式对应的架构质量保证问题

鼓励编写大量的架构文档;有部分文档必须编写,以供评审使用

“可行走的骨架”(Walking skeleton)[6]

在“可行走的骨架”的实现的反馈中进行规划

对于总体计划,需要根据需求建立基于日历的时间表

频繁发布

为了提高灵活性,一般的项目都可能会有较频繁的内部或外部发布。架构评审应该满足这样的场景:计划和评审本身都应该很简短。因为参与者不需要做任何准备,PBAR 可以灵活地规划。它精巧的规模对于非常小的发布周期来说也只有很小的影响。

随用户需求而变

大多数的架构评审都基于需求说明书(通常以书面的形式)。但是由于需求常常变更,所以评审的功能被削弱了。而 PBAR 则关注于质量属性,它比功能性需求更加稳定。

轻量级文档

传统的评审都趋向基于全面的架构文档,但是这很容易让项目为了产出这些文档而多做很多工作。对于这种情况,PBAR 是一种轻量级的选择。

可行走的骨架(Walking Skeleton)

“可行走的骨架”是早期一种贯穿始终的架构实现,经常被作为原型来用于证明架构概念。架构评审的一个完美时间点就是“可行走的骨架”完成之时。因为不需要很多的准备和精力,所以你可以在“可行走的骨架”实现后马上举办 PBAR;而不需要像传统的评审那样,必须进行非常慎重的计划和前置工作。

PBAR 的经验

我们曾在 9 个项目中使用了 PBAR。虽然差不多有一半是学生的软件工程课程项目,但都是拥有真实客户的真实项目。在这些评审中,六个非常成功,有一个部分成功,而另外两个是失败的。那个部分成功和两个失败的评审帮助我们改善了评审过程。表格 2 简要列举了这些项目和结果;“主要问题”这一列包含了架构与重要质量属性之间主要的不协调情况。

基于模式的架构评审

系统

规模

项目阶段

项目描述

被找到的问题个数

主要问题个数

已被解决的主要问题个数

耗费的精力 (以员工小时计算 [评审者 / 团队])

A

大型

实现阶段

流媒体数据的处理与分析

3

1

复制代码
5 (5/0)

B

中型

架构阶段

计算机控制的过程控制

4

1

复制代码
11 (6/5)

C

小型

已发布

嵌入式 GPS 平台应用

2

复制代码
6 (4/2)

D

小型

实现早期

基于 Web 的定期跟踪系统

7

1

1

8 (3.5/4.5)

E

小型

实现早期

分布式订阅管理系统

3

2

1

9.5 (3.5/6)

F

小型

实现早期

电子商务库存管理系统

3

1

1

8 (3.5/4.5)

G

小型

实现早期

安卓手机应用

3

1

1

7.5 (3.5/4)

H

小型

实现早期

基于 Web 的游戏平台

5

复制代码
7.5 (3.5/4)

I

小型

架构早期

基于 Web 的业务流程支持系统

复制代码
4 (2/2)

大多数项目都遵循前面描述的多数实践。大都需要开发人员之间的高度沟通,以及与客户之间高度的日常交流。大部分的项目罕有甚至没有架构文档,没有用文档记录甚至没有使用架构模式。大部分会有频繁的集成,少部分会有频繁的发布。大部分项目会更多地考虑用户的需求变更,并维护好一个灵活的排好优先级的功能列表,还有少部分会明确的创建“可行走的骨架”。

参与者对于评审本身及其结果都非常的积极与确信,个别人显示出极大的热情。他们的反馈展示了来自评审的四大好处:

  • 基本质量属性问题。PBAR 差不多可以平均在每个项目中找出四个问题,其中包括一个重大问题。在一个案例中,架构使用了分层模式,但是需要提升性能,可选的一种方案是规避分层——一条独立的贯穿系统的路径。在另一个案例中,评审暴露出用户接口的设计(基于已存在的软件)相当晦涩,以至于很难扩展。
  • 团队对架构的理解。有这样两种说法,“评审帮助每个人看到了全景图”,并且,“评审有助于澄清和统一系统的愿景”
  • 团队对质量属性需求的理解。举个例子,团队知道系统是可靠的,但是需要更深入的说明。在评审中,我们会决定系统并不需要连续不间断的运行,但是它必须能够处理某些错误的情况。
  • 团队成员需要深入了解软件架构本身。经过 PBAR 过程,团队了解了架构模式以及它们与质量属性之间的关系。

很明显,我们需要在这些利益与成本之间进行权衡,幸运的是,成本相当低廉——总共需要所有参与者耗费的精力不会超过两个工作日。简短的准备时间可以让团队很好的利用评审来应对需求变更。虽然从来没有哪场评审是我们特别为应对需求变更而举办,但在某些情况下,会对它们在很短的时间内进行规划(一周甚至更少)。我们唯一听到的真正的抱怨是关于评审的时间点——大多数都是在开发进行的差不多了才进行评审,个别参与者希望评审可以更早的进行。

如果参与者发现评审的有用之处,并能对那些列举的问题起到作用,我们就成功了。对于 9 个案例中的 6 个而言,已被证实是对的。而导致那三个失败案例的可能因素有以下几点:

  • 那些列举出的问题都已经发生并产生了负面作用。
  • 我们并没有收到评审结果的确认,可能是因为评审是离线(offline)进行的。
  • 评审没有进行完,主要是因为评审者是一名架构新手。(在一个特别的案例中,连需求都还没有与用户确定,在这种情况下,也就无法在违反需求的情况下对架构进行评审)

从失败的评审我们获得了不少教训,评审必须全员参与并且在开发周期的早期完成,但是也不要过早的在需求都尚未被理解的情况下进行。最后,需要一位擅长架构和架构模式的人来引导大家进行。

详细的实例

为了说明 PBAR 过程和它的带来的好处,我们选取一次评审并对它进行详尽的描述。我们将要学习的项目是一个学生课程项目,而学生是没有时间去做冗长的项目评审的。只有三个开发人员的小团队并没有遵循什么方法论,他们只编写了少量的需求,并且没有架构文档。另一项挑战是,该项目开发的是一个安卓应用,而安卓的软件开发套件在当时非常新,并且在不断的变化中;这也影响了应用的开发和实现。

我们从讨论功能和质量属性需求开始进行评审。我们讨论了各种场景,帮助我们理解最重要的四个质量属性:易用性、安全性、可靠性(故障容错)和可扩展性。这对发现故障及容错尤其有帮助。然后我们讨论架构并将它画在白板上,利用方框和连线分别表示组件和连接器。其中一位团队成员做好笔记,这样一来,在评审结束后团队将会得到一些架构文档。我们列举了两种架构模式:点对点和共享资源库。[20]

我们列举了质量属性的三个问题,其中之一非常重要,然后我们讨论解决这些问题的方法,并总结了三种团队可以实现的措施去解决这些问题。伦恩•贝思(Len Bass)和他的同事则称之为策略。[21] 我们在架构图表中进行标注哪些部分可以实施策略,这样可以给团队如何去实现这些策略的概览图。评审总共进行了不到两个小时。

团队记录了以下几点由评审带来的特别帮助:

  • 产出了一些架构文档;
  • 提高了大家对架构的理解;
  • 提高了大家对项目质量属性需求的理解;
  • 列举出一些问题及初步的解决方案。

以上经验证明,PBAR 在即使完全没有架构文档和只有很少的需求文档时也非常有用。

通过这些使用 PBAR 的经验,我们学习了一些如何让 PBAR 更加成功的重要且全面的经验。架构评审者必须来自项目之外,这是所有类型的评审都适用的一种情况,并且与结对编程具有相似的原理——从另一个视角来发现项目成员无法发现的问题。如果团队中有两位评审者会具有更好的效果。

此外,评审应该在架构已足够完备并产生评审意义后尽可能早的完成。非常重要的一点是,需要注意到 PBAR 本身的轻量级特性,这使得它应该尽早实施,甚至是在架构确定之前。然而,如果质量属性需求尚未确定的话,评审很可能会失败。

假使架构师并没有在他们的架构中显式使用模式,那又会怎样呢?这是我们指导过的大多数评审中出现过的情况。但是因为架构模式通常总是存在的,[22] 评审可以正常地进行,而模式自然而然就会被识别出来。

遗憾的是,PBAR 不能找出一些传统架构评审才能找到的问题。取而代之的是,它提供了一种取舍:一种只需要很少时间和精力,并且可以工作在只有少量架构文档的情况下,当然尤其是在无法使用重量级评审过程的敏捷项目中使用的评审过程。PBAR 可以发现在已使用的架构模式和重要质量属性的不协调情况(例如,性能对应分层,又或者是容错对应管道和过滤器);但它无法发现类似由复杂的交互组件产生的性能缺陷等问题。

另一个限制是评审者们必须非常的精通架构,架构模式,质量属性以及策略。这与传统的评审很类似:评审者需要具备类似的专业知识,虽然架构模式知识并不是决定性的。关键的挑战是很多地组织需要物色到具有充分专业性的评审者。

差不多到目前为止所有使用了 PBAR 的项目都非常小,也许并不能很好解决像工业级别项目的大规模的需求。虽然用户会认为这方面经验的不足是一个限制,但是我们依然希望 PBAR 会继续更加成功地发展。

关于作者

尼尔 • 哈里森(NEIL HARRISON) 是犹他谷大学的一名计算机科学副教授。他的研究兴趣包括软件模式,有效组织和软件测试。哈里森曾获得荷兰格罗宁根大学的软件工程博士学位。他是《敏捷软件开发的组织模式》(《Organizational Patterns of Agile Software Development》Prentice Hall, 2004)一书的联合作者。你可以通过 Neil.Harrison@uvu.edu 联系到他。

**帕里斯• 艾维格聊(PARIS AVGERIOU )** 是荷兰格罗宁根大学的一名软件工程教授。他的研究兴趣涉及强调架构建模,认识,进化及模式的软件架构。艾维格聊曾获得希腊雅典国立科技大学的软件工程博士学位。你可以通过 paris@cs.rug.nl 联系到他。


[1] P. Clements, R. Kazman, and M. Klein, Evaluating Software Architectures: Methods and Case Studies, Addison-Wesley, 2001

[2] G. Abowd et al., Recommended Best Industrial Practice for Software Architecture Evaluation, tech. report CMU/SEI-96-TR-025, Carnegie Mellon Univ., Software Eng. Inst., 1997

[3] J.F. Maranzano et al., “Architecture Reviews: Practice and Experience,” IEEE Software, vol. 22, no. 2, 2005, pp. 34–43.

[4] L. Bass et al., Risk Themes Discovered through Architecture Evaluations, tech. report CMU/SEI-2006-TR-012, Carnegie Mellon Univ., Software Eng. Inst., Sept. 2006.

[5] K. Beck and K. Andrus, Extreme Programming Explained: Embrace Change, 2nd ed., Addison-Wesley, 2004

[6] A. Cockburn, Crystal Clear: A Human-Powered Methodology for Small Teams, Addison-Wesley, 2004

[7] M. Poppendieck and T. Poppendieck, Implementing Lean Software Development: From Concept to Cash, Addison-Wesley, 2006.

[8] L. Dobrica and E. Niemelä, “A Survey on Software Architecture Analysis Methods,” IEEE Trans. Software Eng., vol. 28, no. 7, 2002, pp. 638–653.

[9] P. Clements, R. Kazman, and M. Klein, Evaluating Software Architectures: Methods and Case Studies, Addison-Wesley, 2001.

[10] G. Abowd et al., Recommended Best Industrial Practice for Software Architecture Evaluation, tech. report CMU/SEI-96-TR-025, Carnegie Mellon Univ., Software Eng. Inst., 1997

[11] P. Clements, R. Kazman, and M. Klein, Evaluating Software Architectures: Methods and Case Studies, Addison-Wesley, 2001

[12] R. Kazman and L. Bass, “Making Architecture Reviews Work in the Real World,” IEEE Software, vol. 19, no. 1, 2002, pp. 67−73

[13] J.F. Maranzano et al., “Architecture Reviews: Practice and Experience,” IEEE Software, vol. 22, no. 2, 2005, pp. 34–43

[14] E. Gamma et al., Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994

[15] F. Buschmann et al., Pattern-Oriented Software Architecture: A System of Patterns, vol. 1, Wiley, 1996.

[16] F. Buschmann et al., Pattern-Oriented Software Architecture: A System of Patterns, vol. 1, Wiley, 1996.

[17] N. Harrison, P. Avgeriou, and U. Zdun, “Using Patterns to Capture Architectural Decisions,” IEEE Software, vol. 24, no. 4, 2007, pp. 38–45

[18] P. Avgeriou and U. Zdun, “Architectural Patterns Revisited: A Pattern Language,” Proc. 10th European Conf. Pattern Languages of Programs (EuroPLoP 05), Butterworth- Heinemann, 2005, pp. 1003–1034.

[19] F. Buschmann et al., Pattern-Oriented Software Architecture: A System of Patterns, vol. 1, Wiley, 1996

[20] P. Avgeriou and U. Zdun, “Architectural Patterns Revisited: A Pattern Language,” Proc. 10th European Conf. Pattern Languages of Programs (EuroPLoP 05), Butterworth- Heinemann, 2005, pp. 1003–1034.

[21] L. Bass et al., Risk Themes Discovered through Architecture Evaluations, tech. report CMU/SEI-2006-TR-012, Carnegie Mellon Univ., Software Eng. Inst., Sept. 2006

[22] N. Harrison and P. Avgeriou, “Analysis of Architecture Pattern Usage in Legacy System Architecture Documentation,” Proc. 7th Working IEEE/IFIP Conf. Software Architecture (WICSA 08), IEEE CS Press, 2008, pp.147–156

_ _本文首次发表在 _ IEEE Software _杂志. _ IEEE Software _的目标是建立一个引领未来软件开发的社区及实践者。该杂志通过传播可靠,有用,前沿的软件开发信息以保持工程师和管理者把握技术的迅速变化。

原文链接: http://www.infoq.com/articles/ieee-pattern-based-architecture-reviews


感谢侯伯薇对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2012-05-21 00:004202
用户头像

发布了 52 篇内容, 共 22.6 次阅读, 收获喜欢 5 次。

关注

评论

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

游戏资产复用:更快找到所需游戏资产的新方法

龙智—DevSecOps解决方案

游戏开发 游戏资产 艾尔登法环 游戏资产复用

八大误区,逐个击破(终篇):云难以扩展、定制性差,还会让管理员失去控制权?

龙智—DevSecOps解决方案

Atlassian 云版 版本选择 迁移上云

微信视频号如何用 PC 电脑做直播?

boshi

直播 视频号

华为云低时延技术的九大绝招

坚果

6月月更

如何通过7个步骤编写出色的在线用户手册

小炮

准备好迁移上云了?请收下这份迁移步骤清单

龙智—DevSecOps解决方案

迁移计划 迁移上云计划 迁移上云步骤 上云步骤清单 云迁移策略

直播回顾 | 云原生混部系统 Koordinator 架构详解(附完整PPT)

阿里巴巴云原生

阿里云 架构 云原生 混部 Koordinator

学C++还是学Java?做软件研发还需掌握哪些知识和技能?

dvlinker

Java c++ 数据库 网络知识 汇编代码

openGauss Developer Day 2022正式开启,与开发者共建开源数据库根社区

openGauss

Python 设计模式:适配器模式

宇宙之一粟

设计模式 适配器模式 6月月更

Helix QAC更新至2022.1版本,将持续提供高标准合规覆盖率

龙智—DevSecOps解决方案

C语言 静态代码分析 Helix QAC 代码合规率 代码合规

开发协同,高效管理 | 社区征文

武师叔

初夏征文

在宇宙的眼眸下,如何正确地关心东数西算?

脑极体

Fabric.js 手动加粗文本iText

德育处主任

canvas FabricJS 6月月更

Java Core 「16」J.U.C Executor 框架之 ScheduledThreadPoolExecutor

Samson

学习笔记 Java core 6月月更

活动报名 | MongoDB 5.0 时序存储特性介绍

MongoDB中文社区

mongodb

如何轻松快速构建区块链应用?技术大牛带来一线技术实践分享

腾源会

脚本之美│VBS 入门交互实战

Windows Server 6月月更 VBS 脚本之美

远程办公之:如何成为时间管理大师?| 社区征文

甜甜的白桃

初夏征文

如何低成本构建一个APP

Geek_99967b

小程序

好用的人事管理软件有哪些?人事管理系统软件排名!

优秀

企业管理软件 OA管理系统

如何使用物联网低代码平台进行流程管理?

AIRIOT

低代码 物联网,

应用实践 | Apache Doris 整合 Iceberg + Flink CDC 构建实时湖仓一体的联邦查询分析架构

SelectDB

数据库 flink Doris iceberg

SLSA: 成功SBOM的促进剂

安势信息

开源 开源软件供应链 软件物料清单 SBOM SLSA

RabbitMQ基础知识

龙空白白

RabbitMQ

RabbitMQ访问Web端口报错User can only log in via localhost

龙空白白

国内外最好的12款项目管理系统优劣势分析

爱吃小舅的鱼

浅谈如何运营好小红书账号:利用好长尾词理论

石头IT视角

区块哈希竞猜游戏系统开发(dapp)

薇電13242772558

哈希值

Flutter中的GetX状态管理用起来真的那么香吗?

岛上码农

flutter ios 移动端开发 安卓开发 6月月更

小程序容器到底是什么

Geek_99967b

基于模式的架构评审_架构_Paris Avgeriou_InfoQ精选文章