评论

为什么你应该立即使用云开发写小程序?

本文介绍了云开发的优势,包括无需维护服务器、一键部署、前端直接读写数据库和统一的JS语言环境。解释了云开发的计费方式和如何降低费用的技巧,并强调了作者通过云开发实现了工作与生活的平衡。

本文主要内容

  1. 云开发给我们带来的新体验,如何通过把精力放在创造性的工作上,感受工作与生活的平衡。
  2. 介绍云开发的计费方式,了解云开发到底贵不贵,以及如何尽可能降低云开发的费用。
  3. 介绍了 “数据库的设计要优先服务于写代码的体验” 的理念。

一、前言

想象一下,如果编程不再需要处理繁琐的服务器问题,那将是多么幸福的事情。

自2009年毕业后,我就进入了互联网行业,我还记得当时的服务器是自己搭建的。与团队小伙伴自己购买大型服务器并置于北京市中心的机房,每次进入机房都要戴上鞋套,以免脚上的尘土洒落在机房里一层不染的地板砖上。

从那时起,维护服务器就成为了一场噩梦,虽然现在已经有腾讯云等云服务商,但是服务器的远程维护依然让我感觉有一种“牵挂”。那种半夜被叫醒,服务器“挂”了,然后你要赶紧起床去处理的感觉,我再也不想经历。

所以,当我第一次接触到微信小程序云开发的时候,我感觉这份“牵挂”终于放下了。云开发是一个后端即服务(BaaS)的解决方案,它让你可以专注于小程序的前端开发,而不用再去操心所有和服务器相关的事情。

使用云开发,不仅是技术层面的转变,更是生活方式的改变。你可以将更多时间投入到创新创造中。这给我一种侠客游走江湖的感觉,当我合上电脑时,我就能从"江湖"中彻底回到现实世界,与家人、孩子充分享受生活,不再有"牵挂"。这种在工作与生活之间自由切换,享受新的平衡,让我觉得写代码就像拿着手柄打游戏一样,充满了乐趣。这是我推荐你使用云开发最重要的理由。

通过这篇文章,我将带你了解云开发的核心优势,相信能让你感受到这种自由与高效的新生活体验。

二、云开发给我们带来的新体验

前面说到不需要维护服务器是一种享受,本节我们具体的讲讲云开发给我们带来的其他体验。

一键部署

所谓云开发,并不是完全不需要服务器,而是服务器由微信自己去维护与管理,我们只需要上传云函数代码即可。这里的云函数代码,其实就是一个Node.js项目,用户端小程序(前端)可以向微信云环境发起请求,微信云环境会负责调用你的云函数代码,然后返回结果给前端。

因此你唯一需要做的,就是编写小程序代码和云函数代码、然后在微信开发者工具中一键上传(小程序和云函数需分开操作),整个过程完全感觉不到有服务器的存在。

前端直接读写数据库

通常,如果我们要向数据库中写入数据,需要先在后端编写接口,然后前端调用接口。而在云开发中,我们可以直接在前端读写数据库,根本不需要后端接口。这就感觉好比行走江湖多年,突然有一天,你发现根本不需要把剑从剑鞘中拔出来,一个剑气就能直接杀敌,瞬间完成数据库的读写操作。

假如我们需要向商品表中插入一条数据,只需在前端这样写:

// 获得数据库引用
const db = getApp().cloud.database()

// 向products表中插入一条数据
db.collection('products').add({
  data: {
    name: 'iPhone 15',
    price: 4999
  }
})

而读取商品表中的数据,只需要这样写:

const products = await db.collection('products').get()

你根本不需要知道数据库存储在哪里、用户端如何连接数据库、用户和数据库物理上的距离远不远、数据库是否备份、一秒钟有一万人访问能不能抗住,等等。这些问题,微信云环境都帮你很好的解决了。


(云开发就好像一个封装好的魔法水晶球,你只专注于代码,云环境会帮你解决其他问题。)

无需鉴权

发现没有,前面读取数据库的代码中,没有任何鉴权相关的代码。在云开发中,所有的鉴权都是由微信云环境自动完成的。包括数据库权限、用户登录以及_openid的获取、支付接口的调用、云函数调用、文件的读取、所有API的调用,等等,都不需要我们自己去写鉴权逻辑。

这种感觉,就好像有位你并不认识的高人走到你面前,主动帮你打通了任督二脉,你感觉全身通畅,刚刚把手指抬起来,六脉神剑就发出去了。

