职位预期可以理解为:假如候选人来到团队,我们期望候选人能去执行什么事项,能去承担多大职责,能给团队创造多大价值
准备一个面试问题的大纲,确保不冷场,不尴尬:
开始可以让候选人先花一分钟简述下自己的工作、项目经历。 一方面,可以让候选人缓解下压力,这样在后续沟通过程中可以更好发挥。另一方面,我们面试官可以快速判断下候选人描述的情况跟简历内容是否匹配(简历造假、信息不匹配的情况很常见,基本遇到就铁定不会有后续结果了,快速决断避免后续浪费时间)、是否符合公司/团队要求的“及格线”(教育程度、经验年限等,如工作 5 年,前端只有 1 年开发经验,而我们想要一个高级前端开发,遇到这种情况很少能符合岗位预期)。
发现简历信息多而杂,不知道如何下手时,可以让候选人自己介绍下技术挑战最大的项目。 通过候选人对技术挑战大的理解和回答,可以快速预估出候选人的能力“天花板”有多高。然后,再通过候选人详细描述和双方沟通,基本可以认定候选人的业务处理能力、动手实践能力和项目规划能力。
在准备的问题基础上,可以适度考虑“压力”提问。 针对项目中的特定领域问题,连续不断追问一些具体实现、底层原理、业务逻辑等,目的是为了让候选人更彻底的去回答为什么、是什么、怎么做、怎么评估、怎么优化的问题,从而更全面了解候选人在开发过程中的调研广度、思考深度、执行力度和结果高度。“压力”情况下,候选人是否依然表现符合预期,是考察发展潜力的重要标准。知识的广度和深度作为额外补充,两点结合起来就可以推断出候选人的技术职级。
写一写算法。 算法是最适合考察动手能力的方式,无论什么职级的同学建议都考核一下算法代码实现。为避免大量刷题同学碰运气的成分,建议提前准备一些算法时间/空间复杂度分析、算法优化等更高程度的问题,能更真实的反馈结果。过去有候选人曾因为面试流程不安排算法而觉得面试流程不专业,所以为了提高公司的“逼格”,算法环节最好不要省略。单千万别提难度太高的问题,有限时间内除非候选人有相关经历和背景,不然很难达到预期考核效果。我们只需要做一些稍微有点挑战或者需要灵活变通下的题目,来考察候选人解决问题的思路和编码能力,能否真正写出得到预期结果的 code 反而不那么重要了。
作者:漠漠萧寒 链接:https://juejin.cn/post/6892258121134440462 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Fx是一个golang版本的依赖注入框架,在项目中的引用:
import "github.com/uber-go/fx"
Fx应用程序,使用依赖注入来消除全局变量,而无需手动将函数连接在一起。
同时,go.uber.org/fx/fxtest也为Fx应用程序提供了端到端测试的能力。
func NewHandler(logger *log.Logger) (http.Handler, error) {
logger.Print("Executing NewHandler.")
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
logger.Print("Got a request.")
}), nil
}
func NewMux(lc fx.Lifecycle, logger *log.Logger) *http.ServeMux {
logger.Print("Executing NewMux.")
mux := http.NewServeMux()
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
// 这里,NewMux通过传入fx.Lifecycle,用来执行启动和结束的Hook函数
// 注意Hook函数的类型是固定的: func(context.Context) error
lc.Append(fx.Hook{
// 在fx.start的hook中,将http的server启动起来
OnStart: func(context.Context) error {
logger.Print("Starting HTTP server.")
go server.ListenAndServe()
return nil
},
// 在fx.stop的Hook中,将http的server停止
OnStop: func(ctx context.Context) error {
logger.Print("Stopping HTTP server.")
return server.Shutdown(ctx)
},
})
return mux
}
// Register用于注册http server的路由,注册handle是传入的
// 这样就可以被fx框架给连接起来
func Register(mux *http.ServeMux, h http.Handler) {
mux.Handle("/", h)
}
func main() {
app := fx.New(
// Provide 所有我们需要的构造函数, 告诉 Fx 我们想要如何去构造
// 此时并不会执行注册的构造函数
fx.Provide(
NewLogger,
NewHandler,
NewMux,
),
// 下面的Invoke会立刻执行,执行下面函数时,如果需要参数,那么会根据入参类型在Provide中登记的函数的返回值来匹配
// 将匹配到的函数作为入参传入invoke需要执行的函数。这个过程是递归的
fx.Invoke(Register),
// 这部分是可选的. 使用下面的代码, 你可以控制Fx在哪logs5它的事件
fx.WithLogger(
func() fxevent.Logger {
return fxevent.NopLogger
},
),
)
// In a typical application, we could just use app.Run() here. Since we
// don't want this example to run forever, we'll use the more-explicit Start
// and Stop.
// 这里执行fx的start,是为了执行登记通过fx.Lifecycle.Append登记的start Hook
// 此时会执行前面登记的是启动 http server
startCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Start(startCtx); err != nil {
log.Fatal(err)
}
// Normally, we'd block here with <-app.Done(). Instead, we'll make an HTTP
// request to demonstrate证明 that our server is running.
if _, err := http.Get("http://localhost:8080/"); err != nil {
log.Fatal(err)
}
stopCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := app.Stop(stopCtx); err != nil {
log.Fatal(err)
}
}
Output:
Executing NewLogger.
Executing NewMux.
Executing NewHandler.
Starting HTTP server.
Got a request.
Stopping HTTP server.

上图中表现了传统瀑布式的开发模型中缺陷、测试、修复成本的变化曲线,蓝色代表缺陷引入的阶段分布,黄色代表了缺陷发现的时间分布,红色代表了缺陷修复的成本,可以明显看出,缺陷越晚发现修复成本越高。
所以,如果能够在开发阶段,减少引入的缺陷,那么就可以极大的减少人力、时间、信誉成本。
下图就是测试左移的目标状态:
