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 上关注这个项目。在这里你将能学到:

  1. ASP.NET Core
  2. VueJS
  3. 单元测试
  4. 集成测试
  5. More

项目地址:

https://coding.net/u/holmescn/p/CoreCRM/git

https://github.com/holmescn/CoreCRM

CoreCRM 开发实录——开始之新项目的技术选择的更多相关文章

  1. Android Studio开发第二篇创建新项目

    创建新项目很简单,File-New-New Project,这个没什么好说的跟Eclipse都差不都. 第二步SDK选择,有手机平板还有Wear,TV,汽车Auto,谷歌眼镜等几个种平台,这里就先选择 ...

  2. CoreCRM 开发实录 —— 基于 AntDesign 的新 UI

    上一篇说到,因为有新朋友加入,对前端开发有了新的要求.原来基于 Bootstrap 的 UI 就不要了.在网上(其实是 GitHub 上)逛了几圈,最后使用了 antd-admin 这个框架做为基础模 ...

  3. CoreCRM 开发实录——想用国货不容易

    昨天(2016年12月29日)发了开始开发的文章.本来晚上准备在 Coding.NET 上添加几个任务开始搞起了.可是真的开始用的时候才发现:Coding.NET 的任务功能只针对私有的任务开放.我想 ...

  4. CoreCRM 开发实录 —— 前后端分离的重构

    虽然2月初就回来了,可 CoreCRM 一直到5月才开始恢复开发,期间是各种生活中的意外和不方便. 1. 为什么要重构 首先是一件很值得高兴的事情:CoreCRM 有了第一位 contributor! ...

  5. CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]

    上一篇文章我提到:为了使用"国货",我把 Linux 上的构建和测试委托给了 DaoCloud,而 Travis-CI 不能放着不用啊.还好,这货支持 macOS 系统.所以就把 ...

  6. Cocos2d-x 开发 v3.2 建立新项目并添加库文件

    一.添加其它类库     3.0以上的设计耦合性强,项目中模块常以库的形式存在,需常添加链接库.在3.0中经常用到CocoStudio 编辑器的资源数据,所以需要添加CocoStudio 库. 1.1 ...

  7. CoreCRM 开发实录 —— 单元测试、测试驱动开发和在线服务

    测试不是问题,问题是怎么测试. ## 单元测试 我认为单元测试已经是无可争议的最佳开发实践之一.但是很多人并不同意这个观点.他们的说法无非是:写测试需要花很多时间,需求又经常变动,一但变动,一大片测试 ...

  8. CoreCRM 开发实录 —— Profile

    再简单的功能,也需要一坨代码的支持.Profile 的编辑功能主要就是修改个人的信息.比如用户名.头像.性别.电话--虽然只是一个编辑界面,但添加下来,涉及了6个文件的修改和7个新创建的文件.各种生成 ...

  9. CoreCRM 开发实录 —— 单元测试之 Mock UserManager 和 SignInManager

    单元测试的核心就是:只测试眼前的逻辑.这就要求所有的依赖项都要使用仿类来代替,也就是所谓的 Mock Object.在测试 ProfileRepository 和 AccountController ...

随机推荐

  1. 从源码看Azkaban作业流下发过程

    上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...

  2. JavaScript 对数据处理的5个API

    JavaScript对数据处理包括向上取整.向下取整.四舍五入.固定精度和固定长度5种方式,分别对应ceil,floor,round,toFixed,toPrecision等5个API,本文将对这5个 ...

  3. python之路 - 基础1

    1.安装windows安装双版本Python2,Python3 下载Python2和Python3https://www.python.org/downloads/ 分别安装两个版本 进入Python ...

  4. HTML中上传与读取图片或文件(input file)----在路上(25)

    input file相关知识简例 在此介绍的input file相关知识为: 上传照片及文件,其中包括单次上传.批量上传.删除照片.增加照片.读取图片.对上传的图片或文件的判断,比如限制图片的张数.限 ...

  5. HTML 获取屏幕、浏览器、页面的高度宽度

    本篇主要介绍Web环境中屏幕.浏览器及页面的高度.宽度信息. 目录 1. 介绍:介绍页面的容器(屏幕.浏览器及页面).物理尺寸与分辨率.展示等内容. 2. 屏幕信息:介绍屏幕尺寸信息:如:屏幕.软件可 ...

  6. Angular企业级开发(2)-搭建Angular开发环境

    1.集成开发环境 个人或团队开发AngularJS项目时,有很多JavaScript编辑器可以选择.使用优秀的集成开发环境(Integrated Development Environment)能节省 ...

  7. 深入理解 Java G1 垃圾收集器--转

    原文地址:http://blog.jobbole.com/109170/?utm_source=hao.jobbole.com&utm_medium=relatedArticle 本文首先简单 ...

  8. 我这么玩Web Api(二):数据验证,全局数据验证与单元测试

    目录 一.模型状态 - ModelState 二.数据注解 - Data Annotations 三.自定义数据注解 四.全局数据验证 五.单元测试   一.模型状态 - ModelState 我理解 ...

  9. iOS 后台处理

    iOS 后台处理的常见用途 1.进入后台时候删除资源:应用处于挂起状态的时候所占用的资源越少,该应用被iOS终止的风险就越低.通过从内存中清理那些易于重新创建的资源,可以增加应用驻留内存的机会,因此可 ...

  10. 流程表单中js如何清空SheetUser控件数据?

    昨天有人问我js怎么清空.我试了试,发现简单的赋给他空值,并没有用.只能给他赋一个真实存在的值才有用.于是跟踪了一下他的删除按钮. 效果如下 使用场景:可以根据字段的不同类别变更人员. js代码如下, ...