得物人事系统时间轴设计的演化历程

news2024/11/23 18:42:17

1 什么是时间轴

~(以上图片出自电影《星际穿越》)~

如果你看过《星际穿越》,应该对这一幕印象深刻,女儿墨菲所处的房间,按照时间分为了无数个三维空间实体。三维空间加时间组合成四维空间,即时空。

时间轴对于人事核心系统,就像四维时空中的时间,是类似生命周期的概念。了解HR工作的同事应该知道,员工在企业的生命周期,从招聘、offer、实习、入职、转正、晋升、调动、离职、重复雇佣,有一套复杂的生命周期,并且组织本身也是在随时间发展的。

员工、部门、职位等组织结构的发展和变化情况,均需要按照时间顺序准确记录,需要追溯到任意历史一天或未来一天展示当时的数据,并在某个时间做对应的调整。这个被人事系统高度依赖的时间维度,就是时间轴。

2 为什么人事系统需要时间轴

举一个常见的例子,在人力资源规划工作中,HR时常需要根据企业发展,及时设置、调整公司内部的组织架构。并且在调整的公告中,往往会注明执行日期,例如“自签发日期起,开始执行”等。

在实际操作中,调整组织架构是一项复杂的工作,人力资源部发布公告后,相关部门可能需要几天时间来配合完成调整。公司规模越大,调整的难度越高,有时甚至当天无法完成所有调整设置工作,需要延后几天。因此产生了这样2种需求:

  1. 我们需要在历史的组织架构上进行调整,并且该调整行为需要按照制定的执行日期来追溯,执行日期前后,需要展示当时对应的架构、职务数据。

  2. 我们需要设置一个未来的执行日期,在这个日期上提前设置和调整组织架构,系统将在该执行日期到来之时,自动使该数据生效。

基于这2种需求,引入时间轴概念是水到渠成的。

另外,对组织架构和任职记录的历史追溯是必要的,并且有实际业务场景,主要应用在考勤、绩效、薪酬模块。绩效和薪酬模块都天然存在时间上的错位,常见于4月设定Q1的绩效,4月发放3月工资+Q1的奖金等场景。

例如某个员工在3月1日发生了异动:部门调动、职级晋升并有工作城市调动,且从2月开始涨薪。那么4月设定Q1绩效时,因Q1中间有部门调动,应由调动前后的上级联合评定绩效等级。在4月发放3月工资和Q1奖金时,不能按照4月当时的薪酬水平来发放,而是需要考虑从2月1日开始调薪,重新计算3月工资、Q1奖金、补发工资、补缴社保和个税。并且因为工作城市变化,社保需要分别在2个城市缴纳。

如果没有时间轴,异动变化数据无法准确追溯,以上计算依靠人工,对大型集团企业的HR来说将是非常痛苦的。

3 如何设计时间轴

业界对时间轴(时间模型)的优秀设计模式,主要以下有2种,代表产品分别是SAP和PeopleSoft。

3.1 时间区间模式(SAP)

3.1.1 设计原则

以SAP为代表的时间区间设计模式中,每个标准数据(工号或部门Code)的历史数据都标记了其开始时间和结束时间和生效状态,相邻的2条数据接续但无交叉,最后一条数据的结束日期为无穷大(9999-12-31)。

// 部门简化模型
create table table_department
(
    code        varchar(20) not null comment '部门编号',
    start_time  datetime     not null comment '开始日期',
    end_time    datetime     not null comment '结束日期',
    status      int          not null comment '部门状态',
    name        varchar(20) not null comment '部门名称',
    parent_code varchar(20) not null comment '父部门编号',
    manager_id  varchar(20)  not null comment '部门负责人工号',
)

3.1.2 使用方法

// 查询某一时刻的部门架构(含失效部门)
select * from table_department where start_time <= '2023-04-01' and end_time > '2023-04-01';
// 查询某一时刻的部门架构(不含失效部门)
select * from table_department where start_time <= '2023-04-01' and end_time > '2023-04-01' and status = 1;

