分类 方法论 下的文章

软件外包思考 二 验收

交付物

  • 软件

100%实现需求明细列表所有功能,即100%满足业务需求的软件。

  • 文档

5k0RououxvvEVPjH7fWp.png
2HTGkDE3AI1YFw0JSqDm.png

项目验收

  • 验收方式

1、将要交付的软件安装于指定服务器,并完成调试和上线;
2、完成培训后,业务验收人员根据需求明细列表实现情况进行验收评价,研发验收人员根据以下内容进行验收评价。

  • 文档验收

1、文档齐全(参考如上文档清单);
2、文档内容描述准确, 没有歧义和错误的表达;
3、文档内容容易理解, 通过使用适当的术语、图形表示、详细的解释来表达;
4、文档对主要功能和关键操作尽量提供应用实例。

  • 界面验收

1、界面设计符合自己公司的设计规范;
2、外包团队需提供与软件适配的浏览器、手机、PAD等品牌与版本号清单;
3、各界面需要做好PC、手机、PAD等UI兼容与机器适配;
4、原则上,浏览器至少需适配Chrome、Safari、火狐、IE8以上;
5、原则上,手机至少需适配苹果、小米、华为、vivo、OPPO、三星、魅族。

  • 功能验收

1、功能验收范围覆盖(接口、数据库存取、页面功能);
2、提供单元测试用例、集成测试用例和系统测试用例;
3、提供BUG管理跟踪记录表;
4、提供质量分析报告。

  • 性能验收

1、提供性能测试报告;
2、相关重要指标达到以下要求:
LflV5vh3vvXE5jRYzegE.png

  • 安全验收

1、软件中的敏感数据需以密文方式存储;
2、软件需有留痕功能,即保存用户的操作日志、系统异常日志、接口调用数据日志等;
3、软件中各种用户的权限分配合理;
4、扫描出的安全漏洞(包含但不限于:越权访问、XSS跨站攻击、SQL注入、文件上传漏洞、跨站请求伪造等)外包团队需修复完毕。

  • 用户验收

1、外包团队需提供稳定的用户验收环境和联调环境;
2、业务场景功能测试不通过数的比例<1.5%;
3、不存在严重等级为1的错误;
4、不存在严重等级为2的错误;
5、严重等级为3的错误数量≤5;
6、所有提交的问题都已得到修复;
7、以上功能,用户验收测试通过后,由用户负责人签署验收通过确认书。
sOILv5Xlr5n2OevyiEnl.png

源码交接

如涉及到源码交接,按下列规范进行验收和交接。

  • 交接前提条件

1、需提供用户验收通过确认书;
2、涉及交接的软件,原则上建议接受交接软件所有功能,不建议交接软件部分功能模块;
3、跟薪资类无关的软件或功能,所有功能需在线上稳定运行不少于3个月;跟薪资类相关的软件或功能,所有功能需在线上稳定运行不少于6个月;
4、线上稳定运行既线上可用率,需满足:最近3至6个月内,线上没有出现影响20人以上或数据错误的严重bug,且每月线上bug数不超过3个。

  • 源码验收

1、代码应只保留跟本项目相关的代码,无效代码应一律去除;
2、数据库应只保留跟本项目相关的表、视图、存储过程、函数、触发器、定时job等,无效内容应一律去除;
3、特别注意合理做好数据表结构设计,适当冗余提升性能;
4、代码结构清晰无冗余,注释完整有效,避免硬编码;
5、但凡不符合源码验收规范的,外包团队需修复完毕。

  • 其他注意点

1、对于外包团队的软硬件选型,建议业务部门邀请本公司IT团队一起参与决策;
2、与外包团队商签署的商务合同和补充协议等,建议业务部门邀请本公司IT团队一起参与制定;
3、外包团队使用的环境、数据库、网络、语言、框架、技术、组件等需事先获得本公司IT团队认可;
4、如外包项目不符合或无法满足上述验收规范的,建议商务层面延长付款周期、扣除相应款项或终止合同;
5、每一笔合同款在支付给外包团队之前,除了需获得用户验收通过确认书之外,还应通过IT团队验收;
6、以上内容建议附加进商务合同,成为其中一部分。

软件外包思考 一

软件外包存在风险,外包人员技术、态度、交付能力,如果想通过合同或者诉讼降低风险,由于太多的未知因素和太多的主观性,不现实。因此唯一的外包原则应该是:如果外包人员做得不好,有能力随时终止合作且可控费用损失和项目交付。

