Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

1.4 科布西耶——形式追随功能

一部宣言和一栋漏水的房子

1923年,巴黎。一位36岁的瑞士裔法国人出版了一本不到三百页的书,书名叫《走向新建筑》(Vers une architecture)。这本书的语调如此激进、如此自信、如此具有挑衅性,以至于即使在百年后的今天,翻开它你依然能感受到那股扑面而来的锐气。

此人名叫查尔斯-爱德华·让纳雷(Charles-Édouard Jeanneret),但我们更熟悉他的笔名:勒·柯布西耶(Le Corbusier)。

柯布西耶在书中抛出了可能是建筑史上最著名的一句话:

“一所房子是一台居住的机器。”(Une maison est une machine à habiter.)

这句话被误解了近一个世纪。当柯布西耶说“机器“时,他指的不是冰冷的、非人性的、工业化的铁盒子。他指的是功能的精确性、结构的逻辑性、每个部件都服务于一个明确的目的。在他的观念里,一台好的机器(一艘远洋轮船、一架飞机)其外形就是其功能的最纯粹表达。飞机的外形不需要装饰性曲线,它由空气动力学决定。轮船的舷窗不需要巴洛克雕花,它由结构强度和密封需求决定。好的建筑,同理,其形式应由其中发生的人类活动(居住、工作、交往)来决定,而非由建筑师的审美偏好来决定。

这就是“形式追随功能“(Form follows function)。这句话不是柯布西耶发明的(它最早由美国建筑师路易斯·沙利文提出),但柯布西耶把它推到了极致。

柯布西耶同时提出了“新建筑五点“(Les 5 Points d’une Architecture Nouvelle):

  1. 底层架空(Les pilotis):建筑被柱子抬离地面,释放出底层空间。地面归属于人,而非建筑物的地基。
  2. 自由平面(Le plan libre):内部墙体不再承重(承重全由柱子和楼板完成),因此空间划分完全自由,墙面可以按功能需求任意布置。
  3. 自由立面(La façade libre):外立面从结构限制中解放出来,窗户可以是水平的连续长窗,不受承重墙体间距的约束。
  4. 水平长窗(La fenêtre en bandeau):一整条水平的窗户横贯立面,提供均匀的采光和全景视野,而非传统建筑中受结构限制的零星竖窗。
  5. 屋顶花园(Le toit-terrasse):被建筑占用的地面,通过屋顶花园“还给“大自然,屋顶不再是废弃空间,而是居住空间的延伸。

你可能会困惑,这些建筑理念和汽车嵌入式软件有什么关系?

让我把新建筑五点翻译成软件架构的语言。你会发现,这不过就是SOLID原则在物理空间中的表达。

底层架空 = 依赖反转——建立抽象基础层

柯布西耶的“底层架空“是这样操作的:建筑的主体不直接坐在地面上,而是架在一组混凝土柱子上。地面层完全释放,你可以在这里停车、做花园、布置公共空间。一个物质化的隐喻:基础层不参与上层建筑的具体功能,只提供支撑。

软件中的“底层架空“就是分层架构的核心理念:底层抽象不应依赖于上层具体实现。在AUTOSAR架构中,MCAL(微控制器抽象层)不“知道“上面是存ECU抽象层还是CDD(复杂驱动);Flash驱动程序不“关心“它擦除的数据区块是NVM(非易失性存储器)模块的存储内容还是诊断事件日志。MCAL只提供一个标准化的接口,就像柯布西耶的柱子只提供支撑力。

更深一层:“底层架空“还意味着底层释放了上层的自由度。因为柱子已经承担了所有的垂直载荷,上层的内墙可以自由布置,这就是“自由平面“的物质前提。同理,因为你的硬件抽象层已经封装了所有MCU寄存器的细节,你的应用层软件可以专注于“扭矩控制策略“的业务逻辑而不需要关心“这个寄存器的第3位是哪个时钟源的使能信号”。

自由平面 = 单一职责与开闭原则——模块的独立演化

“自由平面”:内墙不承重,只起分隔空间的作用。因此墙的位置可以随时调整,今天这面墙在这里,十年后业主改变了需求,可以把墙拆掉或移到别处,因为结构没有变化。

翻译成软件:模块的内部实现应该可以被修改或替换,而不影响整体结构的稳定性。这就是开闭原则(Open/Closed Principle):对扩展开放,对修改封闭。

在AUTOSAR中,你可以在不改变RTE(运行时环境)接口的前提下,替换一个SW-C的内部实现,比如,把一个基于查表法的PID控制模块替换为一个基于模型预测的控制模块。只要端口类型和接口定义不变,RTE不“感知“这个变化。这就是“自由平面“的软件版:承重结构(接口)不动,分隔墙(内部实现)自由更换。

