纸上得来终觉浅,绝知此事要躬行
Team目前的解决方案是基于QNX的,由于种种原因,决定逐渐切换到Linux平台,而这似乎也是业界的一个趋势,由BMW主推,详见Genivi项目。
切换到QNX对我们一线工程师可以说是一个大利好啊,以前QNX的解决方案只能够有Binary提供,没有源码,学习到的技术有限,并且出了问题还不一定能即时响应。而这一切在Linux平台上都可以改变,我们可以在各种开源的框架(Tracker/LMS/SQLite/GStreamer...)上整合出自己的解决方案,出问题了可以自己阅读源码解决。虽然没有了商业上的支持,意味着出了问题会面临更大的挑战,但是工程师的本性就是拥抱挑战,不是吗? 还有作为一名C++工程师,对新标准和新技术的使用渴望当然也是无比强烈的。目前在公司的Linux平台的交叉编译器的版本是g++ 4.7.3, 这就意味着我可以放心的使用std::shared_ptr了,终于不用自己造这样的轮子了。还有我们的目标平台还支持Boost 1.51.0,泪流满面啊,这意味着以前对部分Boost组件的学习经验也可以派上用场了。
感谢老板的信任,可以让我从一开始就能加入到这样一个全新的项目的开发中。我在中间承担了Tracker/Database等相关模块的开发,而框架设计的工作主要由另外的同事负责。在使用中我能比较明显的感觉到框架中的一些不合理,这些让我觉得很难受,和组内另一个同事聊的时候,他说遇到蛋疼的代码,请无视,可是我想说“臣妾做不到啊”。
下面我客观的评价一下其中我觉得不好的地方(和个人思想有关,如果有异议,请无视),也希望我自己在我自己项目中能够避免这些问题。
比如 源文件/头文件的命名有foobarzoo.cpp/FooBarZoo.cpp/fbz.cpp;成员变量的名字有m_spExample/mspExample/example;成员函数或者全局函数的命名也是风格各异;类的名字也有各种风格CExample/Example...
我不否认合理的使用友元类能够带来设计和代码的简洁,但是过多的使用是不是意味着我们的设计出了一些问题,代码里面有坏的味道了。
不可否认老一批Windows程序员或多或少都接触过COM思想/组件, 我也向周围的几个同事(使用过Direct Show)咨询了一下他们对COM组件的理解,但是基本都没有说出COM真正的精髓的(虽然我也不清楚,但是他没又说说到我的痛点)。而作为年轻一代的Linux程序员,说实话不是愿接受那样的编程风格。 在我们设计里面,为了实现接口查询(QueryInterface)和对象的引用计数,我们的每个类都必须继承IUnknown这样的接口。
class IUnknown
{
public:
virtual HRESULT QueryInterface(HBIID iid, void ** ppObject) = 0;
virtual UInt32 AddRef(void) = 0;
virtual UInt32 Release(void) = 0;
};
可是COM实现这样的接口是为了跨语言实现组件之间的通信啊,而我们的代码最终就只有一个进程,需要QueryInterface干嘛啊。那好,不是还有引用计数吗?而这个不是用std::shared_ptr就可以完美解决了吗。其实最终的类不仅需要继承IUnknown,还必须继承CUnKnown,这个CUnKnown实现了reference count, 然后通过IUnknown中的AddRef/Release来调用。一个类既需要实现IUnknown也需要继承CUnKnown,我认为这是一个相当糟糕的设计(不是说COM,而是对于我们的使用场景),假如哪个类继承了CUnKnown和忘记了IUnknown呢?因为现在的实现里面有个trick是在CUnKnown里面保存了一个IUnknown的指针,在CUnKnown中通过reinterpret_cast来cast this指针到IUnknown*,可是我们没有继承IUnknown啊,天知道运行时会发生什么。 我认为这样的设计是对COM的错误认识照成的,我们为什么不用一个Factory函数来提供类的实例呢?std::shared_ptr
相信读过Real World Haskell(正在啃,真心难啊)的都知道里面对Boilerplate Code的看法吧。
那我们至少也得用RAII来封装啊,手动unlock怎么行呢。
层次太深,目录名字不能准确应模块的功能... 那个叫什么redis的不就一层目录吗?
上面提到的RAII管理资源是一个,还有大量使用char*而不是std::string,使用raw array而不是部分STL组件等。 在这一点上我比较欣然的陈硕的工程能力和思想,这也是我学习的方向。