可以尝试渐进式方法,首先废除传统开发外包大瀑布方式(例如签订需求URS、项目总金额、进度款支付)(不过目前大部分外包会坚持使用瀑布法,并签订大额的预付合同),尝试新方案,项目按照功能或者阶段划分为多个子合同,做小项分包,或者改为签订人力外包合同。

  • 针对我们想要构建的功能,拟定一个顺序列表。
  • 找几名开发人员,最好是独立的自由职业者,但如果同意以下流程,开发工作室也没问题。
  • 对于每名开发人员,挑选列表中最重要的功能,与他们讨论功能需求、预算和成本。
  • 让他们实现那个特性并测试。
  • 让一名内部人员审核他们的 PR,测试升级后的 App,并标出有问题的地方。
  • 符合要求后,合并并部署该特性,这样,所有创始人/用户就可以继续审核该 App,并提供反馈或者根据需要调整。
  • 如果我们对他们所做的工作感到满意,就挑选下一个我们希望他们实现的功能,然后再次重复这个过程。
  • 如果我们对他们的工作不满意,就解雇他们,并寻找替代者。

当前需要做的工作,整理敏捷开发平台或者公共开发平台,并且参照以下原则:

  • 客户合作胜于合同谈判
  • 个体和互动胜于流程
  • 可运行的软件胜于详细的文档
  • 响应变化胜于遵循计划

参考文章:
Experiences working with an Outsourced Dev Shop

亲测推荐 2021 年 SaaS 技术栈:Docker、Django、Traefik 和 IntercoolerJS

我最近发布了个人对Django做为一款优秀应用框架的一些考虑。本文基于此从架构角度做进一步扩展,介绍从开发到生产环境的整体技术栈考虑。

2018 年至今,我一直使用该技术栈构建一些小型 SaaS 应用。

本文最初发布于 www.simplecto.com,经原作者授权,由 InfoQ 翻译并分享。

整体技术栈

随处部署的 Linux 服务器和虚拟机:我使用了 Azure、Digital Ocean 和 Scaleway,并计划在 2021 年将所有部署迁移到Hetzner提供的专用服务器上。

Docker:就是我们常用的 Docker.

Traefik:使用 LetsEncrypt 证书的反向代理和 TLS。

Postgresql:运行在 Docker 中的数据库。

Django:同样运行在容器中。

IntercoolerJS:提供平滑易用的类 Ajax 前端应用支持。Intercooler 的创作者在 2021 年发布了HTMX,是 IntercoolerJS 的更新换代。

Sentry:捕获生产环境中软件缺陷。只需在配置文件中添加几行配置。

Bitbucket Pipelines 替代 CI/CD:鉴于 CI/CD 引入了过多繁琐无用的工具,我在 2021 年不再对个人项目考虑 CI/CD。

ZeroTier:实现 VPN 和控制层。

我在开发小型项目时,采用本地 Docker 容器运行测试,进而直接推送到生产环境。我不考虑使用繁琐的 CI/CD,而是选择了 Bitbucket Pipelines。

7597a5b78ab8a92a0bfadb3fecdfc653.jpeg

上图给出了我所采用技术栈的概览,图中有很多需要详细展开阐述的部分。下面换成列表方式展示。

  • 虚拟机
  • Docker
  • Django
  • 挂载数据磁盘卷
  • 使用长时间运行 Django 命令做为 Workers
  • 挂载数据磁盘卷
  • Postgres
  • 挂载数据磁盘卷
  • Traefik
  • Zero-Tier
  • SSH

托管环境

即便是无服务器架构,也需要一个云服务托管环境。我个人推荐Azure、Digital Ocean和Scaleway。每家都为计算、联网、存储和基本服务提供了充分的选项,支持用户任何构建需求。

同样推荐Hetzner,它提供了各服务层级的硬件、服务和价格。

虚拟机

一些企业应用和个人副业(side projects),并不需要同时为成千上万的用户提供 TB 级数据服务,因此可扩展性并非主要关注问题。对于此,我们可选用最小托管服务选项,通常不高于每月 20 美元。即便是服务价格相对最贵的 Azure,也可选用 Burstable 服务质量的虚拟机。个人推荐Scaleway的开发层级服务器。

注意:在我的技术栈中并没有 Kubernetes,因为我并未考虑可扩展性。

Docker

为确保新的虚拟机运行在最新版 Docker 上,我并没有依赖操作系统本身,而是使用了 curl|bash 方式,即:

curl -s https://get.docker.com | sudo bash

运行上面一行命令,就能获取最适用于当前运行环境的最新版本。

Traefik 实现反向代理

