《代码中的软件工程》心得体会

1. 课程亮点

众所周知,软件工程是一门概念理论抽象、背诵记忆多、不好理解的学科。这课不太受待见,因为如果缺乏实际应用情景,直接灌输理论会让人味同嚼蜡,对老师和学生都是折磨。然而,孟老师另辟蹊径,没有一上来就照本宣科——像其他老师一样讲解软件危机的出现、软件工程的由来、面向过程软件建模的方法……而是“先做起来再说”——从实践出真知,先是以学习VSCode、Vim、Git等热门软件开发工具作为开胃菜,紧接着用一个命令行菜单小程序作为小甜点,在品味完善菜单小程序的过程中,润物细无声般植入代码风格、模块化设计等知识,然后自然而然地过渡到正餐——需求分析、软件设计、软件架构等高级理论的学习。这样做中学、学中做的教学模式虽然进度会慢一些,但却能将大量枯燥乏味的知识点融入一个个鲜活的情景中,比如“通过加互斥锁支持命令行程序的并发访问——引出可重入函数的概念”,能充分地理解其背景意义,更好地消化吸收,掌握更为牢靠,正所谓“慢慢来,比较快”!

雄关漫道真如铁,而今迈步从头越。不知不觉中,体系庞大内容丰富高软已经划上已经划上休止符。回首这过去一个学期的课程,下面几点犹如小石子投入我心,泛起层层涟漪:

1.1 磨刀不误砍柴工——VSCode、Git等工具的学习

用VSCode搭建C++开发环境(Windows系统下)?当看到这项任务时,习惯于IDE一键编译的我感到有些别扭难受,放着IDE简单无脑的一条龙操作不用,干嘛要去费尽周折地用一个“超级记事本”去搞开发?尤其是编译器调试器MinGW下载龟速,VSCode基于JSON的命令行配置方法较为繁琐,初期频繁出错,一山放过一山拦,调试时总是跳出“programme does not exit”的警告窗,让我叫苦不迭,一度想放弃。

踩过一个又一个坑后,终于成功打印出“hello world”,激动心情难以言表,一股强烈的成就感油然而生。下载编译器、修改环境变量、安装npm、创建配置c_cpp_properties.json+tasks.json+launch.json三件套……手动搭建开发环境虽然坎坷,却让以往被IDE所屏蔽的底层原理细节浮出水面。折腾中,我逐渐明白如何调用工具和命令行编译、链接、执行、调试代码以及如何用配置文件让上述步骤永久化、自动化,收获求知和创造的乐趣。原来,配置完C++环境的VSCode会默默地完成这么多工作:当编写代码时,它会根据c_cpp_properties.json中的配置确定语言的版本标准(比如C++11)、头文件所在目录等进而检查语法和标识符;当运行时,它会根据tasks.json调用指定的编译器(如gcc、g++)并传入设定的命令参数,确定工作目录和目标文件的名称和存放位置等;当调试时,它会解析launch.json文件,调用指定的调试器(如gdb)和接收设好的命令参数,确定待调试程序的路径等。现在每当生成调试一个c语言小程序,我都能想象它背后的“丰富”的历程,配置出错也能更快找出原因,定位出错位置,比如后来菜单小程序引入互斥锁,编译时需要链接线程库,我很快知道需要修改tasks.json中的编译命令参数(添加-lpthread),这样的收获是以往IDE中点击“绿色播放键”然后傻傻等结果所不能比拟的。

上述任务给我另一个启发是,对待一项陌生事物,不要试都不试、还没深入了解就敬而远之或视之如敝履。很多时候所谓的“没用”、“麻烦”、“不感兴趣”,只是你不会用、没到那个的情境。就像接下来学的git工具一样,以往大多是个人开发小玩具程序,不需要版本管理,手动多另存为几次改改项目名就好;如果小组合作,截图、QQ传文件、网盘分享……简单便捷粗暴。git?不存在的,太麻烦,没必要,割鸡焉用牛刀?然而,耐着性子琢磨一番git的基本操作init、add、commit、push……,感觉相见恨晚,原来这工具这么简洁高效。几条简单指令,就能记录版本变更,做增量备份,还可还原回退,再也不用费劲地另存为、改文档名了;而且github不仅仅是一个网盘,更是集代码仓库、资源管理、博客、社区的多面手,从团队视角看,代码分享、环境工具保存、进度安排等工作因git而不同,相当从分散无序低效的小作坊进入了统一规范高效的工业化时代,上传、阅读、拉取彼此代码变得异常轻松,在公共仓库创个分支git push即可上传,想下载git pull即可,不必费劲的打包传qq传网盘,节省大量时间开支。因此,不要因为暂时用不到或者初期学习曲线陡峭就嫌弃某个工具,也许你会错失别样的风景。