同时,每个模块应该有一个改变的理由:单一职责原则(Single Responsibility Principle)。柯布西耶的建筑中,一面墙只做一面墙的事,分隔空间。它不负责任何结构性的承重。你的软件模块也应该如此:一个负责CAN通信管理的模块不应该同时负责扭矩限制算法的计算。问题的核心在于:当扭矩控制策略变更时,你不应该修改通信管理模块的代码。

水平长窗 = 接口设计——清晰的、稳定的、均匀的边界

柯布西耶坚定地使用水平长窗:一整条连续的窗户贯穿整个立面。为什么?因为(1)均匀采光(功能优势),(2)全景视野(用户体验优势),(3)立面不再是承重墙(结构前提)。

翻译成软件:好的接口应该是“水平长窗“:清晰、连续、均匀、可预测。一个SW-C的端口定义应该让使用者不需要“猜测“,你不应该需要深入阅读这个SW-C的内部代码才能理解怎么调用它的服务。就像你不会困惑于一扇窗户是“用来采光的“,窗户的存在本身就表明了它的用途。

反例:一个“port“既输出扭矩值又在特定条件下输出故障标志位,且二者的触发条件耦合在同一个API函数中。这不是水平长窗,这是在一扇窗户上同时安装了百叶窗、空调外机和消防梯。所有功能都能用,但没有人能在不看说明书的情况下理解它。接口的职责必须是单一的和自明的。

屋顶花园 = 资源利用——被占用的资源要“还“回来

柯布西耶的“屋顶花园“是一个诗意的想法:建筑占用了地面的绿地,于是它在屋顶上重建花园,把失去的自然空间“还给“人类。功能上:隔热、休闲、排水。

翻译成软件:每一个占用的资源都有回收的责任。 在嵌入式系统中,这个原则直接映射为内存管理、堆栈管理和中断优先级管理。你占用了RAM的某个区域用于动态分配,当你不再需要它时,你必须“还“回去(释放内存,或至少标记为可重用)。你注册了一个CAN消息的接收回调,当ECU关机或模块去初始化时,你必须注销这个回调。这就是为什么AUTOSAR中每个模块都有init()和deinit():init()是“我搬进来了“,deinit()是“我把花园还给你“。

更深一层:在软件架构层面,“屋顶花园“意味着一个设计决策的成本必须被其带来的价值所覆盖。引入一个间接层(比如,抽象工厂模式)确实增加了代码复杂度(占用了“地面空间”)。那么,它是否在未来的可扩展性中“还“回来了?如果这个间接层在整个项目生命周期中只被扩展过一次,那你就建了一座没人上去的屋顶花园,占用了空间却没人使用。

核心洞察:约束的目的是释放。 柯布西耶的新建筑五点不是五条教条,它们是五个“约束“,但每一个约束的目的都是“释放“。底层架空约束了承重方式,但释放了地面空间。自由平面约束了墙体不能承重,但释放了内部空间的可变性。好的软件架构同理:SOLID原则中的每一个字母都是一条约束(你“不能“做什么),但遵守这些约束恰恰是为了释放系统在未来应对变化时的自由度。

但柯布西耶的故事还有一个更重要的部分,那栋漏水的房子。

Villa Savoye:当优雅遭遇现实

1928年,柯布西耶在巴黎郊外的普瓦西(Poissy)设计了Villa Savoye(萨伏伊别墅)。这栋白色盒子式建筑被公认为现代主义建筑的巅峰之作,完美诠释了新建筑五点。建筑历史学家称之为“20世纪最重要的住宅建筑之一“。它如此完美,以至于照片看起来像建筑设计软件的效果图,干净的白色几何体悬浮在绿色草坪之上,水平长窗环绕整个立面。

但它有一个致命的问题:漏水。

萨伏伊别墅的平屋顶设计(屋顶花园理念的核心部件)完全没有考虑到法国北部冬季的雨雪荷载。屋顶排水系统设计不足,水分通过微裂缝渗透到混凝土结构中,导致三楼(业主的起居层)大面积发霉漏水。萨伏伊家族在入住几年后被迫搬出,并考虑起诉柯布西耶。在业主的信中,有一句话被建筑史学反复引用:“楼上的水持续渗透,使得我们无法正常居住。我们把此事交给你来处理。你不会容忍一栋’用来居住的房子’无法居住吧。“直接引用了柯布西耶自己的宣言“房子是一台居住的机器“作为撒手锏。

1939年二战爆发时,Villa Savoye实际上已经被废弃了。它后来被用作德军的弹药库,又经历了盟军轰炸,最终在1960年代被法国政府列为历史古迹并修复。

