V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
fulvaz
V2EX  ›  程序员

我花了两天把接外包的血泪写了出来

  fulvaz · 2017-08-06 23:56:09 +08:00 · 10577 次点击
这是一个创建于 2694 天前的主题,其中的信息可能已经有所发展或是发生改变。

这篇文章是对一次失败的外包项目的反思。

(周五 v2 上有个哥们说周末要全身心做点事情。嗯......我本来想说睡觉,然而最后写了篇长文。至于为啥拖了半年,你看文章长度就知道了,写文章真心累人而且纯粹是信仰)

背景

半年前非常非常缺钱花,因此接了个来自学院老师的外包项目,负责沟通的甲方是一位想转行的学校老师,另外还有投资人,偶尔露脸。而我们这边的主要负责人是我们的老师。和另一位同学商量了一下,直接实践前后端分离,后端以类似 RESTful 的风格设计 api,我负责前端,工作内容是写与公众号绑定的 Web App。然而第一次接外包,踩了很多坑,下面分章节说明。

需求不确定

学校项目往往没有文档。一般来说,这些项目在外面都是没人肯接,因为这些项目往往没有明确的需求,就算有也会常常变,稍微有点软件工程常识都知道这是大忌。当然,作为学生练手,也没啥关系,就是做得很累(就是 9/12/7 这样工作)。具体到这个项目中,文档是一个已经上线某 app 作为参考,甲方与负责人的口头说明,UI 设计是自由发挥,技术选型也是自由发挥。

首先是沟通问题。其实需求变动不多,直接抄某 app 就可以,比较麻烦的是与 app 不同的内容,这种需求问题其实需要反复与甲方沟通、确认的,然而我这里采取的方法是快速出原型,做完一部分就给甲方看,然后沟通。这里最大的错误是我高估了自己的能力,对一个新手来说,写出健壮、高复用的代码实在太难,结果是,甲方要改的时候,我感觉很为难,修改常常意味着重写。其实在与甲方见面的时候应该认真把这部分给描述清楚,而不是三言两语。有一次功能都做完了,然后甲方提出了异议,表示与说好的不一样,后来发现是负责人与甲方意见不一,我们做的是负责人的要求。这种问题在会议上本可以沟通明白的。

UI 设计中消耗了大量时间。让程序员自由发挥设计 UI,叫程序员边写代码边做好 PM 实在是耍流氓。UI 实在是一种见仁见智的东西,IOS7 刚出来的时候也有人大骂库克毁了苹果,扁平化丑。所以是我的 git 分支里面有:indexV6、circleV3......事实上这些问题都应该避免的。厚着脸皮叫甲方搞定设计的问题,或者是自己找好人,让甲方付钱,一般这种情况,我推荐猪八戒随便找一个。不解决这个接下来会非常辛苦,比如说,甲方完全不懂移动 app 的设计规则,死活让你按照上个世纪的网页设计方法---把内容尽可能得塞进一个屏幕中。嗯,我觉得丑,甲方也这么觉得,然后让我改......我......我下次让甲方把 UI 找人弄好了再写前端。

技术选型

作为一个外包项目其实我是有私心的,希望将新技术用于实践中,然而这是非常鲁莽的,特别是在使用前没有提前进行详细的调查研究。

(不想引战,反驳请就事论事。我认为脱离场景讨论框架、语言、编辑器类似的信仰问题纯粹浪费时间。)

这个项目中使用 vue 是一个错误。在 2016 年 12 月时,vue2 刚出不久,整个生态还不完善,那时候很多 UI 库还只能用于 1.x 的版本中,插件也不完善,这对开发非常不利。

首先是 UI 库,我的标准是文档要完善,至少能快速上手,作者还在活跃地维护,满足这些标准的只有 mint-ui 和 element-ui,但是这两个 ui 库还是不够好,幸好有源码,自己研究了下代码,再改了改总算满足甲方需求,但是拖了挺长时间。其次 vue 的生态问题,比如头像裁剪插件,可用的库只有 PC 版,需要使用类似的功能需要自己想办法将类似的插件整合进 vue 中,也花了不少力气。(事实上外包项目应该怎么简单怎么来,最好抄起 jq 就是干。甲方在项目后期苦恼地和我说找不到会 vue 的人。)然后就是因为不熟悉 vue 而踩到的许多坑,这无法避免。

