这篇文档的名称之所以叫做Cookies,是因为本文档是留给下一轮接手该项目的开发者用的。 Cookies是一个网站保存一些必要的状态信息所使用的东西。本文档记录的,也是我们所希望 留给下一轮的开发者的话。本文档包含以下一些部分:项目背景、系统架构、现状及历史遗留问题、建议。
重要的话:请找一个最负责最有组织能力且大家最认同的人做项目经理(文笔好的话更好)。 团队的最终情况和项目经理有很大关系。
(感谢我们项目经理的付出,很给力)
学霸项目目前是由4个项目联合构成的大项目。这一点请 务必注意 。 这个项目中绝大多数的历史遗留问题都是由于我们最初没能及时意识到这个大前提而产生的。
学霸网整体由以下四个部分组成:
- 爬虫组
负责爬取所需的各种内容,抓取原始页面等等。
- pipeline组
负责处理爬虫组抓取的内容,为后两组提供服务。
- 学霸网站
负责展现pipeline组处理出来的内容。
- 学霸APP
同上,不过以Android平台为主。
所以说,当你们接手这个项目时,请 及早和另外的组取得联系 , 并 共同制定目标 。
这里结合项目的背景需求,阐明整体架构以及为何这样设计。
ASCII版架构图:
--------------
| 爬虫 |
______________
|
V
--------------
| pipeline |
______________
|
V
SOLR(搜索引擎)
|
V
--------------
| 后端 |
______________
| Web / APP |
--------------
对于学霸项目来说,最大的难点在于连接。各个组之间的协调相当困难。所以,经过了 多次协商,我们最终确定的方案是上图的那样。首先,爬虫组和pipeline组之间的 数据库的表结构是相同的。他们通过采用同一个数据库的方式实现数据的交互和连接。 而pipeline组处理过的数据,插入到SOLR中,然后展现组(即Web组和APP组)从SOLR 中搜索数据,通过SOLR的返回结果获取到PIPELINE组处理完毕的数据。 Web组和App组采用共用后端的方式连接在一起。即两组共同开发后端,前端(Web页面和APP) 通过约定好的接口调用后端服务,后端通过JSON将数据返回到前端。前端再负责展现。
该架构的亮点在于:Web组和App组共用后端,实现了完美的互操作性。比如:通过Web页面注册 的用户在APP端也能登陆。用户在APP端所做的操作在Web端也能够展现。同时, 展现组的前后端是松耦合的,完全重构前端或者完全重构后端对于另外的部分无影响。 后端与PIPELINE组通过SOLR实现松耦合。
但该架构存在一个严重的局限性:后端依赖的部分数据仍旧无法通过PIPELINE组获得。 具体点说就是tag。tag是由pipeline组处理出来的,但有时后端必须能够通过查数据库的方式 获得tag数据(Question数据等也有可能需要,看你们的情况了)。所以, 上面的架构没法让前两组和展现组完全连接起来(虽然也算是连接起来了吧, 但还存在问题)。
接下来,我会就我所了解的情况,阐述一下目前整个学霸系统的实现现状。
我对爬虫组的了解不多,但是总体的印象是爬虫组的东西够用,但不好。 最难受的一点在于他们依旧依赖于GUI。这一点可能是由于最初设计的架构的限制。 期待这里可以进行重构。或者直接上一个成熟的爬虫框架(Python有Scrapy, Java的就多爆了)也很不错。个人的想法是:爬虫组可以重新设计一下自身的架构, 把爬取、GUI完全分离开。最好采用Web作为GUI。这样,GUI的关闭对于爬虫的 爬取本身没有影响。要不GUI关掉爬虫整个就被关了是很难受的一件事。 其实,对于所有组来说,也许爬虫组整体重写的成本最小,毕竟功能并不多, 而且现在有太多成熟的爬虫框架,随便重写一下也许就能比现在好得多, 重写的成本也不高。
我和pipeline组的负责人有过一定的交流。 私下里他表示很希望下一届直接舍掉原来代码重写。他觉得那代码已经被弄得乱得不行了。 他们组的情况确实比较艰难,很多事情都是项目经理一个人完成的, 每一届都有在Deadline前狂赶进度的情况,而那份代码已经用了好几届了, 所以凭经验来推断的话,直接重写也许是一个很好的做法。 当然,毕竟是一个弄了这么多年的东西,里面实现的功能确实不少。所以具体是否要 重写,还需要认真权衡一下。
APP组的问题在于Beta阶段最终的代码并没能真正和后端连接上。这里有两点原因: 一是沟通不是太及时,以致双方手头的前后端调用约定文档版本不一致。 二是课程压力过大,所以两组联合开发的后端进度拖沓,很晚才完成最基本的API。 个人认为,应该和Web组联合调试一下就OK。连接上后端应该不成问题。
Web组的最大问题在于重构次数过多。几乎相当于重写了两次。而且第二次写得很赶。 所以比较棘手。首先,前后端的技术栈选用的是相对合理的。后端的Django好上手 且利于快速开发。而前端采用了单页应用的模式,相当于做了个Web APP。 采用的框架是时下最主流的ReactJS框架。整个技术栈的选择相对比较合理。 但第二次重构相当匆忙,特别是合作完成后端时,我们尽力将二者之前的后端融合到一起, 所以部分地方其实是存在冲突的。
StackExchange下有一套Tag/Question/Answer的模型定义, 同时还存在一套新的XTag/XQuestion/XAnswer的定义。 这是急待解决的问题。
最新版本的大部分按钮是无法使用的,这是由于第二轮迭代和编译实验等冲突太多, 整个进度完全推不动导致的。
ReactJS部分未使用ReactRouter而是自己折腾了一套简陋的页面跳转机制。 这个是由于知识的不足导致的,最开始不知道有ReactRouter这种东西。 不过这个问题应该不要紧。
集成了Celery框架但没来得及用上。Celery是个异步的任务队列。 设想是可以用于实现新鲜事之类的功能,比如一个人做了什么事之后, 把这个消息异步插入到他的好友的新鲜事里面。这货也是分布式的,应该有很多有趣的用法。
问答部分未能完成,前后端没有来得及连接在一起。后端做了简单的单元测试, 但前端还存在一定的问题。
从心理来讲,这份代码整体的情况尚好。因为实现的功能不多,所以遗留的问题也好解决。 前后端技术栈的基础已经打下了,所以情况应该还比较好。个人建议是这样的:
首先和另外三个学霸组进行沟通,确定两点:是否有某个组希望完全重写, 以及沟通好数据库的约定。个人推荐是使用完全相同的数据库结构, 以及完全相同的数据库管理软件。
第二步,移除代码中StackExchange部分(这部分就是个StackExchange爬虫, 由于和pipeline组没法接上所以才被迫实现的),按照约定重新定义Question、 Tag、Answer等模型。建议以XQuestion、XTag等模型为基础和另外的组商议约定。 因为X开头的这几个模型是和APP组结对编程搞定的,应该更能兼顾双方的需求。
第三步,实现并连接Question的前后端。
按照这个步骤,应该就能解决历史遗留问题。
有一些想法未能实现,如果前两组愿意重写的话,可以考虑这些想法。 另外,还有一些体会也放在这里了,希望能有所帮助。
学霸项目很难吸引到真实用户(除非做得非常给力),和一些自命题的项目相比, 学霸项目在满足用户需求这方面有明显的劣势(比如一些自命题项目解决的是大学生身边的问题, 那么他们就很容易推广),为了弥补这方面的劣势,我们最能够发挥的地方就在于技术。 通过收集海量的数据,帮助用户来找到他们想找到的东西 (做成个类似垂直搜索引擎+知乎社区的样子),才有可能和别的项目一较高下。 另外,最终评审是老师评审,重点在于项目管理和项目质量。 所有评审老师均有计算机相关专业背景,这也就意味着,如果项目整体上更专业化, 更能博得老师的好感。那么,专业性体现在两方面:项目管理和技术栈。
先说技术,对于学霸项目来说,最好的情况就是Alpha迭代完成时四个项目都顺利部署。 之后持续收集数据,并在最终展示上拥有海量可展示数据。那么,海量数据最大的问题在于处理。 目前第二组的处理速度比较慢,而且是单线程。而第一组的爬虫能否脱离GUI单独运行也是迷。 (正常的爬虫应该是不需要GUI就能运行的,可以通过GUI进行管理,但不应当是个GUI程序)。 解决这个问题最简单而听起来比较高大上的方法就是分布式。
这里我提供几个方案:
- 爬虫组/pipeline组Hadoop,Web和App组维持当前状态。
分布式的话可以考虑传说中的Hadoop,如果能用起来的话一定能取得很好的效果。 因为当前的需求很适合Map-Reduce模型。爬虫将数据爬进了, 然后交给pipeline处理后插入到Solr中(同时插入到数据库中),再通过Solr做搜索。 对于海量数据,可以尝试非关系型数据库。Solr自身就带有分布式的功能,很给力的。
- 全栈NodeJS
NodeJS是基于Google的V8引擎的一个后端框架。采用NodeJS的好处在于其本身 是基于JavaScript的。对于网页的解析等各方面应该有很好的适应性。 另外,目前大量的前端框架是基于NodeJS的,如果前后端统一采用JS的话, 也许也是个不错的选择。NodeJS是异步的,应用也很广。四组统一的技术栈 也许会有意料之外的惊喜。这里推荐一个叫做Meteor的东西,Web组和APP组可以考虑。
- 关于React
ReactJS是目前相当火的一个家伙,善加利用会带来不错的效果。不过它与Jquery的兼容性很差, 所以没法使用网上很多现成的Jquery插件。React家族除了Web端使用的ReactJS, 还有移动端采用的React-Native(支持IOS及Android)。所以Web组和APP组可以考虑 在共用后端的基础上,前端全部采用React(APP组用ReactNative,Web组用ReactJS)。 这样也许能共用一部分代码,实现共赢(比如集中一两个大神把两个组的前端都撸出来之类的, 反正如果可以共用的话,可以有效利用人力资源^_^)。
- 全栈Python
全栈采用Python也是一个可以考虑的想法,爬虫可以采用Scrapy框架, 或者利用Celery(已尝试集成到Web组项目中)+Django,这样可能也会很方便衔接。
- 消息队列RabbitMQ
如果想减少改动或者降低耦合度,爬虫组和pipeline组可以考虑下RabbitMQ。 爬虫进程和处理进程之间可以通过RabbitMQ进行通信,实现交互。 这样也有利于实现分布式。
项目管理上要注重流程。推荐使用Git/OSChina Team,或者Git/Github的组合。 这样的好处有两点:一是Git现在太过流行,所以无论是资料还是文档都比较多, 而且Git很好用,相对方便。二是跨平台(如果使用TFS的话就容易局限在windows下了)。 特别注意合并流程,换句话说就是每个人的代码经过怎样的流程才能够真正合并到最终代码中。 例如:每次合并前先进行一次Build,之后进行单元测试,所有单元测试通过才能够合并进去。 这里可以考虑用TravisCI或者其他持续集成工具。 (这里注意,Web组目前已经实现了前后端分离, 所以,后端的调试也是通过单元测试来进行的。这一点变相强迫开发者进行单元测试。 不要把未经测试的代码直接抛给前端,前端的调试是通过浏览器的开发者工具进行的, 更为麻烦。)
这里还有一种可行方案是采用Gerrit,自行搭建一个Gerrit并且对外部开放, 作为网站的一部分。由于学霸项目本身就是为技术用户准备的,这样做也可以称得上是一种特色。 可以四个组一起放在Gerrit上,这样相互之间协调也方便。
最后,建议所有必要的讨论都留下文档。项目展示的时候简单展示下效果很好的。 讨论文档可以由参与者轮流整理。软件工程是注重过程的(我们在这方面有所失误)。
关于这个,我推荐几份文档作为参考。
虽然没法做到那么专业,但建议可以尝试一下。(特别是如果组内有代码能力弱的, 可以让他们专门负责整理讨论记录,整理出类似的文档。再由大神或项目经理审核一遍, 最后放在项目里)
所有行动都要留下证明。比如写了代码要有提交记录。学习了新知识要有文档(摘抄也行)。 讨论了技术方案也要有文档。坚决避免“打酱油”的出现。一个人的力量和七个人的力量 是完全不一样的。每多一个人项目质量都能上去很多。(注意:项目不只有代码)。
团队所要完成的任务包括:文档、测试、开发、部署、宣传推广等。分工时考虑下。
项目经理一定是团队里最给力且有组织能力的(技术功底强最好,不强也可以, 但一定是能组织起事的,能够主导整个团队)。
就学霸项目而言,可以考虑有一个独立的部署工程师(兼运维),专门负责部署项目, 并进行运行维护工作。如果保持当前技术栈不变的话(外加搭建一些必要的工具), 需要学会部署Django项目、部署ReactJS(现代的前端都是需要编译的, 我们采用的是Webpack),外加上Solr之类的,同时部署持续集成工具如Jekins或Gerrit等, 配置MySQL,系统调优等等,要熟悉Linux,或者至少要花时间去熟悉Linux。 所以,有个独立的部署工程师也是可以考虑的。如果还要使用分布式,那么部署Hadoop之类的, 也是需要学习的。找个学习能力强的专门学习这堆东西也是不错的选择 (Solr神马的可能还需要根据需求做配置)。
前端主程序员/后端主程序员按需分配。最好再有一名全栈工程师兼架构师, 作为技术核心参与所有技术相关的工作,进行技术方面的指导。测试最好是搞信息安全方向的, 至少了解或者有能力学习Web渗透相关的内容,对于网站安全进行测试 (而且测试手要黑,下手要狠,你懂的)。
整个团队的最核心是项目经理,项目经理的质量关乎整个团队的成败。 虽说当你看到文档的时候可能已经晚了,但是还是要劝一句:尽量按照团队需求组队员, 而不要按照关系好坏来组(当然,组在一起的人相互熟悉也有好处)。 最好的情况是项目有什么需求就组有相关技能的队友,能节约很多学习成本。
如果你们依旧存在问题,可以联系以下邮箱。作为一个负责任的开发者,我们会尽可能地提供我们 力所能及的帮助。
作为一个线上服务项目,上线方式也是值得思考的一件事情。
如果项目需要频繁的上线,而上线过程中不得不终止为用户提供服务,那么用户会很快抛弃产品,转向其他平台。
切记,互联网用户的惯性很小,即使抢到了很多用户入口份额,稍有不慎也会很快流失!
为了解决这个问题提供一些可行的解决办法:
1.控制上线时间。如果每次上线花费时间以秒计,那么可以暂时回避这个问题。随着工程日间复杂,这将不能解决问题。
2.多机备份。使用多台服务器提供服务,服务器分别更新,注意需要控制服务器切换时间。如Solr可以使用分布式版本,通过zookeeper来维持一致性。
3.使用缓存服务器解耦合。如果对实时性要求不要(显然学霸项目没有很强的实时性要求),那么可以使用缓存服务器保存前端需要的结果,后端的运算服务定期更新缓存服务器,这样后端的短时间下线不会对用户产生不可控的影响。
4.使用持续集成平台,方便进行快速部署。
由于项目目前已经处于可以提供服务的状态,建议在开发过程中持续保证后端处于可服务的状态。
同时,在不保证新功能可以无错误的使用时,可以使用灰度发布的方式,让一部分用户优先使用新功能。
使用这种方式时,日志文件将会是你决策和调整的有利工具,所以不要忘了维护一份好的日志。
目前我们的项目基本不存在日志系统,日志的格式全都交给你们设计。
举个例子:所有接口的请求和返回结果是一定要写进日志的。
有关服务的更多问题,可以参考市面上现有产品的发布策略
Contact me at 815732072@qq.com