前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >那些做了一半的项目

那些做了一半的项目

作者头像
四火
发布于 2022-07-19 06:56:15
发布于 2022-07-19 06:56:15
4261
举报
文章被收录于专栏:四火的唠叨四火的唠叨

最近有一个项目做了一半不做了,准确地说是由于某些原因,项目需要别的团队来接手了,于是我想随便聊聊这个话题。我猜想,“项目做一半撒手”,这应该是一个很常见的现象,因为这样的事情无论大厂小厂,在软件的世界里不断上演。具体来说,有这样几种典型的情况:

  • 业务变动、组织调整,工作重心变了,项目做了一半直接砍掉,或者无限期停工。这大概是最常见的一种情形。
  • 由于前期的调研、设计的严重问题,或是市场等变化过于剧烈,项目做不下去了,静悄悄地黄了。
  • 项目还做,但是转交给某个其它的团队,这是我这一次遇到的情形。项目还存在,只不过所属关系已经发生变更。

文档和隐性成本

无论哪一种,有一点是毫无疑问的,那就是资源投入的浪费,无论是软件还是硬件。即便不砍掉,暂停一段时间,再恢复的时候,要捡起曾经的项目,一样需要一定的成本。而项目要转交给其它团队,软件的交接成本也相当可观。其实这没有什么奇怪的,这是软件的本质所决定的。具体来说,软件开发,特别是上规模的软件开发,就意味着大量的 “隐性成本”。

项目管理的角度来说,我们当然希望规范而且具体,或者说,大家都照章办事,项目设计可以纸面化,事无巨细地把 “为什么要这样做”,和 “‘这样做’ 是 ‘怎样做’ 的” 这样的信息都落地成文字交代清楚。可是你我程序员都知道,这是遗憾到不可能发生的事情。我在中国的大厂待过,也在北美的大厂待过,有个别经历的团队和项目甚至被内部外部视作典范,可是客观地说,文档依然缺失,而且不是缺失一点,而是大量地缺失,再好的项目也是如此。有一个有意思的网站,叫做 Killed by Google,上面记录了被 Google 砍掉的项目。

其实,这并不是什么不可理喻的事情,相反,如果一个一定规模的软件项目,文档清清楚楚,把项目事项和设计细节都交代得清清楚楚,我反而觉得这个项目有着猫腻。因为代码和文档永远有着显著而不可调和的矛盾。为什么呢?因为对于软件工程师来说,一个且只有一个真正的、准确的数据来源(Single Source of Truth),是值得推崇的最佳实践。这样的指导思想是根植于他们脑海中的,一个凡是对 Engineering Excellence 有着追求的程序员,一定会把它放在相当重要的位置。而在多数情况下,文档和代码就是两个数据来源,且无法被统一,但是你我都知道,真正工作的一定是代码,代码才是真正的 source of truth,文档只能成为不断过时的那一个。

我知道一定会有声音说,难道不能及时更新文档吗?比方说,代码逻辑修改了,修改的工程师也负责更新文档。没错,但这过于理想化了,而且,就好像软件的世界里一致性和可用性经常是难以调和的矛盾一样,文档的细致程度,和保持准确性的能力,也一样是难以调和的:文档越是细致,就约难以被及时更新,也就越容易成为过时的文档。文档的更新,不但涉及到工作量的问题,它本身也不符合很多工程师基于代码的思维习惯,因为它的读者有了变化,而且叙述的方式也有了变化;再者,真正在业务中直接生效的,也是代码,文档相应地,总是显得那么间接。

对于大多数工程师来说,特别是某些踏入职场时间并不长的工程师来说,文档的地位要更低一些。就好像 “talk is cheap, show me the code” 已经被不可思议地滥用一样,他们对于代码有着过度的狂热。这原本不是什么坏事,软件工程师总是要立足的代码的,可是,软件工程所谓工程,它一定是一个复杂的结合体,代码只能是其中一部分,有时甚至只是一小部分。随着时间和阅历的增加,越发觉得合适的文档在软件工程中的价值,比方说,就在几年前,关于文档我的一点思考记录在这里,现在其实也已经有了更新。

再回到隐性成本的话题上来。已经说了,在文档缺失或过时的情况下,程序员需要去理解需求,并阅读代码来理解前前后后整个故事,这里面的时间成本和试错成本可想而知,可退一步说,哪怕真的文档齐全,要把这些东西消化掉,也依然需要大量的时间。我们都说程序员是一个终生学习的职业,而每一个项目,就是一个可观测的学习的单元。

是勇气还是荒唐?

这样的决定很多时候并不容易做出。我经历过的多数情况,都来自自上而下的决策。有时候部门调整(reorg),结果一些项目的重要性就发生变更,直接砍掉了。而甚至有时候整个部门或团队都砍掉了,我在亚马逊的时候就经历了这么一回,一个原本负责商品在欧洲内各个国家之间方便流通的团队就这样直接砍掉了,当时作为团队里的一份子,我获得了几个 “下家” 团队的选项。也就是说,工程师重新回归资源池,重新分配归属团队。

但也经历过自下而上的,做过的某个内部应用,本来也是摸着石头过河,第一个版本做出交付了,却发现可用性还是比较差,具体说就是流程还是过于苛刻和冗长,而这个问题又不是一个比较容易解决的问题,很难把它继续推广开去,因此这个项目就烂在半途中了。虽说不能说项目砍掉了,但已经低优先级、无限期搁置了,也就和砍掉没有什么太大区别了。