当然在以后项目的技术选型我会保持慎重,不是新技术差,至少使用前要:1.对自己项目的需求有个详细的规划,需要什么功能,研究该框架的生态,什么插件需要自己写,什么功能有现成库,估摸新框架对项目的影响。2.选用前至少在其他小型项目使用过,对其中的坑有所了解,不要被新框架影响项目进度。比如那时候 vue 严格限制子组件不能直接将信息传递给父组件,设法绕过限制反而使代码更难以维护,后来改需求花了不少时间(现在已经重新加上双向绑定功能,不需要 eventhub 了)。

技术上的问题

技术上的问题远比人的问题简单。

mock server 搭建

内容很简单,只是刚接触确实要推敲,还很麻烦。

项目中使用的是json-server,这个一个非常优秀的 mock 服务器,只需要写 json 就可以生成所需要的 mock 服务,但是 json 的问题是,不够灵活。折中的方法是写 js 文件,下文称这个文件为 db.js ,定义方法看 json-server 的文档。使用 js 文件设定 mock 服务的另一个好处是,这样可以将faker也集成进来,生成随机数据会非常简单。

但是这样也有问题。对需要传参的 api,比如说/album/:uid, 那么我们需要模拟多个用户的相册,然而一下子弄出成百上千的用户数据是会严重拖慢json-server的速度的,而且我们也并不需要那么多的数据,我们只是希望通过不同的uid可以返回一个相册数据就可以了。那利用route就可以解决这个问题。

json-server中定义 route 的方法之一是写 json 文件,我们这里可以将不同uid的请求都指向同一个 api:

album/:id": "/album"

那么,我们只需要在db.js中定义一个album就可以访问任意 id 的相册。

另外,还有偷懒的方法:比如说有两个不同路径的 api,但是他们返回的数据相同,或者是某些需要 api 方法是 POST,而且提交的数据并不需要在页面中使用,那完全可以在db.js中导出一个空数组,然后用路由将所需要的路径指向这个空数组的路径:

// db.js
module.exports = function() {
	data.album = {...}
	data.fakePost = []
	return data
}

// route.json
{
	"/postAct": "/fakePost"
}

这样就引出了另一个问题,一般来说,我们想 api 发送一个 post 请求,服务端通常会返回数据或者是响应码,而json-server只会把 post 请求中的数据发送回来。那么 mock 返回值就需要另一样东西:中间件。其实写一个json-server中间没多复杂,比如:

module.exports = function (req, res, next) {
  if (req.method === 'POST' && req._parsedUrl.pathname === '/userDetail') {
    req.method = 'GET'
  }
  next()
}

这段代码走的事情是,将所有对/userDetail路径的 post 请求拦截,改为 get 方法,然后运行下一个中间件。加了这样一个中间件之后,post /userDetail 请求就相当于 get /userDetail,因此,只需要在db.js中定义/userDetail的返回值,就可以实现 post 请求后返回响应码或者指定数据。

关于 vue 的坑坑洼洼

v-model

非常好用的一个功能,本质上是一个语法糖,vue 的文档已经详细说明了原理,我在这里举一个例子。v-model 应用范围不仅仅是在<input>中,比如说我们需要做一个弹出层的提示框,用户在提示框中输入文字,点击确定后,输入的内容要出现在页面上。我们将弹出层组件命名为popup,正常来说,我们在父组件中需要添加代码监控confirm事件,然后在popup中,点击确认按钮时触发confirm:

// index.vue
// template 
	<div>content in the popup: {{content}}
	<popup @confirm="onConfirm"></popup>
// script
	...
	methods: {
		onConfirm(payload) {
			this.content = payload
		}
	}
	
// popup.vue
// template
	<input v-model="text">
	<button @click="onClick">Confirm</button>
// script
	methods: {
		onClick() {
			this.$emit('confirm', this.text)
		}
	}

那如果使用 v-model 的话,那代码可以简化,应该说,使用这个组件的人会很舒服,因为现在只要需要向组件传入一个 data 就可以了:

// index.vue
// template 
	<div>content in the popup: {{content}}
	<popup v-model="content"></popup>
	
// popup.vue
// template
	<input v-model="inputText">
	<button @click="onClick">Confirm</button>
// script
	props: {
		value: String
	},
	data: {
		...{
			inputText: ''
		}
	}
	methods: {
		onClick() {
			this.$emit('input', this.inputText)
		}
	}

可以看出,在index中,使用popup组件变得非常简单,只需要将content传入v-model即可。