3.1.3 维护方法

  • 添加最新或未来数据时,需将最后一条数据的结束时间改为新数据开始时间,新数据开始时间改为无穷大

  • 插入历史中间数据时,需将有冲突的历史数据开始结束时间做避让,空开新数据的时间区间。如果新数据将历史数据完整包含,历史数据将会被完全覆盖

3.1.4 案例

员工经历和入职、转正、变更、离职、重复雇佣等;部门经历了创建、变更、失效、启用等。

将员工和部门数据组合查询,可以得到任意历史时间的组织架构树和员工当时的任职信息。

3.2 生效日期模式(PeopleSoft)

3.2.1 设计原则

在PS中,生效日期(EFFDT)是最重要的模型元素,另外还有生效状态(STATUS)、生效序号(EFFSEQ)。

每个标准数据(工号或部门Code)的历史数据按其生效日期顺序记录,如果一天内有多条数据,再按生效序号依次记录,员工离职和部门失效的数据,生效状态为0。N条数据分割出了N+1个区间。

create table table_department
(
    code        varchar(20) not null comment '部门编号',
    effdt       date        not null comment '生效日期',
    effseq      int         not null comment '生效序号',
    status      int         not null comment '部门状态',
    name        varchar(20) not null comment '部门名称',
    parent_code varchar(20) not null comment '父部门编号',
    manager_id  varchar(20) not null comment '部门负责人工号',
)

3.2.2 使用方法

select *
from table_department a
where a.effdt =
      (select max(b.effdt) from table_department b where b.code = a.code and b.effdt <= '2023-04-01')
  and a.effseq =
      (select max(c.effseq) from table_department c where c.code = a.code and c.effdt = a.effdt);
// 查询某一时刻的部门架构(不含失效部门)
select *
from table_department a
where a.effdt =
      (select max(b.effdt) from table_department b where b.code = a.code and b.effdt <= '2023-04-01')
  and a.effseq =
      (select max(c.effseq) from table_department c where c.code = a.code and c.effdt = a.effdt)
  and a.status = 1;

3.2.3 维护方法

  • 添加或插入数据时,按期望的生效日期插入,如果当天已存在记录,则按序号添加,或在老序号中间插入

  • 未来数据和历史数据同理

3.2.4 案例

员工经历和入职、转正、变更、离职、重复雇佣等;部门经历了创建、变更、失效、启用等。

将员工和部门数据组合查询,可以得到任意历史时间的组织架构树和员工当时的任职信息。

3.3 优劣势对比

以上2种设计模式,都能实现人事系统对时间轴(生命周期)的需求,他们也各有优势和劣势:

3.3.1 可维护性

  • 生效日期模式(PeopleSoft)更优:维护时只需要对应按生效日期添加数据、修改数据、删除数据,可以较方便地对历史回溯数据进行修改。

  • 时间区间模式(SAP)较难:因其对每条数据的开始结束时间都有不可重叠的强校验,因此编辑任何一条数据,都需要对和其相邻的数据进行同步修改,对人工维护和系统维护都带来了更大的挑战。

3.3.2 易使用性

  • 时间区间模式(SAP)更优:因查询时,只需按所需的日期在开始结束范围内查询,即可确定当时唯一的一组数据。

  • 生效日期模式(PeopleSoft)较难:查询时,有effdt和effseq两个维度需要取max,取值较复杂,且容易出错。以下是一个常见的错误案例:

  • 生效日期模式典型错误案例

    • 在查询某一时刻所有启用的组织架构时,status状态检查需要放在子查询的外层。
// 错误案例, status在子查询中
select *
from table_department a
where a.effdt =
      (select max(b.effdt) from table_department b where b.status = 1 and b.code = a.code and b.effdt <= '2023-04-01')
  and a.effseq =
      (select max(c.effseq) from table_department c where c.status = 1 and c.code = a.code and c.effdt = a.effdt);

