为什么我认为使用blender一定会用到python

Tags blender python


2021-01-15 21:50:00


复杂动作

虽然 FCurve 已经提供了非常灵活的对 data_path 的操作,但是试想如果你有一个动画效果周期性波动并且每次波动增加 周期长度这种操作是没办法用鼠标精准做出来的。

blender 的动画是面向它系统内部的值,并不是相对于你想要的系统的值,例如说你只能操作一个对象在那些frame的大小是多少。但是你很难做到相对于两个移动物体的连线的垂直距离的远近来调整物体大小这样的功能。

这时候你会用到 Driver Function。

没有代码很难抽象整个动画系统成为单独的 Component (组件)

如果说 Shift + A 里面这些可以帮助你添加到场景内的 Mesh 都是一种组件。 那么他就太简单了。 试想如果你有 python 可以针对不同类型的需求去创建类似于可以灵活切换文字的 Show Panel 还可以让他自治的控制旋转速度,大小等。每次都手动做会很累, 所以你需要 Python Class 抽象 Blender Mesh component。

当你拥有组件之后,你可以很方便的使用抽象好的组件放到不同的 blender 工程中方便复用, 区别于 Duplicate 或者从一个 Blender 文件到另外一个, 它带有参数行具有一定的可自适应性。比如说根据周围组件的 Dimension 值来自动化调整自己的 Scale。

组件还有一个好处,你可以放到一个干净的blender工程中单独调试它,提升工作效率。

组件的另外一个好处就是抽象化, 当你的一个常用组件出现问题同一类问题可以一起修复。 例如说你设计了一种灯光,它有一个上级(Parent)的对象,并且整个对象可以 face to 某一类对象, 你有场景一百处使用了这种灯光, 如果用的是python你可以很容易的从 Custom Prop 这个工具中找到有问题的分类并且一起修复他们。 这样问题组件就算再久远,还是有机会去调整的。

animation(动画)调度器

试想你有对象拥有 Array Modifier 每个对象都完成同样的动作,但是他们完成的时间是不同的比如说他们完成的时间需要符合 y = ( x+2 ) ^ 2 其中 x [1,2] 你会发现你的动作完成实现是非线性的。这时候用鼠标是无法精确做出阿里的 。 这时候你就需要一个调度器来帮你完成这些函数的实现和具体的调度值设定。

最后

blender API设计的不错,文档也写的很好,社区内容丰富基本上你想找到的接口都可以找到。从社区情况上来看,有非常非常多的人是用python来创作他们的blender作品的。


本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

bazel 使用经验和记录

Tags bazel


2021-01-15 19:01:18


近期我自己做的项目已经用上 Bazel 这款产品了。 它是我目前学过的最难学的一门技术(工具)了。 下面总结一下我的学习和使用过程和方法。 一方面我想提升自己的总结能力,另外一方面我自己学习的时候很寂寞身边没有人会这门技术,大多都是用一用编译就好了, 并不想深入了解。

我为什么要用bazel

我最近在做3d建模视频我的主要业务逻辑使用的go语言,blender只能使用python语言,不少操作的驱动需要使用python实现。 不少SVG从矢量到标量的计算用到了NodeJS,并且我的项目并不能统一语言去做。

依赖复杂,我有很多种action而且未来还会有更多。例如目前我有的操作:

  1. SVG矢量转标量
  2. 依赖上面的结果让两个svg path 正交 绘制 mesh 并且输出 Wavefront OBJ 3d 模型的格式 (未来还会有更多的 Mesh 建模算法来应对各种不同的建模场景)
  3. 运行blender background 模式调用我写的 python library 和 python RPC server 对接 golang 建模用业务层。
  4. blender建模和动画的结果之间可以相互引用和复用。

所以这是一个相当复杂的 Dag (有向无环图) 因此每当我动一个比较底层的算法我需要 快速的 正确的 构建并且执行Dag依赖树。

当我编译好我的blender工程之后我就可以把blender文件上传到GPU集群来渲染视频。

一个更简单的为什么要使用bazel的例子:

当你自己写了一个 golang 程序帮助你输入一个 SQL 语句输出一个对应的驱动包来避免使用 ORM 当你修改了 code gen 的模板时你怎么知道该更新那些和测试那些依赖于它的目标 ( Target ) 呢?