Traefik 对我简直是天赐之选。尽管 Nginx 也很强大,但其并非针对 Docker 环境构建。Traefik 的两个杀手级特性,为我节省了大量时间:

使用 LetsEncrypt 实现自动 TLS。简而言之,一旦设置,无需操心。结合适用的 API 和 DNS 服务提供商,还可以使用 DNS 验证。

使用 Docker label 实现无需重新加载的自动配置。一旦新服务发布,Traefik 通过监听所有 Docker 相关服务而自动发现更改。这使得服务的添加、移除和合并非常方便,不存在任何麻烦。

我对 Traefik 唯一意见是学习曲线略为陡峭。用户必须自行确定如何进行配置,包括配置文件、命令行选项、YAML、Docker label,乃至组合使用。

提示:我发布了自己使用的Traefik生产环境配置文件,供参考。

Postgres 数据库

亲测推荐,PostgreSQL 从不会令我失望。PostgreSQL 容器可毫无问题地添加到任何项目中。我只需简单地启动容器,绑定端口,挂接数据卷到主机磁盘,仅此足矣。

docker-compose.yml
version: '3.1'


services:


  db:
    container_name: postgres
    hostname: postgres
    image: postgres:11
    restart: always
    environment:
      POSTGRES_PASSWORD: secretsonly
    volumes:
      - ./data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    networks:
      - web


networks:
    web:
        external: tr

用于 Web 的容器化 Django

Django 很好地支持发布到容器中,我多年以来一直这么用。我反复强调开发环境和生产环境匹配的重要性,Docker 为我实现了一切。

我在 2021 年新推出了一个 Django 项目,用做新项目的模板,参见https://github.com/simplecto/django-reference-implementation。

实现异步任务的 Django 命令

我使用做为标准框架组成的自定义Django命令实现异步任务。该模式采用具有 sleep()的 while 循环,轮询数据库相关操作,并采取相应的动作。

截止 2021 年,我已使用这一模式运行一个网站截屏项目一年多,回报丰厚。该项目每日对 1500 个网站做截屏,所有操作由 Django 命令计划和管理。项目地址:https://github.com/simplecto/screenshots。

IntercoolerJS 降低了复杂性

这里如果展开说,需推出多个帖子,恐怕内容太长,以至于不会有人愿意读。我结合 JQuery 和这个小型 JavaScript 库,实现部分类似单页应用的效果,尽管事实上并非单页应用。

IntercoolerJS 保留了 Ajax 的传统优点,从后端 HTML 更新 DOM,无缝且平滑,非常便于实现用户登录和更新小型表单等元素。

强力推荐访问IntercoolerJS官网。

其创立者在 2021 年继承发展了 IntercoolerJS,推出了HTMX。

Sentry 捕获生产中错误

任何应用都会出错,但不应向用户展示。Sentry 提供了一种捕获生产中软件缺陷的易用便捷方式,其特性包括:

开源许可,可在生产中任意部署。

只需在 Django 项目的 settings.py 中添加几行配置,即可生效。

与 Git 代码库和问题追踪系统紧密集成,提供全生产环境的缺陷可追踪能力。

另一个优点是,随时能在生产环境中禁用。

更多信息,可访问Sentry官网。

Bitbucket Pipelines 替代 CI/CD

2021 年,我不在个人项目的部署中使用 CI/CD。其中存在太多工具,复杂性高。我只是使用 PyCharm 运行测试,然后从开发设备直接交付生产环境。

当前存在多种 CI/CD 解决方案,但是我推荐 Bitbucket 提供的 Pipelines 的服务。该服务每月提供数百分钟的免费使用,只需很少费用就能提供自上而下的功能。我自己在使用中很少碰到问题,很喜欢它们的 YAML 配置文件。

我使用 bitbucket-pipelines.yml 文件,实现跨多个 Docker 容器的完全端到端测试,加载数据库,并在几分钟内执行数以百计的测试。该服务是我们团队高效的关键,支持生产环境中每日五次以上 Push。

更多信息,访问Bitbucket官网。

ZeroTier 实现 VPN

最后,推荐一种在很大程度上是可选的、但是最好应具备的技术。Zerotier 是一种独树一帜的网络/VPN 服务,我用其连接所有的个人计算机。它可穿透防火墙联通家庭和办公场所,一分钟即可配置好。

如果所有设备使用 ZeroTier,就可以避免 SSH 中令人头疼的密钥管理,单机上共享带宽。

Zerotier 可运行在 Linux、Mac、Windows、Android 和 iPhone 上,覆盖大部分设备。

ZeroTier 的一个问题在于,我并不完全了解它的工作机制。和 MacOS 和 iPhone 类似,它们会按用户期望工作,并不出问题,只是从用户体验角度看有些不爽。但对于一名 CTO,谁又会去关心具体的细节呢?

总结

希望上面的深入介绍能激发读者对 Docker、Django、Traefik,尤其是 IntercoolerJS 的兴趣。它们简单、易于使用,能在适当时大展身手。

原文链接: Docker, Django, Traefik, and IntercoolerJS is My Go-To Stack for Building a SaaS in 2021
https://www.infoq.cn/article/W4leI4XZ32eSTqFJ8qPl

我成功开发了一个 SaaS 项目,技术栈是这样的

作为一名忠于内心的工程师,每当我看到一家公司发布有关它们技术栈的文章时,我都会泡一杯咖啡,坐下来耐心阅读,看看有没有新的发现。了解其他公司业务背后隐藏的一些技术十分有趣。就像娱乐八卦一样,只不过这是技术层面的探索。

几个月前,我开始开发另一个 SaaS,该项目经历无数次迭代。幸运的是,尽管项目仍处于早期阶段,但是很多网站已经对其进行了集成。

作为一个自负盈亏的独立创业者,我相信正是由于专注于自动化,才让我能为来自 80 多个国家和地区的客户提供可靠服务,并且每周持续提供新功能。当我想要了解服务的运行情况或者其他方面的信息时,我会尝试利用我熟悉的工具。当然,我也明白,在一些特殊情况下这些工具并不会帮到我。

现在,我简要地介绍下平时使用的一些工具。

非常重要的一点是,虽然工具列表看起来很长,并且有一些是非常规且不常用的选项,但实际上我在基础架构上花费的时间很少,如果有的话,每个月平均下来也就是几个小时。还有一点就是个人推荐就像是开处方一样,我认为对我非常有用的一些工具,可能并不适合你。一定要考虑自己的实际情况,并利用好当下你熟悉的工具。

编程语言

多年来,我学习和使用过好几种编程语言,但是对于独立项目,我特别挑选出两种编程语言。这两种编程语言可以在生产力以及可靠性上取得很好的平衡。

Python:很多项目的后端代码都是用 Python 实现的。它可以让我能够以较快的速度发布新功能。另外,我使用 mypy 用于类型提示,这方便我进行代码管理。

Typescript:我以前会有意地避开前端开发的工作。直到大约 4 年前,我发现并开始使用 Typescript。它让我感觉写前端的工作体验更好了,现在我使用它并结合 React 框架一起构建我的项目。

框架

理论上,我会在这里介绍很多这方面的内容,但是相关论坛上有不少介绍,我也是站在巨人的肩膀上学到很多知识。因此我只想介绍几个非常不错的框架:

Django:该框架简直就是独立开发者的宝库。你在该行业中工作的时间越长,你越能体会到避免重复造轮子带来的幸福感。这一框架可以让你走的更远,因为它的功能实在是太全面了,应用场景也很广泛。推荐阅读Instagram如何优化Python提高服务性能、Sentry项目、10大Django构建的网站了解一下 Django 的使用场景。对我来说,该框架不管在性能还是功能方面都能满足我的需求。

React:数据展示相关的 Web 应用是使用 React + Webpack 构建的。在长时间使用 Angular 后,我最终切换到 React,因为它是支持可插拔的视图层,不会对其他功能造成影响。我使用性能表现不错的django-react-templatetags将 React 组件嵌入到我的 Django 模板中。

NextJS:我使用它进行页面、文档等的加载。它让我能重用各种 React 组件,并且可以提高静态页面的性能以及 SEO 优势。

Celery:我使用该框架用于后台/定时任务的管理。该框架的学习成本较高,但是一旦你了解了它的工作原理,并应用到项目中后,你就能体会到该框架的稳定性和可靠性了。

Bootstrap 4:我基于 Bootstrap 构建前端应用。它节省了我很多时间,并且文档资料详细丰富。这就是我选择使用它的原因。

数据库

我最初将所有数据都存储在 SQLite 数据库中,对数据进行备份意味着要将副本数据复制到 S3 之类的对象存储中。之前对于测试过的一些小型站点来说,没有什么问题。但是,随着项目的功能及页面越来越多,我需要更多专门的数据库来支持这些功能:

Clickhouse:我相信 Clickhouse 是为数不多的随着时间的推移而经久不衰的技术之一。说实话,这是一款十分给力的数据库,它能够实现原先在低配置硬件上几乎无法实现的功能。