// 正确案例,status在子查询的外层
select *
from table_department a
where a.effdt =
      (select max(b.effdt) from table_department b where b.code = a.code and b.effdt <= '2023-04-01')
  and a.effseq =
      (select max(c.effseq) from table_department c where c.code = a.code and c.effdt = a.effdt)
  and a.status = 1;

假如需要查询2022-01-01的生效组织架构,部门表中有如下数据

 

错误案例的结果:会错误地查到2018-12-01的生效数据,因为其是小于2022-01-01的最后一条生效数据。

正确案例的结果:2020-01-01是小于2022-01-01的最后一条数据,但因失效,因此会被排除。

3.4 设计模式总结

时间区间模式和生效日期模式都能够满足人事系统对时间轴的需求,但其各有优劣势,技术实现难度也不同,需企业结合其自身情况,选择适合自己的方式。

另外可以看出,人事系统所需的设计模式和通用系统有很大不同。对于通用系统如电商/支付/社交等,数据都是实时生效的,订单发起->支付->发货->收货,数据通过状态机等机制流转并生效,A用户的订单和B用户的订单之间,并没有联系。

在人事系统中则不同,例如将A员工在1月1日设置为B部门的Leader,虽然1月1日B部门内的员工并没有任何异动和职务调整,但他们的所在部门负责人都会自动关联为A员工。因此,每条数据及其历史数据变化,都有关联影响,这些影响会通过时间轴串联起来。因此,时间轴是人事系统中的必要元素,也是人事系统高度复杂性和专业性的体现。

4 得物人事系统时间轴设计的演化

4.1 阶段一:无时间轴,实时生效

19年,得物EHR系统从纯自研起步,参考了钉钉和飞书的部分模式,在该阶段,人事主数据没有设计时间轴概念,所有修改即时覆盖生效。组织架构模型对应的基本数据均只有1条最新条目,虽然有变更记录供回查,但技术上并不支持追溯历史某一天的架构和任职数据。

因该阶段仍处于初期建设的阶段,对于历史数据回溯的需求并不强,且上下游系统较少,因此对时间轴的建设暂未高优先级推进。

4.2 阶段二:按天快照,定时刷新

20年,在这个阶段,得物人事系统建设的模块逐渐增多,主要增加了假勤、绩效等业务板块,这些模块对于时间轴的需求逐渐显现。比如假勤考勤组的分配和回溯依赖历史组织架构、绩效模块。

因此对组织架构做了数据快照备份,相关模块可以通过读取快照查询历史数据,解决了一些燃眉之急。

4.3 阶段三:自研组织架构生命线,时间区间模式时间轴

21年,人事各相关系统对于时间轴的需求愈发强烈,并且无时间轴的设计令人事核心数据质量无法保证,各类数据无序生产,使系统维护难度加大。因此EHR自研开发了生命线模块,使用时间区间模式。所有组织架构变动和任职信息变动,都会生产一条精确到秒的时间线数据。

通过读取生命线中的数据,解决了无法追溯任意历史时间数据的问题。但仍有局限,该生命线仅支持当天异动,自动生产生命线数据。无法对历史数据进行人工编辑和修正。系统中仍存在部分异常数据,因无法人工调整而搁置,影响了整体数据准确性。

4.4 阶段四:引入PeopleSoft系统,规范专业的生效日期模式时间轴

22年,公司实施了PeopleSoft系统,该系统作为老牌人力资源软件,带来了专业且规范的数据库、功能和规则。PS系统此后作为核心人事数据库,EHR系统围绕PS系统做功能开发,使人事数据的准确性和完整性上了一个大台阶。

并且,在PS系统的"指导"下,HR和人事系统的产研部门,从中学到了其诸多专业的设计模式。得物的人事系统数据质量和专业性都大幅提高,也通过主数据平台实现了对公司内部各个下游系统的数据分发,基本满足了HR对于人事系统的核心需求。

4.5 未来展望:自研替代PeopleSoft