这里需要注意的是,popup中必须添加一个名为value的参数,父组件的 content 将会传到 value 中;另外popup中还添加了inputText的属性,原因是,vue 不允许直接修改传入的props。完整代码,请点击

当然这个例子只是为了说明v-model可以减少代码量,事实上这个例子并不合理,有很多改进的地方。事实上组件确认后应该返回一个 promise,让父组件随意处理输入的数据,这些就不展开说了,这又会是一篇文章。

操作 DOM 的问题

vue 虽然提供了数据绑定,但他也允许你直接修改 dom,但是!自行修改 DOM 导致的风险 vue 可不管,你自己改了渲染结果,vue 不知道,因此不推荐修改 DOM。

然而现实是残酷的,vue 不是万能,总有绕不过的坎,比如说,动画、移植插件等。下面是几条操作 DOM 的小规则。

在 vue 的生命周期里面,要到mount才能开始操作 DOM,vue 提供了this.$el,通过这个就能使用原生的 js 代码操作已经生成的 DOM。

如果你所操作的 DOM 依赖 data 中的某些属性,当 data 变化时,你的 DOM 是不会自动变化的,你需要在updated钩子函数中手动更新 DOM。

手动生成的 DOM 不会被组件内的 scoped css 影响,你需要自己在全局,或者是在 js 内写需要的样式。

为什么不允许直接修改 props

'Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "ifLiked"

上文关于v-model的章节中我们提到 vue 不允许直接修改传入的props,vue 的警告信息已经清晰地说明了为什么,然而我们可以简单地通过新建一个data属性的方式绕过,然而绕过并没有解决问题。比如说,有这样一个场景:朋友圈点赞,然后设计如下:

  1. Card 表示一条朋友圈,其data中有一个属性为ifLiked,表示是否被当前用户点过赞
  2. 点赞按钮 Thumb,其props中有一个属性ifPink,用户点赞后,ifPink变为true,按钮变为粉红色。
  3. Card 是 Thumb 的父组件,加载时,Card 通过从服务端获取用户的点赞数据,然后将ifLiked传入 Thumb 的 ifPink中。

看出这样设计的问题了吗?

用户点赞时,Thumb 只修改了作为propsifPink!虽然 UI 看起来是正常的,然而父组件中的 ifLiked 却并不知道用户已经点了赞,因为 vue 禁止子组件直接修改父组件的属性,如果用户通过路由进入了其他页面,然后重新返回朋友圈会发现,自己点的赞全变成了灰色。

解决方法有三个:

  1. 通过事件监听将子组件的数据返回给父组件。然而这是一个糟糕的办法,原因很简单,如果你的票圈层级改为 Card-> Handlers -> Thumbs,Thumbs 并不是 Card 的直接父组件时,代码量急剧上升,因为 Handler 不仅要代理ifLiked,还要代理点赞事件!因为 Card 是无法直接监听 Thumbs 所发出的事件的。

  2. 发出点赞后,重新向服务器获取已点赞信息。

  3. 使用 eventhub 或者是 vuex ”修改“父组件内容(当然不是直接修改啦)。

不得不说,无论哪个方案都非常折磨人,于是:

在 2017 年 4 月底发布的 vue 2.3.0 中,被删掉的.sync回归。日。

一定要进行错误处理

菜鸡代码的死穴是:脆弱。特别是移动端的前端,如果不做好错误处理,肯定要被老板和客户骂死。

程序逻辑的错误其实问题不大,大部分 vue 都给挡住了,大不了就是点击没反应,反正不至于白屏,这里重点说网络错误。

这个项目中的前端做成了 SPA----大量 AJAX,那问题就是,如果有任意一个 AJAX 请求出了问题,但没有对用户的指令,这样的用户体验极差,特别是移动端网络不稳定。此外,出错没有任何提示信息也不利于修复 Bug,用户就两个字:白屏,这真是没办法。项目完结后,我总结了一下必须处理的错误分为两种:

  1. 页面加载时的发生的错误;
  2. 加载结束后网络请求的错误。

对第一种错误,发生时应该提示错误与错误码,然后自动刷新页面。在项目初期时,这样可以快速修复 Bug,错误码可以清晰地分辨出问题出自前端还是出自后端。在项目后期,这些提示就可以全部关掉了,项目已经成熟。如果这个项目可以继续的话,我是会将加载时的错误处理变为:

  1. 自动重新加载 3 次,然后提示网络错误,为用户提供手动重新加载的功能;
  2. 出现手动重新加载页面时,将错误信息、用户访问的页面、发生错误的 api 发送回服务器存 log。