多数时候,这样的损失并不只有纸面上能看到的 “浪费” 那么简单。除了上面所说的隐性成本,还有对团队士气的打击。但是,这里面有一个值得玩味的话题,当一个团队全身心地、毫无保留地投身奉献于一个项目的时候,这里的风险就很容易不可控了。有一位团队经理给下属画饼的时候说过,“你要把 xxx 项目当做你自己的孩子一样”,无疑这对于传递 ownership 的精神,是一个很形象的比喻,可是项目可能会黄,到时候该怎么收场呢?因此我觉得这不是一个特别职业的表达。

最后,回想起来,这种 “做了一半的项目” 还真是挺常见的。非常遗憾,可对于一个大型的组织来说,回头是岸,及时止损,通常可不是坏事。这样的决定无疑需要勇气,更糟的结果是继续这个项目,决策下的越晚损失越大。软件工程似乎就是这样一个无完美解的难题,处处充满了看似可以避免的弯路和糟糕实践,可是换个项目重来一遍的时候,还是一样有这样那样的问题。这有点像是人生,大道理我们都懂,可还是过不好这一生。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
1 条评论
热度
最新
标题里边的models单词写错了
标题里边的models单词写错了
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
Django学习笔记之Models与ORM操作
一、ORM增加 from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30, verbose_name="名称") address = models.CharField("地址", max_length=50) city = models.CharField('城市',max_length=60) state_province = model
Jetpropelledsnake21
2018/07/05
1.3K0
Django之ORM数据库
            django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3
超蛋lhy
2018/08/31
2.6K0
Django之ORM数据库
Django ORM 多表操作(二)
注意:MySQL 中的 limit 相当于 ORM 中的 QuerySet 数据类型的切片,annotate 里面放聚合函数
HammerZe
2022/03/25
1.1K0
Django ORM 多表操作(二)
Django ORM那些相关操作
一般操作 https://docs.djangoproject.com/en/1.11/ref/models/querysets/         官网文档 常用的操作 <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <4> e
新人小试
2018/04/12
2.4K0
ORM初识和数据库操作
这样写上以后django会默认的就去链接数据库,这时你会看到报错了,那么解决的办法就是下面的这样
全栈程序员站长
2022/07/21
2.6K0
Django——model基础
ORM 映射关系:     表名 <-------> 类名 字段 <-------> 属性     表记录 <------->类实例对象 创建表(建立模型) 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄。 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one) 出版商模型:出版商有名称,所在城市以及email。 书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作
用户1214487
2018/01/24
1.2K0
Django——model基础
Django之Model世界
django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)
Wyc
2018/09/11
2.3K0
Django学习笔记之ORM多表操作
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
Jetpropelledsnake21
2018/08/10
2.8K0
Django学习笔记之ORM多表操作
Django之ORM对数据库操作
基本操作 <1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> values(*field): 返回一个ValueQu
人生不如戏
2018/04/11
1.4K0
Django ORM 多表操作
ps:外键字段不需要写表名_id后面的_id,ORM创建的时候自动添加了_id,以及外键以虚拟字段的形式存在
HammerZe
2022/03/25
1.8K0
Django ORM 多表操作
06.Django基础五之django模型层(二)多表操作
    一对一、多对一、多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束。
changxin7
2019/09/29
2.8K0
python 终级篇 django --
                                   一般操作                                             
py3study
2020/01/19
3K0
python 终级篇 django --
Django之模型层(多表操作)
  一本书只有一个出版社,一个出版社可以出版多本书,从而书与出版社之间就构成一对多关系,书是‘多’的一方,出版社是‘一’的一方,我们在建立模型的时候,把外键写在‘多’的一方,即我们要把外键写在book类。
py3study
2020/01/19
6390
Django 模型层之多表操作
Django还提供了一种直观而搞笑的方式在查询(lookups)种表示关联关系,它能自动确认SQL JOIN联系。要做跨关系查询,就使用两个下划线来连接模型(model)间关联字段的名称,知道最终链接到你想要的model为止。
py3study
2020/01/18
1.4K0
django orm 重点大全
1.最简单的跨表,查询外键表中符合主表条件的记录列表 #用户类型表 class User_typ(models.Model): name=models.CharField(max_length=32) #用户表 class User(models.Model): name=models.CharField(max_length=32) age=models.IntegerField(max(100)) type=models.ForeignKey(User_typ)
玩蛇的胖纸
2018/06/08
8250
ORM常用操作
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在
全栈程序员站长
2022/07/21
2.1K0
Django学习笔记之Django ORM相关操作
<!-- p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px "PingFang SC"; color: #000000 } span.s1 { } span.s2 { font: 11.0px Helvetica } -->
Jetpropelledsnake21
2019/02/15
3.7K0
Django Models 查询操作
#1.跨表多对多查询 #模型关系 城市 <-- 作者 <-- 书 #查询haimingwei写的所有书籍 #基于对象-->反向查询(按表名_set) (返回queryset) models.Author.objects.get(name='haimingwei').book_set.values('title') #基于queryset-->反向查询(按表名) (返回queryset) models.Author.objects.filter(name='haimingwei').values('book__title') #基于queryset-->正向查询(按字段) (返回queryset) models.Book.objects.filter(author__name='haimingwei').values('title') #查询spring这本书的作者 #基于对象-->正向查询(按字段) (返回queryset) models.Book.objects.get(title='spring').author.values('name') #基于queryset-->反向查询(按表名) (返回queryset) models.Author.objects.filter(book__title='spring').values('name') #基于queryset-->正向查询(按字段) (返回queryset) models.Book.objects.filter(title='spring').values('author__name')
py3study
2020/01/17
9860
Django进阶知识
django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。
超蛋lhy
2018/08/31
3.7K0
django--ORM的单表操作
它的作用相当于 在该app下建立 migrations目录,并记录下你所有的关于modes.py的改动,比如0001_initial.py, 但是这个改动还没有作用到数据库文件
py3study
2018/08/03
1K0
相关推荐
Django学习笔记之Models与ORM操作
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档