在其他大型互联网公司中,不乏先将PS或SAP等专业软件作为人事底层系统起步,再逐步自研定制开发的案例。因为PS和SAP等标准系统仍存在很多限制,无法满足企业定制需求,自研替代能使其人事系统在满足规范专业性的同时,更加契合企业自身的需求。未来,得物的人事系统也将逐渐走向这个方向。

5 时间轴带给研发人员的挑战

时间轴是人事系统中最重要的设计之一,其重要性贯穿人事系统的每个模块。同时,其复杂度和维护难度也是极高的,需要产研人员具有高度专业性,来应对人事系统高复杂度带来的挑战。

5.1 理解和使用时间轴的门槛

人事系统作为专业系统,对产品和研发的专业性有一定的要求。对于未接触过人事系统的研发人员,需要一定的成本来理解时间轴的概念,正确规范地设计时间轴需要丰富的经验。

5.2 建设难度、扩展性难度

首先是时间轴的选型,如果是选用业界知名产品如PS,一般已经自带了完整的时间轴设计,选用后基本定型,再更换难度很高。如果是自研系统,从0开始设计,首先需要考虑时间轴的应用范围,比如组织架构和任职记录一定需要时间轴;合同信息、奖惩记录等不需要时间轴;公司配置、数据字典等可选是否添加时间轴,需要根据需求来设计。

另外,带时间轴的系统,在员工的入转调离核心流程、组织架构异动调整等,都需要按时间做准确的记录,需要系统设计时有各种完备的规则校验。如果这些核心内容有漏洞,使用体验可能较差,并且数据质量也将无法保证。

5.3 数据维护成本

维护时间轴数据的门槛和成本也很高,大型集团企业的组织架构极其复杂,调整及修正数据带来的影响很大。HR手动调整需要花费大量时间,也需要有丰富的系统经验。如果数据出错,排查的难度也极大,研发人员可能将需要开发对应的工具来协助检查,或搭建数据巡检平台来实现。

5.4 上下游系统的数据交换成本

时间轴对于人事系统是重要且必要的,是因其专业性决定的。但公司内部其他需要人事数据的关联系统没有时间轴的需求,如采购、财务、邮箱和飞书、员工账号系统等。这些系统不需要人事系统的专业数据,也很难和人事系统的时间轴进行数据交换。

因此,通常会将时间轴中的实时人事数据作为对外数据提供给上下游系统。在此类数据交换的过程中,需要注意因为忽略了时间维度,数据需要按照一定的规律和顺序提供,避免出现如先推送了新部门,后推送部门负责人,导致下游在创建部门时判断部门不存在的错误。

6 总结

时间轴对于人事系统是重要且必要的,其将人事数据从离散变为有序,通过把各模块数据按照时间串联起来,构建成一套既可追溯企业发展历程、也支持预先规划未来发展的人事底层数据库。

对于高速发展奔向超大型组织的集团企业来说,以时间轴作为核心来设计人事系统,可以有效支撑组织发展的速度,极大程度避免企业遇到人力资源发展中的效率瓶颈。

参考:PeopleSoft之生效日期

线下活动推荐

时间:2023年6月10日(周六) 14:00-18:00

主题:得物技术沙龙总第18期-无线技术第4期

地点:杭州·西湖区学院路77号得物杭州研发中心12楼培训教室(地铁10号线&19号线文三路站G口出)

活动亮点:本次无线沙龙聚焦于最新的技术趋势和实践,将在杭州/线上为你带来四个令人期待的演讲话题,包括:《抖音创作工具-iOS功耗监控与优化》、《得物隐私合规平台建设实践》、《网易云音乐-客户端大流量活动的日常化保障方案实践》、《得物Android编译优化》。相信这些话题将对你的工作和学习有所帮助,我们期待着与你共同探讨这些令人兴奋的技术内容!

报名方式:点击报名 无线技术沙龙

本文属得物技术原创,来源于:得物技术官网

未经得物技术许可严禁转载,否则依法追究法律责任!

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/597064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

奇怪,能ping通怎么还是上不了网?

