0%

OK,正式说明了

SSO的说明网上有很多我就不在这儿丢人了。找了张小图SSO的作用一目了然。

以下主要记录一下我在产品中SSO的实践案例。

案例1

案例1 是比较标准的基于OpenID方式的SSO,用Node.js写的。

案例1没什么说的,网上样例很多,如果有兴趣可以看下我之前写的,不过比较老了,也是第一次写nodejs。

案例2

则是非标的SSO,用Java+javascript写的。

案例2虽然不是非标的,不过整体流程是具备的,比较适用特定编码场景(Spring Security+OpenID),可能有需要的同学,反正我是没在网上找到这类案例。

客户现场的系统A需要登入到我们提供的系统B,没有单独用户中心即也不存在用户同步,客户要求的是能无缝登入,所以解决办法有用户则直接登入无用户则创建后再登入,登录效果与从登录页面发起的登录一样,所以token解析后用Security的方式执行登录。

前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* sso出现在路径末尾 react router方式 目前采用这种方式 http://.../frame/#/module/xxx?sso=xxx 避免sso一直保留
* @param key 需要获取url参数key
* @returns {string|null}
*/
export function getSsoString(key) {
const str = location.hash;
if (str == null || str.length < 2) {
return null;
}
const arr = str.split('?');
if (arr != null && arr.length === 2) {
const query = arr[1];
if (query != null && query.length > 0) {
const words = query.split('&');
// 将每一个数组元素以=分隔并赋给obj对象
for (let i = 0; i < words.length; i++) {
const tmp_arr = words[i].split('=');
const k = decodeURIComponent(tmp_arr[0]);
const v = decodeURIComponent(tmp_arr[1]);
if (k === key) {
return v;
}
}
}
}
return null;
}

/**
* 单点登录逻辑 在页面token发送到后端进行验证
* @param callback
*/
export function sso(callback) {
const token = getSsoString('sso');
if (token != null) {
req(BASE_WEB_API.SSO, { token }, null, { validateError: true })
.then(response => {
// do something....
if (callback != null) {
callback();
}
})
.catch(e => {
console.error('failed sso --> ', e);
if (callback != null) {
callback();
}
});
} else if (callback != null) {
callback();
}
}

后端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* 跳转到猎豹系统
*
* @param response
* @throws Exception
*/
@PostMapping(value = "/cheetah", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String cheetah(@RequestBody SSOVO ssovo,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
try {
// 验证license
if (!licenseService.isValid()) {
LOGGER.error("license is invalid");
return validateTokenError(request, LICENSE_ERROR_MSG);
}
//解析token
Context.Token userToken = Context.getUserInfoFromToken(ssovo.getToken());
if (isNullOrEmpty(userToken.getUserName()) || isNullOrEmpty(userToken.getPassword())) {
LOGGER.warn("token is invalid:{}", ssovo.getToken());
return validateTokenError(request);
}
LOGGER.info("当前单点登录的用户信息为:{}", JSON.toJSONString(userToken));
//验证内置用户是否存在,不存在则创建
SSOUserVO user = ssoService.checkUser(userToken.getUserName(), Context.getCmsContext());
if (user != null) {
// 执行登录
user.setPassword(userToken.getPassword());
return ssoLogin(request, response, user);
}
//异常时跳转到登录页
return validateTokenError(request);
} catch (Exception e) {
LOGGER.error("sso登录失败:{}", e.getMessage());
return validateTokenError(request);
}
}

private String validateTokenError(HttpServletRequest request) {
return validateError(request, SSO_VERIFICATION_ERROR_MSG);
}

private String validateTokenError(HttpServletRequest request, String msg) {
return validateError(request, msg);
}

private String validateError(HttpServletRequest request, String msg) {
HttpSession session = request.getSession();
if (session != null) {
//使session失效
session.invalidate();
}
SSOErrorVO errorVo = new SSOErrorVO(SSO_VERIFICATION_ERROR, msg);
return JSON.toJSONString(errorVo);
}
/**
* 执行登录
*
* @param request
* @param response
* @param userToken
* @return
* @throws IOException
* @throws ServletException
*/
private String ssoLogin(HttpServletRequest request, HttpServletResponse response, SSOUserVO userToken) throws IOException, ServletException {
try {
//登录
UsernamePasswordAuthenticationToken authReq
= new UsernamePasswordAuthenticationToken(userToken.getUserName(), userToken.getPassword());
authReq.setDetails(new WebAuthenticationDetails(request));
Authentication auth = authenticationManagerBean.authenticate(authReq);
SecurityContextHolder.getContext().setAuthentication(auth);
HttpSession session = request.getSession(true);
// 永不超时
session.setMaxInactiveInterval(-1);
//TODO 静态导入
session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
baymaxLoginSuccessHandler.onAuthenticationSuccess(request, response, auth);
} catch (AuthenticationException failed) {
LOGGER.warn(
"sso: InternalAuthenticationServiceException occurred while trying to authenticate the user.",
failed);
SecurityContextHolder.clearContext();
baymaxAuthenticationFailureHandler.onAuthenticationFailure(request, response, failed);
validateTokenError(request);
}

return null;
}

/**
* 根据用户名,获取用户的token
*
* @param userName
* @param response
* @return
*/
@RequestMapping(value = "/getToken/{userName}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String getToken(@PathVariable(value = "userName", required = false) String userName, HttpServletResponse response) {

try {
return Context.createToken(userName, PasswordUtil.getPlaintextPwd());
} catch (Exception e) {
LOGGER.error("获取token失败:{}", e.getMessage());
formatErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
return null;
}
}

private void formatErrorResponse(HttpServletResponse response, int httpCode, String errorMsg) {
response.setStatus(httpCode);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
try (PrintWriter out = response.getWriter();) {
String errorMsgVo = JSON.toJSONString(ImmutableMap.of("code", SSO_GET_TOKEN_ERROR, "message", errorMsg));
out.write(errorMsgVo);
out.flush();
} catch (IOException ex) {
LOGGER.warn("get token :{}", ex.getMessage());
}
}

处理400异常避免出现白页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @author Gamehu
* @description 接管400异常,个性化错误提示
* @date 2019/12/19
*/
@RestControllerAdvice(assignableTypes = SSOController.class)
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
@Component
public class SSO400ExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Object defaultErrorHandler(Exception e) {
log.warn("---SSO验证异常--- ERROR: {}", e.getMessage());
return ImmutableMap.of("code", SSO_VERIFICATION_ERROR, "message", e.getMessage());
}
}

