善省 - 第十二期 (22年12月)
December 19, 2024 (1y ago)
22年年底了,本期我们主要还是聊聊 遇到的一些问题和值得思考的事情🤔
Scoot给的建议
12月前期的一场分享
Scott分享「2023年择业重点 」
分享脑图

要点总结
1、技术人员经常面对电脑,获取的信息大多来自网上,跟人打交道少,对人的判断有天生的不足、对人的认识是有限的;
2、只满足了公司的要求本身还不够,公司的「期望」也能满足了才有可能在职场上不被k掉;
3、后端语言首推 Java,选 Go 也可以,但是路线可能稍微陡峭一些;
4、工程师容易陷进牛角尖中,例如绩效没有好,晋升没有升,HR说话不好听等,自己骂骂咧咧几句(心里面)就行了,第二天该干嘛干嘛;
核心要义:要学会「重启」自己:重新搞心理建设,把心态建设好。
问答时间:
请教 Scott : 现在前端行业的基础设施是不是已经比较完善了,前端技术人员需求量会成逐年下降的趋势吗 ?
需求量不会下降,只不过是对人的要求变高了,不仅要懂技术,还要懂业务。很好的岗位的需求量变少,例如大厂们,但是他们不代表主流。
请教 Scott : 如果有 Java 基础,如何深入扩
找事情做,想要深入扩展这个东西不是靠看书、看文档能得来的,一定要是在业务场景、做事情中练出来的。
请教 Scott : 作为一个程序员,平时只和电脑打交道,如何在平时培养商业思维呢?
多和产品、运营、创业者聊天,如果他们不愿意聊,多给他们干活,免费干。
请问下:Socct老师定义的心智成熟是怎样的
纯真应该保留,但不应该是全部,剩下的部分是心智成熟,才能与这个社会更好地相处。
请教 Scott : 对于扩边界,对于 3D 建模方向,有什么建议嘛?
尽量往后端扩
请问下 Scott :工作和生活都重要,那卷工作和卷生活要怎么平衡呢?
以前好的时代,或者在国企还可以,但是现在这种情况不太可能,大部分时间还是用来工作,抽出时间生活。用当下更多时间交换后面的时间。
请教 Scott:前端成长需要要先保证自身的前端技术达标,请问怎样才算是达标
不以技术本身来看,公司的技术问题是不是都可以搞得定,看解决问题的能力:经验+技术+天赋的综合体,越练习就会越好。
请教 Scott:如何看待 Web3 呢?
是一个大韭菜盘,多了类似一种货币交换,只是一个技术上的概念。
Nodejs系统的完整性
主要是迁移原来的登录中转系统,这个系统都是我一手写的,由于公司系统升级,需要我从原来的NES集群,给整到K0s里面去(K0s就是我们公司自己搭建的一个集群管理中心底层还是k8s支撑)。
讲道理这个事情我应该再7/8月都给他做了。(但是自从App做了一个基础之后,就再也没有人问津了,所以招来做App的人都被裁掉了,无论是后端还是前端,前端还剩我一个人,去年进来的 我 Ace Aoda.....都被裁完了,了解和熟悉这个项目的目前只有我一个人)从另一个侧面,我深刻体会到一个思想 非核心业务部门的非核心团队,非常的危险,裁员往往就是它们,公司好的时候就可以养着,但一旦经济情况不好就特别容易遭淹,与此类似的例子还有 天猪大大的遭遇(阿里Egg 框架的主要开发者)。
然后说会到Nodejs系统的完整性,我在做迁移的时候,发现目前这个Nodejs应用,它么有链接上zookeeper (配置中心),也没有提供一种很好的启动参数管理(没有配置,所有配置都写在启动脚本去了...这是有问题的),它也没有接入log中心和我们公司系统内部的 prometheus。这些都需要我后面把它们一一处理了
技术上来说就是 @willsoto/nestjs-prometheus 日志 .env预先配置,启动参数去读取文件,而不是读每一个参数, 当然辩证来看,如果读启动参数的话,确实改的时候比较方便, redis 配置也没搞好,node-zookeeper-client
- @willsoto/nestjs-prometheus
- env设计和启动参数
- redis 链接
- node-zookeeper-client
下面👇 是实现
一开始原来的版本
// 设计一个全局的modle 然后别的地方再饮用 里面的service 的时候就不需要在自己的module 去导入了
// 官方文档有写
// 由于 node-zk 是异步 所以我也使用 异步 模块来实现
@Global()
@Module({
providers: [
ZKService,
{
provide: ZOOKEEPER_CLIENT,
useFactory: async (optionsProvider: ConfigService) => {
const zookeeperClient = await getZKClient({
url: optionsProvider.get(EnumInterInitConfigKey.zkHost),
});
return zookeeperClient;
},
inject: [ConfigService],
},
],
exports: [ZKService],
})
//.....
const getClient = async (options: any) => {
const {url, ...opt} = options;
const client = zookeeper.createClient(url, opt);
client.once('connected', () => {
Logger.log('zk connected success...');
});
client.on('state', (state: string) => {
const sessionId = client.getSessionId().toString('hex');
});
client.connect();
return client;
};
// 这样写的话,用的时候直接丢就好啦
@Global()
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
expandVariables: true,
load: [configuration],
}),
FaqModule,
ZKModule.forRootAsync(),
],
exports: [FaqModule],
})
export class CoreModule {}
// 只需要在用的地方 直接用ZkServic 就ok ,但是这样不够优雅,于是进化成啦🧬 这样 把它内聚一下
@Global()
@Module({
providers: [ZKService],
exports: [ZKService],
})
export class ZKModule implements OnModuleDestroy {
static forRootAsync(): DynamicModule {
return {
module: ZKModule,
imports: [],
providers: [ZKService, this.createClient()],
};
}
constructor(
@Inject(ZOOKEEPER_CLIENT)
private readonly zkCk: any,
) {}
onModuleDestroy() {
this.zkCk.close();
}
private static createClient = (): Provider => ({
provide: ZOOKEEPER_CLIENT,
useFactory: async (optionsProvider: ConfigService) => {
const getClient = async (options: any) => {
const {url, ...opt} = options;
const client = zookeeper.createClient(url, opt);
client.once('connected', () => {
Logger.log('zk connected success...');
});
client.on('state', (state: string) => {
const sessionId = client.getSessionId().toString('hex');
});
client.connect();
return client;
};
const zookeeperClient = await getClient({
url: optionsProvider.get(EnumInterInitConfigKey.zkHost),
});
return zookeeperClient;
},
inject: [ConfigService],
});
}
// 用的地方就变成啦 forootAsync
ZKModule.forRootAsync(),
// 其他的redis 还是mq 都可以这样用 都是这样用的
import { ClusterModule, ClusterModuleOptions } from '@liaoliaots/nestjs-redis';
.....
ClusterModule.forRootAsync({
imports: [ConfigModule, ZooKeeperModule],
inject: [MpsConfigService, MpsZKService],
useFactory: async (
configService: MpsConfigService,
zkService: MpsZKService,
): Promise<ClusterModuleOptions> => {
const data = JSON.parse(
(await zkService.getData(configService.zooKeeperRedisNode)) as string,
) as ZooKeeperRedisResponse[];
const cluster =
process.env.K0S_CLUSTER_LOCATION ||
configService.redisClusterLocationDefault;
const { Host, Password } = data.find((_) => _.Name === cluster)!;
const nodes = Host.split(',').map((_) => ({
host: _.split(':')[0],
port: Number(_.split(':')[1]),
}));
return {
readyLog: true,
config: {
nodes,
redisOptions: { password: Password },
onClientCreated(client) {
client.on('error', (err) => {
Logger.error(err, 'CoreModule');
});
client.on('ready', () => {
Logger.log('Connected to Redis.', 'CoreModule');
});
},
},
};
},
}),
// 用的时候直接引入 第三方写的
import { ClusterService } from '@liaoliaots/nestjs-redis'; 就ok ,它会自动租册
// 比如说mq是没有的,怎么办?也很简单,使用动态模块 的特性 自己搞一个就好了
MessageQueueModule.forRootAsync(), 具体代码就不写啦
由上面的两个例子,我们了解 ,很重要!动态注入 和动态模块,在Nest中的运用
Single Page Apps for GitHub Pages
想多了
我这个人,越来越有一种坏习惯了,总是想要的东西很多,一下子 golang 一下子Android 一下子 ios 一下子react 一下子vue2/3 一下子UE...... 还flutter 什么的,总而言之,想要的太多了 这个可不是一个好习惯,想要的很多没有错,但是要有个度,有个访问,这正是所谓的中庸之道,熟话说,很多人都认为人应该全面发展,殊不知,往往有所成就的人,并不是取长补短,而是充分发挥自己的长处 。扬长而避短才是这个时代需要的
D2大会分享 D2 分享笔记 2 - 自渲染跨端框架在字节跳动的实践与展望 - 2022.12.17 上午
在跨端领域,一直都是群星璀璨的,前者有React Native 、Flutter 等。后者有各个大厂的综合自研方案如:阿里的Weex,kraken,腾讯的HippyApp,字节的Lynx 等。目前各种方案在跨端领域遍地开花,方案虽多但它们或多或少都离不开两个话题
- 使用前端技术栈希望更贴切前端开发,为开发提效
- 专注性能上的提升,绞尽脑汁的提升性能,给用户带来媲美甚至超越Native的体验
今年 D2 的前端专场提供了这么一场分享,由来 自字节 Renderkit 的负责人 刘国良老师,为我们分享了《自渲染跨端框架在字节跳动的实践与展望》,全程听下来,发现自己格局还是小了,虽然自己也用过一些跨端方案,但对其理解和方案对比都浮于表面。跟着国良老师的分享,让我更清晰的了解了一段UI 渲染的真正的底层逻辑,不管你是何种方案跨端,对性能的极致追求最终还得落到最核心最底层的渲染管线上,Renderkit的渲染思路和破题方法借鉴了行业先驱但又有自己独特的理解;我在 整体思路的讲解中受益匪浅。对跨端的底层有了更深刻的认识。