我的网工朋友大家好啊 一般如果遇到没法上网的问题&#xff0c;你会怎么办。 可能会尝试去使用ping命令来测试一下网络是不是正常&#xff0c;对吧&#xff1f; 但是有时候会出现&#xff0c;ip能ping通&#xff0c;但是就是无法上网&#xff0c;应该大部分网工都遇到过这种…

虚实连接:惯性动作捕捉系统系列产品多领域广泛应用

近年来&#xff0c;将人体数字化融入虚拟世界已经成为一股浪潮&#xff0c;特别聚焦于姿态动作捕捉和人体运动学分析。此时建立准确的虚拟与现实数字模型&#xff0c;并研究运动参数和力学参数的关联至关重要。同时可推动虚拟现实和人机交互的发展&#xff0c;拓展医疗康复、体…

【Atlas200】继承MxBase类自制插件(C++),以官方例程为例

目录 MindX SDK简介插件的Buffer与Metadata自定义插件Init初始化接口DeInit资源释放接口Process插件入口DefineProperties接口DefineInputPorts接口MindX SDK简介 MindX是一款针对昇腾系列AI芯片的软件开发工具包(SDK),它提供了一系列的API和工具,帮助开发者对昇腾系列AI芯…

1、 快速入门

0、回顾jdbc操作数据库 在MySQL数据库创建一数据库实例mybatis&#xff0c;在其创建一张表 CREATE TABLE employee(id INT(11) PRIMARY KEY AUTO_INCREMENT,last_name VARCHAR(255),gender CHAR(1),email VARCHAR(255) ); -- 再插进一条随意数据&#xff0c;用于测试 INSERT …

day5 -- 函数

学习内容 MySQL支持何种函数&#xff0c;以及如何使用这些函数 brief 大多数SQL实现支持以下类型的函数&#xff1a; 用于处理文本串&#xff08;如删除或填充值&#xff0c;转换值为大写或小写&#xff09;的文本函数用于在数值数据上进行算术操作&#xff08;如返回绝对值…

Linux 6.2 系列生命周期已结束

导读Linux 6.2 系列内核已结束生命周期&#xff0c;在 kernel.org 上被标记为 EOL &#xff0c;这意味着该版本不会再有任何新功能、Bug 修复或安全补丁。 Linux 6.2 于 2023 年 2 月底正式发布&#xff0c;是一个非 LTS 版本&#xff0c;只有为期三个月的支持&#xff0c;在维…

Pixhawk无人机-ArduPilot 软件SITL仿真模拟飞行(SITL+Mission Planner结合)

本文的目的是将SITL仿真结合Missionplanner地面站&#xff0c;之后再探索SITL仿真结合QGC地面站。 Pixhawk无人机扩展教程(7)—SITLMP/QGC运行教程中指出&#xff0c;QGC地面站是安装在与SITL仿真软件一起的笔记本电脑上的&#xff0c;而MP地面站是安装在另外一台笔记本电脑上…

分布式锁的应用场景与分布式锁实现(二):基于Redis实现分布式锁

分布式锁的应用场景与分布式锁实现&#xff08;一&#xff09;&#xff1a;传统锁处理并发及传统锁的问题 基于Redis实现分布式锁 所有代码已同步到GitCode&#xff1a;https://gitcode.net/ruozhuliufeng/distributed-project.git 基本实现 ​ 借助Redis中的命令setnx(key&a…

ES6-ES13学习笔记(5.0)

ES2022的函数 //findLast findLastIndex() ES2022 发现在电脑自带的联想浏览器不支持此函数&#xff0c;还报错了 对于ECMA的支持还和浏览器有关以及浏览器版本有关&#xff0c;然后我使用Google浏览器就可以正常使用&#xff0c; 1.扩展运算符&#xff1a;三个点... ..…

第一行代码 第十三章 高级技巧