PostgreSQL:我必用的关系数据库。默认配置合理,经历了充分的市场检验并且与 Django 深度集成。在 Panelbear 中,PostgreSQL 主要用于与分析无关的应用数据存储;对于分析用的数据,我使用 Django 实现了一个简单的接口从 Clickhouse 查询数据。

Redis:我在很多场景中使用了 Redis,比如缓存、速度限制、任务队列以及作为有生命周期的键值存储。Redis 功能强大且性能稳定,社区文档也十分丰富。

部署工具

与这篇文章描述的一样,我不会将我的基础设施视为宝贝一样对待。服务器和集群本来就是一个工具而已。所以如果某一台服务器出现问题,用另外一台正常的服务器替换一下就好了。这意味着所有的操作在 git 仓库中被描述为代码逻辑,并且我不会通过 SSH 登陆服务器进行一些操作。你可以将这个描述视为一个模板,可以通过一个命令将整个基础架构克隆到任何的 AWS 服务中。

这在灾难恢复时也会对我有所帮助。我只需要运行一些命令,几分钟后,我的应用服务就可以重建并能正常运行了。当我将应用从 DigitalOcean 迁移到 Linode,以及最近往 AWS 迁移时非常有用。所有的操作都通过代码描述和执行。因此,即使在几年后,我也很容易的跟踪项目的相关部署和运行情况。现在所有的公司都拥有 AWS IAM 策略或者 VPC 子网,这些都是通过一些 UI 界面点击操作完成的,现在所有人都离不开这一功能,因为确实给用户带来了很多便利。

Terraform:我使用 Terraform 来管理大部分云基础架构。在我的 Terraform 清单中声明了诸如 EKS 集群、S3 存储、角色和 RDS 实例之类的一些配置。这些数据会同步到另外的加密 S3 存储,以避免我开发用的笔记本电脑发生故障而无力回天。

Docker:我会将所有服务构建为 Docker 映像。甚至有状态的组件(比如 Clickhouse 或 Redis)也作为 Docker 容器打包并运行在我的集群中。这也让我的应用服务可移植性非常高,因为我可以在能够运行 Docker 的任何地方运行它。

Kubernetes:它极大地解放了我繁琐的工作。我并不是盲目地向所有人进行推荐,因为在工作的这些年里,我使用它解决了好几次大型的生产故障。为公司及时解决生产问题,让我感觉十分自豪。我还用它进行容器化应用的管理,这也帮我减轻了工作负担。

GitHub Actions:过去,我常常使用的是CircleCI(这个用起来也不错),但是对于这个项目,我更喜欢使用 GitHub Actions,因为它删除了需要访问代码库以及部署密码的一个不必要的服务。但是,CircleCI 同样具有很多不错的功能,我仍然向大家推荐它。

基础设施服务

我从最开始使用月费 5 美元的 DigitalOcean 单实例服务器开始,逐步转向使用 Kubernetes 来管理服务,因为我正在彻底改变 Kubernetes 提供的一些开箱即用的功能(比如:服务发现、TLS 认证、负载均衡、日志滚动管理、滚动发布、容量管理等)。

但是,即使在较大的服务器实例上,使用 Kubernetes 管理的 DigitalOcean 也同样存在可靠性问题。集群 API 服务经常会随机地停止工作并且无法恢复,这会破坏包括负载均衡在内的许多集群服务,也就意味着服务停机无法对外提供正常服务。每当发生这种情况时,我会重新创建一个新的集群,尽管使用 Terraform 可以很轻松的实现,但是这并不会增加大家对其托管服务可靠性的信心。我怀疑是他们的资源不是特别充足导致的,考虑到他们的服务收费较低,因此这是可以理解的。

不幸的是,几周后,我就无法解决上面提到的问题了。这就是为什么我决定迁移到Linode的原因,在接下来的一个半月的时间里,系统再也没有出现过任何问题。

但是,AWS 向我抛来了更加诱人的优惠,所以我最近又做了一次迁移。AWS 还支持使用托管服务比如 RDS 来减轻 PostgreSQL 的压力,这对我来讲是个很大的优势。我的迁移工作没有那么复杂,因为我的所有基础架构都是通过 Terraform 和 Kubernetes 配置清单进行描述的。系统迁移可能会花费或长或短的时间,所以一定要有耐心。这一方面的话题可以在其他文章中找到。

AWS:提供可预测服务以及大量的托管服务。我主要在全职工作的时候使用过它,所以我没有花费很多时间来处理问题。我使用过的 AWS 服务主要有 EKS、ELB、S3、RDS、IAM 以及专用 VPC,未来我可能会使用 Cloudfront 和 Kinesis 服务。