这个故事不是一个关于“现代主义建筑很失败“的笑话。它是对我们所有软件架构师的一个根本性告诫:

优雅的设计必须经得起现实的考验。

柯布西耶在设计Villa Savoye时考虑了一切:比例、光线、空间流动、功能分区、几何纯粹性,但他在平屋顶的防水细节上没有给予足够的工程设计严谨性。他没有充分考虑到“法国北部冬季的冻融循环“、“平屋顶排水坡度在实际施工中的偏差”、“混凝土在干湿交替中的膨胀系数“这些“工程细节”。

每当我看到一份写得完美的软件架构文档,用PlantUML画得漂漂亮亮的组件图,完美的分层,恰到好处的依赖反转,无可挑剔的接口抽象,我的第一反应是一个问题:“这个架构设计在第一次SIL(Software-in-the-Loop,软件在环)测试中能否存活?当真实CAN总线上出现了一个不在设计规范中的异常报文时,这个优雅的架构会怎么反应?当硬件抖动导致一个2ms的Task实际运行了2.4ms时,这个无可挑剔的调度策略还成立吗?”

形式必须追随功能。但如果形式不满足功能的非功能性约束(可靠性、实时性、可测试性),最好的形式也是错误的。

核心洞察:优雅的标准是“在所有约束条件下都正确“,而不是“看着漂亮“。 这是Villa Savoye漏水的教训:优雅的定义在工程约束面前需要重新校准,而不是放弃追求优雅。在汽车嵌入式软件中,一段200行的函数,如果它的WCET(最坏情况执行时间)可被静态分析证明、分支覆盖率达到MC/DC标准、且代码评审已经确认其正确性,它就是优雅的。相反,一段被拆成10个单行函数的“整洁代码“,如果因为函数调用的上下文切换开销导致Task超限,它就是不优雅的。

马赛公寓:建筑是为了谁?

但柯布西耶的故事不能以“漏水“结尾,因为那样会错过他最重要的贡献。

1952年,二战后七年,法国面临严重的住房短缺。柯布西耶在马赛设计了一栋后来被称为“马赛公寓“(Unité d’Habitation)的住宅大楼。这不是一栋普通的公寓楼,这是一座垂直城市。

马赛公寓有12层,容纳1600名居民。但柯布西耶不仅仅设计了居住单元,他在楼内嵌入了一条商业街(第7和第8层),包括面包店、书店、餐厅、理发店。他设计了屋顶剧场、幼儿园、游泳池、跑道。他把有幼儿园的那层称作“空中街道“,因为孩子们可以在走廊里奔跑,就像在地面一样。他把公寓的起居室设计为两层通高的空间(部分户型),让你在50平方米的单元内依然获得宽敞的空间感。

马赛公寓不是“把房子堆起来“。马赛公寓是“把一整个社区折叠成一栋楼“。它的底层架空不仅仅释放了地面空间,架空的高度设计为能够让消防车通过。它的水平长窗不仅提供了采光,每一扇窗户都安装了内置遮阳装置,适应马赛的地中海气候。它的色彩也经过了详细设计,每个阳台的内侧涂着不同的明亮颜色,打破了混凝土灰色的单调。

为什么马赛公寓伟大?因为它完成了一建筑学中最艰难的转变:从“建筑是关于建筑师的“到“建筑是关于住在里面的人的“。

Villa Savoye是为萨伏伊一家富人设计的私人别墅,它失败了,因为建筑师更关心自己的理论而非用户的居住体验。马赛公寓是为1600名普通工人家庭设计的公共住房,它成功了,至今仍然住满了人。不是因为柯布西耶放弃了现代主义,马赛公寓是新建筑五点的忠实实践。他在这个项目中将“用户需求“的优先级提升到了“理论纯粹性“之上。

马赛公寓的屋顶没有漏水。因为柯布西耶吸收了教训,他采用了有坡度的排水层、更耐候的防水材料、更严格的结构细节审查。

核心洞察:软件架构的终极用户不是评审员和委员会,而是那些与你的软件交互的人。 驾驶员(他信任刹车功能)、维修技师(他依赖诊断数据来定位故障)、安全评估员(他需要追溯链条来判断系统是否安全)、以及接替你维护这段代码的未来工程师(他会在凌晨三点被叫醒,因为一个生产缺陷报告指向了你三年前写的模块)。你的架构是否优雅,应该由这些人在十年后的使用体验决定。

SOLID原则与马赛公寓:为“弹性“而非“优雅“设计

当我说SOLID原则是“软件版的柯布西耶五点“时,我指的是它们都服务于同一个目的:让结构在变化中保持稳定。

