searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Hello Coding

2023-10-26 09:35:26
4
0

前言

    所有的程序猿们入门的第一道程序几乎都是“Hello world",从模仿键入样例代码开始期待一健运行成功,直到弹出"Hello world"带来的喜悦。 貌似这是成功的第一步,也是开启兴趣大门重要的一步。而后不断的学习,不断的深入,透着现象看着本质,就越发深沉和平静。可靠程序的背后需要经历千锤百炼,犹如修行。

什么是程序

    什么是程序?!

    这是一个疑问句,也是一个感叹句,不同的人有不同的理解。

    或许:

    程序是为了求解。寻找定制的答案。

    程序是为了筑梦。编织虚幻,透着真实。

    程序是人类思想的一部分,是人类智慧的一部分。

又一种程序

    任何事物都不可独立存在,其间都有千丝万缕的联系。一个事物的呼出必然会是另一个事物的呼入,另一个事物的呼出可直接或间接作为第一个事物的呼入,几者相互独立而又相互作用。程序本身即时如此,"IO"是程序的基本属性,守I守O是程序实现的原则,犹如诗歌踩着节拍去寻找最美弦律。

 

有开有关

    有开有关,或称之为有开有合。事务的处理必需要有闭环,而确保闭环的重要手段即是对开合的处理。开合往往并不单单意味控制程序的开始和结束,而同时需要对程序整个生命周期中逻辑和数据的开合处理。比如对逻辑的开合要求有:if/else、switch default、信号、互斥锁、函数对等;数据的开合有:申请/释放、增/减、标记/反标记、引用/解引用、值传递等。

    逻辑的处理往往呈对称性,比如从小方面来说,在处理if条件的逻辑时,需要考虑else分支是否覆盖,某些隐含的else处理也需要一并考虑进来,或为空,或注释。大的方面逻辑正向流量和反向流程是否对称,比如回退路径;类/模块/函数调用是否有结果并可感知回馈,全流程可追踪可回溯。

    现代程序一般会设计为逻辑服务于数据,即围绕数据设计逻辑或称之为数据加工,而coding时往往会反过来:如先设计数据结构,再考虑主体逻辑。这种方式实现了设计和实现之间的互哺,可相互佐证,从而使程序向前递进。问题可能主要出现在中间数据上,中间数据的开合处理往往容易被忽视。所谓中间数据,即程序运算过程中产生的临时数据,用于辅助运算的中间变量、内存、信号、标记等。

    无论是逻辑开合还是数据开合,封装是一种好的应对方式,即对逻辑或数据实现开封装和闭封装,可以采用类、函数/方法的方式。封装可保证逻辑执行的完整性,数据访问的安全性,或可进行可维护性方面的设计,规避了离散数据或分支逻辑的系列问题。

 

范围限定

    任何事物总会是有边界的,但边界并不意味着封闭,其目地在于保持事物本身的个性,维护事物的独有属性,同时也是维持并外部事物的交换的渠道。其中,边界的识别和管理对事物尤为重要,边界才可保证事务的独立性和多样型,可见,万物多样性和独立性是相辅相成的。

    程序通常会划分成若干模块,各个模块内聚的同时又相互耦合,即使单个模块或函数组成的程序,其也不是独立存在的个体,需要参与到外部世界的活动之中,于是便有了IO。程序内的边界考量对程序的后继维护尤为重要,这些考量包括边界的识别和边界的设定。

    其一,识别数据的边界,特别是IO数据的边界,守住模块/函数/接口间呼入呼出。如函数入参、出参、返回值是否符合预期范围;如指针空间是否有效;如变量运算前后值域的有效性,含翻转。特别的,计算机运算位数(8/16/32/64)隐含的数值边界;耦合数据间隐含的同效边界,如回家吃饭,必须满足回家为真,吃饭为真的双重条件。

    其二,识别逻辑的边界。逻辑本身是没有“感情”的,其同时/分时运算过程中,无法感知其本身行为,但在引入数据后,逻辑诞生出了记忆。故而,逻辑守界在于守数据,只有数据不耦合,逻辑才能维持独立性。数据的不耦合并不意味着逻辑着没有数据关联,而是要求在运算过程中,不能产生数据耦合,即要求多个逻辑不能在同一时间操作关联数据。在程序实现时,尽量将逻辑解耦,何持其分时/同时运算的独立特性,如使用栈变量、线程变量;如需共同协作完成某一事务需要访问共享数据时,需要保证数据的互斥性。

