V2EX 首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

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

  fulvaz · 197 天前 · 8340 次点击
这是一个创建于 197 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

(周五 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 条附言  ·  197 天前

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

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

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

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

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

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

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

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

@cjyang1128 @freelee 不不不.....菜鸡写踩坑总结,大神写架构设计。
    31
fulvaz   197 天前
@zpf124 给你举个例子你就明白为啥会被前端砍死了

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

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

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

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

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

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

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

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

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

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

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

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

谢谢楼主
    45
winglight2016   197 天前
LZ 最主要的问题是开发经验不足,跟着高手做上几个项目就明白有哪些坑需要避免,哪些其实不是坑,比如:json 格式和 mock server 没有半毛钱关系,用在线服务或者本地 http 服务、又或者 chrome 插件都可以做,再比如:前后端分离也没有任何问题,只有沟通问题,甚至不是文档问题
最后,外包项目不要用新技术,要用自己熟悉的,这一点完全正确,不然风险太高承担不起
    46
371657110   197 天前
我怎么感觉 vue 无辜躺枪呢...
    47
wobuhuicode   197 天前
框架无关,单纯 LZ 自己经验不足。做学校之类的外包项目,最好还是用 10 年前的前端技术。并不是守旧。而是这类项目需要最稳定是技术,和想把外包做得最赚钱(最短时间做最多事情),成熟稳定的技术(已有的模版和框架)是基础。
    48
hantsy   197 天前
>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。
    49
hantsy   197 天前
经验总结,精神可嘉,但技术方面的细节太多都是误导人的,特别是 API 设计部分,可当前人之车。
    50
lansh2014   197 天前
外包这活怎么说呢。不是很缺钱还是不要做。得不偿失。今年年前的时候一口气接了几个棋牌游戏的外包。钱是缓过来来了(房子装修买家具)。但命感觉都快搭进去了
    51
fulvaz   197 天前
@maomaomao001 这确实可以,后来我直接操作 DOM 来实现头像裁剪。但是我还是希望不违反 vue 的规则(单向数据流)来完成功能,嗯,我还是理解不够深刻,我再研究一下。

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

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

然而我失业中.....非常尴尬🤦‍♀️
DigitalOcean
关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   鸣谢   ·   1445 人在线   最高记录 3541   ·  
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.0 · 78ms · UTC 13:57 · PVG 21:57 · LAX 05:57 · JFK 08:57
♥ Do have faith in what you're doing.
沪ICP备16043287号-1