对第二种错误,自然提示网络错误,让用户重新点击,重新发送。当然了,如果用户发送的请求是发送已输入数据,发生错误的时候,将已输入数据保存到 LocalStroage 中,重新加载页面是将输入信息也提取出来。

最后要说明的是,在用户进行任意网络请求时,请加上反馈,比如进度条,比如提示加载成功。

至于在我的项目中,实施的方法很 low,我简单带一下。首先,网络错误会在 Promise 中抛出,在调用 API 时处理 reject 就可以了,然后是自定义错误码的处理,后端的同学会将自定义错误以 JSON 的方式返回而且 HTTP 状态码统一返回 200,以防止运营商劫持。错误 JSON 格式如下:

{
	errcode: 5001,
	errmsg: ''
}

项目的 AJAX 通过vue-resource实施,而这个库带有interceptors,又是一个中间件,具体用法可以看文档,我定义了这么一个中间件:

Vue.http.interceptors.push((request, next) => {
  request.credentials = true
  next(response => {
    // 从 response 中获取数据
    let data = utils.response2Data(response)

    if (data.errcode && data.errcode !== 0) {
      response.status = data.errcode
      response.statusText = data.errmsg
      response.ok = false
    }
  })
})

这个中间件会将全部返回的请求都拦截检查一遍,如果发现数据中同时有errcodeerrmsg的字段,就自动将响应的statusstatusTextok替换,这样就能触发 Promise 的 reject 了,错误便可以在组件中统一处理。

关于 API 设计

因为缺乏文档的关系,在 API 设计上我与后端一起设计,首先说明我写一个组件的工作流程:

确定数据结构 - 设计 API - 写 setting - 写文档 - 写 api 实现 - 组件设计 - 写页面

  • 确定数据结构:确定该组件所需要的数据,设计字段,以及该字段应该使用什么方式保存;

  • 设计 API:事实上我只是设计数据传输的字段,至于 API 的路径我不需要关心;

  • 写 setting:由于前后端工作不同步、需求文档缺乏,API 也只能边做边设计,这样就导致后端不知道需要提供什么字段,至于路径的设计更无从谈起。我提出的解决方法是,我与后端一起维护一个setting.js,其大致结构如下:

    var dev = true
    var apiPrefix = dev ? 'http://localhost:3000' : 'http://api.server.com'
    
    let devApis = {
      'circlesApi': apiPrefix + '/circles',
      ...
    }
    
    let apis = {
      'circlesApi': apiPrefix + '/circles', 
      ...
    }
    
    let api = dev ? devApis : apis
    

    这个setting.js中将开发的 mock API 与生产环境的 API 路径分离,这样我开时的 mock API 便的路径可以随便定义,写完后将setting.js的字段与定义告诉后端,后端在根据我提供的 API 行为文档自己去实现即可。需要说明的是由于setting.js是外部文件不用直接当做 ES6 模块导入,因此会存在缓存问题,即setting.js更新不及时,所以在请求时后 url 后加上一个随机的参数以强制刷新缓存,如url?timestamp=hash()

  • 组件设计:拆组件,哪些可以复用,如何高复用 blablab,数据流 blablabla

  • 写页面:写啊。

然后,我们两都是第一次搞前后端分离,在 API 设计上存在一些问题,经验总结如下:

  • 客户端知道尽量少的信息就可以使用 API,尽量精简 POST 请求中 JSON 数据的字段数,可以算的绝对不传。

  • 很多文章说应该使用 HTTP 方法作为一个动词,路径中充满名词,然而我们实践下来发现,HTTP 方法的动词要么不够用,要么不够直观,另外,不同人对 HTTP 方法的意义有不同的理解(比如 PATCH 与 PUT ),虽然翻文档可以解决问题,然而文档如果不更新(比如我们),API 就变的非常难以理解,到项目中期,我们将 API 的风格变为:

    	POST /moments => POST /moments/add
    	PATCH /moments/:id => POST /moments/:id/like
    	PATCH /moments/:id => POST /moments/:id/unlike
    	GET /moments 不变,不影响理解
    	POST /moments/:id/comment
    	POST /moments/:id/edit
    

    可以看出我们只使用 POST 与 GET 方法,路径的构成为名词 + 路径末尾动词,这样 API 所表达的意思直观得多。(这部分其实见仁见智,因为 RESTful API 设计没有统一的标准)

  • 如果响应的某个字段为空, 空数据请用''(空字符串), 这次项目中后端使用 null 表示空数据,而我的 mock 服务使用空字符串,因此上线后各种姿势的错误,然后花了非常多时间过滤响应的 null。请各位后端手下留情,空数据一定一定要用空字符串。

CSS

  • 开发前要订好全局样式, 即标题文字大小, 描述文字大小, 颜色, 全局背景颜色,统一修改,不然散落各处那个酸爽;

  • 移动端慎重使用 overflow-y:scroll, 手机滑动会卡顿,iphone 也不例外;

  • 使用rem别用px,鬼知道甲方要不要你适配 ipad。

其他

  • 用 vue-cli 的话,看看这个文档会让你少走许多弯路。这个文档详细说明了vue-cli的 webpack 模板设置与常见问题,包括静态文件处理、css 处理器添加、环境变量、单元测试问题等;

  • yarn 很棒,简单好用;

有空也可以去学学 react 和 angular,这两位老大哥的社区里面关于设计模式的内容非常值得看;

  • mint-ui 的源码很值得看,他们的设计非常棒,比如 MessageBox 的回调处理,看得我目瞪口呆,还有这种操作。有空再写写 mint-ui 源码分析;

  • 发包含 id 的数据考虑是否要先 parseInt,可能后端只接受id: 1而不接受id: "1",说多都是泪;

  • this.$route 和 this.$router 是两个完全不一样的东西;

  • 再说一次:如果后端发 null 和 undefined 给前端, 毫不犹豫地拿刀去见他。

PS

  1. 其实感觉甲方也挺惨,遇到我这种坑货,中间出了一堆坑全要耐着性子等我处理完。而且甲方人也很好,提前给尾款,过年还发红包,简直良心。但愿以后也能遇到良心老板。

  2. 哎,有耐性写这种文章的也就我这种有信仰的失业人员了。

  3. 这篇文章让我回想起了写硕士论文的恐惧,哎,网上分享干货与教程的大大真是伟大得不行,另外开源项目中负责写文档的哥们也是条汉子。

  4. 啊,失业也不是坏事,终于把这几千字憋了出来。

第 1 条附言  ·  2017-08-07 12:14:02 +08:00

关于后端传null的问题,经@zpf124提醒

vue会直接将null渲染为空字符串,然而各位后端同学还是不要传null !

第 2 条附言  ·  2018-07-31 10:19:08 +08:00
写这篇文章快一年了, 我也工作快一年了

最近还是有人收藏这篇主题, 实际上现在我觉得这篇文章错漏百出........
54 条回复    2017-08-08 16:10:54 +08:00
pqee
    1
pqee  
   2017-08-06 23:59:53 +08:00 via Android
我觉得需求分析部分是很多没接过外包的人最容易忽略的重点。技术部分只是缺乏经验而已。
hst001
    2
hst001  
   2017-08-07 00:10:59 +08:00
第一次见到超长主题被 v2 折叠的,写这么多可见楼主血都吐干了
Luckyray
    3
Luckyray  
   2017-08-07 00:13:30 +08:00 via iPhone
先收藏了慢慢看……
mikulch
    4
mikulch  
   2017-08-07 00:14:12 +08:00
没文档吗。
isb
    5
isb  
   2017-08-07 00:18:52 +08:00 via iPhone
适配引入了淘宝的 flexible,可有试一下,最近也做 SPA ……有点吐血。需求一直变,关键是接口还是一种改。。加油吧。
iAcn
    6
iAcn  
   2017-08-07 00:24:12 +08:00 via Android
收藏了,以后接学校的外包时参考经验
RLib
    7
RLib  
   2017-08-07 00:42:03 +08:00   ❤️ 1
外包基本都是包坑的
herozzm
    8
herozzm  
   2017-08-07 01:07:49 +08:00
lz 做项目辛苦了,写文章更辛苦了
万幸(也是低概率)遇到了好甲方(我一开始是猜甲方跳墙不要 lz 辛辛苦苦做的项目的,这样的才叫血泪)
designer
    9
designer  
   2017-08-07 01:21:27 +08:00 via iPhone
非常棒的分享
doxiami1
    10
doxiami1  
   2017-08-07 01:32:23 +08:00
我感觉现在的前端框架都是坑,几年就会被淘汰,无法像 jquery 那样活十几年
fulvaz
    11
fulvaz  
OP
   2017-08-07 01:35:38 +08:00
@mikulch 当然没有啊,有文档哪用沦落到叫学生做
@pqee 对,以前看书听分享不觉得有啥,等自己做的时候就能深刻体会软件工程有多重要
@isb 适配到 vue 中吗? 有 github 链接没,最近失业,有空可以看看
@RLib 倒不能这么说,只是没法沉下心认真做很烦躁
uncleroot
    12
uncleroot  
   2017-08-07 03:02:31 +08:00 via Android
好文,软件工程的意义只有实战中才有体会啊。
lsmgeb89
    13
lsmgeb89  
   2017-08-07 03:15:20 +08:00
挺好的,做完项目写总结和反思是提高的好方法。
maomaomao001
    14
maomaomao001  
   2017-08-07 07:31:42 +08:00 via Android
你用 vue 用的不太对劲啊。。。。有的 vye 不太适合的地方,你直接获取 dom 节点,交给 jquery 去处理,完全没有问题的
b1rd
    15
b1rd  
   2017-08-07 08:15:16 +08:00 via iPhone
学生有锻炼的机会挺好的
ytmsdy
    16
ytmsdy  
   2017-08-07 08:48:51 +08:00
将所有对 /userDetail 路径的 post 请求拦截,改为 get 方法....
这个做法在未来的维护中是一个大坑!

挺好,编码,总结,提升。
patx
    17
patx  
   2017-08-07 09:01:05 +08:00 via Android
感谢分享
miaotaizi
    18
miaotaizi  
   2017-08-07 09:02:28 +08:00
组件多的时候, 还是老老实实用 vux 架构, 不然就是虐心
freelee
    19
freelee  
   2017-08-07 09:34:04 +08:00
好文,感觉楼主这都不能算是新手啊,楼主的能力已经完爆很多人了
下次一定要让甲方把图都画好,自己再动工,其实他把图准备好的过程中,他自己就已经分析过一遍需求了,省了很多沟通的功夫
netsail
    20
netsail  
   2017-08-07 09:35:27 +08:00
支持分享
chairuosen
    21
chairuosen  
   2017-08-07 09:43:10 +08:00   ❤️ 1
记得 overflow-y:scroll 的卡顿,用-webkit-overflow-scrolling: touch;可以解决
Hozart
    22
Hozart  
   2017-08-07 09:51:07 +08:00
好奇一下 LZ 在大几的时候做的项目
cjyang1128
    23
cjyang1128  
   2017-08-07 09:57:56 +08:00
很棒,其实我感觉最大的问题就是木有找人做 UI,楼主感觉很厉害,最近也在学习 vue,希望能像楼主一样这么厉害
daysv
    24
daysv  
   2017-08-07 10:04:16 +08:00
为啥不用 vuex
rosu
    25
rosu  
   2017-08-07 10:04:18 +08:00
感谢分享。
写作真是靠信仰,过程艰难。
有时候写出来是一回事,而当时的经历怕是只有自己才懂。
祝好。
hareandlion
    26
hareandlion  
   2017-08-07 10:14:19 +08:00 via iPhone
血泪教训,感谢分享
anyele
    27
anyele  
   2017-08-07 10:15:09 +08:00
能写这么多也是厉害
eric1202
    28
eric1202  
   2017-08-07 10:31:57 +08:00
鼓励鼓励!
zpf124
    29
zpf124  
   2017-08-07 10:34:45 +08:00
后端的问一句,不能用 null 是为什么啊,undefined 应该不会出现,不过我写的许多接口返回的都是 null...

大多数返回 null 都是类似于 用户从来没有设置过个人介绍 这种情况, 这种介绍应该不会用于去计算导致报错吧,
难道页面会直接展示一个 “ null ” 字符串么...
fulvaz
    30
fulvaz  
OP
   2017-08-07 10:39:49 +08:00
@maomaomao001 具体哪一点用得有问题?

@ytmsdy 可以稍微展开一下说吗? 我没 get 到,为啥会维护难?

@miaotaizi @daysv 用了,但是总感觉杀鸡在用牛刀,我的需求里面直接用 `.sync` 也不会影响以后的维护和对代码的理解,甚至 eventhub 也不需要,为了这个用 vuex 实在太过。当然其他部分也用了感觉很棒,比如需要跨页面共享的数据,比如个人信息、新私信数量、余额、是否 vip 这种;

@chairuosen 是的,然而解决了 iphone 的问题,安卓的卡了起来,后来我干脆直接绕过了。

@cjyang1128 @freelee 不不不.....菜鸡写踩坑总结,大神写架构设计。
fulvaz
    31
fulvaz  
OP
   2017-08-07 10:51:49 +08:00
@zpf124 给你举个例子你就明白为啥会被前端砍死了

如果你们需要这样的 JSON 结构

```
{
id: 1,
sex: 'male',
friends: []
}
```

如果你的项目不要求用户填性别,新用户也没朋友,你发 null 和 undefined 的结果是

```
{
id: 1,
sex: null
friends: null
}
```

那前端的现实结果是:
性别:null
朋友:

通常来说前端会遍历数组,然而遍历 null 页面就崩了。而在 vue 中这么玩,直接白屏,重新加载页面也没用。

你可能会说前端就应该检查。然而这么检查代码量就很大了好吗,就算我写中间件检查,那个中间节也一堆代码,不仅要判断字符串 null,还要判断数组、对象是否为 null,如果那个对象是个大对象还有有嵌套,性能那个惨。

学习一点前端知识,对前端好点。话说现在不是都要求前端一定会写后端么。
nicevar
    32
nicevar  
   2017-08-07 11:02:43 +08:00
我觉得再接几次你就烦了,其实外包的活有现成的东西改了就用才是最靠谱的,像你这样挺折磨的,外包的项目大多数没有完整的文档的,因为他们根本没有产品经理哈哈,随便画几个草图,让开发人员自由发挥,结果做出来对方觉得不是这个味,然后就是左修右改。
下次接活前一定要对面给个相对比较完整的文档,虽然很难,说到这里我想偷笑,不少正规大公司文档也是很坑人的,以前给移动公司做了个项目,完全是天马行空搞出来的,领导头一热时不时蹦出来一个需求,那个代码改得自己最后都没法看
fulvaz
    33
fulvaz  
OP
   2017-08-07 11:18:24 +08:00
@nicevar 哈哈哈哈哈

我肯定不接下一次啦,这次纯粹练手
jedyu
    34
jedyu  
   2017-08-07 11:19:01 +08:00
@fulvaz 不论前后端,不要相信别人传给你的数据.
zpf124
    35
zpf124  
   2017-08-07 11:36:30 +08:00
@fulvaz 数组对象之类的确实是问题,如果你们没判断 null 就用了里面的元素 确实直接尿了,但其他类型应该不会吧,vue 之类的应该会啥也不显示吧。
vjnjc
    36
vjnjc  
   2017-08-07 12:05:56 +08:00
居然这么长。。。所以接外包就是怎么快怎么来,不要重构,是这个意思么?
fulvaz
    37
fulvaz  
OP
   2017-08-07 12:12:27 +08:00
@zpf124 我又回去试了一下,确实为空,嗯,确实写错了
falcon05
    38
falcon05  
   2017-08-07 12:20:03 +08:00 via iPhone
用心写文章的都是好人
fulvaz
    39
fulvaz  
OP
   2017-08-07 12:20:44 +08:00
@vjnjc 怎么容易改怎么来

然而我想表达的是:没有金刚钻别揽瓷器活
pqpo
    40
pqpo  
   2017-08-07 13:47:06 +08:00
现在看到长文先拖到最后面看看是不是广告 ==
wuhaoworld
    41
wuhaoworld  
   2017-08-07 14:25:42 +08:00
没有文档,你们就先写文档,画原型,跟需求方确认后再开始开发。改文档可比改代码容易多了
TimRChen
    42
TimRChen  
   2017-08-07 15:20:10 +08:00
楼主的分享对我思考项目优化有一些帮助,谢谢楼主
maomaomao001
    43
maomaomao001  
   2017-08-07 17:05:46 +08:00 via Android
其次 vue 的生态问题,比如头像裁剪插件,可用的库只有 PC 版,需要使用类似的功能需要自己想办法将类似的插件整合进

只针对这一点,你看可以这样,项目中用 jquery, vue 用来双向绑定,组件化什么的,改用 jq 的地方,你用 vue 的获取 dom 属性的方法,交给 jq 处理完全没有问题
tanranran
    44
tanranran  
   2017-08-07 17:57:11 +08:00
非常好的干货

对于新手和老手都有帮助.

谢谢楼主
winglight2016
    45
