Eric Guo's blog.cloud-mes.com

Hoping writing JS, Ruby & Rails and Go article, but fallback to DevOps note

Upgrade Brew Installation Python 3 Package

Permalink

I have a long history with python, recently due to I'm starting using cursor.so, I started to give a try again in python, but now in MacOS brew version.

List all installed package:

python3 -m pip list

Setuptools can be updated via pip, without having to re-brew Python:

python3 -m pip install --upgrade setuptools

Pip can be used to upgrade itself via:

python3 -m pip install --upgrade pip

List of all outdated packages:

pip list --outdated

Upgrade package one by one:

python3 -m pip install --upgrade ipython

Install via requirements.txt via proxy

python3 -m pip install -r requirements.txt --proxy socks5://127.0.0.1:6153

2023年的工作小结与计划

Permalink

之前在2020年定的计划已经过半,由于今年发生了很多重大变化,特别是AI,深度生成技术的突然出现,有必要重新订立一下新的计划。

这里订立计划还是和2020年一样的原则:一,计划不能和世界线的发展发生大的偏差和背离;二,订立的计划必须能够执行。

世界线

世界发生了深刻的变化,IT 的所有领域几乎都发生了停滞,中台的提出者阿里直接拆分了,鸿蒙失败了,唯一的亮点技术 chatGPT 的确可以提高程序员30%的生产力,但是无论从美国还是中国,这种本质上能够代替人类书写代码的技术,只会进一步降低开发成本,无法增加新的需求(除了 AI 技术本身的硬件需求以外)。

所以目前单位的工作核心任务还是降本增效,减少浪费,减少重复开发,确保现有平台得到充分的利用,能够让现有的平台,代码适应新的 AI 时代是工作的重点。

IT技术发展预测

语言

计算机语言和人类语言将发生融合现象,简洁的计算机语言,比如类型可省略的 ruby, javascript,python 会进一步流行,未来人人都是程序员。

新的计算机语言将极难出现,因为 chatGPT 技术不会对这些新的计算机语言进行训练,这就无形中大大提高了新语言的引入门槛。最终计算机语言会分裂为两个大类,高速语言和胶水语言,高速语言有C/C++, Rust,胶水语言有 ruby, javascript,python,如果两方面的特性都需要,那么选Go。

数据库

MySQL 和 PostgreSQL永远是唯二的选择。Oracel 在 M1 推出后的两年还没有支持苹果架构,其他数据库也完全无法同 MySQL 和 PostgreSQL 的人气和成熟度相比较。

跨平台

已经没有跨平台了,现在只有移动端平台和桌面端平台,移动端平台就是微信小程序或者移动端网页,桌面端管理类应用已经全部web化,专业类应用也会逐渐web化,因为Chrome在113版本发布WebGPU,长期看CAD应用也将Web化。操作系统平台已经没有人关注,如果真的有的话,也只会考虑生态与支持的软件能不能允许的更好。目前苹果的生态最生机勃勃,微软的生态存量软件最丰富。鸿蒙已经失败了。