引伸阅读:

最近产品提了一个需求,要做菜单优化。

菜单优化:

  1. 重写菜单数据初始化sql脚本,数据结构两层变为三层
  2. 权限数据调整
  3. 兼容原有菜单权限数据

这里面第三点是最麻烦的,兼容原有的菜单数据,我给需求说了两个方案。

PlanA:从时间方面(因为是个小迭代,整个迭代的功能只有一周时间开发)考虑管理员菜单权限保留,其它普通角色菜单权限一律置空,需求也接受(因为客户现场大多数情况都是用管理员账号)。

PlanB:保留原有数据,但是需要1-2天预研一下升级方案是否可行,我提出的方案是直接用sql脚本做,需求也认可,PlanA为兜底方案。

我就提个解决方案,结果这事最后让我支援一下给做了…,所以在这简单记录一下过程产物。

PLV8

简单地说就算PostgreSQL里加个扩展,这个扩展就是V8引擎,是的,你理解的没错,就是Google开源的JavaScript引擎,有了这个扩展那就能在sql里写js代码了,这对于在脚本里写逻辑那可是爽歪歪了。

安装过程我就不多说了,网上有很多,大体流程就是

  1. 从GitHub wget 下来
  2. make install
1
2
3
4
5
#添加扩展
CREATE EXTENSION plv8;

#验证plv8的版本,出来版本号就证明装上了
SELECT plv8_version();

然后你就可以写JS代码了,ES6、coffeeScript等都可以,只要最终是v8能解析的就成。

好现在开始写了,一开始不太了解,打算用存储过程做,但是后来老前辈提醒我,我这个是升级脚本,只需要执行一遍就成,所以没必要做存储过程,最后还得删掉,因为留着没意义。

然后建议我用DO $$的写法,此方式执行完不会留下其它痕迹就跟执行一条长sql一样,贴个代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
DO
$$
plv8.elog(INFO, '------------------------------------update user menus start------------------------------------');
buildTree = function(list) {
try {
let temp = {};
let tree = {};
for (let menu of list) {
temp[menu.id] = menu;
}
for (let i in temp) {
if (temp[i].parent) {
if (!temp[temp[i].parent].children) {
temp[temp[i].parent].children = {};
}
temp[temp[i].parent].children[temp[i].id] = temp[i];
} else {

tree[temp[i].id] = temp[i];
}
}
return tree;

} catch (error) {
plv8.elog(ERROR, 'buildTree ' + error);
}
};

getTreeOfMenus = function() {
let cmdb = require('xxx');
let result = cmdb.service.query('default', '{xxx{id name}}', {});
return buildTree(result);
};
let allMenus = getTreeOfMenus();

delete allMenus['xxx'];

let ids = [];
idsOfflatten = function(data) {
try {
for (let id in data) {
ids.push(id);
if (data[id].children) {
idsOfflatten(data[id].children);
}
}
return ids;
} catch (error) {
plv8.elog(ERROR, 'idsOfflatten ' + error);
}
};
let flatIds = idsOfflatten(allMenus);
plv8.elog(INFO, 'new menu ids:' + flatIds);
getNormalMenus = function(menus) {
try {
plv8.elog(INFO, 'old menus : ' + JSON.stringify(menus));
let old_keys = Object.keys(menus);
old_keys.forEach(id => {
if (!flatIds.includes(id)) {
plv8.elog(INFO, 'delete menu id: ' + id);
delete menus[id];
}
});
return menus;
} catch (error) {
plv8.elog(ERROR, 'getNormalMenus ' + error);
}
};

updateMenus = function() {
try {
let ROLE_ADMIN = 'admin',
ROLE_DOMAIN = 'domain';
let query = 'SELECT name, menus, role_type FROM xxx';
let updateAdmin =
'UPDATE xxx SET menus=NULL, last_modified=CURRENT_TIMESTAMP where name = $1';
let updateNormal = 'UPDATE xxx SET menus=$1, last_modified=CURRENT_TIMESTAMP where name = $2';
let execCount=0;
plv8.execute(query).forEach(row => {
let roleType = row.role_type;
if (roleType === ROLE_DOMAIN || roleType === ROLE_ADMIN) {
let adminCount = plv8.execute(updateAdmin, [row.name]);
plv8.elog(INFO, 'update admin user menus is null ,count: '+adminCount );
adminCount>0 ? execCount+=1:null;
return;
}

let newMenus = getNormalMenus(row.menus);
let normalCount = plv8.execute(updateNormal, [newMenus, row.name]);
plv8.elog(INFO, 'update normal user menus , ' + JSON.stringify(newMenus)+',count:'+normalCount);
normalCount>0 ? execCount+=1:null;
});

return execCount;
} catch (error) {
plv8.elog(ERROR, 'updateMenus ' + error);
}
};