并且你并不想写一大堆重复的类似的代码 干体力活 希望机器生成代码, 并且你知道 Golang 没有泛型造成很多重复代码时, 我们唯一的选择就只能是设计一个Code Generator。

学习路线

这里记录一下我的学习路线方便当我自己忘记知识点可以看这篇文字帮助自己复习, 我的学习目标并不是 使用 bazel 而是熟练的掌握开发 rules 应对各类情况。

Concepts 了解基本概念全部读完。

举个例子:

Transitive dependencies
Bazel only reads dependencies listed in your WORKSPACE file. If your project (A) depends on another project (B) which lists a dependency on a third project (C) in its WORKSPACE file, youll have to add both B and C to your projects WORKSPACE file. This requirement can balloon the WORKSPACE file size, but limits the chances of having one library include C at version 1.0 and another include C at 2.0.

当你的 Workspace 越来越大时如果你能想起这里来。 你会发现并不是忘记读了什么文档使用什么方法而是就这样设计的。

Concepts 里面有非常多设计者的意图,是一个系统设计非常好的学习资料。

Extending Bazel 中的 Extension Overview 和 Concepts

Extending Bazel 其实就是写rules来处理自己的工作情况。 这里一定都要读完,意义很大比如一个重要的概念 Depsets 你读完文档之后并不知道它是 immutable variable。 如果你并不理解文档的情况下就会一脸懵逼的碰到 rules 的设计问题,很多变量是只读的文档里面没有提到但是你要反应过来。 所以前期文档阅读量不足会耽误很多时间。因为遇到问题你反应不过来。

换个角度继续学

当我看完上面的文档时还不知道怎么下手, 云里雾里, 这时候有一个重要的 blog 出现: https://www.jayconrod.com/posts/106/writing-bazel-rules--simple-binary-rule

这些文章需要拿出来反复琢磨:

  1. Writing Bazel rules: simple binary rule 帮助你学习如何构建好一个target
  2. Writing Bazel rules: library rule, depsets, providers 帮助你学习如何处理好依赖,很重要,因为你知道bazel的核心依赖算法是DAG
  3. Writing Bazel rules: repository rules 帮助你把外部的软件转换成一个 bazel 系统可以接受的依赖很重要,比如说你构建时依赖了 blender 的二进制文件去运行, 它就会帮助你做到类似于 rules_go 一样下载 golang 的 toolchain

以上是写的非常好的非官方的tutorial。

我看到这时还是不会写。接下来开始读源码推荐阅读:

  1. 一个复杂的: GITHUB REPO 去看首页文档写的重要API的实现。
  2. 一个简单的: GITHUB REPO 去看比较简单的case的关键rules实现。

当我看到这里时我基本上已经写了个大概。因为已经大概熟悉了 Skylark 这门语言。进入爬坑阶段。

最重要的我常常需要参考的关键数据结构

Actions https://docs.bazel.build/versions/master/skylark/lib/actions.html 这是核心中的核心 Files https://docs.bazel.build/versions/master/skylark/lib/File.html 写 rules 其实就是灵活的处理你的代码文件与编译器之间做沟通。 DefaultInfo https://docs.bazel.build/versions/master/skylark/lib/DefaultInfo.html 理解好这个概念可以帮助你与其他开发者写的 Rules 很好的做对接和依赖。

爬坑经验

代理方案选择

  1. linux iptables ip filter 省事
  2. windows Proxifier

windows 注意:

因为 Proxifier 是按照进程为最基本单位的, 当你看不到具体那个进程网络卡住了可以使用工具,可以看到进程树:

process monitor: https://docs.microsoft.com/en-us/sysinternals/downloads/procmon

目前我的进程rules: bazel.exe;java.exe;fetch_repo.exe;Conhost.exe;go.exe;git.exe;git-remote-https.exe; 供参考

管理你系统外的依赖

系统外依赖的定义是: 你并不关心实现的代码。仅仅是下载, 比如说 GJSON 这类的

Cons:

你在A项目中引用了B项目 B项目引用了GJSON 那么A的workspace 也需要管理 GJSON 依赖。 这时你的 WORKSPACE 文件会像气球一样膨胀 我遇到这个坑是因为我对 Concept 文档理解的不够深入。

Pros:

可以实现 Shadowing dependencies 在文档: https://docs.bazel.build/versions/master/external.html 提到的

关于 actions run 这个函数的坑

这些坑都是希望假如我身边有人会这技术我希望他能提前告诉我的

  1. declare_file 一定要放到output里面。 这样当你的 actions.run 结束时文件没创建, 会显示编译错误。
  2. inputs 一定要把你依赖的所有文件都放到这个数组里面。 就算 bazel query 时的确显示出了正确的依赖关系, 但是 inputs 没有声明这些文件在actions中依赖了你会你修改了文件不会重新编译。 会破坏编译的正确性。
  3. mnemonic 只能是一个单词,放入要给动词可以帮助你理解正在并行编译时在做什么动作。
  4. executable 不要依赖与你的path或者一个绝对路径那就出现了环境依赖,要使用 target 来保证整个系统时封闭的来保证你的 正确性
  5. use_default_shell_env False = 有节操 True = 没节操 如果你选择省事至少放到Docker容器里面定义好Path运行。不然会出现环境依赖以及脱离 bazel 环境管理的软件依赖。
  6. tools 假如你在构建中依赖了其他的二进制文件, 例如我在运行 blender 我的入口时 python 的 RPC Server, 我用 Golang 写 RPC client 你很熟练的通过 arguments 或者 env 把你的 Golang client 二进制文件放到了 执行的地方,但是你会新奇的发现 bazel 系统的构建 DAG 树的 Graphviz 图纸是有依赖的但是它并不构建, 然而你读了很多遍文档也不知道为什么你依赖的二进制 bazel target 不编译因为文档的描述是这样的: tools: List or depset of any tools needed by the action. Tools are inputs with additional runfiles that are automatically made available to the action. 现在我可以高兴的告诉你这时候要放到tools里面。出现这个问题并不是文档有问题,是 bazel 的设计者经验丰富抽象层次高造成的。但是我给跪了。

input 数组的开发技巧

例如说你依赖了 py_library 这个 bazel native rule

第一你需要debug看这个rules返回给你什么info

下面时rules label attr

"util":attr.label(),

输入参数label例子: 下面这个例子的util其实就是一个 py_library rule

util = "//blenderutil:util",

下面时skylark 调试代码, 可以看到有什么Info

print(ctx.attr.util)

一点点的调试最后可以得到下面的代码:

for f in ctx.attr.util[PyInfo].transitive_sources.to_list():
    input_list.append(f)

你会得到你所有依赖的内容如果你的依赖很复杂 比如说 A->B->C A->D->C 你会发现C重复了。可以直接用depset解决这个问题 new_var = depset([这里时你的数组,或者直接把变量放进去])

executable 的例子

定义label

"_blenderRunner":attr.label(
    default = Label("//blenderRunner:blenderRunner"),
    executable = True,
    cfg = "exec"
),

action.run 参数例子

executable = ctx.executable._blenderRunner, 

一些感悟

为什么 golang 要用 bazel

目前 gomod 已经做的够好了,就算在我的这个工程里面也会使用 golang gomod 来开发和测试我的代码。 但是与 bazel 结合其实成本并不高有重要的工具叫 gazelle 他可以帮助你转换 gomod 项目成 bazel 项目。 也可以帮助你同步 gomod 到 bazel。

通过如下命令:

bazel run //:gazelle # 初始化 
bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%go_dependencies # 更新

需要注意:

  1. 你还是要显式从 WORKSPACE 或者你自己的 bazel function 中声明你的 go_repository rule 来定义依赖。
  2. 关于 golang bazel 项目吐槽最多的 protobuf 生成之后 IDE 很难结合的问题可以结合这个思路 https://github.com/nikunjy/golink 另外我在自己读 bazel rule 开发文档的时候看到其实我们是可以通过创建软连接来帮助IDE找到我们已经生成的代码。
  3. 上面的问题还有另外一个解决思路, 修改 Gocode 的实现,目前 Gocode 这个项目已经有 daemon 了。 但是它扫描代码并不积极。

一个恰到好处的设计

从actions.run这里可以看到, 每个参数设计的都很到位, 尤其是限制的很到位, 并且每个每个参数都不能删掉, 并且很好的兼顾了各种情况。 新手只可能对概念的理解和知识的掌握不到位, 很难产生一些错误, 这大概就是牛逼的架构师设计的接口。 把安全做到语言级别, 给你报错而不是你在写代码的时候给你各种需要主动遵守的规范。