由于所有的代码都运行在微信自己的服务器上,因此微信可以确保代码的安全性,我们只需要专注于业务逻辑的编写,不用担心自己的服务器被攻击,数据被盗取等问题。

前、后端都是JavaScript

在云开发中,前端和后端都是JavaScript(或TypeScript),这意味着你可以使用相同的语言编写前、后端代码。

云端return的数据,并不像传统服务器那样返回一个json字符串,而是直接返回一个对象,例如:

// 实现加法计算的云函数代码
exports.main = async (event, context) => {
  const {x, y} = event
  return {
    sum: x + y,
  }
}

而在前端代码中,可以直接这样调用:

const result = await wx.cloud.callFunction({
    name: 'add', // 这里add是云函数的函数名称
    data: {x: 1, y: 2}
})
console.log(result.sum) // 3

看,前后端已经被打通了,前端传给后端的数据是js的对象,后端返回给前端的数据也是js的对象。

而且,由于前、后端都使用JavaScript,那么前、后端就可以共用一些工具函数,例如数据库的读取操作(但要注意前、后端对数据权限的处理与前端不一样),字符串和时间的处理,等等。

如果原本有一段代码是运行在前端的,突然有一天想把它移动到云端(为了防止别人阅读代码,或前端性能不足等原因),几乎不需要做太大的改动,只需要复制粘贴到云函数中即可。

所谓的后端只是一个运行在云端的云函数,站在你的角度,你只是在写一个函数,而不是在写后端,更不需要学习任何的框架,云函数return返回前端需要的数据即可。

从开发体验上来说,你根本不觉得自己在写后端。

三、云开发到底贵不贵?

前面已经介绍了云开发带来的新体验,但是作为开发者你可能听说过“云开发比传统服务器贵得多”的说法,那这种说法对不对呢?这个问题不能简单的回答“对”或者“不对”,因为这需要你进一步理解云开发的计费方式,然后根据自己的业务需求来判断。

总体而言,云开发是按照“基础套餐+按量计费”的方式收费的,这有点像手机话费套餐,通常来说你是用不完基础套餐资源的。如果某种资源的使用量超过了套餐限制,那你就需要额外后付费(而不是像传统服务器那样先购买配置)。

接下来我会根据自己的使用经验,重点介绍你可能关心的问题。

最低基础套餐费用

目前,云开发最便宜的基础套餐是19.9元/月,并且可以10个小程序共用一个套餐(小程序需同属于一人或公司)。

假设你有10个小程序,它们共用一个云开发环境,那么每个小程序的服务器成本可以低至2元/月。这种感觉有点像你进入一个客栈,店小二说“客官,我们这里吃一个饼是20元,吃十个也是20元,您要吃几个?”,不多吃几个都对不起自己。

当然,这里有一个前提,就是你的小程序用户量都不大,所有小程序消耗的资源总量不超过基础套餐的限制。那如果用户量大怎么办?我们后面会讲到。

“调用次数“产生的费用

就像你的手机套餐有通话分钟数、短信次数、流量等,云环境也有调用次数、容量、流量、云函数资源使用量、文件存储、CDN等。

其中需要重点介绍的是“调用次数”,它包含数据库的读写次数、云函数的调用次数、文件存储的读写次数。在每月19.9元的基础套餐中,每月有20万次的“调用次数”额度,超出的部分会按照0.5元/万次另收费。

我们来计算一下0.5元/万次的“调用次数”是什么概念,假设平均每个用户每日会消耗20次调用次数,你的小程序每天有500人访问,每日消耗就是1万次,也就是0.5元,这个费用,让其中一个用户看一个视频广告就能赚回来(注意,实际情况中除了调用次数的费用,还可能产生其他费用)。

在上面的代码中,向数据库中写入一条数据会消耗一次“调用次数”,读取数据时也会消耗一次“调用次数”。

// 获取数据库引用不会消耗“调用次数”
const db = getApp().cloud.database()

// 下面的写入操作会消耗一次“调用次数”
db.collection('products').add({
  data: {
    name: 'iPhone 15',
    price: 4999
  }
})

// 下面的读取操作也会消耗一次“调用次数”
const products = await db.collection('products').get()

另外,每次使用callFunction调用云函数时也会消耗一次“调用次数”。

如果小程序在“调用次数”上超过了基础套餐的限制,那很可能是你对数据库的读写过于频繁(或者说数据库设计不合理)。

当我们使用云数据库的这种计费方式时,我们必须在编码习惯上有所转变,在设计数据库和编码时就要考虑到对“调用次数”的影响。