跨平台的意义相比 Java 时代,意义已经很小了,web 平台本身就是跨平台的,而各个平台也同样可以通过一系列服务暴露平台本身的特有服务,所以未来没有操作系统之争,更多的是一种融合。(美国Windows的桌面市场占用了跌倒了57%

Web 平台

随着 chatGPT 完全使用 web 平台发布,随着Chrome 的能力越来越多(包括通知,驱动蓝牙硬件等等),Web 平台的重要性进一步提高。

但是新的 Web 开发框架不会再大规模出现了,因为新的框架 chatGPT 无法辅助编程,所以无法推广,这个情况和新语言类似。

人工智能

AI 会进入高速发展期,智能与智能的自动化应用和结合是重点,需要重点关注智能的落地和应用。

Serverless

越来越多的人发现,云计算的成本比自建机房高,现在已经开始了下云运动,Serverless更多的成为一种软件架构上的概念,而不是软件发布的概念。

DevOps / 运维自动化

自动化运维将只留下换硬盘的工人。Google 已经开始对 SRE 进行裁员了。

数据平台/中台

概念已经死了,阿里拆封了,搞中台的 N+1 了。数据平台也是个伪概念,只有数据是真的。

已经完成的工作小结

经过 4 年开发,基本各种需求都或多或少的建构了信息管理平台。当然这些系统由于建构时间有先后,建构人员有不同,质量良莠不齐,运营成本差异大,用户满意度也各不相同。我主力制作的基于 Rails 全栈框架的,在质量和运营成本上都基本做到了最优。用户满意度方面,本质上用户还是希望自己做的越少越好,系统做的越多越好,所以过去几年,满意度提升缓慢。由于现在我们代码的质量基础都很优异,所以还是留下了极大的改进空间,所以随后几年可以做的事很多。

经过 4 年基本建立了两个数据仓库,一个 Oracle 的,一个 MySQL 的。各个业务线的数据都能在单位内部,特别是 IT 部内部流通,MySQL的仓库性能也基本不用考虑太多,是今后的重点发展方向。

未来一年计划

进一步推动 API 互通

目前单位针对各个业务口,需求口的系统基本已经建立了,但是还没有相互调用,相互互通,在保证安全的前提下,通过API相互调用还需要加强。

探索引入深度生成技术

深度生成技术包括语言文字生成,图片生成等。在帮助用户减少工作量方面,大有可为。

逐步提升用户体验

随着前端开发技术的发展,用户将越来越挑剔,前端界面也将越来越复杂,单个页面所能做的事情也会越来越多,在保持低成本开发的同时,要提升用户的体验,就必须开发复杂的用户界面,需要在 Rails 做后端的基础上,逐步引入 Turbo 和 React 。

加强团队合作

谨慎评估员工的表现和贡献,提高员工工作效率和满意度,在需求清晰的情况下,尽量不打扰开发人员,帮助他们始终高效开发,同时也通过Gitlab统一代码管理平台,进行适度监控,适当鞭策开发。

Fix Yarn Packaging Signature Invalid - EXPKEYSIG 23E7166788B63E1E Yarn Packaging

Permalink

When running apt-get update at Ubuntu 20.04.5 LTS, got below errors:

W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: https://dl.yarnpkg.com/debian stable InRelease: The following signatures were invalid: EXPKEYSIG 23E7166788B63E1E Yarn Packaging <yarn@dan.cx>
W: Failed to fetch https://dl.yarnpkg.com/debian/dists/stable/InRelease The following signatures were invalid: EXPKEYSIG 23E7166788B63E1E Yarn Packaging <yarn@dan.cx>
W: Some index files failed to download. They have been ignored, or old ones used instead.

To resolve just running below command.

export YARNKEY=yarn-keyring.gpg
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo gpg --dearmour -o /usr/share/keyrings/$YARNKEY
echo "deb [signed-by=/usr/share/keyrings/$YARNKEY] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list

Deploy New Rails 7 and Ruby 3.2 App in Ubuntu 20.04

Permalink

Create new user

adduser pp_vendor
sudo su - pp_vendor
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys # and paste your public key
chmod 600 .ssh/authorized_keys

Enable new user as sudo

sudo su -
cd /etc/sudoers.d/
echo "pp_vendor ALL=(ALL) NOPASSWD:ALL" > 85-pp_vendor-user

Install Rust

sudo apt install rustc
rustc --version # here is rustc 1.61.0

Install rbenv and Ruby 3.2.1

sudo apt-get install libyaml-dev
sudo apt install rbenv
sudo su - pp_vendor
mkdir -p "$(rbenv root)"/plugins
git clone https://git.thape.com.cn/rails/ruby-build.git "$(rbenv root)"/plugins/ruby-build
git clone https://git.thape.com.cn/rails/rbenv-china-mirror.git "$(rbenv root)"/plugins/rbenv-china-mirror
rbenv install 3.2.1
rbenv global 3.2.1
echo "gem: --no-document" > ~/.gemrc
eval "$(rbenv init -)" >> ~/.bash_profile # or past the `rbenv init -`
rbenv shell 3.2.1

Create MySQL DB user

mysql -u root -p
CREATE DATABASE pp_prod character set UTF8mb4 collate utf8mb4_bin;
CREATE USER 'pp_vendor'@'%' IDENTIFIED BY 'pp_vendor_password';
GRANT ALL ON pp_vendor.* TO 'pp_vendor'@'%';
FLUSH PRIVILEGES;

Link rbenv to make capistrano works

mkdir -p ~/.rbenv/bin
cd ~/.rbenv/bin
ln -s /usr/bin/rbenv rbenv

create deploy folder

cd /var/www
sudo mkdir pp_vendor
sudo chown pp_vendor:pp_vendor pp_vendor/
echo "machine git.thape.com.cn login Eric-Guo password token_of_personal" >> ~/.netrc

Manually Do Upload in ActiveStorage in Rails Console

Permalink

Upload file is at local:

rails console
a=Article.last
a.download_file.attach(io: File.open("/home/deployer/Manual.docx"), filename: "使用手册区.docx")

Upload file is at remote:

rails console
file = URI.open(remote_file_full_url)
a=Article.last
a.download_file.attach(io: file, filename: remote_file_name)

Some Pro User MacOS Settings

Permalink

Lock the fix area of the Dock.

defaults write com.apple.dock contents-immutable -bool yes
defaults write com.apple.dock size-immutable -bool yes
defaults write com.apple.dock position-immutable -bool yes
killall Dock

Setting recent application number, default is 3.

defaults write com.apple.dock show-recent-count -int 5;
killall Dock

Setting macOS lauchpad columns and rows

defaults write com.apple.dock springboard-columns -int 10
defaults write com.apple.dock springboard-rows -int 6
defaults write com.apple.dock ResetLaunchPad -bool TRUE
killall Dock

More modern macOS can not stop upgrade from setting, but still can clean the red dot.

Adjust menu area

# 指定间距
defaults -currentHost write -globalDomain NSStatusItemSpacing -int 6
# 指定内边距
defaults -currentHost write -globalDomain NSStatusItemSelectionPadding -int 5
# 当前间距查询
defaults -currentHost read -globalDomain NSStatusItemSpacing
defaults -currentHost read -globalDomain NSStatusItemSelectionPadding
# 重置
defaults -currentHost delete -globalDomain NSStatusItemSpacing
defaults -currentHost delete -globalDomain NSStatusItemSelectionPadding

From reddit

defaults write com.apple.systempreferences AttentionPrefBundleIDs 0

Install Open Project in a Shared Rocky Linux Server

Permalink

The target server has the Rocky Linux installed and running the homeland forum already. I already downgrade the node.js from 18 to 16 to meet the open project needs.

Setup open_project user account

adduser open_project
cd /etc/sudoers.d/
echo "open_project ALL=(ALL) NOPASSWD:ALL" > 30-open_project-user
sudo su - open_project
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys # and paste your public key
chmod 600 .ssh/authorized_keys

Install rbenv and ruby-build

whoami # should run as a open_project
git clone https://git.thape.com.cn/rails/rbenv.git .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
~/.rbenv/bin/rbenv init # also edit ~/.bash_profile
# As an rbenv plugin
mkdir -p "$(rbenv root)"/plugins
git clone https://git.thape.com.cn/rails/ruby-build.git "$(rbenv root)"/plugins/ruby-build
git clone https://git.thape.com.cn/rails/rbenv-china-mirror.git "$(rbenv root)"/plugins/rbenv-china-mirror

Install Ruby 3.2.0

Ruby 3.2 need Rust to build JIT.

yum --enablerepo=powertools install libyaml-devel
yum install -y rust
rbenv install -l
rbenv install 3.2.0
rbenv global 3.2.0
rbenv shell 3.2.0
echo "gem: --no-document" > ~/.gemrc
gem update --system

Prepare the capistrano deploy folder

whoami # should run as a open_project
cd /var/www
sudo mkdir open_project
sudo chown open_project:open_project open_project/

Create postgresql db user and import DB

sudo su - postgres
createuser open_project
psql
ALTER ROLE open_project LOGIN;
CREATE DATABASE open_project_prod WITH ENCODING='UTF8' OWNER=open_project;
logout
psql -d open_project_prod -f open_project_db.sql

Using mirror when deploy

Run in the release rails root folder

bundle config mirror.https://rubygems.org https://gems.ruby-china.com

Setting the open project settings

/etc/environment
OPENPROJECT_EDITION=bim
OPENPROJECT_APP__TITLE=Open Project
OPENPROJECT_HOST__NAME=op.cloud-mes.com
~/.config/systemd/user/open_project_puma.service
[Unit]
Description=Puma HTTP Server for open_project
After=syslog.target network.target
[Service]
Type=simple
WatchdogSec=10
Environment="OPENPROJECT_EDITION=bim"
WorkingDirectory=/var/www/open_project/current
ExecStart=/home/open_project/.rbenv/bin/rbenv exec bundle exec puma -C config/puma_prod.rb -e production
ExecReload=/bin/kill -USR1 $MAINPID
# if we crash, restart
RestartSec=5
Restart=on-failure
StandardOutput=append:/var/www/open_project/shared/log/puma.log
StandardError=append:/var/www/open_project/shared/log/puma.log
SyslogIdentifier=open_project_puma_staging
[Install]
WantedBy=default.target
systemctl --user daemon-reload
bundle exec rake openproject:plugins:register_frontend
bundle exec rake i18n:js:export
bundle exec rake db:seed

Downgrade Node 18 to 16 in Rocky Linux

Permalink

When start developing open project, I found it only support Node.js 16 and confirm Node.js 18 not working currently, so I need downgrade the node version in a Rocky Linux server to build a staging environment and here is how:

Uninstall node 18

dnf remove nodejs
cd /etc/yum.repos.d/
rm nodesource-el8.repo
yum update

Install node 16

curl -fsSL https://rpm.nodesource.com/setup_16.x | bash -
dnf install -y nodejs
node --version
dnf install -y yarn

以Rails应用为例谈谈如何做好软件系统的依赖项目管理

Permalink

现代软件体系

现代软件是人类合作的结晶,以homeland这个以Rails开发的小型论坛为例,Ruby 语言的依赖项有211项,Javascript 依赖项目更是达到了1811项,这无疑会遇到应用依赖的组件管理困难。例如,组件的许可证变动引发巨量修改,JS 组件中发生故意投毒事件,所以很多真正非常非常关心软件正确性的公司,基本的软件组件采用策略是 0 依赖。例如 37 signals,基本他们从来不用不是自己开发的组件(其他人会依赖他们组件,他们从来不依赖别人的组件);Google 的 Go 语言也自带了从机器码汇编器,做到了编译过程的 0 依赖,同时编译出来的 Go 程序只依赖于自身和libc库,基本也做到了 0 依赖;苹果公司的每一个新版本的 macOS,越做越小,依赖越来越少,最新的版本 perl python ruby 这些脚步语言也不再随操作系统发行。

这些组件依赖的管理方法才是提高软件质量的根本途径,但这样做的开发成本太高,代价过大,并不适合绝大多数的中小型企业。中小型企业往往会选择了一种类似市集开发的模式,尽可能的利用已有的组件,而不管这些组件是哪家公司的,只要协议上允许,无需付费,基本上管理层会同意任何组件的使用。(稍大一点的公司会有一个引入的评审,但国内不多见。)

这基本构成了现代的软件体系,一个有很多薄弱层的高楼。

依赖项的管理策略

如果巨量的依赖性不可避免,那么依赖的管理就必须重视,Gitlab已经将依赖扫描作为基本功能提供,Github也会定期扫描托管的代码库,及时报告有漏洞的组件版本给开发者,而开发者基本上可以有三种策略来管理依赖。

永不升级

也就是从来不更改任何本软件系统的依赖项。这些依赖项在开发初期啥样,开发完毕也是啥样,上线后还是一样,10年以后还是完全一样的这些依赖项。现代依赖管理工具是支持重复安装锁定的依赖项的,所以重装机器,新的开发人员都可以对齐到最初的依赖项版本。

这个策略的优势是成本极小,引入组件依赖的Bug的概率为 0(当然无法避免自己写出 Bug 或者一开始的依赖项就有 Bug 的情况)。

但这个策略的劣势很多,比如即使从来不升级,还是无法保证应用运行的服务器物理上不损坏,VMware不升级,服务器的操作系统openssl版本不变动。这些变动往往在锁定依赖的软件系统上表现为无法在新硬件,新操作系统运行,从而导致这些应用最终只能安装在一个特定版本的操作系统上。

以 10 年的尺度来看,永不升级的项目基本就是死的,因为 10 年后的开发者是无法复现 10 年前的环境的,微软的系统这点上要远好于 Linux ,当然兼容性永远以稳定性为代价,众多的互联网公司实际还是使用 Linux ,其实已经做出了稳定性优先于兼容性的选择,那么永不升级的策略也只能在 Linux 上有 10 年左右的寿命。10 年以后即使系统还能跑,但是企业将非常非常难以找到懂 10 年前的技术的开发者。年轻的开发者一般 25 岁入行,35 岁跑路,除非企业愿意在 35 岁跑快递的那些不思进取的开发中寻找雇员,否则将非常难以找到维护人员。那些紧跟技术潮流的资深开发或者新人也基本上不愿意学习 10 年前的技术和依赖,所以,永不升级在商业上就不是一个合理的策略。

另外一个绕不开的问题是,在任何一个时间点开始的项目,他们的依赖在随后的岁月中必然会发现很多安全漏洞,由于永不升级策略,这些安全漏洞不可能被弥补,所以除非企业的应用完全不考虑安全性,否则永不升级策略客观上也是完全不可行的。

周期升级

周期性升级策略是一个折中的策略,每年或者每个季度升级一下,升级到最新的组件依赖项,并且一般会升级很多依赖项,是周期的长短而定,开发团队需要去解决这些依赖项的冲突或者Bug或者适配新功能,周期性升级策略一般伴随着大版本的更新,也必须走UAT用户确认测试流程,这些开发工作量都不小,很可能由于软件开发项项目压力而延期。一旦延期就将积累更巨量的依赖项更新,延期只会导致适配工作量的继续增加,基本上这是一种技术债。

以笔者经验,周期性升级的痛苦值是最大的,最后开发团队都会选择两条道路:

  1. 再也不升级了,开发感觉折腾的没完没了,从企业角度来说,周期升级成本也高,又没有得到任何短期内的商业优势,很容易感觉得不偿失。
  2. 选择依赖项永远保持最新策略。

永远最新

永远最新策略很简单,就是保持一个项目的所有依赖项都是最新的,一旦那个组件出了新版本,立刻升级上去,然后经过简单的冒烟测试(能跑起来就行)或者较为完整的CI(持续集成测试,会自动测试软件的一些基本功能),直接发到生产开始跑。

这个策略听起来十分的暴力,项目的依赖项没有经过测试就直接上了生产,但是其实结果并没有看上去那么可怕。原因有很多:

  1. 项目的依赖项作者一般都是资深开发,引入bug的概率并不大,而且依赖项本身在发布的时候基本都做了测试
  2. 项目的依赖项都是有 Semantic 版本控制的,开发在升级依赖项的时候,如果是大版本升级,也不可能直接无脑升级,肯定还是会根据组件的文档去做适配,由于永远升级策略在单个时间点只有一个依赖项升级,所以这部分工作量并不算多,一个合格的开发在每天开始工作前检查,升级,可能也就占用30分钟以内的时间。
  3. 项目产生的Bug有明确的指向,因为永远最新策略升级速度快,每次依赖项的变动往往只有一个,所以一旦生产有Bug,基本上立刻可以判定刚刚升级的依赖项有问题,修复Bug的速度可以少于3分钟,如果人的心脏停止,那么在6分钟以内也是可以救回来的,所以3分钟的Bug基本上可以认为没有Bug,只要运维人员,开发人员配合好,新依赖项基本可以认为引入不了Bug。

永远最新策略的优势就是克服了永不升级的问题,项目永远是活的,可以在任何正常的Linux下安装,可以使用任何主流的工具,永远能找到年轻的开发者。

当然永远最新也没有任何安全漏洞,毕竟一旦有安全漏洞,这些依赖的组件必然会发版本,然后应用就用上了。

永远最新由于一次只升级一个组件,理论上的改动是最小的,相比周期升级,一次升级的工作量也是最小的。

唯一的劣势可能就是必须有开发维护人员永远维护,像心跳一样不能停,一旦停就开始累积依赖更新,很快就会变成周期更新或者永不更新。

软件供应链

最近软件供应链这个词也在公开的面向企业管理者的媒体中频频出现,比如国内的再谈“开源软件供应链安全” 但实际上,开源软件没有供应链的概念,各个中小企业没有给任何它们依赖的组件付费,而供应链的本质,是企业依赖了其他人的组件,并因此付费。

所以在缺乏付费支持的情况下,软件组件并不是以一个供应链的机制在运行,虽然软件系统的确类似于硬件产品,依赖了众多的组件,但组件开发者和使用者之间,是不存在类似供应商的关系的,但不可否认的是组件开发者和使用者之间的确存在紧密的联系,笔者更愿意概括为:开源软件的责任。

使用开源软件责任

笔者认为开源软件的目的实际上是节约成本:

  • 节约使用者的成本
  • 通过找到开源软件的用户,并把用户变成开发者和测试人员,节约开发者的成本
  • 通过同一套代码,同一个概念模型,同一种开发方式降低沟通成本

所以开源软件作者和用户虽然没有法律意义上的相互责任,但是却有隐含的责任条款:

开源作者必须提供容易追溯审查的源代码,尊重使用者的兼容性要求,在满足绝大多数用户的前提下,提供安全无bug的新版本。

开源使用者也有责任有义务紧跟开源作者发布的新版本,因为作者刚写完脑子里面对新改动是最有印象的,如果使用者能够及时使用到生产/开发中,实际上是在帮助开发者测试。

开源软件使用者在长时间的使用某个开源组件后,也客观上能够成为新的开源组件维护者,人都是要死的,用户量庞大的开源组件却是永生的,维护者最大的心愿也是能够找到下一任维护者,让开源软件一直有维护,大家一直能使用。从这点看,开源软件开发方式实际上是一种来自未来共产主义的模式,更加需要各个参与方的自觉自我激励。

关于安全

Rails有异常多的安全实践,开源组件的安全性可以非常高,以Rails源码为例,任何一次递交,至少有1000个资深开发会扫一眼更改的代码。Rails也有专门的安全邮箱用来报告漏洞(不公开),直到发布完毕补丁版本后这些修补才会公开。

安全性的前提就是使用最新版本的组件,因为只有最新版本的组件才是没有任何已知问题/安全漏洞的。

推荐策略

所以软件系统的依赖管理策略其实只有一种,就是永远保持最新,这既是社区的要求,也是安全的要求,同时也是项目自身活力和吸引新的开发者/雇员的要求,当然大型的软件系统都是周期发版本的,所以也可以认为是一种周期更新,但是这种周期更新还是应该尽量的短,毕竟当只改了一个组件的依赖版本,而系统挂了,那肯定就是那个组件的问题,不用排查,而如果同时改了10个依赖的版本,那就没那么容易判断了。