大四实习总结
这是我第一次真正去公司工作, 虽然公司规模还大不, 但总得来说, 整体的氛围是相当不错的, 作为职场新手的我学习到了不少东西.
刚进公司的时候, 我写了一个多礼拜的前台控件, 学习到了如何快速地对一个大型软件有个整体上的把握, 我的观点是在短时间内要很好的把握大型软件的方方面面是无法实现的, 也没有实现的必要(即便不了解每一个细节, 也绝对不影响早期简单工作的进行). 那应该如何快速融入工作呢? 首先, 最重要的是找到一个”切入点”, 具体来说, 可以是在运行软件的过程中, 任意定位一个你能够理解的功能(这个功能不应该是核心功能, 而是一个非常小的功能, 甚至可以简单到在前台控件上显示一些数据), 定位完成之后, 在平台中找到那个功能的实现代码(之所以需要小功能, 就是为了方便理清实现该功能的代码的思路, 大的功能的实现代码往往涉及多个文件, 甚至多个项目, 难以快速把握和理解). 在理解该代码的基础上, 利用”自下而上”的学习方法, 由点及面, 慢慢了解软件的整体架构. 整个过程中, 最为困难的就是”切入点”的确定, 这个可以由有经验的工程师指定几个小功能作为新手的”切入点”, 这里的用意并非希望他们去完成这几个小功能(让有经验的工程师写, 可能只需几分钟便可完成), 而是为了让新手能够快速达到”可以工作”(不是详细了解软件架构)的状态, 从而有效地帮助新手克服心理上的焦虑感.
写了一个多礼拜控件之后, 牟博士希望我能够尝试介入显示模块的开发, 在几天适应期之后, 我就开始了平台上的开发工作. 这里让我感触最深的就是, 如果牟博士没有这么做, 那我在整个实习过程中学习性价比将会大大降低, 能够认识到员工的特长并委之相适应的工作自然是公司管理人员的重要责任, 但我作为一个开发人员, 思考如何定位自己在公司内的责任, 并主动地说服上司我为什么能够比别人更好地完成某项工作才是更为重要的. 我的观点是让别人看到你希望完成某项工作的强烈意愿并提供实实在在的证据以证明你能够很好地完成该项工作(比如从前的经历或者提出某些有用的建议甚至是demo性质的实验品). 总结起来就是让上司看到你的诚意加上与之相匹配的能力.
严格来说, 这是我第一次参与”工程性”的项目, 其中对我理解面向对象的编程范式起到了非常大的帮助. 首先是C#的学习, 在之前我对于C#的实践仅限于本科时代的软件工程大作业. 这次实习给我的感触是C#相对于C++来说彻底的面向对象, 与其说C#通过语言内建很好地支持了面向对象编程, 也许说C#”强制”程序员以面向对象的思维方式来思考并以语言内建来很好地支持这些想法的实现会更容易理解C#的本质. 其实前面这句话隐藏有了一个trick, 它默认了思维方式和实现方式之间的过渡关系是水到渠成的. 所谓”脱离语言思考, 依赖语言实现”, 由思维方式自然地过渡到语言的实现方式毋庸置疑是一个非常理想的状态, 在C#中这确实是事实, 但在一门多编程范型的语言(C++)中呢? 关于C++的话题下文再详细讨论. 回到面向对象的话题, 以前我对于面向对象的认识主要集中在如何设计出一个精美的class(复杂的类层次结构), 将关注的重点限制在了class的设计上. 而现在, 我认为比起如何思考class本身, 更为重要的是”messaging”, 即如何建立不同的class之间有效的消息传递方式(低耦合, 高内聚; 对扩展开放, 对修改关闭). 我的这个思维误区很好地对应了C++到C#的进化过程, 为什么C#中要利用单继承和interface来代替C++中的多继承模型? 根据前文的思路, C#中的单继承正是为了限制class的设计过分复杂, 而interface则很好地定义了一种class-level的消息传递协议(delegate则是另一种function-level的消息传递协议). 详细来说, Interface代表的是一种特性, 而类与类之间的交互在很多场合(越好的设计中这样的场合越多)需要的是具有某种特性(实现了某个接口)的对象. 在面向对象中, 所谓的封装并不是简单地设定access-level, 而是在类中实现某一具体的功能并以接口的形式提供给使用者. 当然, 类与类之间的消息传递也可以通过父子类的多态来实现, 这样可以在保证父类不变的情况下不修改依赖父类的代码, 但这么做仍然依赖于父类的实现. 所以, 最好的情况就是通过接口来实现类与类之间的消息传递, 这样, 在双方依赖接口统一接口的情况下, 对于类的修改就不会影响到外界的代码, 这就是针对接口编程而不针对实现编程的好处.
现在看来, 当时之所以会对面向对象产生这样的思维误区, 其实是由于学习C++的时候过分注重一些语言细节, 而忽视了C++多编程范式的本质. 将C++的语言实现方式想当然地等同于思维方式本身. 我并非是指只应该学习C++中面向对象的sub-model, 而是指不应该在脑中想当然地认为自己在以面向对象的”思维方式”来思考, 却陷进了C++的数据抽象以及泛型编程等其他sub-model的”语言实现”中. 相对于C#来说, C++的语言细节实在是数不胜数, 在大型软件的项目中, C++的入门台阶之高远不是C#, Java可以比拟的, 这无疑给程序员造成了巨大的压力. 为了总结我在C++中的思维误区, 依旧从面向对象说起. 在C#中有两个非常重要和基础的概念, 值类型和引用类型. C#中的引用类型与C++里的引用类型虽然在语法上类似, 在概念上却完全不是一回事, C#中的引用类型更加类似于C++里智能指针的概念. C++最为优秀的一点, 就是在保证效率的同时引入了高级的抽象模型. 但是尴尬的是, C++中class的语言内建是值类型, 比如代码中出现了{MyClass myObject;}这样的代码, C#会认为是你声明了一个类型为MyClass的null引用, 而C++却会在stack上像int类型那样构造一个值类型的对象; 另一方面, C++中又必需通过引用类型(引用or指针)来获得多态的行为. 换句话说, C++语言内建支持的编程泛型, 并不是面向对象, 而是数据抽象, 而C#中为了区别这两个概念, 采取了将struct(值类型)与class(引用类型)这两个关键字区别对待的方案(C++中这两个关键字唯一的区别就是默认的access-level不一样).