定制开发

有些问题不是一个网站能解决的。当需要的是一个工具、一个应用、一次系统集成,或是一套不该再靠人工完成的流程时,我们就会转而构建这些。

团队小而资深,对项目范围坦诚相待。如果市面上已有产品能解决您的问题,我们会如实告诉您,而不是收费替您重新造一遍。

登记表

我们承接的项目类型

描述定制软件最有用的方式,是看它消除了什么问题。以下是最常见的几种情形,以及我们通常会为此构建的方案。

问题类型及其常见解法
问题 我们构建的方案
同一件手工任务每天重复,却由一位资历远超此任务的人来做 一个内部工具,把流程固化下来:一个表单、一个处理队列、清晰的操作记录,以及与团队实际运作方式相匹配的权限设置。
两个互不相通的系统 一套负责在两者之间做映射的集成方案,一方故障时能安全重试,需要人工介入时也会及时提醒。
整个业务运转依赖一张没人敢动的电子表格 一个背后有真正数据模型支撑的小型网页应用,让两个人可以同时操作,也不会有人不小心覆盖掉上个季度的数据。
每周都要有人手动整理的一份报告 一个定时任务,自动收集数据、进行核对,并把报告发送给需要它的人,每次运行都有记录可查。
工作发生在办公桌之外:在手机上、在货车里、在车间地面上 一款移动应用,建立在与系统其余部分相同的基础之上,共享同一套数据模型、同一套评审标准与自动化检测,让手机端与桌面端对事实的认知永远保持一致。
硬塞进官网、最终撑不住的客户流程 一个拥有独立网址的正式应用,并沿用网站的设计系统,让它依然与整个品牌浑然一体。
没人能报价,因为根本没人界定过范围的项目 一个简短的需求梳理阶段:以书面形式定义出最小可运行版本,同时同样清楚地列出我们不会构建的部分。

判断依据

我们如何决定构建什么

  • 先做出能用的最小版本。一个范围虽窄但已投入实际使用的工具,两周内教给你的东西,比一份完整的规格说明书三个月教给你的还多,等弄清楚哪些部分真正重要之后,再逐步扩展也不迟。
  • 刻意选择成熟无聊的技术。比起有趣的新技术,我们更愿意选择久经验证的方案。定制软件的好坏,要看未来有人需要修改它的那一天,而不是它上线的那一天。
  • 尽早把数据模型定对。界面重画的成本很低,但数据结构调整的成本很高,所以我们会先确定数据的形态,再着手设计界面。
  • 能买则不自建。如果市面上有授权产品能满足您的需求,我们会如实建议您直接使用。比起收费替您重新发明一遍,我们更愿意只构建把它连接起来的那一小部分。
  • 为接手的下一位开发者而设计。可读的代码、有文档记录的搭建流程,以及能说明意图的测试。衡量一份工作好坏的标准,是别人能否安全地对它做出修改。
图 1 界面、服务、调度与存储,在动手写代码之前先画出来。

技术栈

我们实际采用的技术

把技术栈说清楚,也是坦诚讲清楚项目边界的一部分。技术背景的买家应该能在一屏之内判断我们是否是合适的团队,非技术背景的买家也应该能把这一节直接转发给自己的开发者,得到一个明确的答案。

编程语言

TypeScript,贯穿始终

界面

Astro、原生 HTML 与 CSS,真正需要时使用 React,另加移动应用

服务端

Node 与 Cloudflare Workers

数据

兼容 Postgres 的数据库,版本化的 SQL 迁移

平台

Cloudflare Pages、Workers、对象存储、定时触发器

检测

Playwright、Vitest、静态类型检查、自动化无障碍审计

  • 全系统统一语言。 TypeScript 贯穿界面、API、定时任务和测试,每次改动都会做类型检查。统一语言意味着统一工具链、统一评审标准,浏览器和背后服务之间也不需要转换层。
  • 按需选择渲染方式。 内容会编译为静态 HTML;真正需要客户端状态的界面,会使用组件框架,并且只作用于屏幕上确实需要它的那一部分,而不是把一个框架整体包裹在永不变化的内容外面。
  • 移动应用,同样的严谨标准。 当工作更适合握在手里、而不是停留在浏览器标签页里时,我们会以同样的标准来构建这款应用:同样以 TypeScript 为核心的工具链,同样的评审标准,同样的自动化检测,以及与背后服务相同的数据模型,而不是另建一套独立的真相。某个具体应用应该采用哪种技术栈,是我们在撰写项目范围时与您共同决定的事,而不是套用在每个项目上的固定偏好。
  • 关系型数据库,而非文档堆砌。 使用兼容 Postgres 的数据库和带类型的查询层,结构变更都经过评审、按顺序应用且可回退。没有人会手工修改生产环境的数据库结构。
  • 默认无服务器,因为没有服务器需要惦记。 代码运行在 Cloudflare 的边缘平台上,文件使用对象存储,定时任务由调度型 Worker 处理。您没有需要在半夜打补丁的机器,也不用去猜测容量该留多少。
  • 通过有文档记录的接口做系统集成。 与其他系统对接时使用它们的 API 和 webhook,内置重试、幂等处理,并记录每一次调用。如果某个服务商根本不提供 API,定时抓取文件或数据源是我们刻意选择的退路,绝不会用抓取页面这种方式凑合,因为那种做法下个季度就可能失效。
  • 环境和密钥是配置项,不是口耳相传的经验。 基础设施在代码仓库中声明,凭据保存在密钥管理系统中,并以环境变量的形式提供给运行中的服务,换一台新机器,当天下午就能把项目跑起来。
  • 如果您已经有自己的技术栈,就用您的。 如果您的团队已经在维护一套还算合理的系统,更合理的做法通常是在其中开展工作,而不是再引入第二套做事方式。如果问题恰恰出在您现有的技术栈上,我们也会如实告诉您。