如果你并不享受这些对你的限制,还不如用 python 或者 make 之类作为构建工具。

一些 bazel 相比其他构建系统的好处

  1. 封装的好,会让构建过程产出结果稳定,受环境的影响可以做到尽量小,也可以让依赖多个版本并存
  2. Starlark 语言设计的好, 类似 python 写起来贼舒服被裁剪的很好, 一方面是影响话编译环境的API都被裁掉了(你并不能很容易的写文件到磁盘到任意位置)内部帮助你构建的变量都是只读的。当然它的好是相对于 GnuMake 和 CMake 相比。
  3. 因为拓展性好,基本上你能想到的语言都有了现成的Rules支持。
  4. 对 Code Generation 非常友好。
  5. 正确 快速 实至名归

最后

很开心我看到了 Bazel 的门, 希望我能早日入门。


本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

小型团队内网创建docker registry

Tags docker registry ssl nginx


2021-01-14 12:07:26


docker registry 是作为容器相关自动化关键底层基础设施,作为一种重要的artifact存储形式,对接CI/CD Kubernetes 都非常方便。

结构设计:


                                       ---> registry (run in docker container)
http traffic -> host nginx with ssl ---|
                                       ---> registry UI (run in docker container)


部署过程

1. 部署docker容器

docker run -d -p 5000:5000 --restart=always --name registry -v /data/registry:/var/lib/registry registry:2
docker run -d -p 5001:80 --name registry-ui -e DELETE_IMAGES=true joxit/docker-registry-ui:static

注意:

  1. regisry 存储放到了 host 的 /data/registry 位置需要可以修改
  2. ui 允许删除数据,更多选项参考:这里 的Run the static interface 段落
  3. 我快速的读了一下这个 registry-ui 的代码其实它是个静态网页项目,dockerfile 的内容显示其实里面就是个nginx 所以说明书上面的 跨域registry_urlSSL 相关配置可以直接如下的 Nginx reverse proxy配置中直接干净快速的解决。

2. 部署Nginx

$ cat /etc/nginx/sites-enabled/registry
server {
        listen 443 ssl;
        server_name hub.philo.top;
        ssl_certificate     /etc/ssl/1_hub.philo.top_bundle.crt;
        ssl_certificate_key /etc/ssl/2_hub.philo.top.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        client_max_body_size 2048M;
        location / {
                proxy_pass http://127.0.0.1:5001;
        }
        location /v2 {
                proxy_pass http://127.0.0.1:5000;
        }
}

server{
        listen 80;
        server_name hub.philo.top;
        return 301 https://$host$request_uri;
}

注意:

  1. 第一行是命令是提示文件存放位置
  2. 安装nginx的方法是 apt-get update && apt-get install -y nginx
  3. server_name 命令需要改成你自己的域名
  4. 证书淘宝买 5 块钱 店铺名字 鼎森网络科技有限公司 因为是内网使用的证书所以用Let’s encrypt比较麻烦。
  5. 命令 client_max_body_size 不要裁剪,因为docker pull 和 push 的 http body 很大。
  6. location / 的作用是路由到 ui container
  7. location /v2 的作用是路由到 docker registry
  8. 别忘了设置域名A记录
  9. SSL 证书最好是要配置上的,原因是docker pull过程默认是要证书的不然需要特别配置trust同理 kubernetes 也有类似的需求稍微衡量一下5块钱还是值得的
  10. 下面的一个Server是为了强制HTTPS

本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

网关服务器部署DNS的冲突问题解决

Tags ubuntu dns systemd-resolved


2021-01-14 10:40:11


因为5.4内核对网络的管理修改很多,在自己部署DNS服务器时,发现systemd-resolved.service占用端口53

所以这里Ubuntu 20.04 的运维SOP如下:

  1. netplan 设置nameserver 127.0.0.1 apply
  2. systemd-resolved.service stop && disable
  3. 部署你自己的dns server
  4. delete softlink /etc/resolv.conf 写入 nameserver 127.0.0.1