winglight2016  
   2017-08-07 18:01:09 +08:00
LZ 最主要的问题是开发经验不足,跟着高手做上几个项目就明白有哪些坑需要避免,哪些其实不是坑,比如:json 格式和 mock server 没有半毛钱关系,用在线服务或者本地 http 服务、又或者 chrome 插件都可以做,再比如:前后端分离也没有任何问题,只有沟通问题,甚至不是文档问题
最后,外包项目不要用新技术,要用自己熟悉的,这一点完全正确,不然风险太高承担不起
371657110
    46
371657110  
   2017-08-07 18:23:22 +08:00
我怎么感觉 vue 无辜躺枪呢...
wobuhuicode
    47
wobuhuicode  
   2017-08-07 18:49:22 +08:00
框架无关,单纯 LZ 自己经验不足。做学校之类的外包项目,最好还是用 10 年前的前端技术。并不是守旧。而是这类项目需要最稳定是技术,和想把外包做得最赚钱(最短时间做最多事情),成熟稳定的技术(已有的模版和框架)是基础。
hantsy
    48
hantsy  
   2017-08-07 19:17:17 +08:00
>POST /moments => POST /moments/add
PATCH /moments/:id => POST /moments/:id/like
PATCH /moments/:id => POST /moments/:id/unlike
GET /moments 不变,不影响理解
POST /moments/:id/comment
POST /moments/:id/edit

这个不用见仁见智了吧,任何一份 RESTful 权威设计文档都找不到这样的设计, 你仅仅是使用 HTTP 协议而已,it is not REST at all。
hantsy
    49
hantsy  
   2017-08-07 19:22:15 +08:00
经验总结,精神可嘉,但技术方面的细节太多都是误导人的,特别是 API 设计部分,可当前人之车。
lansh2014
    50
lansh2014  
   2017-08-07 19:57:51 +08:00
外包这活怎么说呢。不是很缺钱还是不要做。得不偿失。今年年前的时候一口气接了几个棋牌游戏的外包。钱是缓过来来了(房子装修买家具)。但命感觉都快搭进去了
fulvaz
    51
fulvaz  
OP
   2017-08-07 20:58:34 +08:00
@maomaomao001 这确实可以,后来我直接操作 DOM 来实现头像裁剪。但是我还是希望不违反 vue 的规则(单向数据流)来完成功能,嗯,我还是理解不够深刻,我再研究一下。

@lansh2014 +1 脖子从那以后一直不舒服,那段时间也容易失眠。

hantsy 啊,对,到后面我们完全放弃了 REST,只能说我们两个菜鸡还没理解如何设计 API,于是我们使用了这样的补救方案。 但能详细说说是哪几个技术细节有问题吗?我再看看。
fulvaz
    52
fulvaz  
OP
   2017-08-07 21:02:00 +08:00
@hantsy 啊,对,到后面我们完全放弃了 REST,只能说我们两个菜鸡还没理解如何设计 API,于是我们使用了这样的补救方案。 但能详细说说是哪几个技术细节有问题吗?我再看看。
hantsy
    53
hantsy  
   2017-08-08 12:01:46 +08:00
@fulvaz REST 一词来 Fielding 博士的论文,InfoQ 有中文版本,评估 REST 质量可以看 Rechardson Mature Model,设计可以参考 Heroku,Github API 文档,这些几乎被当作 API 设计的典范。
在互联网应用,API 设计应该重中之重,API 本身一旦确定下来,在一个版本中对外应该保持不变,即使 API 后端的实现发生变化(如,变换语言,框架,架构迁移) 。
当然国内几乎都是流行前端开发与后端开发人员自己决定,出来的结果可想而知。关于设计细节,之前我个人也在 V 上发表过自己的意见,不想再重复了。国内没有什么公司重视这些,更多是关心一张皮弄出来就行了,REST 不 REST 不重要,API 是 UI 的附带品,你现在做的这些已经足够在 90%公司混得不错了。
fulvaz
    54
fulvaz  
OP
   2017-08-08 16:10:54 +08:00
@hantsy 感谢回复。我再去研究下 REST 的设计例子,还有时间再去看看论文 ---- 我觉得也就比别人多这么点优势了,知道怎么看论文。

然而我失业中.....非常尴尬🤦‍♀️
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2880 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 30ms · UTC 14:18 · PVG 22:18 · LAX 06:18 · JFK 09:18
Developed with CodeLauncher
♥ Do have faith in what you're doing.