第13章 高级技巧 全局获取Context的技巧 回想这么久以来我们所学的内容&#xff0c;你会发现有很多地方都需要用到Context&#xff0c;弹出Toast的时候需要&#xff0c;启动活动的时候需要&#xff0c;发送广播的时候需要&#xff0c;操作数据库的时候需要&#xff0c;使用通…

图解LeetCode链表题(中等)剖析

文章目录 &#x1f490;文章导读&#x1f490;1.合并零之间的结点解题思路 &#x1f490;2.链表中最大孪生和解题思路 &#x1f490;3.链表的随机节点解题思路 &#x1f490;4.复杂链表的复制解题思路 &#x1f490;5.两辆交换两表中的节点解题思路 &#x1f490;文章导读 &…

关于python pycharm中输出的内容不全的解决办法

控制台输出&#xff1a; 解决方案&#xff1a; pandas 库 # 显示所有列 pd.set_option(display.max_columns, None) # 显示所有行 pd.set_option(display.max_rows, None) # 设置value的显示长度 pd.set_option(max_colwidth, 100) # 设置1000列时才换行 pd.set_option…

DataFrame/字典/列表之间的相互转换

DataFrame —> 字典 参考&#xff1a;pandas关于to_dict的使用_pandas to_dict_曼珠沙华Devil的博客-CSDN博客 pandas提供了 DataFrame.to_dict() 函数&#xff0c;将DataFrame类型转化为字典类型 DataFrame.to_dict(orientdict) # orient 可省略 对于写入的orient不同…

闭包基本知识汇总

闭包基本知识汇总 一、什么是闭包&#xff1f; 闭包是指有权限访问另一个函数作用域中的变量的函数&#xff0c;在Javascript中&#xff0c;只有函数内部的子函数才能读取局部变量&#xff0c;因此可以把闭包简单理解成 “定义在一个函数内部的函数” 。所以&#xff0c;在本…

AI当道,元宇宙赛道是风口还是噱头?

一个新概念的诞生往往要经过无数次的锤炼&#xff0c;宛如一场漫长、深刻的头脑风暴。而发展到今天&#xff0c;处在风口之上&#xff0c;各行各业都急切往元宇宙概念靠拢&#xff0c;元宇宙已经与资本市场共舞。 伴随着全球多家行业巨头的布局以及元宇宙在游戏领域的率先落地…

c#快速入门(上)

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb; c#和c不同之处&#x1f449;&#x1f3fb;程序文件的…

华为OD机试真题 Java 实现【简单的解压缩算法】【2023Q1 200分】,附详细解题思路

一、题目描述 现需要实现一种算法&#xff0c;能将一组压缩字符串还原成原始字符串&#xff0c;还原规则如下&#xff1a; 1、字符后面加数字N&#xff0c;表示重复字符N次。例如&#xff1a;压缩内容为A3&#xff0c;表示原始字符串为AAA。 2、花括号中的字符串加数字N&…

tcpdump 抓包工具详细图文教程(上)

目录 一、tcpdump 抓包工具的基本介绍和学习基础 1.1 常用的抓包工具 1.2 tcpdump 抓包工具介绍 二、tcpdump 抓包工具使用环境和初体验 2.1 编译安装 tcpdump 2.2 抓包 三、讲解 TCP 协议报文报头 四、tcpdump 抓包工具常规过滤规则 4.1 tcpdump 的 host 和 net 过…

Flutter 又一元老离职,感谢 Tim 这些年的付出

前天在 insiders 收到 Tim Sneath 的离职邮件时感觉很震惊&#xff0c;因为他绝对是 Flutter 团队的元老级人物&#xff0c;几乎每次一次 Flutter 版本发布和社区活动都有他的身影&#xff0c;可以说他是我的 Flutter 领路人之一。 Tim 是在 2017 加入 Flutter 团队&#xff0…

SpringCloud微服务踩坑系列:UnknownContentTypeException

错误信息如下&#xff1a; org.springframework.web.client.UnknownContentTypeException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.cyf.internalCommon.dto.ResponseResult] and content type [text/plain;charset…