注意,Docker daemon会默认指定 8.8.8.8 8.8.4.4 作为dns 不会再取系统配置 (Docker 20.10.1 行为) 所以如果做了特别的DNS配置需要对Daemon配置方法参考这里 https://forums.docker.com/t/local-dns-or-public-dns-why-not-both-etc-docker-daemon-json/54544


本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

iptables 使用 Redsocks 时候 Docker 没有网络问题的分析

Tags iptables docker redsocks network


2021-01-13 20:33:10


今天我自己遇到了一个故障,Docker里面没有网络。

最开始以为是我iptables设置有错误。通过仔细阅读文档发现估计并不是iptables的配置有问题。

后来发现一个特征,凡是走Redsocks RETURN target 全都可以联通,发现这个主要是我无意间发现内网是通的。

所以定位核心故障是Redsocks不通的,这时候发现Redsocks的Listen address 是有问题的. 因为Docker是通过网桥来到local的所以IP地址不是本地所以redsocks需要监听0.0.0.0

所以正确的配置如下

chnroute 生成中国的ip地址

curl 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | grep ipv4 | grep CN | awk -F\| '{ printf("%s/%d\n", $4, 32-log($5)/log(2)) }    ' > chnroute.txt

我们默认绕过中国的ip地址

redsocks 配置文件

base {
        // debug: connection progress & client list on SIGUSR1
        log_debug = off;

        // info: start and end of client session
        log_info = on;

        /* possible `log' values are:
         *   stderr
         *   "file:/path/to/file"
         *   syslog:FACILITY  facility is any of "daemon", "local0"..."local7"
         */
        log = "syslog:daemon";

        // detach from console
        daemon = on;

        /* Change uid, gid and root directory, these options require root
         * privilegies on startup.
         * Note, your chroot may requre /etc/localtime if you write log to syslog.
         * Log is opened before chroot & uid changing.
         */
        user = redsocks;
        group = redsocks;
        // chroot = "/var/chroot";

        /* possible `redirector' values are:
         *   iptables   - for Linux
         *   ipf        - for FreeBSD
         *   pf         - for OpenBSD
         *   generic    - some generic redirector that MAY work
         */
        redirector = iptables;
}

redsocks {
        /* `local_ip' defaults to 127.0.0.1 for security reasons,
         * use 0.0.0.0 if you want to listen on every interface.
         * `local_*' are used as port to redirect to.
         */
        local_ip = 0.0.0.0;
        local_port = 12345;

        // `ip' and `port' are IP and tcp-port of proxy-server
        // You can also use hostname instead of IP, only one (random)
        // address of multihomed host will be used.
        ip = 1.2.3.4;
        port = 8089;


        // known types: socks4, socks5, http-connect, http-relay
        type = socks5;

        // login = "foobar";
        // password = "baz";
}

iptables 配置

set -x
set -e

# 下面两句是添加中国的ip表
sudo ipset create chnroute hash:net
cat chnroute.txt | sudo xargs -I ip ipset add chnroute ip

# 在 nat 表中创建新链
iptables -t nat -N REDSOCKS
## 首先这个代理要屏蔽网络代理出口服务(直接return嘛)

# 下面是添加例外端口的例子
#iptables -t nat -A REDSOCKS -p tcp --dport 59237 -j RETURN
# 下面是添加例外ip地址的例子
#iptables -t nat -A REDSOCKS -d 45.76.241.57 -j RETURN
#iptables -t nat -A REDSOCKS -d 45.32.79.211 -j RETURN
#iptables -t nat -A REDSOCKS -d 144.202.84.244 -j RETURN

# 过滤Docker container 网段 (默认的)
iptables -t nat -A REDSOCKS -d 172.17.0.0/16 -j RETURN
# 过滤局域网段
iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN
# enable 中国的ipset
iptables -t nat -A REDSOCKS -p tcp -m set --match-set chnroute dst -j RETURN
# FWD 需要走代理的情况,直接打到redsock的tcp port
iptables -t nat -A REDSOCKS -p tcp -j REDIRECT --to-ports 12345

# 让上面这个过滤用途的Chain 在PREROUTING中使用(本Linux系统作为 Gateway时候使用)
iptables -t nat -I PREROUTING -p tcp -j REDSOCKS
# 为本机的代理append chain
iptables -t nat -I OUTPUT -p tcp -j REDSOCKS
# 使用docker的时候FWD的DROP的据说是为了安全,但是这里,得给FWD了。不然转发机器无法上网
iptables -P FORWARD ACCEPT

