www.slaveoftime.fun/blog/22
前言
最开始入行的时候我做的是.NET, WPF 和 WinForm。所有的东西都是 MVVM, MVC,面向对象等等。作为一个非计算机专业的入行者,我那时候以为世界就是这样,多写多记总能搞定的。当然我花了很多的时间学习和实践最后才转行成功的。
差不多在2017年,我开始做一些网站开发的外包项目,开始学习angular,后来去了某知名国际电商,那里使用vuejs。所以这两个框架和相应的生态我都有一定的了解和经验,但是如果让我现在来回看用这些框架需要写的代码,我还是觉得很陌生和复杂:
<mat-form-field class="fullwidth">
<mat-icon matPrefix class="field-prefix-icon">vpn_key</mat-icon>
<input matInput placeholder="{{'Login.Password' | translate}}" [formControl]="password" type="password"
[readOnly]="isLoadedIn">
<mat-error *ngIf="password.invalid">{{'Login.PasswordNotValid' | translate}}</mat-error>
</mat-form-field>
<button
class="loginButton"
mat-raised-button
type="submit"
[disabled]="formGroup.invalid"
*ngIf="!isLoadedIn">
{{'Common.BtnLogin' | translate}}
</button>▲ angular 的语法
就比如 *ngIf, translate 管道 , 以及一些带有限制性的嵌入语法,这些东西我都花了很多时间去学习和使用,但是现在我基本都忘了。就比如如何在angular中自定义一个管道,如何创建自己的属性(@)。尽管这些语法很像WPF里的Xaml(这也是我当时在那个项目选择angular的原因),所以开始的时候接受很快,但是后来越搞越复杂,后期的维护也比较困难。尽管有typescript的辅佐,但是还是比较复杂,有时候看自己的代码,我都会以为是别人写的。
<div id="app-2">
<span v-bind:title="message">
Hover your mouse over me for a few seconds
to see my dynamically bound title!
</span>
</div>▲ 来自vuejs官网
Vuejs也是类似,有很多模板语法,而且还没有typescript加持(那个时候),加上我大部分的时间都是做后端,所以对这些语法基本上是边查边用。更不要说什么父子组件通信,数据sync,数组的更新,mixin的混乱,method,computed,watch这些了。而且智能提醒又比较差,所以基本上我写代码的时候,先拷贝类似的形式,再修改;深度使用的时候每次得去找到相应的文档对照着使用。
比较典型的错误就是组件重用了,一旦改了break changes,对应的都只能通过字符串匹配去查找使用的地方进行修改,没有运行时错误。项目简单还行,一复杂就。。。
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})▲ 来自vuejs官网
好运气来了 F# |> 🤘
也是从2017年,我开始接触F#的编程,毕竟都是.NET生态的东西,得保持学习啊。
最开始的时候我并不觉得它有多好,但是如果就是写写函数的话,它确实方便简洁,写脚本也方便。但是平时的代码都是业务密集型的,也不知道怎么用F#来替代C#让面向对象的东西写起来更优雅。
当然,我现在还是觉得C#写面向对象的东西是最好的。但是,后来我也意识到,我开始用F#的姿势和想法就是错的,不应该去套C#的想法去写F#。
再后来,我接触到了Giraffe和Fable。
General.Handlers.errorHanler
>=> General.Handlers.setCurrentUserForDbContext
>=> General.Handlers.cacheIfHasCacheId
>=> choose [
GET >=> routeCi "/sitemap.xml" >=> Sitemap.Handlers.getSitemap
subRouteCi "/api/v1" apiV1Routes
SSR.Handlers.renderMainApp
text "404 not found"
]▲ 用Giraffe写webapi
所有东西都是显式表达出来,我不需要学MVC,以及如何自定义action filter,如何用attribute去管理api版本和权限。我只需要学习什么是HttpHandler就可以了,最后我就成了超级玛丽管道工,我的工作就是制造管道和连接管道了,工作从此变得简单和明了。
div </> [
Classes [
Tw.flex
Tw.``flex-row``
Tw.``items-center``
Tw.``my-04``
Tw.``ml-04``
]
Children [
if not state.IsRegistering then
Button.primary [
ButtonProp.Label (tran "User.Form.Login")
ButtonProp.OnClick login
ButtonProp.ButtonAttrs [
Disabled hasFormErrors
]
]
Button.seconday [
ButtonProp.Label (tran "User.Form.StartRegister")
ButtonProp.OnClick (fun _ -> Register |> dispatch)
ButtonProp.ButtonClasses [ Tw.``ml-04`` ]
]
else
Button.primary [
ButtonProp.Label (tran "User.Form.Register")
ButtonProp.OnClick (fun _ -> Registering |> dispatch)
ButtonProp.ButtonAttrs [
Disabled hasFormErrors
]
]
]
]▲ Fable
使用Fable,我可以用熟悉的F#函数去控制业务逻辑,UI逻辑。再也不需要去学习和查阅angular和vuejs的模板语法和特殊语法了,以及某些靠字符串约定的东西了。我只需要知道函数需要什么参数,然后传递给它就可以了。div无非就是一个需要传入两个参数的函数,第一个是html属性的数组,第二个是其他子节点的数组。所以使用Fable,我基本上没怎么学,当然也没有多少资料让我来学,但是我还是熟练地掌握了它,以至于在用它做完一些兼职的项目后,还有时间来搞一个自己的网站,以及这个网站的设计本身也是一个可重用的框架,我给一个客户开发的简单门户网站就是基于我自己这个网站的雏形,并且还一直保持着代码的共享。
Fable.React是对reactjs的绑定,所以通过它可以享受整个react的生态。当然也有vuejs的绑定,但是用的人太少,也不成熟。
有时候我觉得自己很幸运,能够遇见这么一些省时的技术来增加自己的收入,F#🖖
结语
当然所有的事情都不是完美的,F#写面向对象的语法我就一直记不住(还好基本不写),工具链也不像C#的那么强,社区也非常小众;Fable的使用和配置,以及和js的交互我也花了很多时间学习。不过还好这些都是基础,并不是框架。以后任世界变化无常,框架流行抑或黯然离场,我都可以以不变应万变。
总体来说,我现在还是喜欢并打算把F#发扬光大的。当然啦,作为一个热爱编程的人,学习还是不能停下的,有了F#和Fable我可以不学那些框架里几年后就会被淘汰的东西,但是新技术,比如WebAssembly,rust,机器学习,云计算,甚至5G还是要学的。