逐一对照:

  • S(Single Responsibility):一面墙只做一面墙的事。一个模块只有一个改变的理由。在Villa Savoye中,柯布西耶没有遵守这个原则,平屋顶同时承担了“防雨“、“隔热”、“花园”、“建筑宣言“四重职责,结果四个都没做好。在马赛公寓中,屋顶被明确划分为几个功能独立的区域(泳池、步道、剧场),防水的任务交给了专业的防水层,而不是建筑形态本身。

  • O(Open/Closed):马赛公寓的混凝土框架体系(柯布西耶称之为“酒架“系统,即bouteiller),承重结构是固定的酒架格子,但每个单元内部的隔墙可以根据住户意愿调整。扩展开放,修改封闭。你的软件架构的“酒架“是什么?可能是RTE的接口定义,可能是操作系统的Task配置,可能是NVM的Block划分。这些一旦确定,修改代价极高。但每个SW-C内部的算法实现,如同公寓单元内的隔墙,应当是自由可调的。

  • L(Liskov Substitution):如果一个子类型不能替代其基类型而不引发错误,那就不是真正的子类型。在马赛公寓中,每一种“房间类型“(单人间、双人间、复式)都满足“可供居住“这个基类契约。你不能设计一个“没有水管的房间“然后称之为“居住单元“,它违反了基类契约。软件中的接口设计同理:你的NVM接口承诺“写入操作是原子性的“,如果你为某个特殊Flash设备实现的写入操作不是原子性的,你就违反了里氏替换原则,任何依赖NVM原子性语义的上层模块都可能在你替换Flash驱动后崩溃。

  • I(Interface Segregation):不应该强迫客户端依赖它不使用的方法。马赛公寓的公共服务按楼层垂直分布,面包店的顾客不需要走到屋顶泳池才能买到面包。如果设计成“所有公共服务都在顶层“,那就会强迫不使用泳池的人也承受从顶层下来的电梯等待时间。你的软件接口同理:一个硕大的“SystemManager“接口提供了100种服务,但一个简单的温度传感器SW-C只需要其中一种(比如,获取系统时钟),却被迫“知道“其他99种接口的存在。这不是优雅,这是接口污染。

  • D(Dependency Inversion):高层模块不应该依赖低层模块,两者都应该依赖抽象。马赛公寓的排水系统不依赖“某一户每天用水多少升“,它依赖抽象的“每层最大用水量和最不利排水点“的设计参数。你的Brake Control SW-C不应该依赖“具体车型的制动盘材料摩擦系数“,它应该依赖抽象的“制动力与液压压力的映射函数“,而这个抽象的具体参数化通过标定数据注入。


本篇小结

  • 柯布西耶的“新建筑五点“ 将建筑从“装饰性形式“中解放出来,确立了“形式追随功能“的现代主义核心原则。这一原则在软件工程中体现为SOLID原则对模块化设计的系统化表达。
  • 底层架空→依赖反转:底层抽象为基础,不依赖上层实现;上层需要底层的能力,但底层不“知道“上层的存在。这正是AUTOSAR分层架构(MCAL→ECUAL→SWC)的设计哲学。
  • 自由平面→单一职责与开闭原则:每个模块(每面墙)只做一件事且不承担结构性责任;模块内部实现可变,但接口(承重柱)不变。这是软件架构应对需求变化的基础机制。
  • Villa Savoye的漏水事件是一个关键教训:优雅的架构设计必须经得起现实世界的物理约束。在汽车嵌入式系统中,这意味着你的架构必须在实时约束(WCET)、存储约束(RAM/ROM)、通信约束(CAN带宽)和安全约束(ISO 26262)下证明其正确性,而不只是“在纸上漂亮“。
  • 马赛公寓代表了柯布西耶从“自我表达“到“为人设计“的成熟转变。这一转变在软件架构中意味着:架构的最终评价标准,是它如何服务于驾驶员、维修技师、安全评估员和接班工程师这些活生生的人。
  • SOLID五原则与建筑的对应是一种帮助你内化设计原则的思维工具,而不是空洞的类比。下一次你设计一个模块接口时,想一想“这片墙会不会因为不该它承担的任务而倒塌“。

【下集预告】 柯布西耶教会了我们“形式追随功能“:一栋建筑的形态必须服务于居住在其中的人。但还有一个问题柯布西耶没有完全解决:谁来检查这栋建筑是否可以安全地使用? 建筑行业有独立的监理工程师,他们不是设计者,不是施工者,他们唯一的职责就是签字确认建筑符合安全规范。那么软件行业呢?我们的“监理“是谁?为什么建筑有强制性的第三方审查而软件没有?下一节,我们将深入“结构安全审查“的世界,你会发现,代码评审、静态分析和独立安全评估,本质上就是在做建筑师一百年来一直在做的事情。