注意事项

  1. 如果你要用本机作为gateway别忘了做这个操作: https://linuxconfig.org/how-to-turn-on-off-ip-forwarding-in-linux
  2. Redsocks 的 upstream socks5 要改成你自己的

本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

ubuntu下使用netplan修改网络信息

Tags ubuntu netplan network


2021-01-13 12:23:15


从Ubuntu 17.10之后默认使用netplan来修改网络信息

一个例子:

l@l:~$ cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    ens33:
      dhcp4: no
      addresses:
        - 192.168.123.44/24
      gateway4: "192.168.123.1"
      nameservers:
        addresses:
          - "192.168.123.102"
  version: 2

修改之后使用命令 enable config:

sudo netplan apply

本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

决策框架

Tags thinking


2020-12-09 13:24:00


我这里的决策指的是确定实现目标的过程和方法。对我来说全工作范围和大部分生活重要决定的场景都需要使用这种决策框架。

一个核心的目标是不要 “case by case” 的想问题

那么你要做如下事项:

  1. 确定问题是根问题杜绝 XY 问题。要研究问题发生的原因,事情解决的原理,做到知其所以然。
  2. 对你没接触过的事务研究并制定过程框架,不要怕慢。
  3. 尽可能对你的执行框架找到引用,比如说RFC,IEEE,paper,official best practice。
  4. 组织内容形成文档,内容至少要又用于描述什么时候用框架的背景,所需要调查的事项以及为什么有这么多事项用于灵活增减执行,所需要使用问题解决的方法大概的过程可能遇到的困难,检查节点和最后能得到的结论或者结果。
  5. 最后要像纪律一样不折不扣的执行,不然以上所做的东西都是空中楼阁。

这样做的好处很多:

  1. 有助于提升你的总结能力。这种总结的积累可以帮助你在工程设计相关走的更远,同时你的精彩总结可以为其他人形成示范效应成为你 布道 的工具。
  2. 当你十分确定某项工作符合某种框架之后,你可以很轻松的把工作交给其他人来做,减少你自己的重复工作省下时间去思考更新更深入的事情。同时也可以为你节约思考的时间。

观察其他人的实践发现要注意的点:

  1. 设置检查点和检查方法方便 查看健康状态
  2. 同步你的方法和想法毫无保留的以方便你的队友 获取足够的认同
  3. 前后一致。

一些不好的例子:

  1. 用PS命令作为监控程序的依赖,这违反了引用和业界最佳实践的做法。
  2. 不要觉得对项目有掌控感的时候说我们不需要项目管理角色而失去掌控感的时候又觉得需要。
  3. 工程速度要求与人员人数质量和工作标准不匹配。测试和git工作流规范是重灾区。

本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。

极度求真极度透明

Tags thinking


2020-12-08 20:20:00


这两样价值观是我从《原则》这本书里面学习到的。 我在执行的时候虽然与书中有很多不同。 但最后结果我很满意,我创建了一个有着不错的执行力和凝聚力的 “2披萨饼” 团队。

如果对标题的概念不熟悉可以略读这里的 介绍文章

极度求真实践

高频反馈

想要得到真实的情况首要实现条件是及时准确的反馈。 我们可以通过设定准确简单的条件来让你的合作者们主动反馈而不是通过会议。

及时性例子:

  1. 告诉你的合作者如果你卡住了一小会觉得自己解决不了问题直接叫我。
  2. 当我自己做事情卡住的时候我会尝试尽量不打断别人的情况下与同事聊聊天收听反馈。
  3. 当我做到一些节点的时候及时与同事分享,并且通过分享结束之后收听关于你做的事情的反馈和与分享无关的反馈。

TIPs:

  1. 主动打断有助于调用整个大脑皮层包括潜意识来帮助你思考创造性的问题。
  2. 经常打断和切换思绪可以帮助你的状态保持在高效的状态。如果长时间纠结同一个事情多半不会有进展,如果对你的状态值求积分会发现不如多打断保持在高效状态来的划算。

准确性例子:

  1. 周期性,安排在轻松的话题之后尽量保持对方在打开状态。大概两三天一次。
  2. 固定性,总是提问固定的问题会帮助你的合作伙伴在工作细节中注意这些固定问题的内容。提问固定问题有助于搭档理解你的做事方法并且能够深入的执行并且在工作中多注意。

