2016年11月,接受了一个工作,是对“悟空CRM”进行一些修补。这是一个不错的 CRM,开源,并提供一个 SaaS 的服务。正好微软的 .NET Core 和 ASP.NET Core 也发布了。于是就有了这个想法:使用 ASP.NET Core 来开发一个 CRM。当然这里面的私心是:朝后坦白讲,悟空CRM 的代码真的是不怎么样。大量的代码堆在 Controller 里,多个功能在一个 EndPoint 里混合。权限管理也有些乱来。View 里充满了“临时解决方案”。所以我真的是一边改,一边难受。由于11月我还在做一个 Xarmin 的小程序,所以对 CoreCRM 的开发就定在12月开始了。
因为修改悟空CRM,本来以为对业务的逻辑已经比较熟悉,先开始的时候照着悟空CRM的UI直接开始撸就可以了。在尝试了几个页面之后发现这样比自己直接写还麻烦。而在这中间,我的老毛病有犯了:在几种技术方案之间不停地权衡和尝试。这样,时间就一天天的浪费掉了。技术方案的选择经历了:VueJS + jQuery,React.NET,aspnetcore-spa (ReactJS + Redux),最后又回到 VueJS + jQuery。CSS 框架使用的是 Bootstrap 3.3.6,这个是一直没有变(虽然我也曾经想过使用4.0的alpha版,不过最后还是忍住了)。图标使用了font-awesome 4.7.0,也是没有改。一直折腾了一个月(这中间还有因为对 ASP.NET Core 不够熟悉而付出的学习成本),整个12月将要过完的时候,我才只完成了 Layout 和 Login。(其实原来的首页、结构架构也完成了,但只有UI的部分)。
关于技术选择
为什么要选择 ASP.NET Core?
我的一个基本判断是:带有类型检查的语言应该是未来的趋势。虽然从历史角度看,动态类型和静态类型总是交替上台表演的。不过,随着程度规模的不断变大(想当年一个 DOS 程序就几十,几百K,求伯君可以使用彙編擼一個 WPS 出來,而現在一個手機 App 也是几十MB),动态语言的一些不方便的方面是突显出来了。特别是多人协作开发的时候,因为没有类型的静态类型检查,很多错误都只能在运行的时候才能发现。其实这个问题如果配合上足够的单元测试,也是可以减轻一些的,然而到了2016年,还是有很多人把测试当成负担。结果就是大量的 bug 和安全漏洞,以及改了补了一个洞,又开了三个洞。
从现实情况看,PHP 7 已经引入了一些类型标注,Python 3.5 也有这样的东西,JS 系里有 TypeScript 这样的 Transpiler(而且,Angular 2 这样的框架已经开始在使用 TypeScript 进行开发了),以及 Facebook 的 flow。所以,动态语言在漫漫的静态化。虽然只是提供了类型的运行前检查,但也减少了很多运行时的问题。
那么,现在比较成熟的静态类型语言,我知道的就是三个:C++、Java 和 C#。C++ 是出了名的复杂和开发效率低下。虽然我对 C++ 的熟悉程度比 C# 要高的多,但 C++ 做 Web 的挑战还真是大得让我不敢尝试。Java 虽然现在是 TOIBE 上排前三的语言,也一度占到了榜首好多年,但我还是不太喜欢 Java。我觉得 Java 写进来太死板,太多的架构代码,感觉很琐碎。最后我选了 C# 这个 sugar language。然而,其实我也不太会 C#,今年并没有安排学习 C# 的任务。只是年初的时候因为学习 F#,所以学了一点点的 C#。但用起来还真的不错。同时,微软终于开眼,开始与开源社区深入合作,而不是把开源当成敌人,于是有了 .NET Core 这个跨平台的 Runtime。
遇到一个问题
中间的一次挫折,差点让项目中断。ASP.NET Core 的 ORM 使用的是 Entity Framework Core,而 EF Core 基本上是对固定的模型比较好用。而 CRM 这种需要定制的系统,需要对一些表进行定制(比如一个客户需要保存哪些信息,这不可能有一个通过的模板)。我尝试了几种可能的方案,都不能在 EF Core里实现动态的模型。本来以为自己又一次做错了架构选择,不过,退后一步想,我为什么非要使用 EF Core呢?然后去搜了一下,发现 StackOverflow 的 Dapper.NET 可以支持动态的 model。于是这个危机才算解除。
前端框架选哪个?
因为后端的技术选择了 ASP.NET Core,这就对前端的技术选择造成了一定的限制。如果我是使用 PHP 或者 Python 开发的话,我可能会使用前后端分离的技术。但 ASP.NET Core 对 HTML 这个层做了一些的工作(我想JSP可能也是这样的),比如根据运行时的环境选择加载不同的 JS 和 CSS 文件(还支持 CDN 的 fallback,非常贴心);支持 class 的自动补全和智能提示(这个非常提升生产力),甚至还支持对 Font-awesome 的预览;支持 Partial View 和 View Component,也就是对 View 的按功能分割也可以直接实现。所以,前端的部分其实只是做一些局部的更新。
现实局部更新最简单粗暴的方法就是使用 jQuery。不过,jQuery 的时代已经过去了,那种 query and modify 的时代已经和现在这个 MVVM 一统天下的局面不符合了。使用 jQuery,必然还需要在 JS 里写一些难看的 HTML。所有的结果就是导致代码的维护成本高起。而在 2016 年,我们有什么样的前端框架可以选择呢?首先是我最喜欢使用的 VueJS,这个其实算不得一个 framework,最多是一个 micro-framework,提供了 view model 和 model 的绑定和双向更新;一些条件渲染和组件化。使用进来非常简单和直接。可我为什么还要配合上 jQuery 呢?主要是因为要使用 bootstrap 的一个 JS 组件。但在直接使用 VueJS + jQuery 这个方案的时候,还是有一些问题。因为我没有做服务器端渲染(SSR),所以页面在打开的时候总会闪一下,那个是 VueJS 对模板重新编译再插入到 DOM 造成的。好像 VueJS 1.x 的时候没有这个问题,2.x 引入了 virtual DOM,好像也引入了这个问题。解决方法比较直接的就是SSR,不过,我准备使用异步组件的方式来做。
ReactJS一直是我想尝试的一个前端框架。因为不但可以在 Web 里使用,还可以把同样的经验转移到 React Native 的开发中。比如 Route、Rudex 等都是相通的。同时 React 也直接实现了 SSR,解决了前面说的问题。为了尝试 ReactJS,我前后尝试了两个技术:ReactJS.NET 和 aspnetcore-spa。前者是 Facebook 出品,后者是微软出品。ReactJS.NET的优势是:有一些 Tag Helper,可以和 ASP.NET Core 的 View 整合的比较好。但遇到的一个问题是,在 macOS 上没法运行。虽然我已经提了 issue,和一个 pull-request,但问题好像不会在短时间内解决。只好先放弃这的方案。
微软自己搞的 aspnetcore-spa,只可以在各种平台运行的。但使用的时候发现:1. className 没有 class 的补全功能;2. Server-Side 的验证还没法整合(虽然在 README 里写了这条,但没有 docs,不知道怎么用)。
也就是说,ReactJS 的两种方案,就算可以使用,也因为破坏了 ASP.NET Core 的 View 直接提供的功能而在使用的时候不免遇到各种问题。而尝试这两种方案,消耗了我两周的时间(要研究怎么用,发现问题,解决问题,与社区沟通……)
最后,还是回到了 VueJS + jQuery 的道路上来了。不过,使用方法做了一些改变。最初的使用方法是:在 body 下面创建一个 div 做为所以内容的 container,然后把各种 modal, list 都扔进去,挂上 attribute。这样的结果就是:因为有好多的 modal,和一些 list,结果整个模板变得很大,编译的时候就会闪。新的方法是,使用 Vue 的动态组件的功能,在需要加载的时候,通过一个独立的 Controller 加载到页面,虽然在加载的时候会显示一个 Loading,但因为每个组件都不大,应该不是什么大问题。
公开的开发过程
CoreCRM 选择使用 Apache 2.0 协议开源(其实我也不知道应该选什么,MIT、BSD 好像都不错的样子)。反正代码都开源了,开发的过程我也开放出来好了。这里我会记录每一次开发的思考、决策和反思。
如前所述,目前 CoreCRM 还在初级阶段,只有登录和登录的做成测试。不过,在这篇文章这后,项目会慢慢展开。
持续集成
在12月初的开发中,我并没有引入持续集成。一开始的三天是在混沌中度过的。然后我决定先写 UI(HTML和CSS),然后再把后端完成,最后前后端集成。实践的结果是:因为一直在写UI,所以感觉一直没有什么进展,除了登录,什么功能也不能使用。这样的感觉很不好。特别是只有我一个人在开发的时候,更需要一些小的成功来激励我继续前进。所以,在 12 月的第四周,我开始研究怎么使用持续集成(因为离发布还很远,所以,所有的发布功能都被关闭了)。现在已经接入了 Travis-CI 和 AppVeyor 两个 CI 平台。登录功能的测试也已经通过。
代码库和项目管理
这里有一个问题:因为我是使用 Coding.NET 做为主要的版本库的(因为这个服务是在国内,速度上比 GitHub 要快一些),但 Travis 并不支持非 GitHub 的 Git Repo,所以,只好再在 GitHub 上开一个镜像。虽然 AppVeyor 可以直接使用 Coding.NET,我也没配置这个功能(只是尝试了一下,然后删的时候删错了……)现在两个 CI 都配置在 GitHub 上了(那你干嘛不直接就在 GitHub 上搞?)。反正现在只有我一个人搞,这还不是一个问题。如果以后有其他人一下参与,我可以做一下同步的功能,自动把 Coding.NET 的代码同步到 GitHub 上进行测试。
使用 Coding.NET 的一个原因是,Coding.NET上还支持一些简单的项目管理。这样,可以直接在上面写任务,完成任务,也是一种项目开发的体验。如果以后有多人参与了,在持续集成方面,我还想把 Worktile 拉进来(测试完成后的提示等)。
邀请
如果你也对 ASP.NET Core 和 .NET Core 的未来感兴趣,想参与到这个项目中来,欢迎到 Coding.NET 上关注这个项目。在这里你将能学到:
ASP.NET Core
VueJS
单元测试
集成测试
More
项目地址:
https://coding.net/u/holmescn/p/CoreCRM/git
https://github.com/holmescn/CoreCRM
原文地址: http://www.cnblogs.com/holmescn/p/corecrm-startup.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注