举个例子,假设用户首次进入小程序时会从数据库读取小程序配置信息,例如首页的banner图、字体大小、导航栏的文案、提示弹窗文案等。通常你会把这些配置都放在同一张表中,但你有可能不会一次性读取所有配置数据,而是在使用到A数据时就读一下A数据,使用到B数据时就读一下B数据,并且下一次使用到相同的数据时,又会再读取一次。如果这样写代码,就会成倍的增加“调用次数”的消耗,那所谓的“云开发比传统服务器贵得多”就很可能发生。

你肯定立刻能想到,可以使用缓存来减少调用次数。这确实是行得通的,以后有机会我会专门用一篇文章把我的经验分享给你。

按量付费与预付费

作为程序员,我们按年支付购买的传统服务器,通常99%的CPU时间都是闲置的。因此,当你在对比云开发和传统服务器的费用时,你不能假设你可以100%利用传统服务器的资源(10%都不行),然后根据这个资源利用率来计算云开发的费用,这种对比方式没有意义。

如果你的产品用户量不大,那么云开发的费用并不高(每年约240元)。但如果用户量大呢?用户量大你怕啥,你的产品肯定赚钱了呀!此时云开发的成本就不是问题了。(当然也有用户量大但就是不挣钱的产品,这不是应该用哪种服务器的问题,而是应该放弃的问题。)

如果你的产品有一定的用户量,那么节约这点云开发的成本并不是你应该优先考虑的。一个产品的稳定性才是更重要的,没有人愿意使用一个不稳定的产品,为了节约一点点成本,而牺牲产品的稳定性,最后导致自己错过好不容易偶遇的机会,那是远远不值得的。

并且,就算你今日有一万个用户,不代表三个月后也会有这么多用户,未来是不可预测的,提前规划购买了高配置的服务器所带来的损失,可能比云开发的成本费用还要高。

我需要为开发或测试单独购买云环境吗?

云开发并不支持在本地电脑上进行调试(这里指脱离云环境),因此你必须有一个付费的云环境来进行开发和测试。因此,有些开发者会购买两个云环境,一个用于开发和测试,另一个用于生产环境,但我认为这种做法不适合个人或小企业(已有一定用户规模的除外)。

首先,多一个开发环境意味着每年要多出240元左右的成本。其次,在开发环境和生产环境之间的数据同步和代码同步是一个很繁琐的事情,一会切换到开发环境,一会切换到生产环境,这会让写代码这件原本很幸福的事变得很劳累。

因此,我个人主张使用同一个云环境进行开发和测试。为了避免误删数据,我们需要对数据库的接口进行一定的封装,让开发环境自动访问xxx表,而生产环境自动访问p_xxx表(这里的p_前缀表示production)。由于这个问题展开后篇幅较多,我会在以后的文章中详细介绍。

如何尽可能降低云开发的费用?

如果你不改变编码习惯,那云开发的费用可能会成指数级增长。

这里介绍10个常用的降低云开发费用的编码习惯:

  1. 合理设计数据库结构,减少读写次数。例如,当显示一个商品详情页时,要尽可能仅读取一次数据库,这就要求设计数据库时,把商品的基本信息、商品图片、用户评论等都放在同一个数据文档中。

  2. 尽可能一次性读取较多数据。例如,当显示一个列表页时,尽可能一次性读取1000条数据,然后分多次显示给用户。(云开发API有单次只能读取20条的限制,后期我会介绍如何超过这个限制。)

  3. 使用本地缓存。例如,当用户首次进入商品列表页时,将商品列表数据缓存到本地,这样用户从商品详情页回到列表页时,就不需要再次读取数据库。甚至,可以在读取列表数据时,把详情页数据也一并读取,这样用户进入详情页时,就不需要再次读取数据库。(单次读取数据的总大小有限制,以后详细介绍。)

  4. 使用webp格式的图片。webp格式的图片比png、jpg小很多,这样可以减少网络流量的成本。

  5. 降低云函数的内存配置。云函数的费用是按照“内存配置x运行时间”计算的,内存配置越高,费用越高。目前默认是256M,你最低可以手动降到128M,这样就能降低一半的费用(通常你连128M也用不到)。

  6. 在云函数中,尽可能用Promise.all并发执行,以减少云函数的运行时间。例如,你有10个文件要下载,你可以使用Promise.all并发下载。

  7. 文件尽可能放在“静态存储”中,而不是“动态存储”中,后者的存储费用是前者的20倍。

  8. 宁可存储冗余数据,也要减少数据库的“调用次数”。例如,一个商品的用户评论,可以把用户的头像、昵称和评论内容都存储在商品文档中,而不是存一个用户id,然后再用id去用户表中读取用户的头像、昵称。什么,你说万一用户修改了昵称或头像怎么办?请看下一个建议。

  9. 能不update的就不要update。毕竟用户修改头像和昵称并不影响其他人阅读商品评论,如果用户修改了头像和昵称,那么他在商品评论中的头像和昵称不更新也没关系。这不仅仅是为了减少“调用次数”,更重要的是能不写的代码就不要写。

  10. 避免重复计算。例如,有一个云函数会消耗10次“调用次数”,但不同的用户调用这个云函数时,返回的结果是一样的,那么可以把结果缓存到数据库中,下次直接读取函数缓存结果。

