我注意到,许多技术人员在介绍产品方案时,往往喜欢从技术实现开始讲解。为什么会这样呢?这可能是因为技术实现不仅展示了技术的复杂性和深度,也是技术人员获得高薪的基础。因此,从技术实现开始讲,更符合他们的思维习惯。然而,一旦我们从技术实现入手,就在一定程度上限定了产品的使用方式。

大多数人对产品的使用方式,要么觉得它是理所当然的(大家都这么用,所以我的产品方案也是这样用),要么没有投入足够的思考,很少去探索是否存在更好的使用方法。然而,当我们观察这个世界时,会发现众多的技术研究和发明,归根结底都是为了让人们更好地使用功能、满足需求。因此,使用方式应该在技术实现之前进行优先考虑。为此,我梳理出了一套优先考虑产品使用方式的表达框架。

1. 表达框架

  1. 背景介绍(方案在怎样的环境下诞生)、产品目的(该产品要解决什么问题?达到什么效果?)
  2. 产品的多种使用方式设计(使用者如何使用该产品),从中比较并选出使用方式最佳的方案
  3. 使用方案的实现方式分享

说明:如果第2点选出的最佳方式难以实现,可以解释选择次优方式的原因是实现难度较大。

2. 案例

接下来,我将通过一些具体的例子来展示这种表达方式。

2.1 分布式锁

  1. 背景和目的

    在分布式环境中,一个Java应用通常会部署多个实例。这些实例的某个函数可能会被同时调用,导致并发问题。为了确保该函数能够串行执行,我们需要一种机制来实现类似于Java单机应用中的synchronized功能。

  2. 各种方案的使用方式:

    2.1) 代码调用的方式

    方法中的代码里调用组件的lock(key)获取锁,调用unlock(key)释放锁,代码示例:

    @Resource
    private DistributedLock lock;
    
    public void someMethod() {
        String lockKey = "some-key";
        boolean lockResult = false;
        try {
            lockResult = lock.lock(lockKey); // 获取锁
            if (lockResult) {
                // 加锁成功的业务代码
            } else {
                // 加锁失败的处理代码 
            }
        } finally {
            if (lockResult) {
                lock.unlock(lockKey); // 释放锁
            }
        }
    }
    

    2.2) 使用注解的方式

    方法上注解@Synchronized,代码示例:

    @Synchronized(key = "some-key") // 当加锁失败时,抛出异常
    public void someMethod() {
        // 加锁成功的业务代码
    }
    

    2.3) 方案汇总比较

    比较两种使用方式的优缺点:

    使用方式 优点 缺点
    代码调用方式 用法灵活,复杂的加解锁分支逻辑也可支持 使用比较手动,代码量较大,要处理好finally解锁细节,易出错
    注解方式 使用简单,不必关注加解锁细节 非常灵活的场景较难支持

    经过优缺点分析,我们发现大多数场景是简单加锁,因此注解方式的灵活性不足可以接受,所以最终选择了注解方式。

  3. 注解方式的分布式锁技术实现分享,比如redis实现方案、zookeeper实现方案等。

2.2 导入excel校验报错提示

  1. 背景和目的

    在一些复杂的业务系统中,用户习惯导入和导出Excel文件来录入数据。系统需要对用户上传的Excel内容进行校验,并提示用户进行修正。由于Excel文件的特性以及批量导入的方式,校验提示远不如页面表单友好。当用户上传的Excel有多个问题时,他们常常需要根据错误信息多次修改后才能成功提交,导致录入体验不佳。因此,我们需要设计一种较好的方式来帮助用户录入正确的数据。

  2. 各种校验数据的方式:

    2.1) 第一个错误弹框提示

    一旦系统检测到首个错误,立即返回错误信息,提示用户进行修改:

    2.2) 全量错误弹框提示

    系统会对所有数据进行检查,并一次性返回所有校验错误的信息,提示用户进行修改:

    2.3) Excel文件内批注提示

    系统将对所有数据进行检查,并将错误信息以批注的形式添加到用户上传的Excel文件中。每个有问题的单元格都会被标注,用户可以直接在Excel中进行修改,修改后即可重新上传:

    2.4) 方案汇总比较

使用方式 优点 缺点
方式1 校验速度最快 当错误较多时,用户需要多次上传才能完成修正,导致体验极差
方式2 将全部错误一次性告知用户,避免方式1多次上传的缺点 校验速度较慢,用户需要手工找到对应的行列进行修改,需来回切换Excel和页面提示
方式3 避免方式1多次上传的缺点;用户不需要手工定位行列,避免方式2用户手工查找行列的缺点 校验速度较慢

经过优缺点分析,方式3的用户体验最佳,但需要特别关注全量检查的性能问题。

  1. 方案3的实现方式分享。

2.3 内网穿透

  1. 背景和目的

    在开发过程中,我们经常需要在一个内网中访问另一个内网中的服务。例如,本地机器访问云端内网测试环境的MySQL端口进行SQL查询;手机通过互联网访问本地机器开发时暴露的端口进行调试;外网的nginx服务器代理转发另一个内网中的http服务并将其暴露到互联网;等等。如果服务双方处于同一个内网,或者服务提供者已暴露在外网,则可以直接通过IP/端口访问。只有在这些条件无法具备时,我们才需要使用额外的技术手段,这通常称为内网穿透。

  2. 各种内网穿透的使用方式:

    2.1) 端口转发

    这种方式会把需要访问的端口,映射到公网或同一内网的其他机器上,从而使当前内网的机器能够访问:

    2.2) 透明代理

    这种方法通过底层转发,使本地机器能够直接访问另一个内网的服务,就像网络是互通的一样:

    2.3) 方案汇总比较

    使用方式 优点 缺点
    端口转发 安全性高,转发的端口范围可控 当需要访问的端口量较多时,配置和维护工作量较大;使用者必须在不同的内网中使用不同的IP端口
    透明代理 对使用者友好,无需改变目标服务的IP端口 安全性较低,另一个内网全量暴露到当前内网

    建议根据具体情况进行选择。以下是我的实际场景:

    我需要部署一套自用的CI/DI、测试环境、实验环境,所需的机器资源较大,约16核32G内存和10Mbps带宽。如果选择云服务商,费用每月大约900元,一年超过1万元。因此,我选择购买一台家用主机,并为家里的宽带申请了公网IP,按主机5年报废,算上电费,实际每月平均费用约80元,大幅节省了开支。在这套部署架构下,生产服务器需要访问家里主机,有些不重要的生产应用希望能够随时可以迁移到家里主机。因此,我希望实现生产环境和家里的2个网段互通,这样可以将网络配置维护可以降到最低。考虑到这两个网络的访问权都仅限于内网,不会暴露到公网,因此安全性可以接受。最终,我选择了透明代理方案。

  3. 透明代理方式分享。

3. 总结

这套表达方式的目的,是让技术出身的产品设计者,更加关注用户的使用体验。