let updateCount=updateMenus();
plv8.elog(INFO,'total of successes :'+updateCount);
plv8.elog(INFO,'------------------------------------update user menus end------------------------------------');
$$ LANGUAGE plv8;

小结:

PostgreSQL很强大,这是我初试水,后续有机会会再写写工作中的一些PostgreSQL的实践例子。

其实PostgreSQL几乎可扩展主流的所有编程语言比如C++、Java、nodejs等。

参考文档:

背景

由于我们产品是基于docker做的部署,所以不管在开发过程中还是在处理客户现场问题时,多多少少都要用到一些docker命令,此篇做个简单的记录,把我用到的命令记录下来。

先看图

说命令之前先看图了解下便于更有代入感。

架构图(不包含Dokcer Engine等细节)

命令

各种查看

docker COMMAND --help

查看docker相关命令的信息,里面有每个命令的说明。

docker ps、docker ps -a

docker ps 这是最常用的,查看容器的运行状态,查问题时不ps一下心里都没底,该命令会列出所有正在运行的容器,当然 等同于docker container ls。

另外docker ps -a,可用于显示所有正在运行和退出的容器。

docker info、docker version

docker info 该命令用于获取当前安装的docker版本以及有关操作系统的几条信息。

docker version 列出有关Docker客户端和服务器版本的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Client:
Version: 18.09.7
API version: 1.39
Go version: go1.10.1
Git commit: 2d0083d
Built: Fri Aug 16 14:20:06 2019
OS/Arch: linux/amd64
Experimental: false

Server:
Engine:
Version: 18.09.7
API version: 1.39 (minimum version 1.12)
Go version: go1.10.1
Git commit: 2d0083d
Built: Wed Aug 14 19:41:23 2019
OS/Arch: linux/amd64
Experimental: false
docker search xxx

该命令只有在我自己玩得时候用过(不想重复造轮子),搜索registry上得镜像。

docker images

列出所有的镜像,通常只需要关注REPOSITORY、TAG两列就行。

1
2
3
4
5
6
7
8
9
10
11
root@feature1_dev:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
172.17.162.141:5000/baymax-nginx 1.17.6 231d40e811cd 6 months ago 126MB
172.17.162.141:5000/pg10-cmdb 1.3.0 284de991364f 10 months ago 370MB
172.17.162.141:5000/myflink 1.8.1 96c4d2af10fc 10 months ago 449MB
172.17.162.141:5000/yandex/clickhouse-server 19 58006c9044b7 13 months ago 514MB
172.17.162.141:5000/zookeeper latest f336949ce7a1 19 months ago 148MB
172.17.162.141:5000/redis latest 1babb1dde7e1 20 months ago 94.9MB
172.17.162.141:5000/kafka latest 568143d73a6b 20 months ago 339MB
172.17.162.141:5000/dubbo-admin latest 954bf5f29e96 2 years ago 492MB

docker logs -f container_name

查看容器的日志,我用的也较少。