新加坡🇸🇬
机会永远都不说留给没有准备的人的,机会和成本往往不是 能够达到一个非常好的平衡,这个时候你需要的就是二者取其一!,如果有机会去新加坡,我选择去,毕竟这年头,这种机会不总是有的
关于websocket 相关的项目(代理)
最近遇到一个意思的需求:本地的环境无法连接,我需要连接到线上的两个接口 一个是init的post 接口 ,一个是init之后拿其返回的session 去发ws:// 和 wss://, 但是如果本地 前端的8080 直接去call 线上这两个api会有 cors问题,所以我使用了node去 做了一个代理。 目前会先代理到 post 的init 接口,然后在去代理到ws的接口,建立起长链接
const express = require('express')
const axios = require('axios')
const bodyParser = require('body-parser')
const { createProxyMiddleware } = require('http-proxy-middleware')
const app = express();
const port = 3000; //端口号
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// cors
// 允许跨域
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Allow-Credentials","true");
if(req.method === "OPTIONS") res.send(200);
else next();
});
// `http://localhost:3000${initialState.Config.Technique?.ChatBotConnection?.HubUrl}` 直链线上
// proxy init API
app.post('*', async (req, res) => {
try {
const v = await axios.post('https://chat.newegg.com' + req.url, req.body, {
headers: {
"cookie": "NID=725z2Q2Q0M72721j9D; NVTC=248326808.0001.febfd2a17.1672812596.1673491265.1673493057.6; NV_NVTCTIMESTAMP=1673493330"
}
})
res.send(v.data)
} catch (error) {
console.log('error => ', error);
res.send(error.info)
}
})
// proxy ws
app.use("/onlinechatservice/connection/chatwithbot",
createProxyMiddleware({
target: 'https://chat.newegg.com',
changeOrigin: true,
ws:true,
})
);
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})