之前主要说的是,我是如何产生这个圈子小程序的想法和如何上线的。有兴趣的朋友可以回去参考前面两篇文章。这次来给大家讲讲,在技术上是如何实现的。
如何快速把想法变成产品
分享作为独立开发者经历和一些上线经历
技术栈
前端主要是基于Taro++dva框架实现的,后端基本上是以Ruby on Rails为主。
这里说下为什么要做这样的技术选型,关于技术选型,在《奔跑吧,程序员》一书中有很详细的分析,后面我会我在我的读书笔记系列把这本书做一次分享。
这里主要说下技术选型主要判断,如果是快速成型的项目,应该选择更加轻量的语言和有大量社区组件支持的,另外一个就是自己熟悉的。
前端
为什么用Taro?主要是以往自身经历决定的,以为本身我做了13年技术研发,虽然后面几年自己动手的时间少了,但也算在一线工作。前几年React Native刚兴起的时候,对于有着js开发经验和安卓开发经验的我很快就上手。借着之前饿了么做hybrid和移动端动态模板渲染的经验,让我迅速理解了React的设计理念和原理。
所以这次就顺利的用了以React为主的Taro前端开发框架,虽然uni-app大名鼎鼎,但毕竟要重新了解vue。原先redux那一套回忆起来相对比较快。这里不去争论对错,能让你舒舒服服的快速完成,那么就是对的。
说回,记得以前写js碰到最大的问题是无法提示,对于我们这种全栈开发来说,切换太快了,所以会花很多时间查他下面有哪些方法等,为了节省代码量,有段时间还疯狂的写coffee script。虽然项目里写的还不是很规范,但确实解决了我很大一块问题。
看到这里肯定有人想说,那是你没用对。就好像Vim、Emacs一样,很多人觉得太方便了,为此我还专门花了时间去学vim的快捷键。但是最后用起来还是习惯不了,切换模式dd删除,我还是比较喜欢在VS Code里用`command + x` 来当删除用,十几年的习惯,不是说改就改的。
还是那句,没有对错,只有你自己习惯就好。
后端
其实这几年写的比较多少的还是Java,但这里就不多说了,现在的项目也没做过太大的压测,但如果用户量大到扛不住,那么再说甜蜜的烦恼问题。重新花时间调研了下Ruby on Rails,发现新增了很多特性,如Job、、Webpack、等等,对于全栈开发来说支持越来越好了。
最重要的是Ruby on Rails对测试的支持非常好,我个人习惯就是如果代码没有测试覆盖,我很容易改出问题,因为时间久了或者对这块业务不熟悉了,很容易有问题出现。
小程序
项目结构
先丢张基本的结构图让大家了解下
大概的流程是这样的,这里不做过多讲解,有兴趣的朋友自己去看dva框架和redux。
下面主要这次开发圈子小程序碰到的一些问题和我解决的思路和方式,如果你有更好的,欢迎找我交流。
登录
说真的,登录是非常烦人的一件事。之前一直有一定的概率出现**Error: error::digital ::bad decrypt**,后来在官方的文档中找到:
在 等返回加密信息的回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 不是加密时使用的 ,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 进行登录态检查,避免 login 刷新登录态。
所以后来我调整成
在进入页面后,会进行一次login,然后把获取的code保存起来当用户点击登录按钮,会再一次进行检查,避免登录态失效然后把获取到的`code`, ``, `iv`全部提交到服务器进行解密和校验
穿透问题
圈子小程序里有个功能,用户可以评论某个人的帖子,然后会导致一个问题,就是底层的输入框会在弹层上层。具体可以参考下面这张图,我当时没截图。无论你怎么设置z-index都没用。
导致这个问题的原因是,是原生组件,层级会高于网页组件,所以我是这样解决的。
当失去焦点后,把内容存储到内存里隐藏,并显示一个View填充之前缓存的内容
不过这样做又会导致另外一个问题,有可能因为焦点问题,缓存里没内容,用户直接点了发送按钮,这个时候就需要判断提交的内容里有没内容,有就直接提交,没有就用缓存里的。都没有就做非空提示。
还有就是有同学提到,输入框会被键盘盖住的问题。类似下图
这里解决方式也相对比较好解决,参考官方文档这个属性
dva-model-extend和model层
往往在实现逻辑的时间发现很蛋疼的问题,就是几个页面逻辑差不多,但有有点不太一样,然后这个页面又耦合了一些其他模块的逻辑。最常见的例如下面这个。
上图里面几块业务就涉及了圈子、帖子、用户、赞、评论逻辑,还有自己页面的一些逻辑,那么我们应该怎么去划分呢?大家可以参考下图
业务基础类
主要是负责通用逻辑实现的,比如获取用户相关的,帖子相关的等等,但他们没有自己的,不能直接调用,只能作为基类存在。
业务类
就是负责通用业务真正被调用的,比如用户类、帖子类等等。这样做有什么好处,那就是任何页面都可以去调用。
比如我想在帖子列表的页面里获取每个人的用户信息,那么我可以直接一个user的type。他的逻辑相对标准。
界面类
就是为每个页面提供特性服务的类,比如上面图里,我有定制对帖子的返回内容要单独存一个state,那么我就可以继承基础业务类,然后更改他的
的action实现。并且每个界面类都会关联一个page。
数据类
为什么数据类单独的?这有什么用。在前端,我们碰到的很大的一个问题就是,比如A页面用了用户信息,B页面也用了用户信息。如果按照以往的做法,每个页面单独维护一个用户信息,然后通过来更新到每个页面,这样做的问题是大量的冗余数据放在内存里,然后event满天飞,最后也不知道这个页面的数据被哪个地方触发改变了。
所以需要以前数据层来维护,有点像前端的内存关系型数据库,界面拿到一堆ID,然后在要显示的时候才会去数据层查询具体的数据,然后渲染界面。
数据渲染
上面提到,以往我们都是直接渲染数据的,然后通过改。这样还会碰到一个很麻烦的问题。
还是圈子小程序的例子,如果我要删除一张帖子里的评论,我需要怎么做?
找到帖子该帖子的数据找到帖子里的评论数据因为评论可能是子评论,还需要在先找到上级评论后再找到当前评论。防止其他页面数据未更新,发送事件通知其他页面也需要重复一次以上操作
最开始一度让我很奔溃,根本没有办法继续持续下去,而且还很容易出问题,测试的工作量也倍增。
然后我找到了前端神器,这个库可以帮我们完成上面数据层说的工作。具体流程可以参考下图。
为节约篇幅,这里不做过多解释。因为所有页面都是引用性质,所以一旦数据发生变化,所有页面都会跟着变化。并且处理数据只需要处理一层的关联,不需要处理多层的数据结构,因为它帮你把数据进行扁平化处理了。
总结
上面分享了项目的基本结构、逻辑分层、数据处理的一些思路,相信应该对大家开发小程序有一定帮助。
后端
说完前端的基本架构,现在来说说后端。对于初期的项目来说,前端只要处理好数据和逻辑的架构,其他都是一些界面的问题和css相关体力活和不断的多设备兼容调优。
后端的事情比较了多了,比如监控、数据处理、微服务、容灾等等,这些年或多或少接触了一些,但作为新项目,这些东西反而不是最重要的。
实现一个新项目,最重要是如何更快的迭代和提供新接口。crud仔的名声不是随便说说的。
从早年的到现在的微服务,概念一直在更新,但本质上没有太大的改变。都是希望降低风险,早年我在小秘书的时候就开始做SOAP和WSDL,但对于创新业务来说,技术不应该作为阻碍效率的存在。
当我听到为了一张表而专门创建一个服务的时候,我反而觉得是为了微服务而搞微服务。当我想改一个问题的时候,我需要从网关一路改到最后层的服务,明明几分钟能解决的事情,在调试上硬花了一整天。
每个人观点不一致,技术没有对错。面对不同的背景,每个人选择不一样。我见过很多技术架构很好,但迭代慢死掉的公司。也见过很多内耗很严重,但依然发展很好的公司。
前面稍微说的有点偏题了,回到主题。初创项目主要处理好几件事情。当然你有其他观点,欢迎讨论。里面有些地方参考了ruby-china的源码,非常感谢。
接口及响应模板
怎么理解接口及响应模板呢?说白了就是你的接口能返回数据。
这次我没有采用Grape的Gem,而是直接使用了Rails Api和的渲染模板。
首先我创建了一个父级渲染模板
# app/views/layouts/api/v1/.json.
json.code 200
json.message @message.blank? ? ‘’ : @message
json.data JSON.parse(yield)
也就是无论如何都会返回code,message,data这三个key,data可能为Array或者Object
然后在er.rb里指定父layout
layout ‘api/v1/'
然后在的目录里为每一个实体做一个通用的模板,如_user.json.,通过参数判断是简易还是复杂对象。
比如你在列表里user可能主要3个值,,id,avatar,当你具体查看某个人的资料时,你可能需要知道他的其他信息,例如age,gender,等等。
然后相应的接口渲染可以参考下面的
json.partial! ‘user’, user: @user, detail: true
基本上你接口的响应就到这里就结束了。补充一点,如果你是使用Rails Api的话,使用需要加入以下引用
class r < ::API
include ::Layouts # if you need layout for .
include :: # if you need render .
错误捕获及告警
这里分为几块
错误码
你可以选择新建一个专门的类来维护错误码
module Api
module V1
module Code
*请认真填写需求信息,我们会在24小时内与您取得联系。