docker commit -a "gamehu" -m "what f" container_id IMAGE_REPOSITORY:TAG`

通过容器id创建一个新的镜像,

Container

docker start 、stop、restart、rm、kill

高频使用了,后接 container_id/container_name,依次分别为:启动(已存在)容器、停止容器(会进行正常时间等待其停止)、重启重启、删除(已停止)容器、立即停止容器

docker exec -it container_id

使用的较多,通常是为了测试而替换容器内的内容,命令用于访问正在运行的容器,并启用交互模式,可用一些基本的命令。

1
2
3
4
root@feature1_dev:~# docker exec -it 58f5d79c10a3 /bin/bash
root@58f5d79c10a3:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@58f5d79c10a3:/#
docker inspect container_id

查看容器的相关信息,用的也较少。

Image

docker run、create

基于镜像创建一个新的容器,run是创建并启动,create是创建但不启动。

示例:docker run -i -t -p 1000:8000 image_name/image_id:TAG,使用镜像,以后台模式启动一个容器,将容器的 8000 端口映射到主机的 1000 端口

docker build <path to docker file>

此命令用于从指定的dockerfile构建镜像。

docker push IMAGE_NAME:TAG

做完镜像推送到镜像仓库。

docker rmi image_id/image_name

删除镜像,通常是处理现场问题,要替换镜像的时候用一用。

docker inspect image_id

查看镜像相关信息,我制作镜像的时候会用一用,用的很少。

docker save image_id> xx.tar

导出镜像,通常是修复现场问题时做该操作,导出已修复的镜像。

docker load < xx.tar

导入镜像,通常是修复现场问题时做该操作,载入已修复后的镜像。

docker tag image_id tag_name

修改镜像的TAG,通常是修复现场问题时做该操作。

感谢

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。


最近看了李笑来先生写的《区块链小白书》对其中的理解一个新事物正确的姿势在此做一个备忘。

1. 不要滥用类比

你将要尝试着学习并理解的,是一个前所未有的重大创新,其中有很多你一下子难以理解透彻的概念,很少有人能一下子全都弄明白……

在这样的时候,人们会不由自主地抄近路走捷径 —— 滥用类比:

“哦! 我明白了,这就好像是……”

比如,你经常会看到人们挣扎着理解了半天,突然冒出一句:“哦,我懂了,比特币就是电子黄金!” 类比是约等号(≈),而“这就是”是等号(=),约等号和等号之间的差别有时甚至超过十万八千里。 比特币与电子黄金之间的关系甚至干脆就谈不上是约等于…… 全然不是一个东西。

在理解全新事物的时候,滥用类比的危害非常大,因为你压根就找不到什么过往已经存在的东西真的和这个创新竟然一模一样 —— 否则,它也不可能被称为创新了,是不是?

这种不恰当的类比被滥用多次之后,就再也没办法形成正确的理解了 —— 因为理解一个创新需要理解多个前所未有的概念,每个都做了不恰当的类比之后,多次非常不恰当的约等于拼接起来之后,无论如何都没办法达到一个与正确理解相近的效果。

请务必注意,每次你的脑子里不由自主地冒出 “这就好像……” 这个念头的时候,你都要把它强压回去。

2. 重复重复再重复

遇到暂时无法理解的概念,不要担心、不要纠结、不要停顿,你要做的事情很简单:

  • 继续读下去;
  • 读完之后再重复读很多次……

这是学习任何新知识或者在任何新领域探索的 “必杀技”。这背后有一个重要的原理:

绝大多数难以理解的知识,是因为它内部有很多 “前置引用”。

所谓的前置引用,就是一个在后面才能深入理解的概念竟然在此之前已经被引用了,导致的结果是学习者总是处于懵懂的状态。学校里的知识却不是这样的,学校里的知识总是线性层层递进的,理解了前面,就能理解后面…… 关于 “前置引用”。

“硬着头皮读完,而后重复读很多次” 这个策略,就是可以轻松突破 “前置引用” 所设置的障碍。这个技巧,事实上可以用在任何领域。

3.借助群智的力量

快速掌握新知识,快速适应新领域,还有个重要的技巧,就是借助群智的力量。事实上,在学校里,你早就应该发现这个技巧了 —— 如果你能跟那些学霸经常聊天,经常玩耍,你就会发现总是在不经意之间,很多重点难点就那样轻而易举地被解决掉了……

这首先因为人是社交动物,然而更为重要的是,交流这个东西,随意的交流总是比刻意的交流更为有效 —— 因为随意的交流总是刻意解决那些连你自己都没意识到的问题…… 可偏偏,这些你自己意识不到的问题恰恰是最重要甚至最关键的问题。如果不借助这种群智的力量,很难想象还有什么办法可以解决这种隐秘的关键问题。

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。

背景

过去一年多的时间,整个产品是从0到1的,整个前端团队也几乎是从0到1(大多都是后端转的前端),被产品迭代的车路推动,滚滚向前,处于野蛮生长的阶段。最近产品大体进入了一个思考过去未来的阶段,相对较平缓。可以有喘息的时间干点想干的事情了。

你知道的,干一行爱一行,既然在前端了就想着咋个把它做的更好,因为以前做后端,后端的工程化的工具箱(CI、CD、监控…有一大堆实践)是很成熟的也较容易搭建起来,不过前端相对就很陌生了,据说也没那么容易。

记录

刚好关注了【前端早早聊】,发现里面有这部分的内容,盗了两张图,让我对前端工程化有了很宽的认识,做个记录,后续慢慢实践。

本文引用的图片,如有侵权请联系我删除。

最近看《圆桌派》聊的一个话题斜杠:理想还是欲望?一专还是多能?。想在这儿随便说说。

这个词其实前两年说的比较多,当时另一个说法是一个人的标签很多。为什么出现的频率高,也流行,更多的原因是在于那其实是大大多数的梦想。

里面窦先生说了一下,欲望和理想的区别:一定要结果的就是欲望,热爱过程的是理想。所以对于追求斜杠,你是出于欲望还是理想?从我个人来说,我对斜杠的追求我归为欲望,因为很显然我是需要结果的,不管是物质上的还是精神上的我都是有所求的。

我一直认为,斜杠青年:其实是一个很奢侈的一个愿望。

我比较俗啊,我对斜杠的定义是,每个斜杠都应该是一份事业且他们是相互独立(跨界)的,就像《圆桌派》里说的一样你虽然干了很多份事业但是其实他们都是有关联性或者有递进性的这其实不算是斜杠,因为你始终还是在那个圈里。

既然是事业那就肯定会有付出和回报当然咱们谈的不仅限于钱,最起码你要花时间和精力去做,且会收到反馈。人的时间和精力都是有限的,你把有限的时间和精力花在了多个不同的行业,且都得到反馈,这才算是斜杠。

比如你上午卖炒河粉,下午coding,晚上酒吧驻唱。这我觉得可以说是:餐饮/互联网/演艺,三个斜杠。

所以为什么说斜杠是很奢侈的,首先你的精力要跟上,其次你的时间能自己做主,然后你还得技术过硬。当然跟现实生活中一样奢侈品再贵,也总有些人是能消费的。所以不是说斜杠就没有,只是那是很小的一部分。

大家别把斜杠玩坏了,也别一味的飘飘然的追求斜杠,很多时候你自己要先静一静想一想,别听风就是雨的,不仅飞不高还摔得疼。

就算你有这个欲望,不得现有实力和条件吗,先让自己有这些条件然后再想吧。

延宕其实直白的说就是拖延的意思,有人就感觉了,装逼非要搞个不常见的,就是因为不常见所以你才会好奇啊,才会去查一下这个词时代表什么意思。良苦用心在于为了加深印象撒。

正文

此篇内容源起最近要准备进行一次分享,筛选分享主题时,想到了拖延,首先我自身就有这个问题,然后我敞开怀抱感受了一下,身边很多人都或多或少存在拖延的问题。

目录

  • 拖延原因分析
  • 拖延的特征
  • 造成的危害
  • 怎么破

首先这篇不是一个从心理学角度写的东西,当然咱也没这个段位。这是一个不严谨但具有严重个人色彩的分享,只在于刨析自己从而能给朋友们提供一些思考和建议。

拖延原因分析

白话点说可能有下面四个原因:

  1. 对成功所需的能力缺乏自信
  2. 对要去完成某个任务有反感心理:认定做事的过程中会遭遇很多困难,结局也会很惨
  3. 目标和回报太遥远,感受不到对我有什么意义
  4. 无法自我约束,例如容易冲动和分心

加粗部分是我认为对我影响最突出的部分。

首先咱们得说导致拖延的因素有很多,具体你是哪一类,你可以买本《拖延心理学》对号入座。我暂时认为自己时拖延早期患者,所以列出的主要是自己审视有的。

目标和回报太遥远,感受不到对我有什么意义

先分析一下,目标和回报太遥远,感受不到对我有什么意义,这个点其实很有意思,你回过头看一下自己列的目标也好还是flag之类的…,大多数都会有一个比较共通的点,那就是列的太大太虚,然后也没有反馈的环节。

上图所示就是以前我列的目标,注意看打勾的标识完成的,红圈的表示未达成的。我来自我检讨一下啊,首先打圈的一看就不符合smart原则,当然也没法用PDCA那套。第二个原因是这几个都没有进行反馈设定,这就让你总感觉这个目标好像老离我挺远,慢慢的就觉得没意思了,也没用积极性了。

但是相反打勾的我都完成了,主要有两方面的原因。

  1. 这几个都是有明显的反馈环节的,比如团队分享,首先意义对我和对同事而言都是正向的。分享完之后也能收到同事给与的一些讨论和评价,这也是一个反馈的环节。这就让这件事变得有结束有结果有意义了,当然就有积极性。
  2. 这件事很具体,也比较小,跨越的周期不长,比较符合smart原则,事情就变得可达。
无法自我约束,例如容易冲动和分心

先根据 Tim Urban在TED的演讲,刨析一下拖延时的大脑活动情况,我觉得真是讲到我心里去了,具体大家可以搜一下演讲的名字叫<你有拖延症吗>。

如上图在有拖延症的大脑里会有一只Monkey(分心/诱惑),它经常会跳出来,告诉你其实你的时间还有很多,要不我们逛逛YouTobe、BiliBIli…,它会不断的骚扰你,最终你会沦陷让其掌握大脑。其实就是抵御不了诱惑,容易分心。那什么时候我们会突然警醒呢,就是有一个东西出现的时候,如下图,这个东西叫恐慌。它一来Monkey就被吓跑了,但是往往这个时候,已经来不及了,被动了。

拖延特征

我们说说怎么辨别,你是否存在拖延这个问题。

  1. 看它是不是让你烦恼不已

    内在结果:必须承受某些内在情绪的折磨,从恼怒、后悔到强烈的自我谴责和绝望

    外在结果:影响家庭、工作、社交….

  2. 在一开始,你往往信心满满

    在完成目标的一开始,往往信心满满 ,但是最后其实都不能很好的的完成或者说完成不了,往往整个过程如下图。

  3. 自我

    自我价值感 =能力(具有独立性,反对受控制) =表现(通过拖延,“我”说了算),不愿意遵守那些不是我们自己所制定的规则并顺应别人的需要 。

  4. 追求完美

    咋一看还挺牛x,原来拖延还有这么美丽的特征,但是注意我们这儿说的是适应不良型的完美主义,“完美主义”者往往对自己期待过高,不够现实,当无法实现这样的要求是,就不知所措。失望之余,通过拖延让自己从中退却。适应不良型的完美主义,对自己的要求跟对自己的表现的期待之间存在一种矛盾。

拖延的伤害

怎么破

说了那么多,最终咱们得找到解法,当然前提是你有拖延困扰并且你愿意付诸行动改变这个毛病。

以下是我亲身实践且认为效果良好的方子,现在我也还在这么做,这是个持久战别想着10天半个月就有多大的改变,也别相信什么21天就能养成xx习惯,普通人就踏踏实实干就行了。

破法1:你得接受
  • ​ 接受自己能力有限这个事实得人不太会为此过于烦恼 。
  • ​ 接受遵守那些不是我们自己所制定的规则并顺应别人的需要。
破法2:和原因对上号
  • 看看这方面的书以及专业的一些心理视频或者找心理方面的人士咨询,找到自身造成的拖延的原因,才能对症下药,人是个体,个体就有差异千万别总去套别人那套方法论,要找到适合自己的。
破法3:明确的目标与可行性的计划

找到一个目标,然后将它分解成几个小的步骤,跨出小小的第一步,学习怎样记录时间,以及如何优化周围环境使之向有利于成功的方向推进。

  • 目标smart且够小,可达。既非常小,又可以给你带来进步感和成就感。

  • 执行过程中引入监督、奖惩机制

  • 整个执行目标的过程按照PDCA不断循环

  • 训练强大的执行力

    执行能力的基本要素:注意力控制、 认知弹性、 目标设定、 信息处理

    1.启动任务(起始,产生行动的想法)。

    2.维持注意力(持续跟进,专注于一个事项)。

    3.抑制冲动(在行动前有所思考,而不是马上反应)。

    4.转换注意力(从一个事项到另一个事项,转变关注的焦点,有弹性地加以回应)。

    5.流程记忆(记得计划、指令和以前学到的知识,在学习新知识和应对新环境的时候可以记起和运用到旧的知识)。

    6.情绪控制(调整和管理情绪)。

    7.组织材料(获取所需的材料,并依序编排)。

    8.自我监测(具备自我评价的相应语言能力,在必要的时候能够通过自我交谈闯过难关)。

    9.时间管理(时间意识,以及对待时间的务实态度)。

    10.计划(按优先次序考虑问题,找出达成目标的各个步骤,提前为以后的需要和相关进程做好准备)

破法4:学会怎样判断时间**

时间四象限

学会利用零碎时间

预防意外干扰,抵制诱惑

不要太分散精力

找出你的最佳时间

享受你的“自由”时间

  • 主观时间和客观时间,做到平滑过渡。很多人就是忽略客观时间所以才老是导致拖延,时间不是跟着你的意志走的。
  • 列出“非计划”时间,除开必须做的事情,剩下多少时间可以用于实现你的目标,给他排出来。
  • 积极的时间约束(番茄工作法…),主要是提高专注力,人不可能24小时都是专注的,就算你说你可以那请你看看猝死的例子…
破法5:积极一点

记住一点:不断地否定自己或者消极对待是要消耗很多能量地。

领导告诉了我一句话:如果你今年没觉得去年的自己是个SB那你就没有在成长,所以别动不动就沮丧、消极。

所以又对应上前面说的,要从一个个小成就不断地激励自己。

破法6:利用你的身体减轻拖延

锻炼,很多人一提到锻炼就会马上接一个词“身体”,其实锻炼不仅仅是锻炼身体其实还是一种脑力的、心理的活动,锻炼是一种释放,通常锻炼你是不会受其他东西影响的,比如你不能玩手机不能看电视等等…这就迫使你专注起来,并且大脑会开始想事情,有点类似冥想的意思。

你的大脑是比较放空的,你可以进行整理、归纳、思考等一系列活动,同时锻炼完事之后又特别爽,释放了身体和心理上的一些无用的东西。

今天内心膨胀的以为自己是个人才,所以随心所欲的看了门课。以下记录了我觉得对我有意义的点。

根据业务布局和业务的洞察来理解和分析业务的变局时什么,再次基础上呢再来看搭建什么样的阵型,组织阵型来匹配业务,为了这样的一个人才搭建,需要准备怎样对人才进行赋能,这个赋能是系统性的赋能,不是对单个个体,甚至不是对团队,而是一个系统性的赋能。最后沉淀褚一套人才管理的机制,用这样的一套人才管理机制不断推动人才。

人才

业务布局=人才体积

人才体积:人才在多大的业务空间中去发挥作用,所以业务布局决定了人才体积

组织阵型=密度

人才分布的密度和人才分布的层次

人才赋能=人才质量

对组织化导向的人才赋能,我组织想对我整个的人才产生怎样的一个牵引力。核心是我是要提高我得人才适应未来业务成长需求,适应未来变局的整体的能力的拉伸。

密度=质量/体积

所以单独对人才进行培训和赋能是不够的,而是要对人才的密度进行一个拉升,即提升人才质量的同时,要让业务体积处于合适的范围内。

人才称重:人才在组织中的重量,发挥的作用。

人才称重的三种方式:

  1. 通过人才赋能提升人才质量
  2. 通过业务布局减少人才体积(冗余)
  3. 通过组织机构的调整来优化人才在不同组织单元中的密度,激活组织的有效性。

四大模型

主要说说人才管理机制模型:

汰换、激励、约束、牵引

汰换:这是一个必然的过程,当你想懈怠的时候觉得无趣的时候,问问自己你对于公司的价值是什么

牵引:企业文化价值的输入、企业向心力的培养等

业务变局

业务结构与人才结构

解释,在什么情况下先发展业务还是先发展人才。

依赖的手段则是进行业务摸底人才摸底(核心团队)

组织变阵

说明什么地方配置更加优秀的人才,合理的调整人才结构和组织结构

人才赋能

迎接未来面对变局的能力

人才管理机制

通过上述内容,沉淀出一套符合自己公司的人才管理机制

小结

从这个课我知道了人才管理不是我之前那么单纯的理解,很容易被这个词午到,人才管理其实不仅仅说的是人才管理,还包括业务布局、组织变阵、人才赋能、机制建立等因素。

所以我理解一下下,人才的定义是不是:专业技能过硬,有战略眼光且能适应业务未来的变局,且有组织向心力?

为什么要谈个人发展?

这个话题其实我很怕的….,因为我发育迟读书少,所以一直都懵懵懂懂+凄凄惨惨戚戚,自认为放荡不羁其实就是无知逗逼。我是从17年开始才意识到有个概念叫“以后的路咋走”,文气点就是个人发展。因为17年开始面临买房、小孩儿上学等一系列问题,深深感到自己的无力,表象就是缺钱,内里就是焦虑。那段时间常常展开双臂抬头望问天“咋整?我该咋整?”,夜深人静常常哭湿了我的小黄人枕巾。就想着不能这样,得变,得抗。

这两年其实我一直在摸索适合自己地发展路径,虽然现在个人发展长远地战略还不是非常明确,但是至少我认识到了个人发展地重要性,并且找到了最近3-5年自己地发展路径。

当然这篇不是来说我的,是结合之前老大的分享以及平时自己的学习来试着说明一下,个人发展的必要性。

**我们先聊聊几个点,看是否能达成共识。达不成共识可能这篇文章对你来说就没什么意义 **

工作压力大,没时间

不用我说大家都知道,个人发展是需要时间来铺垫的,同时个人发展肯定跟工作会有联系,这种联系根据个人的处境可强可弱。另外一个共识点是,工作肯定会压缩我们的可自由支配的时间。所以很多时候我们会得出一个结论,工作压力大,没时间。作为程序员我承认确实会存在这样的情况,究其原因:公司的业务压力大,需要堆人堆时间来跟上时代的节奏。另外一点则是个人的精力有限,就像电池一样,在工作上就把电耗尽了,就算会有一些休息时间,也已经没电了。但是我们可以这么想想:现在的工作强度是否有利于个人发展?得到报酬能否多到让我暂时放弃个人发展的程度?工作压力是否真的有我们想象得那么大,时间是否真的就没了?

所以核心的问题是,我们对个人发展这件事情有多重视?愿意投资多少时间和精力?

我的观点是:如果光感受到工作压力大让你没有时间,但又无法获得一些正反馈,那这不是你有没有时间得问题,而是先考虑这份工作是不是应该继续做下去的问题。如果有正反馈,我们再想想是否现在处境就算我想要的的”个人发展”。

怎么来判断,我通常是这样做的:

  1. 列出来公司的晋升制度,薪酬制度。
  2. 尽可能的根据各种反馈,试着评估一下公司的发展前景或者产品线的发展前景。
  3. 列出来所在职位的工作内容(在不晋升的情况下),以及如果晋升了的工作内容(从与领导交流,加上观察基本上能预估出80%左右)。
  4. 列出来如果因为某些因素,导致被动的离开公司,自己会怎样?

不出意外你列完之后,会说一句“卧槽xxxx”,这样就对了,好好考虑一下个人发展的重要性吧。

有点扯远了,其实我是想说,自己愿意的话,不会没有时间。

工作生活要平衡

我不想这么辛苦,我期望生活和工作平衡

很多人都期望活少钱多还开心,朋友圈那些天天晒美食,旅行,老婆孩子热炕头的生活就是理想人生。每个行业都有其辛苦的部分,这才是现实。有的要付出体力之苦,有的要付出健康的代价,有的要付出脑力之苦。既然选择了薪酬相对高一些的IT行业,持续学习新技术,新知识就是你必须面对的。你是想要今天的生活和工作平衡,还是中年油腻后的生计艰难?

假如你不是富二代,官二代,还是更现实,更长期地看待工作和生活平衡的事情。如果你从事的工作是你热爱的工作,不存在平衡问题,从中获得的成就感就是你生活的一部分。如果你从事的工作是你谋生的手段,想持续获得这个收入,就遵循这个工作的本质规律。

以上是老大的原话我觉得已经说的很透彻了,我认为要想追求工作生活的平衡是不可能的,当然我不是说工作和生活就必须得纠缠在一起才好,我是觉得平衡这词应该是心理上的划分而不是物理上的划分。

个人发展战略

然后我们再来说怎么找到属于自己的个人发展战略,内容总结来自圈外商学院的个人发展战略主体纲要,因为平台不让看了,我就直接不要脸的引用有识之士的了。大家如果觉得有用请去链接点赞,就当我对其微薄的回报了。

一、一个模型,帮你找到真正热爱的工作

  • 冰山模型;美国著名心理学家麦克利兰

    • 显性30%;

      • 知识(专业,书籍),慌乱
      • 技能(编程,技术),焦虑
      • 能力(思考能力,学习能力),挫败低效
    • 隐性70%;

      • 价值观(判断事物标准),矛盾纠结
      • 性格特质(行为偏好),心累
      • 动机(成就动机,权力动机),没热情
    • 四个步骤找到适合的工作

      • 找专业;找自己喜欢的专业和爱好的相关岗位
      • 搜索岗位;在招聘网上,搜索岗位的要求
      • 分析需求;用冰山模型,分析这份岗位需要的知识,技能和能力
      • 对比自己;用冰山模型匹配自己的价值观,性格特质和动机,确定适不适合。

二、四大要素,决定你的市场价值

  • 用冰山模型说明该投入到哪里,才能提升自己的市场价值

    • 投入知识;容易获取,但如果不能运用来解决问题,几乎没有竞争力。
    • 投入技能;有门槛,但市场价值取决于稀缺程度,所有技能都会走向供需平衡,高收入不可持续,需要不断持续学习新技能。
    • 投入能力;能力可迁移,积累到一定高度,行业不对称,也能发挥作用。
    • 投入自我发现;难以改变和发现,但如有清晰的认识,找到相匹配的工作也能提升价值。
  • 为什么大多数人都选择投入到知识和技能,不断碎片化学习,练习并不稀缺的技能。

    • 因为知识和技能容易习得
    • 惰性让自身受限于岗位
    • 没明白工作本质是解决问题
  • 汇总;我们的时间,永远应该花在正确的事情上,而不是容易的事情上。

三、四类迹象,发现你的隐藏能力

    • 虽然成功的道路有千万条,但成功人士基本都在遵循了一个原则,就是将自己的自身天赋发挥到了极致。
    • 天赋就是隐藏的能力,让一个人可以在同样起点的情况下,更加加速成长。
  • 天赋探索方法;“SIGN”

    • 自我效能(Self-efficacy);对某类事情非常有信心,觉得自己肯定能做好。
    • 本能(Instinct);迫不及待想要尝试的事情
    • 成长(Growth);发现自己明显比别人进步的快一些
    • 满足(Needs);做完后及时很累,也会觉得满足
  • 如何在日常中发现自己的SIGN特质

    • 围绕SIGN特质问自己

      • 自我效能;认为自己能教别人什么?别人向你请教什么?跟别人聊天倾向聊什么?聊什么话题会让你感到自信?做什么事情不会感到焦虑和担心?
      • 本能;做什么事的时候很少拖延?长时间休息后,你最想念工作的哪个方面?你宁愿放弃休息时间也要做的事情是什么?
      • 成长;什么事情会让你沉浸其中忘记时间?不容易感到疲累和厌烦?
      • 满足;过去工作和生活中,有什么让你获得巨大的成就感和满足感?
    • 围绕SIGN特质问他人

      • 你觉得我身上有什么不同于别人的特质?

      • 你最欣赏或者佩服我的方面是什么?

      • 在你看来,我做什么的时候最兴奋?

      • 我做过什么让你印象深刻的事情么?

      • 在以下方面,你觉得我那些更加擅长?

        • 思维方式;条理清晰,逻辑严密,脑洞很大,专注专业
        • 沟通协调;化解冲突,争取资源,知人善用
        • 计划执行;执行力强,强求完美,目标导向

四、三种方法,将知识内化成能力

  • 惰性知识;不能及时有效调用,占用大脑内存的知识

  • 如何把知识内化成能力,让自己的能力快速提升的三个方法

    • 1.掌握20%的核心;二八原则,一个领域的20%的核心内容,能够解决80%的问题

      • 如结构化思维20%的三个特征;主题鲜明,归类分明,逻辑递进。
      • 擅长找师傅,找领域内专业人士,了解领域的核心20%
    • 2.知识和问题相互靠

      • 让知识和问题链接起来,知识向问题靠,问题向知识靠。

      • 知识(想应用)问题;看到一个知识就去思考这个知识可以用来解决什么问题?

        • 如;马斯洛的五层次需求,可以用来分析奢侈品为什么这么贵?
      • 问题(找解释)知识,遇到问题,抛弃第一反应,去想想有什么方法论模型可以用

        • 看书遇到有趣的理论,先记下思考3个可以用该模型解决的问题。下次不要下意识反应,学会去翻一下以前的笔记,把问题补充到笔记里。
    • 3.做系统化训练

      • 刻意练习;一个月中,显示每天练习三段式,再提炼主题,然后积累结构
      • 我们的习惯,是高估几天的变化,而低估几个月的变化。
  • 汇总;如何具体到行动中;

  • 1.找专业人士了解领域的核心20%,先去学习20%

  • 2.在学习的过程中,思考各个知识点的应用场景,并记录下来,遇到问题再回去找

  • 3.能力提升是一个系统性过程,所以需要坚持至少1个月。

五、三大系统,让学习不靠意志力

  • 为什么我们如此难坚持

    • 意志力是有限的,并不是学习这件事情类到你,而是“坚持”
    • 移动互联网时代,诱惑越来越多
    • 威尔海姆。霍夫曼主持的一项研究表明;人们醒着的时候,把大约1/4的时间用来抵制欲望。
  • 意志力不够用,就用行为改变来学习。

    • 决定事情时起作用的大脑内部的两个系统;理性和感性。
  • 如何让我们坚持做一件事的三个关键因素;

    • 理性上;知道要学习(树立明确的目标)

      • 明确的目标是坚持学习的第一步
    • 感性上;愿意去学习(利用情绪冲动)

      • 截止日期的紧迫感
      • 比较产生的焦虑感
      • 鼓励带来的成就感
    • 情景上;制造适合学习的场景(创造学习环境)

      • 人是社会动物,我们会观察周围人的行为来调整自己的行为。
      • 如果可以利用环境,就不要用你的意志力来抵制欲望

六、三个建议,让你不做“定制化人才”

  • 1.调整主体,给自己定好发展方向
  • 2.提升能力,让自己成为横向可迁移的人才
  • 3.提升认知高度,让自己成为纵向可拓展的人才

源引感谢:

本文引用的内容,如有侵权请联系我删除,给您带来的不便我很抱歉。

最近看了《抉择》,虽说本身是一本企业管理的书,但是对人自身也是特别有指导意义的…