1.2 看似寻常最奇崛,成如容易却艰辛——命令行菜单程序menu.c的重构

  • 循序渐进,步步为营,克服畏难情绪!
    正所谓“站在岸上学不会游泳”,然而往往却因“水深”而不敢下水。软件项目开发也一样,往往因为功能复杂代码量太大而畏葸不前。好在,孟老师的课程项完美解决上述问题,没有一上来就让你实现成百上千行代码的程序并符合各种工程规范,而是从最简单的打印类似“helloworld”信息开始,然后逐步引入链表结构体、编码规范、菜单与数据结构分离、模块化……把复杂的功能分解成一个又一个的小问题,让你不至于觉得太难,然后逐个击破,同时收获成就感增强信心。这样的打怪升级的过程,不知不觉中完成了一个功能丰富的项目,回首向来萧瑟处,也无风雨也无晴,原来,貌似很复杂的程序只是一只纸老虎。
  • 麻雀虽小,五脏俱全
    虽然上述项目的总体规模不大(不到500行?),功能也比较有限(仅3个命令,查询打印为主),没有使用太高级的数据结构(只用链表),然而它不仅需要使用前面已学的技能(VSCode需配置C++开发环境、用Vim编写代码,编写makefile文档,用git管理版本并推送到云端),而且在每一次迭代中老师会要求在设计中用上新学的知识,如使用统一的代码规范(函数名用帕斯卡法、变量用骆驼法、悬挂式风格等)、从直接使用结构体成员到使用接口从而屏蔽实现细节、规范接口设计降低耦合度(用函数参数代替全局变量,实现参数化上下文)、调用线程库引入互斥锁从而确保函数可重入、业务和数据模型分离提高代码复用度……
  • KISS的启示——少即是多
    以往,我写程序时喜欢让代码“四世同堂”,在main函数里尽可能把所有代码写上,即使遇到需要重复使用的代码块,也会把尽可能多的代码封装在一个函数中,让每个函数无比强大复杂,而且这些函数也放在main所在的文件中。这样程序规模小时优势明显,代码很紧凑,执行效率高。然而工程规模一大,问题层出不穷,梳理逻辑、定位功能、排查调试bug变得很麻烦,经常要跳过大量无关的代码。
    在学习menu菜单程序中,老师反复提及kiss法则,keep it simple and stupid! 一行代码只做一件事,一个函数只完成一项功能!就像下面的GetLinkTableHead函数,只是完成获取链表头指针的功能,没有其它功能特性,也没有创建额外的变量。这样虽然增加额外的代码(函数封装、传参、传返回值),但却让函数逻辑功能简单明了,容易阅读,精力消耗小,不易出错,即使出错也容易排查。事实上,软件开发中只有20%时间写代码,80%时间却消耗在debug上!让函数功能单一化,易于避错、检错、排错,从而不用在debug上空耗光阴而徒增挫败感。简约而不简单,藏巧于拙,是一种大智慧!
    有鉴于此,我打算修改重构工程实践项目,用KISS法则把复杂的函数进行功能分离、简化,降低组员阅读修改难度,提高可维护性。
tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable)
{
    if(pLinkTable == NULL)
    {
        return NULL;
    }    
    return pLinkTable->pHead;
}

1.3 “没学过软件工程更好!这样免受先入为主的思想束缚!”