Cloudflare:我主要将其用于 DDoS 保护、DNS 服务以及负载各种静态资源的边缘缓存(目前减少了 AWS 的 80%网络出口带宽费用——它们的带宽定价是在是太贵了!)。

Let’s Encrypt:免费的 SSL 证书授权服务。我在 Kubernetes 集群中使用了 cert-manager,它根据我的入口规则自动颁发和更新证书。

Namecheap:我常常使用的域名注册服务商。它允许 MFA 登录,这是一个十分重要的安全功能。与其他域名服务商不同,它们不会每隔几年就会突然增加域名的高昂续费费用,十分的良心。

Kubernetes 组件
以下组件可以自动完成大部分开发运维工作。我也使用其他的一些组件,但是我最想推荐给大家的是下面几个:

ingress-nginx:一个性能稳定的使用 NGINX 作为反向代理和负载均衡的网络入口控制器,控制入口流量到集群节点的网络流量负载均衡。

cert-manager:该组件可以按照入口规则中的定义自动颁发和更新 TLS 证书。

external-dns:借助 DNS 服务(例如 Cloudflare)同步公开 Kubernetes 服务和网络入口。

prometheus-operator:可以自动监控大部分的服务,并可以通过 Grafana 对数据进行展示。

flux:可以实现在 Kubernetes 中进行连续交付。当我要发布新的 Docker 映像时,可以通过拉取镜像进行部署。

命令行工具

我使用的命令行工具有很多,但经常使用且值得推荐的就下面这几个:

kubectl:与 Kubernetes 集群进行交互的工具,可以对日志、pod 和服务进行监控,并且可以 SSH 登陆到运行中的容器。

stern:Kubernetes 的 pod 日志查看工具,方便易用。

htop:交互式系统进程查看工具,真的比系统自带的 top 工具好用。

cURL:网络请求工具,可以对请求头进行检查。

HTTPie:与 cURL 工具类似,但是对于 JSON API 而言更简单易用。

hey:网络负载测试工具,可以提供详细的延迟分布报告。

监控工具

Prometheus:可以高效地存储时间序列数据并进行监控。可以追踪所有群集和应用程序的性能指标。比使用 Cloudwatch 进行应用程序监控要便宜得多。

Grafana:可以对 Prometheus 监控数据进行展示。所有的展示数据以 JSON 文件进行描述,并在 git 仓库中进行版本控制。

Sentry:对应用程序异常情况进行监控。该工具在发现带有其他元数据的未处理错误时进行告警通知。

Loki:受 Prometheus 启发而发展出来的一款日志聚合系统。它附带了 prometheus-operator 功能,可以帮助我在整个群集中对海量日志进行搜索。

邮件工具

Fastmail:我优先选用的商务电子邮箱,功能齐全且稳定性高。

Postmark:我主要将其用于交易电子邮件(电子邮件验证、每周报告、登录安全警报、密码重置等)的收发。他们的电子邮件传输速度非常快,邮件移动应用程序在业界也是一流的。

开发工具

GitHub:源代码托管及版本控制工具。

PyCharm:可能是 Python 最好的 IDE 工具。使用它可以轻松地重构和导航整个项目代码,而不仅仅是单个代码文件。 即使使用大型动态代码库,该工具的使用表现也很好。

VS Code:非常适合 Typescript / React 编程,并且可以用作通用代码编辑器。

Poetry:Python 打包及有锁文件的依赖管理工具。

Yarn:具有本地缓存的快速 JS 依赖项管理工具。

Invoked:我使用它将所有代码库任务包装在可调用的命令中。例如,使用inv build可以准备静态资源,打包前端/后端环境依赖,并生成 docker 映像。这样,就可以在本地执行与 CI 运行的相同的命令。

其他工具

Panelbear:当然,除了 Panelbear,还有什么能比 Panelbear 更好的工具来跟踪 Panelbear 的网站分析呢?内部测试是有很大收益的,因为我就是我自己的客户。

Healthchecks.io:当计划作业未能正常运行时,就会通过电子邮件或者 whatsapp 通知到我。它也是基于 SaaS 的辅助程序,这个工具我使用了好几年了,非常高兴可以推荐给大家。

Trello:我使用它来记录和跟踪一些问题、需求及想法等等。

Figma:用于为目标页面快速制作模型、横幅和插图,它取代了Sketch作为我的入门工具。

原文链接

https://panelbear.com/blog/tech-stack/

写代码有这16个好习惯,可以减少80%非业务的bug

每一个好习惯都是一笔财富,本文整理了写代码的16个好习惯,每个都很经典,养成这些习惯,可以规避多数非业务的bug!希望对大家有帮助哈,谢谢阅读,加油哦~