时间限定

    道生一,一生二,二生三,循环往复,周而复始。

    程序的演进亦是如此,如生命般,不断演化、不断重构。初生如婴儿,纯洁而希望盈;鞭策磨练壮如虎牛;然万千变化,守中不易;伏槽梦华年。

    程序终将陷入上述故事循环,而维持程序的生命周期管理,延长其过程尤为精彩。

    生命周期的管理包括追踪生命的存在性和健康性,同样的从数据和逻辑两个角度来阐述生命周期的维护过程。

    首先,数据会经历诞生、变更、销毁三个阶段:新生数据不应有记忆,故而需要进行初始化;数据变更时需要及时被消费者感知,特别是寄存器变量、副本数据,在生产端和消费端皆需要考虑数据是否及时有效;销毁后数据需要保证不残留,并确保不被任何相关或不相关的模块引用。

    其次,逻辑同样遵循相同的时间法则,但逻辑本身没有灵魂,其需要围绕数据进行运算,包括准入、准出两个时间节点及两点之间的时序控制。如果把逻辑具体实现为模块/函数/接口,则需要逻辑触发的条件设定,即满足范围限定要求;逻辑准出除需要满足范围限定要求外,还要求满足时间依赖性,如逻辑执行的快慢需要符合节拍,最终满足程序模块间的同步需要。

空间限定

    又一种边界。

    不同于范围边界,空间限定在于对程序的作用范围进行约束。

    冯诺依曼下的计算机体系,仍然离不开数据和算法,这种分离式设计限制了算法的自我演进,但其仍然是现有最好的计算机架构。如下仍然从两个维度展开论述。

    数据自定义开始,便有了作用范围,如栈数据、线程级数据、进程级数据、核间数据、全局数据,这是数据的静态属性决定的,但并不意味着是数据的设定作用范围。数据的设定范围总是小于静态范围。如线程级数据虽被可全线程指定使用,但在设计范围内,其是否满足被指定逻辑的访问要求,避免数据外溢风险,有序数据封装仍然是有效的闭合方式。

    数据闭合为被动防护,受静态范围影响,无法有效防护逻辑侧对其的越界使用,故而需要逻辑侧需要同步考虑其作用范围。由于逻辑的本无附加属性,不知从何时起,其与数据耦合后,诞生了运算的意义,故而逻辑的空间受限于数据的空间。除需要静态识别出逻辑作用的数据外,还需要避免逻辑使用了边界外的数据。这类边界外的数据,通常是运算导致了错误的结果,通常发生在底层开发语言支持指针/引用类数据时,一种有效的方式是避免直接地址访问,采用间接访问更为安全,如索引。

    另一方面,逻辑空间除显示逻辑外,需要同步考虑间接或隐式逻辑的安全边界。逻辑调用第三方模块/函数/库时,需要同步考虑被调者的作用范围,当然,通常被调用者需要支持重入要求,并避免产生逻辑耦合。这类要求在安全性方面尤为严格,如使用strcpy函数、调用shell等。

天地大同

    存在即合理。

    无论对于新增逻辑还是变更逻辑,需要最大化满足现有逻辑架构,并以此作为后继程序实现原则。假设,程序从诞生开始,便是符合最初的架构和需求,以及后续演进需求的;那么,对于新增逻辑或变更逻辑,需在当前约定的范围内展开活动,保持现有架构和模块特点;于是,程序便从始至终便维持住了统一性。

    如现有架构无法满足新需求的需要,而需要作出例外设计时,则尽量旁路原有架构,减少对原有数据和逻辑的耦合;但这会加重程序分裂,加重程序维护难度。而这通常发生在程序生命周期的末期,此时,需要将程序重构纳入后继规划中。

0条评论
0 / 1000