TIP:关于提问有个技巧,尽量使用一些评价你的搭档之外的工作内容。例如: 最近你实现的工程感觉怎么样? 更好的提问方法是: 你觉得我与你一起讨论设计的项目执行起来还有什么我值得学习和注意的地方吗?有什么你学到的能跟我分享的吗? 其实这两种提问方式提问的内容是一样的,但是第二个更方便开口说话。

形式大于内容

参考《彼得原理》出现这种问题的特征为:

  1. 无意义的会议和简报。
  2. 决策效率低下,没有结论,一个健康的会议因该是结论之间的碰撞。
  3. 无法做出有效干预决策的SOP,例如无需说明理由的审批流程。

事情的决策或者流程的制定,要对决定和思考过程动机要解决的问题都有透明的说明。把其他人的工作看成是在帮助你解决问题和推进问题,而不是与你的合作者机械性的运作流程和决策。

当你遇到问题的时不要盲目开会浪费大家时间(三人以上为工作相聚视为开会)而是要使用six pager的形式给出文档或者解决方案最重要的是要拿出 引用 业界最好的引用。

用战术上的勤奋掩盖战略上的懒惰

目标进度有问题有两种情况:

  1. 设计有问题,例如人员和财务预算问题。
  2. 人的能力有问题。

这种情况是无法通过加班来弥补的, 除非是急活(故障,事故类)疲劳战术只能让大家损失上升的空间,如果团队整个能力不上升,那就变成了体力劳动。

所以没办法在工程上做出战术调整的方式来挽救局面。只能做战略调整例如:

  1. 承认你失败了。好好总结为什么失败了知道此路不通也是个不错的结果。
  2. 给出足够理由增加资源投入。
  3. 给出一个能给出下一个重要决策的时间点。

不要妄图通过:

  1. 喊口号
  2. 价值观教育
  3. 做一些无聊的小游戏

来解决战略问题。

承认事实

以激励伙伴一起工作努力为例,如果以极度客观的角度去激励员工就不需要通过 画大饼 的方式了。 你只需要:

  1. 完成某个项目你的简历里面可以写 XXX ,这样你在找下一份工作的时候可以补全你的 XXX 短板。
  2. 不要光低头拉车要抬头看路多想想你的这个季度简历多了点什么吗?

例子中参考的重要观点来自 《联盟:互联网时代的人才变革》。

对欺骗性工作0容忍

不要做让你回不去的事情。

  1. 形式大于内容折腾其他人/折腾预算最后并没有达到效果并且不停止犯错还不承认的行为。
  2. 指出问题后又进行遮掩把别人当傻子的行为。
  3. 承诺事先就知道自己做不到的事情。

极度透明实践

规划的透明

季度开始之前应该对整体工作情况进行总结,学到的经验教训思考进行全面的公开,做的好的不足的地方进行充分的思考和评价。对接下来的工作执行计划进行公开。

尽量避免细碎的工作,尽量打包工作成为不同的区块方便不同的人有清晰明确的边界负责推进,并且共同商量执行计划。

最后请相信写下来的力量

遇到困难

要有勇气,勇于承担,坦荡的活着会让你感受舒畅。

  1. 大方的承认自己做的不好的地方,无论是设计错误,还是经验不足,如果要试错请事先讲明。
  2. 大方的承认自己做了傻逼事情,并且至少要勇于解决自己拉的屎,并且要感谢帮你顶锅的人(比如说你的领导)。

与你的伙伴透明

领导大多工作内容是欺上瞒下。其权力扩张的途径最根本的方法是通过人头数的扩张。

所以为了你的合作伙伴:

  1. 不要让他们知道了某些事情时候感到意外。
  2. 不要欺上瞒下。

信息的全部透明非常有利于建成梯队。

最后

这两种重要的价值观并不能决定你是谁,但通过价值观去做事却决定了你是谁。 人们的价值观驱动了你如何做决定,这些决定的积累成为了人和人之间不同的根本原因。


本人博客文章采用CC Attribution-NonCommercial协议: CC Attribution-NonCommercial 必须保留原作者署名,并且不允许用于商业用途,其他行为都是允许的。