相信如果你能做到以上10点,那么云开发的费用不会很高。

四、云开发是一种享受编程的体验

如果说你已经感受到使用云开发不需要和服务器打交道的幸福体验,并且也不再担心云开发的费用,但你依然犹豫不决,那我相信一定是你担心从MySQL等关系型数据库迁移到文档型数据库会让你不习惯。

先说我个人的感受,在前、后端直接操作数据库给我带来的便利性,远远超过了那种不想改变编码习惯的排斥感。

如今,我们还有Copilot、ChatGPT等AI工具,当你想要插入或更新一条数据时,Copilot会一秒钟帮你写完数据库的API调用代码,而复杂的查询语句可以让ChatGPT或Claude帮你写,这大大的降低了我们学习文档型数据库的时间成本。

接下来,我们通过一个案例,来看看小程序云数据库的优势。

给商品添加评论

假设我们有一个商品表products,并且商品的评论和其他信息是存储在同一个文档中的,如:

{
  "_id": "id_1",
  "name": "iPhone 15",
  "price": 4999,
  "comments": [
    {
      "content": "good",
      "time": "2022-01-01"
    },
    {
      "content": "bad",
      "time": "2022-01-02"
    }
  ]
}

那么,当我们要给商品添加一条评论时,只需要这样写:

// 获得数据库引用
const db = getApp().cloud.database()
const _ = db.command
db.collection('products').doc('id_1').update({
  data: {
    comments: _.push([{
      content: 'very good',
      time: new Date()
    }])
  }
})

关键是,上面这段代码,可以直接写在前端,不需要后端接口(云函数),当然你也可以很方便的复制到云函数中。

允许冗余数据

与使用MySQL关系型数据库的习惯不同,当我使用文档型数据库时,我会经常存储冗余数据。

这样做不仅仅是为了减少数据库的“调用次数”,更重要的是让写代码的体验变得更好。

举个例子,如果要删除一个商品以及这个商品的评论,如果使用关系型数据库,你至少要写两个SQL语句,一个删除商品,另一个删除商品的评论(如果你还有商品图片表、商品类型表、搜索关键词表、相关商品推荐表等,那就需要更多删除语句)。而在文档型数据库中,你只需要删除一个文档即可,如:

db.collection('products').doc('id_1').remove()

我个人认为,牺牲一点存储空间,换取写代码的体验,让产品尽快上线,是非常值得的。

数据库的设计要优先服务于写代码的体验

说句扎心的话,你写的程序很可能没人用。既然是这样,那就在写代码这件事情上,尽可能少花时间,用最低的时间成本去验证产品的可行性,这才是最重要的。(当然,如果你在腾讯、Google这样的公司,那这个建议对你来说是不适用的。)

不要想着你的产品将来可能会有很多人用,如果真的有很多人用,你再花时间去重构代码也不迟,我相信到时候你不会嫌弃这点工作量的。

天下武功,唯快不破,在从0-1创造一个产品验证想法上,也是如此,云开发就是我们的凌波微步和无影手。

因此,数据库的设计要优先服务于写代码的体验,一句代码就能完成的不要写多句,能不update的就不要update,能不写的代码就不写,产品上线速度应该是你最关心的问题。

结语


(快速迭代,验证想法)

用最少的开发时间、最舒适的编码体验,完成产品最可能被用户需要的基础功能。去验证你的想法是否满足真实的用户需求,发布后立即进入到下一个产品的研发,不用管服务器端的琐事,把精力放在创造性的工作上,享受创造的乐趣,感受幸福的生活,这就是你应该立即使用云开发的理由。

(本文作者刘永辉,安顺果然赞科技有限公司法人,转载请注明出处。)

最后一次编辑于  06-28  
点赞 8
收藏
评论
登录 后发表内容