公众号:「捡田螺的小男孩」

  1. 修改完代码,记得自测一下
    「改完代码,自测一下」 是每位程序员必备的基本素养。尤其不要抱有这种侥幸「心理:我只是改了一个变量或者我只改了一行配置代码,不用自测了」。改完代码,尽量要求自己都去测试一下哈,可以规避很多不必要bug的。
  1. 方法入参尽量都检验
    入参校验也是每个程序员必备的基本素养。你的方法处理,「必须先校验参数」。比如入参是否允许为空,入参长度是否符合你的预期长度。这个尽量养成习惯吧,很多「低级bug」都是「不校验参数」导致的。

❝ 如果你的数据库字段设置为varchar(16),对方传了一个32位的字符串过来,你不校验参数,「插入数据库直接异常」了。 ❞

  1. 修改老接口的时候,思考接口的兼容性。
    很多bug都是因为修改了对外老接口,但是却「不做兼容导致」的。关键这个问题多数是比较严重的,可能直接导致系统发版失败的。新手程序员很容易犯这个错误哦~

所以,如果你的需求是在原来接口上修改,,尤其这个接口是对外提供服务的话,一定要考虑接口兼容。举个例子吧,比如dubbo接口,原本是只接收A,B参数,现在你加了一个参数C,就可以考虑这样处理。

//老接口
void oldService(A,B);{
  //兼容新接口,传个null代替C
  newService(A,B,null);
}

//新接口,暂时不能删掉老接口,需要做兼容。
void newService(A,B,C);
  1. 对于复杂的代码逻辑,添加清楚的注释
    写代码的时候,是没有必要写太多的注释的,好的方法变量命名就是最好的注释。但是,如果是「业务逻辑很复杂的代码」,真的非常有必要写「清楚注释」。清楚的注释,更有利于后面的维护。
  1. 使用完IO资源流,需要关闭
    应该大家都有过这样的经历,windows系统桌面如果「打开太多文件」或者系统软件,就会觉得电脑很卡。当然,我们linux服务器也一样,平时操作文件,或者数据库连接,IO资源流如果没关闭,那么这个IO资源就会被它占着,这样别人就没有办法用了,这就造成「资源浪费」。

所以使用完IO流,可以使用finally关闭哈

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/jay.txt"));
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}finally {
    try {
        if (fdIn != null) {
            fdIn.close();
        }
    } catch (IOException e) {
        log.error(e);
    }
}

JDK 7 之后还有更帅的关闭流写法,「try-with-resource」。

/*
 * 关注公众号,捡田螺的小男孩
 */
try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) {
    // use resources   
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}
  1. 代码采取措施避免运行时错误(如数组边界溢出,被零除等)
    日常开发中,我们需要采取措施规避「数组边界溢出,被零整除,空指针」等运行时错误。

类似代码比较常见:

String name = list.get(1).getName(); //list可能越界,因为不一定有2个元素哈

所以,应该「采取措施,预防一下数组边界溢出」,正例:

if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){
  String name = list.get(1).getName(); 
}
  1. 尽量不在循环里远程调用、或者数据库操作,优先考虑批量进行。
    远程操作或者数据库操作都是「比较耗网络、IO资源」的,所以尽量不在循环里远程调用、不在循环里操作数据库,能「批量一次性查回来尽量不要循环多次去查」。(但是呢,也不要一次性查太多数据哈,要分批500一次酱紫)

正例:

remoteBatchQuery(param);

反例:

for(int i=0;i<n;i++){
  remoteSingleQuery(param)
}
  1. 写完代码,脑洞一下多线程执行会怎样,注意并发一致性问题
    我们经常见的一些业务场景,就是先查下有没有记录,再进行对应的操作(比如修改)。但是呢,(查询+修改)合在一起不是原子操作哦,脑洞下多线程,就会发现有问题了,

反例如下:

if(isAvailable(ticketId){ 
    1、给现金增加操作 
    2、deleteTicketById(ticketId) 
}else{ 
    return "没有可用现金券";
}

为了更容易理解它,看这个流程图吧:
微信图片_20201207085819.png

1.线程A加现金
2.线程B加现金
3.线程A删除票标志
4.线程B删除票标志
显然这样存在「并发问题」,正例应该「利用数据库删除操作的原子性」,如下:

if(deleteAvailableTicketById(ticketId) == 1){ 
    1、给现金增加操作 
}else{ 
    return “没有可用现金券” 
}

因此,这个习惯也是要有的,「写完代码,自己想下多线程执行,是否会存在并发一致性问题」。

  1. 获取对象的属性,先判断对象是否为空
    这个点本来也属于「采取措施规避运行时异常」的,但是我还是把它拿出来,当做一个重点来写,因为平时空指针异常太常见了,一个手抖不注意,就导致空指针报到生产环境去了。

所以,你要获取对象的属性时,尽量不要相信「理论上不为空」,我们顺手养成习惯判断一下是否为空,再获取对象的属性。正例:

if(object!=null){
   String name = object.getName();
}
  1. 多线程异步优先考虑恰当的线程池,而不是new thread,同时考虑线程池是否隔离
    为什么优先使用线程池?使用线程池有这几点好处呀

它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗。
提高响应速度。
重复利用。
同时呢,尽量不要所有业务都共用一个线程池,需要考虑「线程池隔离」。就是不同的关键业务,分配不同的线程池,然后线程池参数也要考虑恰当哈。之前写过几篇线程池的,觉得还不错,有兴趣的朋友可以看一下哈

一文读懂线程池的工作原理(故事白话文)
面试必备:线程池解析
源码分析-使用newFixedThreadPool线程池导致的内存飙升问题

  1. 手动写完代码业务的SQL,先拿去数据库跑一下,同时也explain看下执行计划。
    手动写完业务代码的SQL,可以先把它拿到数据库跑一下,看看有没有语法错误嘛。有些小伙伴不好的习惯就是,写完就把代码打包上去测试服务器,其实把SQL放到数据库执行一下,可以规避很多错误的。

同时呢,也用「explain看下你Sql的执行计划」,尤其走不走索引这一块。

explain select * from user where userid =10086 or age =18;
  1. 调用第三方接口,需要考虑异常处理,安全性,超时重试这几个点。
    调用第三方服务,或者分布式远程服务的的话,需要考虑

异常处理(比如,你调别人的接口,如果异常了,怎么处理,是重试还是当做失败)
超时(没法预估对方接口一般多久返回,一般设置个超时断开时间,以保护你的接口)
重试次数(你的接口调失败,需不需要重试,需要站在业务上角度思考这个问题)

❝ 简单一个例子,你一个http请求别人的服务,需要考虑设置connect-time,和retry次数。 ❞

如果是转账等重要的第三方服务,还需要考虑「签名验签」,「加密」等。之前写过一篇加签验签的,有兴趣的朋友可以看一下哈

程序员必备基础:加签验签

  1. 接口需要考虑幂等性
    接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是「用户连着点击两次」,你的接口有没有hold住。

❝ 幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。

一般「幂等技术方案」有这几种:

查询操作
唯一索引
token机制,防止重复提交
数据库的delete删除操作
乐观锁
悲观锁
Redis、zookeeper 分布式锁(以前抢红包需求,用了Redis分布式锁)
状态机幂等

  1. 多线程情况下,考虑线性安全问题
    在「高并发」情况下,HashMap可能会出现死循环。因为它是非线性安全的,可以考虑使用ConcurrentHashMap。所以这个也尽量养成习惯,不要上来反手就是一个new HashMap();

❝ Hashmap、Arraylist、LinkedList、TreeMap等都是线性不安全的;
Vector、Hashtable、ConcurrentHashMap等都是线性安全的 ❞

  1. 主从延迟问题考虑
    先插入,接着就去查询,这类代码逻辑比较常见,这「可能」会有问题的。一般数据库都是有主库,从库的。写入的话是写主库,读一般是读从库。如果发生主从延迟,很可能出现你插入成功了,但是却查询不到的情况。

如果是重要业务,需要考虑是否强制读主库,还是再修改设计方案。
但是呢,有些业务场景是可以接受主从稍微延迟一点的,但是这个习惯还是要有吧。
写完操作数据库的代码,想下是否存在主从延迟问题。

  1. 使用缓存的时候,考虑缓存跟DB的一致性,还有(缓存穿透、缓存雪崩和缓存击穿)
    通俗点说,我们使用缓存就是为了「查得快,接口耗时小」。但是呢,用到缓存,就需要「注意缓存与数据库的一致性」问题。同时,还需要规避缓存穿透、缓存雪崩和缓存击穿三大问题。

❝ 缓存雪崩:指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。
缓存穿透:指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,进而给数据库带来压力。
缓存击穿:指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求打到db。

/* * @Author: your name * @Date: 2016-09-06 00:00:00 * @LastEditTime: 2020-03-17 18:29:35 * @LastEditors: Please set LastEditors * @Description: In User Settings Edit * @FilePath: \htdocs\usr\themes\default\footer.php */