遥记得,第一节课时,老师调查同学们的课程基础时如是说道,这给基础较薄弱的跨考生比如我注入一剂强心针,本科非计算机专业的学生,在学习CS时经常遭受来自外界和自身的质疑,它们像躲在暗处的毒蛇一样,时不时咬你一口,毒杀数量可怜的信心勇气,徒增不少焦虑——怎么别人那么快就掌握,我半天不得要领,要不认命吧?。
而在这里,我不仅感受到对初学者的包容与耐心,更是开始领略到要辩证看待问题,万事万物皆有两面性,要全面分析其优劣势,然后趋利避害。就像以前没学过软件工程这一点,虽然有上手难度大、掌握新知慢、需要学习知识多短期内压力山大、容易跟不上进度等诸多缺点,但也避免已有相关知识所造成的思维定性,不容易被条条框框束缚,减少新接触的知识与以往旧观念冲突,更容易从不同角度看待思考问题从而激发创造性思维。
例如,前面C语言实现的menu小程序中,有一个巧妙的设计:在链表结点中,将起链接作用的指针放在成员列表首位。当谈及其作用时,老师用了“实现多态”的表述,一些经常在Java、C++接触使用“多态”的同学觉得不可思议——面向过程的C语言怎么会有多态?我倒没有觉得这里用多态有太多不妥,虽然它不符合“八股文”的说法,或许我对面向对象中的多态用法体会不深吧[笑哭]。不过,我们应抓住其精神实质而不是拘泥于形式,上述指针链接的结点同处一个链表,相当这些结点都有公共的入口,这与C++中多态中必须用基类指针指向不同子类相似;再者,放结点首位的链接指针可以通过强制转换指针类型而改变结点的范围和成员构成(不同类型的结点可以用相同的名称的函数指针,然后指向不同的函数实现),从而接受到同一消息可以通过改变结点类型、调用同名不同体的接口做出不同的响应,这与C++多态中子类通过继承同名虚函数但做不同的实现相似。
课程里类似的事例很多,老师把一些哲学观点融入其中,始于软工却不止于软工,触发我对代码背后本质的思考,或许这正是课程名中“高级”的写照。

2. 存在不足

  • 命令行小程序未能在后面的理论章节充分利用
    虽然这学期孟老师让我们用go改写该程序,然而其面向过程的痕迹太严重。如果能用面向对象的程序语言以及开发方法重构该程序,并且结合情景对其进一步拓展,比如开发出ATM机菜单程序。然后在此过程中应用封装、继承、多态等思想,比较“继承”和“组合”两种策略的优劣,进而引申出MVC软件架构、利斯科夫替换原则等抽象理论,不仅可以温故知新,而且教学效果可能会更好。
    另外,软件工程诸多工具和方法其实是面向大规模代码而生,menu菜单程序的小身板撑不太起这些高级特性,在不足500行的程序里使用模块化设计、实现代码复用有点显得生硬,让简单功能复杂化,一些地方一行代码能解决的事却需要进行函数封装?总之,小程序进行使用大项目的开发手段(比如模块化),没能充分体现出这些高级手段的优势。或许,menu菜单程序作为过渡品,后面使用“工程实践基训项目——情感管理系统”会更好。首先,这项目大家做过,较为熟悉;其次,其规模较为适中,而且涵盖很多面向对象的特性、软件开发的设计方法;再次,好作品是改出来/重构出来的,借助高软的知识,反思此前设计开发中存在的问题,并做改进,是一种不错的学习方法。

  • 部分课程作业难度偏大,缺乏细分步骤、引导过程
    《VScode远程开发的逆向分析》这作业整体难度很高,VSCode的Remote功能丰富、结构略为复杂 、代码量较大、研究资料较少,对于软件工程初学者尤其是基础较为薄弱的跨考学生来说,逆向分析深感难以下手。如果能把给出引导的步骤,比如“克隆VSCode代码,分析目录结构-编译调试执行,体验归纳其功能-分析其时序与交互过程-分析需求……”把大问题分解成几个小问题,便于逐个击破,或许学习效果会更好。

  • 课程知识量较大,讲解速度偏快,缺少周期性回顾
    虽然课程时间跨度有一整个学期,然而涵盖的知识点较多,而且前面工具学习、命令行程序设计等实践部分花费不少时间,导致留给后面理论部分讲解的时间相对不足,因而后面讲课速度偏快,不利于知识吸收。再者,前面实践部分是面向过程开发,而后面的理论部分更多围绕面向对象开发,前后知识联系不够紧密,学了后面容易忘记前面。如果讲解设计模式、软件架构等知识时,能多结合前面已学的命令行程序或工程实践基训项目(情感管理系统)则更好;同时,可以阶段性安插复习课、发放练习题(判断、选择这类小题,题量不用太大)进行回顾巩固。

参考资料《代码中的软件工程》https://gitee.com/mengning997/se

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值