标准

与网站项目相同的工程标准

两条服务线之间的工程标准从不降低,因为内部工具往往要被员工连续使用多年,而他们并没有选择别的工具的余地。标准代码及其完整历史记录、能拦截不合格版本上线的自动化检测、一条命令即可完成且可一步回退的发布流程、达到客户同等标准的无障碍界面、绝不进入代码的密钥,以及底层不依赖任何专有平台,这些都已经在企业网站一节详细说明,这里不再重复。

软件比网站多出两件更重的事,值得单独说明。

数据比代码活得更久

架构变更是代码仓库中的迁移脚本,按顺序应用且可回退;备份是托管平台的职责,而不是某人写过一次就再没管过的脚本;您的数据可以导出为能在别处加载使用的格式。

运行中的系统必须可被观测

任何在无人盯着的情况下运行的事,都会留下记录:运行了什么、什么时候运行、影响了什么、又在哪里失败。一个悄悄停止工作的定时任务会主动告诉我们,而不是一个月后被某个纳闷报表怎么没收到的人发现。

边界

我们的边界在哪里

把边界说清楚,本身就是值得信赖的一部分。我们是一支小而资深的团队,因此只承接能做好的工作,做不好的会直接说不。

我们不转售授权平台,不会为并非由我们开发的项目派驻人力,也不会为尚未界定范围的问题报价。如果某部分工作应该交给专业人士处理,我们会直接告诉您,而不是让您花钱买教训才发现。

技术边界同样具体:

  • 使用模型可以,数据科学不做。 我们会调用托管模型或现成服务,并为您的应用构建界面和相应的连接逻辑。训练模型、统计分析,以及仓库级别的数据管道,不是我们做的事。
  • 托管平台可以,您自己的服务器不做。 我们部署在托管的边缘和无服务器平台上。如果工作必须运行在您自己的机房、由您管理的机器,或需要有人持续打补丁的操作系统上,我们就不是合适的团队,而且会在第一次通话时就如实告诉您。
  • 认证体系需要专业人士与我们协作。 我们把真正的安全工程当作分内之事来做,但针对某个具体认证体系的正式审计,并不是我们出售的专长。如果您的项目需要这类审计,我们会在您签字之前就说清楚,而不是事后才发现。
  • 固件与转售。 嵌入式固件不是我们的专长,任何价值本质上是转售许可证、而非我们实际完成的工作的项目,同样不是。

运营维护

谁来负责后续运行维护

定制软件上线并不等于完工。系统会被使用,随后就需要修改。由谁负责运营、由谁负责修改,应该在项目一开始就纳入范围,而不是六个月后靠一封尴尬的邮件才提出来。

我们负责托管,并持续维护运行

这是默认的安排:我们按月付费为您托管并运营这套系统,上线后的改动也遵循与建站期间相同的流程,也就是新建分支、预览、完整的检测,以及一次即可回退的部署。编写它的人,也是持续在生产环境中盯着它的人,这通常正是安静地修好问题、和为了追究谁的责任而争论不休之间的差别。

身为一支小而资深的团队,也有其代价,我们更愿意如实说明:我们不提供 24 小时值班轮岗,也不承诺以分钟为单位的响应时间。如果您的项目确实需要这些,请尽早告诉我们,我们会如实说明能否满足。

或者由您自己的团队接手

如果您的合同中包含这项条款,这套软件可以迁移到您自己的托管环境,交由您自己的开发者维护:标准代码、测试、有文档记录的搭建流程,以及一条命令即可完成的部署。这也正是前面提到的”为下一位开发者而设计”真正的用意所在。这是我们在您需要时会写进书面约定的一个选项,而不是默认的安排。

平台本身也提供了帮助。静态网站和无服务器服务都没有需要打补丁的服务器,也没有需要保持更新的操作系统,剩下需要处理的只是依赖和平台的更新:这是一项可以按计划进行、可审阅的变更,而不是紧急事件。

描述您的问题 [email protected]

开始合作不需要一份规格说明书。通过联系表单,或发邮件至 [email protected],用您自己的话描述这项工作即可。