Oracle首席工程师:技术面试中,怎样的问题才是好问题?( 四 )


我来举一个具体例子 。 比如 , 有这样一个问题:
怎样设计一个流量控制系统?
这就是一个模糊到没法再模糊的问题了 。 不知你会不会产生下面这样的问题:

  • 什么系统需要流量控制?
  • 现在的流量是多少?
  • 需要支持到什么时间精度?
  • 流量控制的规则怎么定义?
  • 超过流量的请求怎么处理?
  • ……
其实 , 这些都或多或少是需要面试官和候选人一起逐步思考、分析和明确的 。 在这个过程中 , 可以考察到的内容太多太多了 。
事实上 , 针对不同程度的候选人 , 上述这个问题给出的最原始的模糊程度是不一样的 , 问题越是模糊 , 对于候选人的要求也就越高 。 对于一个工作十多年的 , 有着多年系统设计经验的工程师来说 , 上面这些问题大致都应该是他/她能够主动提问 , 或是主动引领以致明确的 。
值得一提的是 , 理想的问题里最好还有一些隐藏的 “坑” 。 候选人能否把这些坑识别出来 , 也是对于工程能力方面一个很好的考察点 。
比方说 , 优秀的候选人应该想到 , 流量控制可以基于绝对时间窗口 , 或是相对时间窗口来进行 , 但是要真正保护系统 , 相对时间窗口才是最理想的 。 当然在实现难度上 , 相对时间窗口往往会更难一些 。
而对于一个没有工作经验 , 并将要研究生毕业的候选人来说 , 问这样一个模糊的问题 , 往往带来了过大的难度 , 不但不容易推进面试的进程 , 还可能给候选人带来沮丧的心理 。 我们不希望看到 , 候选人拿到问题以后就懵了 , 如果发现候选人推进有困难 , 面试官需要介入并帮助 。
因此根据候选人的程度 , 这需要面试官主动回答这些问题 , 或是直接缩小或明确问题的范畴 , 当这个问题的范畴缩到最小时 , 这可以是一个存在多种解法的算法题 。
极端地说 , 这个问题可以一直缩小到这样的程度:
假定说有这样一个 API , 名字叫做 isAllowed , 这个 API 在系统每次收到请求的时候就调用 , 传入的是请求对象 , 传出 boolean 值表示是否允许这次调用——如果最近一分钟内调用次数小于 10000 次就允许 , 反之则不允许 。 你能否将这个 API 实现出来?
如果候选人还一脸迷茫 , 可以提供这样的参考 API:
class RateLimiter {
public boolean isAllowed(Request req) {// TODO
}
}
你看 , 这只是一个将问题明确、细化和分解的过程 , 并没有涉及到实际实现代码该用的算法 。 但是 , 上面提的那些问题 , 要么通过这个例子明确了 , 要么给出具体数字了 。
这本身 , 就将一个模糊的问题 , 降低难度明确为一个具体的算法问题了 。
2、不止一个解
前面一步已经谈到了有不同的方式可将模糊的 “实际问题” 映射成一个可解的 “软件问题” 。 而现在 , 这个 “软件问题” 依然没有标准答案 。
可能会有几个参考答案 , 它们互相比较起来各有优劣 。 但大多数情况下 , 候选人的思路都会在这几个参考答案的思路之中 , 不过有时也能看到特立独行的新奇思路 。
如同前一步所说的那样 , 对于不同级别的软件工程师职位来说 , 需求分析、系统设计这些方面的要求可能有着很大的差别 。 但是在这一步 , 对于数据结构和算法这样的基础能力 , 却是接近的 。
这里谈到的流量控的算法 , 实现方式有很多种 , 代码复杂程度 , 控制精度 , 时间复杂度和空间复杂度等等都有着非常大的区别 。 当然此时涉及到的 , 只是基本算法层面的话题 。
我可以再举一个我曾经常用在面试中的例子:
某社交网站有两百万的注册用户 , 每个用户都有积分属性 , 且积分根据用户在社交网站上的行为而不断有小幅度的频繁变更(比如登陆一次就+1 分 , 评论一次就+2 分等等) , 怎样设计一种算法 , 能够高效、准确地实时获取指定用户在所有用户中基于积分的排名?
上面的问题从模糊逐步落实到实现上的时候 , 异步、定时地排序 , 是最容易想到的方案 , 而题目表述中的 “高效” 和 “实时” 这两个修饰词让这个问题变得困难 。 这个过程中 , 我见到的不错的办法就至少有七、八种 , 比方说 , 下面这个推进问题解决的例子:
候选人:在需要的时候进行排序 , 方案是……
面试官:好 , 这样的方式下 , 时间、空间复杂度是多少?
候选人:……(说着说着自己意识到时间消耗可能巨大)
面试官:对 , 你能否优化?