阅读视图

发现新文章,点击刷新页面。
☑️ ⭐

善用 MVP 思维,5 天时间零成本搭建小报童排行榜

前言

你好,我是小柒。
Java 程序员,热衷自动化。

前段时间花了 5 天左右,借助 Notion + CloudFlare + Github Actions 零成本搭建了一个支持一键分销的小报童排行榜: https://xiaobot.osguider.com。在这里复盘一下过程,希望能够对你有所启发。

善用 MVP 思维,用最小的成本最快地实现最核心的功能,尽早触达用户,尽早获取反馈,不断迭代,不断升级。

什么是小报童排行榜?

小报童排行榜是一个罗列了(几乎)所有小报童专栏的导航网页。可以帮助你一键分销所有小报童专栏

小报童排行榜-最近更新专栏

为什么要做小报童排行榜?

  • 主要是因为小报童官方没有公开的专栏索引列表,但这个痛点确实是在的。既然有需求未被实现,机会不就来了?
  • 实现足够简单,成本足够低,做这个游刃有余。
  • 折腾副业,没自己的产品始终感觉没底气。所以,小报童排行榜可以是我的产品支撑,也可以是我向外链接的突破口。
  • 能给我带来收益:哪怕是最基础的小报童分销,也能带来一些收益。且不说后面依据这个产品的放大升级。

小报童排行榜给我带来了什么?

  • 我能做成一件事的信心
  • 和我一起做事的朋友
  • 借助小报童排行榜,链接到了更多朋友
  • 副业生态的起点
  • 一点点小钱

一些有趣的统计数据

  • 迄今为止我收录了 308 位作者的 403 个小报童专栏。其中:
    • 有 26 位作者的 38 个专栏订阅数量超过 3000,占比 9%。只要订阅数量超过 3000 就能跻身前 10%。
    • 有 50 位作者的 72 个专栏订阅数量在 1000 和 3000 之间,占比 18%。只要订阅数量超过 1000 就能跻身前 30%。
    • 有 97 位作者的 105 个专栏超过 1 年没有更新,算是已完结的状态。有人入场,有人离场。机会、永远都在那里等你,剩下的、就是你能否主动抓住它了。
    • 15 亿国人,你的竞争对手只有 308 位。其实只要开始,就已经是成功了。
  • 有很多数据不太好看的专栏(订阅数量为 0),其中绝大部分是订阅制而非买断式。因为小报童展示的订阅数=当前仍在订阅状态的用户数,当用户订阅到期不再续订时,这个数量就会减少。所以单从数据好看的角度考虑,买断式的专栏会更好一点。
  • 上线至今,小报童排行榜分销佣金收入 371.61 元,给朋友们定制一键分销系统(扣除返现后)收入 210 元。对于在互联网上流浪多年的我和 Huazi,这个正反馈极佳

我把手上已有的小报童专栏排名数据整理成了一个 Excel 表格,如果你想要自己做一些数据分析,可以通过 osguider 微信我领取。

搭建一个小报童排行榜,可以有多简单?

按照我以往程序员的思维,如果想要做一个小报童排行榜,至少要经历以下步骤:

  • 需求分析
  • 概要设计
  • 数据库设计
  • 爬虫&业务代码编写
  • 前端代码编写
  • 部署上线

带着完美主义的思维,最后可能是因为设计配色不满意、可能是因为前端代码没写好,也可能是爬虫做不出来……从而不了了之,前功尽弃。

这件事情,真的需要这么复杂吗?

需求分析

需求分析需要考虑两个层面:我想做什么?我能做什么?其中:

我想做的事情很简单:把所有小报童专栏汇聚到一个网页,供用户查阅和订阅。
我能做什么主要取决于我能从小报童官方拿到什么样的信息。经过简单的分析,我可以从小报童官方获取到以下信息:

  • 专栏名称
  • 专栏作者
  • 专栏介绍
  • 专栏订阅数量
  • 专栏内容数量
  • 专栏价格
  • 专栏分销比例
  • 专栏分销链接
  • 专栏创建时间
  • 专栏更新时间

小报童排行榜的核心功能是列举出所有的小报童专栏信息,Notion 数据库可以完美实现这个功能!说干就干!

数据库搭建

按照可以从小报童官方获取到的信息搭建 Notion 数据库,这个过程就像是给 Excel 添加多个列字段,非常简单。
这里不再赘述 Notion 的使用,如果你对 Notion 感兴趣,可以通过这几个链接学习。中文用户指南 | Notion Academy | Notion Help Center

一条 Notion 数据库记录长这个样子:

notion数据库记录-生财有术

汇总的列表长这个样子:

notion database-table-小报童专栏


Notion 极其强大!支持任意的页面嵌套,支持把任意页面发布为公网可以访问的网页,甚至可以给同一个数据库定制不同的视图!
那么依据这个功能,我们实际上已经完成了最简单的 MVP:手动收集小报童专栏信息,并通过 Notion 展示。

小报童排行榜的第一个 MVP 长这个样子:

小报童排行榜 Notion Site

数据爬取

作为一个程序员、作为一名 RPA 教练,手动录数据多少有点说不过去了吧?

我们来看几个小报童专栏分销链接:

  • 生财有术项目精选:https://xiaobot.net/p/shengcaiyoushu?refer=6f4ecc2b-70e9-4f58-82de-71e5b1f357ee
  • IP合伙人·八年成事(百问百答):https://xiaobot.net/p/IP10?refer=6f4ecc2b-70e9-4f58-82de-71e5b1f357ee

稍加比较就能发现,分销链接由以下几个部分组成:

  • 域名:https://xiaobot.net/
  • 小报童专栏 ID: shengcaiyoushu / IP10
  • 分销标识:refer=6f4ecc2b-70e9-4f58-82de-71e5b1f357ee

其中:域名是不变的,分销标识只跟发起分销的用户有关系,所以在收集专栏信息的时候,我们只需要收集小报童专栏 ID 即可。这一个步骤,现在确实是手动收集和录入的。
但在这之后,我们可以通过拼接域名和小报童专栏 ID 得到指定小报童专栏的页面地址。访问专栏页面,可以获取到我们需要的几乎所有信息,通过 RPA/写代码 手段轻松获取(这里我的方案是通过 CloudFlare Workers 调用小报童接口获取数据,再使用 Notion API 写入数据库)。
请适当控制 RPA 运行频率,保护服务器负载。

小报童专栏主页-生财有术项目精选

到这里,内容的自动爬取和更新也搞定了。

页面编写 & 自动发布

Notion 也有缺点。毕竟是海外的产品,国内访问速度非常不稳定,根据我自己的测试,Notion Site 在极端情况下需要 10-20 秒才能加载出来,这个速度用户肯定是无法忍受的。在我的认知体系内,写一个静态页面是比较好的解决方案。

在看过我自己写的丑得不能再丑的 HTML Table 之后,我的设计师伙伴 @Huazi 终于还是忍不住亲自上场了。他负责页面样式,我负责内容填充,完美配合。

技术选型大概是这样的:

  • 页面样式:HTML + CSS + JavaScript + Tailwind CSS
  • 内容渲染:通过 JavaScript 脚本调用 Notion API 获取数据,再使用 eleventy 把数据渲染到 HTML。
  • 自动化:通过 Github Actions 每天定时执行内容渲染逻辑,然后自动发布网页到服务器。

至此,第二版小报童排行榜问世:小报童排行榜

小报童排行榜-最近更新专栏

赋能

前面的小报童排行榜只能帮助我自己分销所有小报童专栏,分销佣金也只能我自己拿,怎么让别人愿意帮我推广小报童排行榜呢?最简单的方法当然是让利!
通过给别人定制一键分销网页,页面里所有小报童专栏全部改成别人的分销链接。这样别人也可以通过自己的一键分销网页分销小报童专栏获取收益,我收取一定的技术维护费用,各取所需,各享其利。

实现也很简单,增加一个 Notion 数据库记录分销商信息:

Notion数据库-分销商

通过 Cloudflare Workers 读取 Notion 分销商数据库信息,然后通过 eleventy 渲染子页面并发布即可。这里有几个一键分销页面,可供参考:

  • https://xiaobot.osguider.com/osguider/
  • https://xiaobot.osguider.com/HeyHuazi/
  • https://xiaobot.osguider.com/76718400/
  • https://xiaobot.osguider.com/whyvincent/
  • https://xiaobot.osguider.com/Help000000/
  • https://xiaobot.osguider.com/fxm99960/
  • https://xiaobot.osguider.com/LSL021102/
  • https://xiaobot.osguider.com/yzhm111/
  • https://xiaobot.osguider.com/baojie_xmg/
  • https://xiaobot.osguider.com/liuliuzaish/
  • https://xiaobot.osguider.com/yi25390/
  • https://xiaobot.osguider.com/HX1747023971/
  • https://xiaobot.osguider.com/595683079/
  • https://xiaobot.osguider.com/1738407610/

未来的计划

  • 表单提交自动收录:小报童专栏作者填写金数据表单,cloudflare workers 自动爬取专栏信息并收录到 Notion 数据库。
  • 表单提交自动生成一键分销链接:想要构建一键分销系统的朋友填写金数据表单,cloudflare workers 自动构建一键分销页面。
  • 知识星球绑定销售:做一个知识星球强化个人 IP,小报童排行榜作为赠品而不是单独销售。这样可以把认可产品的朋友带入到我的 IP 圈,逐渐影响,让他们认可我这个人,进而创造更多合作的机会。

后话

当然,现在的小报童排行榜并不完美。
比如现在还不支持分页,比如现在只能用 Ctrl + F 做检索,比如不支持用户自定义要分销的专栏列表。
如果你也觉得有些不爽的地方,欢迎找我聊聊,万分感激。

致谢

感谢我的队友 @Huazi,没有他,小报童排行榜不会如此美观,不会如此受人欢迎。

关于我

重新认识一下。
你好,我是小柒,微信 osguider
Java 程序员,热衷自动化。生财有术 RPA 航海教练(23 年 12 月)。


小报童排行榜 作者,支持一键分销所有小报童专栏,也可以给你定制专属分销链接,欢迎体验。


开源服务指南主理人,依托 Notion 搭建了完整的自动化工作流和图文生成体系,这个后面也会写复盘。

目前实现了:

  • 每天自动从 Github 爬取开源项目信息
  • 自动调用 ChatGPT 开源项目简介
  • 手动审核 ChatGPT 生成的简介并标记审核状态
  • 借助 Pipedream 和 Notion 把已审核的开源项目自动汇总成 Markdown 格式的文章
  • 借助 mdnice 把 Markdown 文章自动转为微信公众号图文
  • 手动分发(等后面抽出时间这里可以用 Automa 做自动分发)

了解开源服务指南:

  • 官网
  • 微信公众号:开源服务指南

做过一个不起眼的导航网站:看见导航 收藏了很多我见过且觉得值得推荐的网页和工具,可能会对你有所帮助。


写过一写 Java 开发工具的使用经验:Intellij IDEA 最佳实践


也欢迎访问我的个人博客:Seven’s blog


🔲 ⭐

开源服务指南博客文章自动生成

  1. GitHub Actions 可以添加运行参数。我只需要设置 filepath 和 content 两个参数,然后配合 shell 脚本就可以自动生成和提交博文到 GitHub 仓库,进而触发自动构建和发布。

  2. GitHub Actions 提供了 REST API 来触发前面的工作流,这样我就可以通过 HTTP 请求来自动生成和发布博文。

  3. 开源服务指南数据库现在是建立在 Notion 上的,Notion 也提供了 REST API 的交互方式。所以我只需要定时扫描 Notion 数据库,获取状态刚变更为 “已发布” 的博文,提取文章内容,通过第 2 步中提到的 REST API 来触发第 1 步中提到的 GitHub Actions 即可自动生成和发布博文。这里我使用了 Cloudflare Workers 实现。

  4. 怎么监测 Notion 数据库文章状态变动呢?想要监测状态“变动”,我们需要知道变动前的状态和变动后的状态,进而需要有数据库缓存变动前的状态,能做,但麻烦。所幸,pipedream 帮我们做好了这个事情。它能够监测 Notion 数据库变动,并且触发工作流执行。


所以,最后的工作流程就是:

  • Pipedream 监测开源服务指南 Notion 文章数据库变动,提取状态为“已完成”的文章,把文章 id 通过 HTTP 请求发送给 Cloudflare Workers;
  • Cloudflare Workers 根据文章 id 查询文章内容,把文章路径和文章内容作为参数,发送请求给 Github Actions;
  • Github Actions 把文章内容写入文章路径,提交文章源文件到 Github 仓库;
  • Github Actions 监听代码提交,持续集成和发版;

嗯,云服务挺好用。

置于为什么不直接用 Pipedream 提取参数触发 Github Actions 工作流,个人主观意愿影响比较多:Pipedream 代码编写体验略差,稳定性欠佳,所以在逐步往 Cloudflare Workers 迁移。这个回头细讲。


附录:

  • Github Actions 文档
  • Cloudflare Workers 文档
  • Pipedream 文档
  • 第 1 步中提到的 Github Actions 代码:
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
name: Create Post

on:
workflow_dispatch:
inputs:
path:
description: 'File path'
required: true
content:
description: 'File content'
required: true

permissions:
contents: write

jobs:
create-file:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Create Post
run: |
cat << EOF > ./content/post/${{ github.event.inputs.path }}
${{ github.event.inputs.content }}
EOF

- name: Commit and push changes
run: |
git config user.name "username"
git config user.email "email@osguider.com"
git add ./content/post/${{ github.event.inputs.path }}
git commit -m "add post: ${{ github.event.inputs.path }}"
git push
  • 第 2 步中提到的 HTTP 请求:
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
import axios from 'axios';

const filePath = 'daily/daily-01.md';
const fileContent = 'Hello World';

const owner = "osguider";
const repo = "blog";
const workflow_file = "create-post.yml";
const url = `https://api.github.com/repos/${owner}/${repo}/actions/workflows/${workflow_file}/dispatches`;
const headers = {
'Authorization': `Bearer ${process.env.GITHUB_REPO_PAT_BLOG}`,
'Accept': 'application/vnd.github.v3+json',
'Content-Type': 'application/json'
};
const data = {
'ref': 'main',
'inputs': {
path: filePath;
content: fileContent;
},
};

axios.post(url,
data,
{ headers: headers })
.then((response) => {
console.log('GitHub Action dispatched successfully!');
})
.catch((error) => {
// TODO 错误通知
console.log(`Failed to dispatch GitHub Action: ${error}`);
});
☑️ ⭐

MySQL 数据库数据同步方案调研

名词

  • CDC(Change Data Capture): 数据变化捕获
  • ETL(Extract Transform Load):数据提取、转换、载入

工具

特色Canalmysql_streamergo-mysql-transferMaxwellDatabusDataX
开源方阿里巴巴Yelp-zendeskLinkedIn阿里巴巴
开发语言JavaPythonGolangJavaJavaJava
活跃
高可用支持支持支持-支持-
文档详细还行详细详细详细还行
数据源MysqlMysqlMysqlMysqlMysql
Oracle
MySQL
Oracle
OceanBase
SQLServer
PostgreSQL
DRDS
ALL_RDBMS
ODPS
OSS
OTS
Hbase0.94
Hbase1.1
Phoenix4.x
Phoenix5.x
MongoDB
Hive
Cassandra
TxtFile
FTP
HDFS
TSDB
TDengine
OpenTSDB
接收端编码定制Kafka等(MQ)Redis
MongoDB
Elasticsearch
RabbitMQ
Kafka
RocketMQ
HTTP API
后续支持更多
stdout
Kafka
Kinesis
Nats
Google Cloud Pub/Sub
Google Cloud Bigquery
RabbitMQ
Redis
SNS
编码定制?MySQL
Oracle
OceanBase
SQLServer
PostgreSQL
DRDS
ALL_RDBMS
ODPS
OSS
OTS
Hbase0.94
Hbase1.1
Phoenix4.x
Phoenix5.x
MongoDB
Hive
Cassandra
TxtFile
FTP
HDFS
TSDB
TDengine
ADS
OCS
Elasticsearch
全量数据初始化不支持支持支持支持(maxwell-bootstrap)-支持
数据格式编码定制Json(固定格式)Json(规则配置)
模板语法
Lua脚本
Json (固定)编码定制?-
备注需要写代码定制接受端可扩展性更强,但是上手难度更高数据同步非实时
实际使用配合 datax-web 体验更佳

alibaba/canal | 文档 | Docker

基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费。

canal-work-flow

由Java开发,分为服务端和客户端,拥有众多的衍生应用,性能稳定,功能强大;canal 需要自己编写客户端来消费canal解析到的数据。

Yelp/mysql_streamer | 文档

wj596/go-mysql-transfer | 文档

zendesk/maxwell | 官网 | 文档

linkedin/databus | 文档

Databus是一种低延迟变化捕获系统,已成为LinkedIn数据处理管道不可或缺的一部分。Databus解决了可靠捕获,流动和处理主要数据更改的基本要求。Databus提供以下功能:

源与消费者之间的隔离
保证按顺序和至少一次交付具有高可用性
从更改流中的任意时间点开始消耗,包括整个数据的完全引导功能。
分区消费
源一致性保存

上手难度较高。

alibaba/DataX | 简介 | WeiYe-Jing/datax-web | qlangtech/tis

DataX 是阿里云 DataWorks数据集成 的开源版本,在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS 等各种异构数据源之间高效的数据同步功能。

配合 DataX-Web 可视化配置任务。

osheroff/mysql-binlog-connector-java | Maven

在 Java 中消费 Mysql Binlog。

参考文档

  • MySQL数据 实时同步到Kafka –Binlog canal、Maxwell、Kafka Connect 实现MySQL增量同步
  • 实时数仓 | mysql的binlog实时同步工具对比
🔲 ⭐

IC卡、ID卡、CPU卡、RFID 和 NFC 的区别与联系

RFID 卡

是指非接触式类电子卡片/标签,包括有ID卡、IC卡和NFC卡以及其它等电子卡/标签。他们主要的区别在于工作频段。

NFC

NFC,全称是Near Field Communication,“近距离无线通信”,NFC本质信息双向交换。

NFC和RFID都是基于位置相近的两个物体之间的信号传输,NFC技术增加了点对点(P2P)通信功能,NFC设备彼此寻找对方并建立通信连接。P2P通信的双方设备是对等的,而RFID通信的双方设备是主从关系。

NFC 的工作频率是 13.56Mhz,所以只能读取和模拟 13.56Mhz 的 IC 卡。

ID 卡

全称身份识别卡(Identification Card),低频(频率有125Khz、250 Khz、375 Khz、500 Khz等)。
只能读卡,不可写入、不可存储、不可加密的感应卡,(卡面)含固定的编号,出厂时固化了ID。

  • 特点

    卡面上有 10 位或者 8 位数字(卡号)。

  • 安全性

    安全性较低,ID 卡不可存储,所以卡片持有者的权限、功能操作要完全依赖于网络系统。
    很容易复制

  • 应用

    门禁系统、企业工牌

IC 卡

全称集成电路卡(Integrated Circuit Card),也称智能卡(Smart Card)。
可读写数据、容量大、有加密功能、数据记录可靠、使用更方便,如一卡通系统、消费系统等。

  • 网络依赖性

    IC 卡可记录用户资料,可脱离网络使用

  • 安全性

    IC 卡的加密和反复读些的特性,使其安全性远大于 ID 卡

  • 应用

    门禁卡、地铁、校园一卡通。
    二代身份证属于 type B 射频 IC 卡

CPU 卡

如果不强调的话CPU卡也是IC卡的一种,是高级版的IC卡,CPU卡有信息处理的功能,优点是存储空间大、读取速度快、支持一卡多用功能等特点 。如果不强调无线的话,电话卡中SIM卡就是典型的CPU卡。

  • 安全性

    CPU卡内含有随机数发生器,硬件加密算法等,配合芯片上的OS系统,达到金融级的安全级别,防止重复卡、仿制卡、卡上数据非法修改

  • 应用

    金融、保险、交警、政府行业等多个领域,小额支付行业
    SIM 卡

参考资料

  • IC卡、ID卡、CPU卡、RFID和NFC的区别
  • ID / IC 卡基本原理介绍与门禁卡 DIY
☑️ ⭐

月刊-202310

开发技巧

  • 如何在chrome中实时修改JS 给目标网站持久化注入 JS 脚本
  • MySQL 参考资料 一份还不错的 MySQL 参考资料
  • UI Events JS 中的事件调度和 DOM 事件流程
  • JavaScript 事件顺序 JS 中的事件调度顺序
  • 选择(Selection)和范围(Range) 选择(Selection)和范围(Range)
  • 防抖与节流 防抖与节流
  • The Open Graph protocol Open Graph 协议,使任何网页都能成为社交图谱中的富文本对象。

看世界

  • vitorpamplona/amethyst Android Client for nostr
  • Never write a commit message again (with the help of GPT-3) 使用 GPT-3 生成 git commit message
  • BlinkDL/ChatRWKV AI 聊天软件 ChatGPT 的一个开源替代品,家用电脑就能跑。
  • sun0day/dns-detector 一个基于 Node.js 的命令行工具,从 DNS 服务器获取某个网站的所有 IP 地址,逐一进行延迟测试。
  • nackily/imglib 轻量级的 JAVA 图像处理库
  • Podman Desktop 一个跨平台桌面应用,可以使用图形界面进行 Docker 容器管理。
  • liuxiaojun666/ID-Photo-miniapp-wechart 一款开源的证件照制作小程序
  • huajian-pro/resume-design 开源免费的简历制作应用
  • Open Source Alternatives 企业日常运营工具的开源替代方案
  • Meta360笔记 内容丰富的笔记
  • 10分钟云部署Stable Diffusion
  • Figma-Linux/figma-linux-font-helper 适用于 Linux 操作系统的非官方 Figma Helper 客户端,可以让你尽情使用本地字体

人工智能

  • yzfly/LangGPT 可以更好地使用 GPT 的 Prompt
☑️ ⭐

待办清单:化被动主动

我有一个天赋,脑海时常能蹦出来许许多多的奇思妙想,如漫天星海,美妙无穷。
我有一个烦恼,思维总是会迷失在纵横交错的巨大迷宫,似瀚海孤舟,无所适从。


我把事情装在脑子里,经常需要冥思苦想:

  • 接下来要做哪件事?
  • 我是不是忘记了哪件事?
  • 我今天到底做了什么事?

这些思虑,既消耗能量,也消耗情绪。效率大打折扣,精神苦不堪言。

我经常会这样否定自己:忙时碌碌无为,闲时无所事事

碌碌无为:是记不得自己一整天到底忙完了什么事情;
无所事事:是想不起自己接下来还有什么事情没有做。


昨天实践了一下屡次被我捡起,又屡次被我忘记的方法:待办清单

不过是花费几分钟把事情从脑子里搬出来,写入到待办清单。生活便发生了天翻地覆的变化:

我从被动地等待事情从脑子里蹦出来,变换为主动地把待办事项从清单中挑出来。

我可以清晰地知道自己还有什么事情没做
可以自由地给它们安排优先级和处理时间
我可以轻松地回顾自己在什么时间做了什么事情

对生活的掌控感、对已完成的任务的自豪感、对未来事项能够按时完成的自信感……油然而生。

放过大脑,让它专注于解决问题,而非不断选择。
武装自己,让我们主动安排,而非被动浮沉。


番外:

几乎我所有富有创造力的想法,都是在上下班路上、吃饭时突然迸发出来的。
所以,停下来,给自己一点放松的时间,也能有事半功倍的效果。
​(And,不要骂我,为什么把上下班路上和吃饭称为放松时间。)

🔲 ⭐

裹挟

江河湖泊,
每一滴水都在往前走,
但它们决定不了自己的流向。

或许,
我们不应该一直低头猛冲。

偶尔抬头看看天,
看能否厚积薄发,升华自我,
变成一片云。

只是,
被风裹挟着的云,
和被河裹挟着的水,
又有什么区别呢?

🔲 ⭐

月刊-202208

拓认知

  • 学习,没有捷径

开发资源

  • CompVis/stable-diffusion

    根据文字描述生成精美图片。

  • megaease/easegress

    全功能型的流量调度和编排系统。官网 | 文档

  • alibaba/DataX

    支持超多数据库的离线数据同步工具。

  • gerrit

    code review 工具

  • 3D 白模生成 blender + 插件 domlysz/BlenderGIS

  • 前端学习资料

    • 入门:https://www.freecodecamp.org
    • 补充:https://scrimba.com/learn/frontend
    • JavaScript: https://zh.javascript.info
    • MDN: https://developer.mozilla.org/en-US
    • Vue: https://vuejs.org
    • React: https://reactjs.org or https://beta.reactjs.org
    • ES6 Standard: https://www.ecma-international.org/publications-and-standards/standards/ecma-262/
  • CSS 库

    • 50projects50days
      50 个 web 小 demo,用来学习再好不过了
    • 30-seconds/30-seconds-of-css
      一些 css 代码片段,可以拿来学习练手
    • Tailwind CSS
      一个功能类优先的 CSS 框架
    • animate.css
      css 动效库
    • normalize.css
      让你的 HTML 默认样式保持跨浏览器的一致性
    • bulma
      基于 Flexbox 的现代化响应式 css 框架
    • IanLunn/Hover
      给你的网站添加 hover 动效
    • tobiasahlin/SpinKit
      有趣的页面加载动效
  • 商城系统

    • wei-it/weiit-saas
      weiit-saas是一款Java开源项目,属于weiit团队自研产品,意在通过技术封装,让企业无需代码开发,帮助企业一键生成小程序、公众号,让企业拥有独立品牌的自营商城。
    • fuint会员营销系统
      一款实体店铺会员管理和营销系统。
    • 开店星开源小程序商城
    • Lilishop B2B2C商城系统
    • 免费开源的B2B2C商城系统

看世界

  • 10 个你没见过的 GitHub 的高效开源神器,YYDS!
  • 盘点 7 个神级笔记开源应用!
  • craiyon 根据文本描述生成图片
🔲 ⭐

免费申请 JetBrains 全家桶开源授权

JetBrains 开源授权

JetBrains 针对部分群体推出了一系列特惠计划,其中包括 开源开发许可证。通过开源开发许可证,我们可以免费使用 JetBrains 旗下几乎所有开发工具。
本文讲述了如何申请 JetBrains开源开发许可证

申请条件

jetbrains-open-source-license-condition

总结一下:

  • 条件:

    • 项目符合 开源 定义
    • 开源项目正在积极开发且最近三个月内有更新
    • 申请人是这个开源项目的项目所有者或主要贡献者,提交申请时所填写的邮箱要和项目贡献人的邮箱以及 Github Profile 邮箱保持一致(申请期间 Github Profile 页面的邮箱不能隐藏,工作人员需要通过这个邮箱复核申请者的身份)
    • 不提供开源项目的付费版本,也不提供与该开源项目相关的任何付费服务(比如付费支持、咨询等)
    • 开源项目未获得商业公司或组织(NGO、教育、研究或政府组织)的资助
    • 不为项目的核心开发者支付工资
    • 鼓励开源项目提供社区标准文档,比如在 README 文件中提供 项目描述、行为准则贡献指南
    • 暂时对项目质量没有要求
  • 限制

    • 许可证仅提供给项目负责人和核心项目提交者
    • 许可证有效期为一年,如果一年后这个项目仍符合申请条件,可以继续申请
    • 免费许可证只能用于开发非商业开源项目
    • 不能与任何第三方共享许可证

申请过程

打开 JetBrains 开源开发许可证申请页面 Request for Open Source Development License 并填写申请资料:

intellij-open-source-license-request-new-customer

有以下几点作特别说明:

  1. Do we Know you?
    申请新的授权或者延续之前已经申请过的授权,如实填写即可;
  2. Tell us about your project
    • Project website: 如果项目有独立主页,填写项目主页地址;如无,填写同 Repository URL 即可;
    • License URL: 如有,填写项目开源协议地址;如无,在 Github 项目主页点击 “Add file” -> “Create new file”,文件名写 “LICENSE”,页面右侧会自动出现 LICENSE 选择提示,选择并添加适合自己的开源协议即可;
    • No. of required licenses: 表示要申请的开源开发许可证数量,数量需小于或者等于项目活跃核心开发者数量;
  3. Tell us about youself
    • Email address: 这里所填写的邮箱要和项目贡献人的邮箱以及 Github Profile 邮箱保持一致(申请期间 Github Profile 页面的邮箱不能隐藏,工作人员需要通过这个邮箱复核申请者的身份)

资料填写完成后提交申请,会跳转到如下页面:

intellij-open-source-license-request-confirmation

同时,我们会收到一封邮件,告诉我们 JetBrains 已经收到了刚刚提交的申请,团队大概会在一周内审查我们的开源项目。

intellij-license-request-notice

耐心等待几天,JetBrains 会在审查完成之后发送另一封邮件。告知我们申请已通过审批并指引我们领取 License,或者告知你拒绝审批的原因

intellij-license-request-result

如果审批通过,可以点击邮件中的 “Take me to my license(s)” 链接,将 Licenses 绑定到对应的帐号。


至此,我们已经免费拿到了 JetBrains 的开源开发许可证,许可证有效期一年,届时可视官方政策继续申请。

If you find that JetBrains software has been useful for your project, please consider mentioning JetBrains support on your project’s homepage. Feel free to use the JetBrains logo and a link to our website such as https://jb.gg/OpenSourceSupport.

参考文档

  • 免费申请和使用IntelliJ IDEA商业版License指南
☑️ ⭐

学习笔记-专利写作第一课

why-how-what

找到 KeyPerson 利益点,提高专利通过率

专利申请流程全景图

好专利的四个标准

  • 创新性:人无我有,人有我优;
  • 侵权认定:公开(专利内容)换取独占(20年),需要用公开的内容判定他人是否侵权;
  • 市场价值:
    • 以量取胜,专利需要在某个领域积累一定的数量。才能够在这个领域形成威慑力;
    • 聚焦业务,专利需要和公司核心业务相关;
    • 专利内容最好和实体设备相关(方便计算侵权价值);
  • 不可替代性:需要考虑别人是否有可能通过优化绕过我们的专利;

高通过率的专利申请策略

核心角色:业务部门老大、法务代表

业务部门老大:这个专利和我们部门有什么关系?
公司法务代表:公司核心业务 >= 未来发展方向 >= 发明人所在的部门的技术方向

专利发明人选题策略:本职工作相关 >= 公司核心业务 >= 公司未来方向

撰写专利交底书

  • 对创意进行足够的抽象,才能覆盖更多的范围(比如手机闹钟,可以抽象成一种提醒服务);
  • 将概念中的逻辑结构进行标准化论述和概念明确;

专利交底书、专利文书和内部审批流程的关系:
专利交底书、专利文书和内部审批流程的关系

  • 名: 核心成员应该是第一、第二、第三发明人之一;

  • 利: 必须俺劳分配,切忌平均。核心成员 80%;

  • 专利不一定要应用在现有业务中,也可以是未来的布局;

  • 发明专利的前因:从因果论的角度出发,分析行业现有技术的发展情况、普及相关知识、发现不足,提出创新方案;

  • 名称、关键词以及解释

    • 将专利的核心理念进行具象描述,力求把专利讲清楚;
    • 用一句话来概括这个发明,无论多长,只用一句话来组织;
    • 提取这句话中的关键名词或者动名词,去除所有的无关词汇,得到关键词。如果有些关键词是不常见的技术属于,就补充相关解释;
  • 现有技术方案:用来解释相对生辟的技术,也可以不写;

  • 现有技术的不足以及创新解决思路:这一部分非常关键,是专利中说明书的主要部分,代理要写得很清楚,知识产权局需要看;

  • 发明创意的后果:核心思路和示意图。前者是抽象的概念和方法,后者是据悉那个的可行性方案。

    • 核心思路和示意图
      • 用语言来描述核心思路,并配上效果图
      • 用流程图和示意图来表达

    专利,应该是一个常见功能的简化和抽象,需要屏蔽功能设计时和工程化时要考虑到的各种极限情况,把本次创意中最核心的环节表达出来。

  • 其他替代方案:系统化地描述更多可能性

    • 不要被参数限制,要更多地描述创意本身
    • 不要通过“和”限制,要通过“或”来扩大
    • 合理扩展各种可能性,提高保护范围

专利示例

  • 预设光标样式与用户输入文本样式保持一致(来源:参考了 PS 的实现,把专利从图形迁移到文本)
  • 滑动解锁
  • 提醒用户节假日关闭闹钟

QA

怎么查询专利是否已经被申请了

  • 伯腾网 国内、WIPO 联合国知识产权、欧美专利
  • Google 专利 国外专利
  • 国家知识产权局 国内专利,最权威、最新
🔲 ⭐

使用 git 备份和恢复 dotfiles

前言

Unix 用户的配置文件一般存储在以 . 开头的文件中,这些文件被统称为 “dotfiles”。

本文讲述了一种极其优雅的通过 git 备份和恢复 dotfiles 的方法。

备份

  1. 初始化 git 仓库

    1
    2
    3
    4
    5
    6
    # 初始化 git 仓库
    git init --bare $HOME/.dotfiles
    # 指定 git 仓库和工作树路径并创建指令别名,简化操作
    cp -a .bashrc{,.bak} && echo "alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'" >> .bashrc && source .bashrc
    # git status 不显示未跟踪的文件
    dotfiles config status.showUntrackedFiles no
  2. 创建远程仓库,比如 git@github.com/seven/dotfiles

  3. 添加文件

    1
    2
    3
    4
    dotfiles add .zshrc
    dotfiles commit -m "add .zshrc"
    dotfiles remote add origin ${git_repo}
    dotfiles push

恢复

1
2
3
4
5
6
7
8
9
10
# 把 dotfiles 克隆到本地临时目录
git clone --separate-git-dir=$HOME/.dotfiles ${git_repo} $HOME/dotfiles-tmp
# 用临时目录中的文件覆盖本地文件
cp $HOME/dotfiles-tmp/.* $HOME
# 删除临时目录
rm -r $HOME/dotfiles-tmp/
# 指定 git 仓库和工作树路径并创建指令别名,简化操作
cp -a .bashrc{,.bak} && echo "alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'" >> .bashrc && source .bashrc
# git status 不显示未跟踪的文件
dotfiles config status.showUntrackedFiles no

git 参数讲解

  • git init --bare ${path}

    Create a bare repository. If GIT_DIR environment is not set, it is set to the current working directory.

    ${path} 目录创建一个空的 git 仓库。

  • git --git-dir=${git_dir}

    Set the path to the repository (“.git” directory). This can also be controlled by setting the GIT_DIR environment variable. It can be an
    absolute path or relative path to current working directory.

    Specifying the location of the “.git” directory using this option (or GIT_DIR environment variable) turns off the repository discovery that
    tries to find a directory with “.git” subdirectory (which is how the repository and the top-level of the working tree are discovered), and
    tells Git that you are at the top level of the working tree. If you are not at the top-level directory of the working tree, you should tell
    Git where the top-level of the working tree is, with the –work-tree=${git_dir} option (or GIT_WORK_TREE environment variable)

    If you just want to run git as if it was started in ${git_dir} then use git -C ${git_dir}.

    指定 git 仓库的路径。

  • git --work-tree=${path}

    Set the path to the working tree. It can be an absolute path or a path relative to the current working directory. This can also be
    controlled by setting the GIT_WORK_TREE environment variable and the core.worktree configuration variable (see core.worktree in git-
    config(1) for a more detailed discussion).

    指定工作树的路径。

  • git clone --separate-git-dir=${git_dir}

    Instead of placing the cloned repository where it is supposed to be, place the cloned repository at the specified directory, then make a filesystem-agnostic Git symbolic link to there. The result is Git repository can be separated from working tree.

    把 git 仓库克隆到指定的目录 ${git_dir} 下,然后做一个与文件系统无关的 git 符号链接到该目录。从而使 git 仓库和工作树分离。

这里需要搞懂 git 的两个概念: “git 仓库” 和 “工作树”。
假设我们使用 git clone git@github.com/seven/dotfiles 把远程仓库克隆到了本地的 dotfiles 目录。dotfiles 目录就是“工作树”的路径,dotfiles/.git 目录就是 git 仓库的路径。

举一反三

  • 可以为不同的系统或者不同的电脑创建不同的分支
  • 可以通过灵活指定 git 仓库和工作树路径,达到备份其他文件的目的

参考文档

  • Hacker News
  • The best way to store your dotfiles: A bare Git repository
  • Dotfiles - ArchWiki
  • 用 Chezmoi 管理配置文件
☑️ ⭐

IntelliJ IDEA 最佳实践 - 精选插件

前言

IntelliJ IDEA 提供了强大的插件系统,并且有着完善的插件生态。

成千上万追求极致的开发者们为 IDEA 开发了不计其数的插件,可以极大程度地帮助开发者提升开发速度、代码质量、以及开发的舒适度等等。

本文收集了最受开发者喜欢的一些插件,罗列至此,希望能够对你有所帮助。

插件的安装和卸载章节被我放在了文章较后的位置,如果你需要查看这些内容,翻看文章后面的 安装卸载 章节即可。

精选插件

Rainbow Brackets

这款插件名为彩虹括号,可以帮助我们更好地匹配括号和定位代码块。
主要功能包括:

  • 使用不同颜色渲染多层嵌套的括号;
  • 通过高亮显示帮助我们更好地定位代码块(ctrl + 鼠标右键单击 触发);

idea-plugin-rainbow-brackets-highlines

相关资料

  • izhangzhihao/intellij-rainbow-brackets

AceJump

AceJump 插件可以让我们在脱离鼠标的情况下在代码编辑器的可视区域快速移动光标位置

idea-plugin-ace-jump

SequenceDiagram

SequenceDiagram 是一款代码时序图插件,可以帮助大家更好地梳理代码逻辑。
主要有以下功能:

  • 生成代码时序图;
  • 导出时序图;
  • 导出 PlantUML 文件;

idea-plugin-sequence-diagram

相关资料

  • Vanco/SequencePlugin
  • SequenceDiagram

SonarLint

SonarLint 是一款代码质量检查插件,主要功能包括:

  • 帮助我们发现和修复 bug;
  • 检查代码坏味道,并提供修复建议。

SonarLint 更侧重代码质量检查。

idea-plugin-sonar-lint-report

Alibaba Java Coding Guidelines

阿里巴巴代码规约插件,可以帮助我们养成良好的代码规范编程风格

插件有实时检测和主动检测两种模式,如果该插件导致 IDEA 卡顿,可以关闭实时检测功能,在必要时手动检测修复即可。

Alibaba Java Coding Guidelines 更侧重代码规范检查。

idea-plugin-alibaba-java-coding-guidelines

相关资料

  • alibaba/p3c

Alibaba Cloud Toolkit

Alibaba Cloud Toolkit 插件允许我们通过一系列的配置来制定代码的一键发布策略。
可以极大得简化代码发布流程。主要功能包括:

  • 管理服务器,快速上传文件、执行命令、连接服务器、查看服务器文件等;
  • 定制一键发布策略,完成一键发布功能;

插件植入了很多阿里云自己的产品,介意的话可以卸载这款插件。

idea-plugin-alibaba-cloud-toolkit-host-list

idea-plugin-alibaba-cloud-toolkit-deploy-to-host

Key Promoter X

Key Promoter X 是一款快捷键提示插件,如果你进行了可以使用快捷键但是并没有使用快捷键触发的操作,插件会自动在屏幕右下角提示可以使用哪些快捷键来触发同样的操作。

如果你觉得某个提示对你造成了打扰,也可以单独禁用指定快捷键的提示。

idea-plugin-key-promoter-x

Presentation Assistant

Presentation Assistant 是一款快捷键展示插件,适合在直播或者录屏的场景使用。
如果你触发了某一个操作(不管是不是使用快捷键触发的),这款插件都会在屏幕上展示你可以使用哪些快捷键触发同一操作,方便他人复现操作步骤。

idea-plugin-presentation-assistant

Grep Console

Grep Console 可以帮助我们更好地处理打印在 IDEA 控制台的日志,主要功能有:

  • 对打印出来的日志信息进行过滤和筛选(支持正则匹配);
  • 自定义不同等级日志的配色方案;
  • 快速定位异常日志位置;

Translation

Translation 是一款翻译插件,主要功能包括:

  • 直接在 IDEA 中进行中英互译;
  • 直接把中文文字替换为对应的英文变量名;

idea-plugin-translation-replace

Maven Helper

Maven Helper 可以帮助我们在 IDEA 中更好地开发 maven 项目,主要功能包括:

  • 更方便地执行 maven 命令;
  • 分析和排除 Maven 冲突;
  • 自定义 Maven goals;
  • 在当前 Module 所在的路径中打开 Terminal;

idea-plugin-maven-helper-menu

idea-plugin-maven-helper-dependencies-analyzer

MybatisX

MybatisX 插件可以让我们更方便地使用 Mybatis, 主要功能包括:

  • 关联 Mapper 文件和 xml 文件,并且支持快速跳转;
  • 代码提示;

MyBatis Log Plugin

Mybatis Log Plugin 可以把 Mybatis 的 log 替换成可执行的 SQL, 帮助我们更快更直观地进行代码调试工作。主要功能包括:

  • 还原 MyBatis 输出的日志为完整的 SQL 语句;
  • 把 SQL 日志里面的 ? 替换为真正的参数值;

idea-plugin-mybatis-log-plugin-log

相关资料

  • kookob/mybatis-log-plugin

Git Commit Template

这款插件为 IDEA 提供了版本控制工具 commit message 的模板,可以帮助我们规范 commit message 信息。

idea-plugin-git-commit-template

CodeGlance

Code Glance 插件会在编辑器右侧嵌入一个 Sublime 风格的代码缩略图,帮助我们快速定位代码。

如果你能熟练地使用快捷键,这款插件就没有多大的优势了。

IDEA Mind Map

IDEA Mind Map 插件允许我们在 IDEA 中绘制思维导图。

idea-plugin-idea-mind-map

安装

在线安装

  • 进入 IDEA 设置页面;
  • 点击 Plugins 进入插件设置面板;
  • 选择 “Marketplace”;
  • 在输入框填写自己想要安装的插件名称并回车搜索;
  • 在搜索结果中选中自己想要安装的具体插件;
  • 点击页面右侧插件详情页中的 “Install” 即可安装成功;
  • 安装完成之后,需要重启 IDEA 才能使插件生效。

idea-settings-plugins-install-online

离线安装

  • 首先在 JetBrains 插件市场 搜索并下载自己想要的插件;
  • 打开 IDEA,进入 插件设置 页面;
  • 点击 “Installed” 选项卡右侧的 “齿轮图标”,然后选择 “Install Plugins from Disk…“;
  • 选择自己刚才下载好的插件,确认安装即可;
  • 安装完成之后,需要重启 IDEA 才能使插件生效。

idea-settings-plugins-install-from-disk

卸载

  • 进入 IDEA 设置页面;
  • 点击 Plugins 进入插件设置面板;
  • 选择 “Installed” 进入已安装插件列表页;
  • 在输入框填写自己想要安装的插件名称并回车搜索;
  • 在搜索结果中选中自己想要卸载的具体插件;
  • 点击页面右侧插件详情页中的 “齿轮图标”, 然后选择 “**Uninstall…**” 即可卸载成功;
  • 卸载完成之后,需要重启 IDEA 才能使操作生效。

idea-settings-plugins-uninstall

后记

最近花了一周时间系统整理了 Intellij IDEA 的最佳实践,内容涵盖了 基础配置原生能力精选插件几个模块。

地址为: **idea.diqigan.cn**,相信会对你有所帮助。

如果你有更好的插件推荐,欢迎参与文档编写,或者直接与我联系。

☑️ ⭐

月刊-202012

优秀文章

  • 和软件开发相关的一些思考

    1. deadline 带来的生产力一定程度上是以牺牲质量为代价的;
    2. 在软件开发或者是学习过程中,需要不断地根据实际情况去调整计划。不要一刀切得使用固定的 ddl;
    3. 大多数开发者都会高估自己的开发速度,低估软件工程的复杂程度;
    4. 单一技术不能解决所有问题,争论某种技术最好并没有实际意义。关键是什么工具和技术更适合解决你现在的问题;
    5. 技术总归是要为人服务的,产品的出发点应该是“人”。“人”需要什么功能,什么技术更适合完成这个功能;
    6. 多和人沟通,了解不同人的想法、不同人思维的差异,可以让我们更容易地去接受这个世界存在着的不同,让我们更谦虚。
  • 给你一份时间管理秘籍

    无事心不空,有事心不乱,大事心不畏,小事心不慢。

    专注可以解决世上绝大多数问题,剩下的需要一点运气。

  • 合理合法地多赚钱

    关于金钱,说到底也是一种资源,这种资源和其他的资源没有太大区别,资源越多,你的自由度越大。

  • 说 6 点,关于高效学习

  • 这是个意外

    生活没有起承转合。

  • 影响王兴的一本书

    有限游戏在边界内玩,无限游戏却是在和边界,也就是和 “规则” 玩,探索改变边界本身。

    有限游戏是有明确的边界和目的,参与者的目的就是为了获取最后的胜利,结束游戏。

    无限游戏是持久的,创新的,建设性的,充满奇迹的,参与者的目标是为了继续玩这个游戏,无限博弈是一种开放的心态。

    无限是一个过程,有限是个瞬间。

  • 怎么才走到这一步的呢?

    面对复杂性、不确定性,计划是无法完美的,这是极限。但不断制定计划,并根据反馈修改计划,正是价值的来源。在这个过程中,锻炼出估算能力、对风险的敏感度、收集信息的方法论、控制平衡的艺术、对业务本质的思考、对因果逻辑的理解,才是胜出的关键。

工具

  • 奶牛快传

    不限速文件传输工具。

  • 推荐22款终端生产力工具,效率快到飞起!

    一个涵盖了多款优秀终端工具的清单。

  • DBeaver

    开源跨平台的数据库管理工具,支持多种数据库。

  • 开发过程中必不可少的5个开源工具

    介绍了几种 Linux 下比较好用的工具。

  • screenity

    一款开源免费的 Chrome 录屏插件。

  • 自选基金助手

    可以实时查看基金走势的 Chrome 浏览器插件。

  • PaddleHub

    无需深度学习背景、无需数据与训练过程的 AI 框架。

技术点

  • 听说你的资源被盗用了,那你知道 Nginx 怎么防盗链吗?
  • 解决Alpine缺少字体的问题
  • java 后台实现 WebSocket 客户端:
    • Spring-Boot快速集成WebSocket服务端 客户端(客户端消息同步回调)
    • SpringBoot+WebSocket实现服务端、客户端
  • Jenkins export and import jobs 迁移导出导入任务实践小结
  • Jenkins 配置秘钥时报错的原因以及解决方案

看世界

  • Tiffany色的集装箱

    一位选择在山上住集装箱房的姐姐,记录了自己的生活点滴。

  • Kaspersky Cyberthreat Map

    卡巴斯基做的全球网络攻击图,3D Map 做得很好。

  • 你脖子痛不痛?

    很多时候我们会认为意外永不来临,但改变总是突如其来,命运拿走你曾经拥有的东西,不会和你打一声招呼。

  • Google 搜索成最大入口,简单谈下个人博客的 SEO

    个人博客 SEO 简介。

☑️ ⭐

《寄生虫》观后感

电影信息

寄生虫 기생충 (2019)

寄生虫.png

电影简介

电影《寄生虫》讲述了一个韩国贫苦人家凭借机遇、能力和心机把自己一家四口安排到一个富贵人家工作,最后因被前帮佣一家发现而引起冲突并导致真相败露的故事。

观影感悟

寄生虫

为什么电影的名字会被命名为《寄生虫》呢?

其实,在我看来,人人都是寄生虫。

员工寄生于公司,家人寄生于家庭,人民寄生于国家……

这本无可厚非,社会本身就是互相依赖的。员工、家人、人民会为自己的公司、家庭、国家作出属于自己的贡献,公司、家庭、人民也常常因为员工、家人、人民的贡献而变得更好。这种寄生是良性、互利、可持续的。

那么电影中的“寄生虫”有什么特别呢?

他们越过了自己本应坚守的那条“线”,那条道德之线、善恶之线、职操之线。电影中朴社长也多次提到了逾越界线的问题。

设下计谋抢走了前司机和帮佣的工作,此为道德之线;为了隐瞒实情,禁锢甚至误杀了前帮佣,此为善恶之线;身为家教,却和自己的学生恋爱、身为司机,却屡屡谈及雇主家事、身为帮佣,却在雇主家中举办家庭聚会,此为职操之线。

基宇一家人本都是有能力之人,他们能很好地担任老师、司机、帮佣的工作。只是这些越线,使他们变得略加丑陋和可怜。

身上的味道

电影中也多次提及基宇一家人“身上的味道”,不同的人也有不同的猜测:香皂的味道?洗衣粉的味道?地下室的味道?挤地铁的人身上特有的味道?

在我看来,这是贫穷和阶级的味道。

不止是身体,我们的品行也是有“味道”的。

想要祛除这种味道,要提升生活品质,要提升自身能力,要扩展认知边界,要升华自身境界……

这很难,但好在不是不可能。

救赎

最后男主说:“我要努力赚钱。”并想像自己买下这栋房子之后的情景。

我想,对于他来说,这就是最大的救赎吧。

寄生在他人的屋檐之下,终究不如筑起属于自己的高楼大厦。

后记

为什么想写这篇观后感?

我出生在贫穷的小山村,对基宇一家的种种无奈颇有感触。我能嗅到有些人“身上的味道”,我也在找寻属于自己的救赎。

如果可以,我也希望所有人都能找到属于自己的救赎。

安得广厦千万间,大庇天下寒士俱欢颜。

☑️ ⭐

ARTS-14

Algorithm

832. 翻转图像

解法一

使用双层循环。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int[][] flipAndInvertImage(int[][] A) {
int[][] result = new int[A.length][A[0].length];
for (int i = 0; i < A.length; i++) {
int columnNumber = A[i].length;
for (int j = 0; j < A[i].length; j++) {
result[i][j] = A[i][columnNumber - j - 1] ^ 1;
}
}
return result;
}
}

执行用时:1ms,内存消耗:36.6MB。

解法二

减少内层循环次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int[][] flipAndInvertImage(int[][] A) {
int[][] result = new int[A.length][A[0].length];
int innerLoopTimes = (A[0].length + 1) / 2;
for (int i = 0; i < A.length; i++) {
int columnNumber = A[i].length;
for (int j = 0; j < innerLoopTimes; j++) {
result[i][j] = A[i][columnNumber - j - 1] ^ 1;
result[i][columnNumber - j - 1] = A[i][j] ^ 1;
}
}
return result;
}
}

执行用时:1ms,内存消耗:36.3MB。

解法三

尝试在原有数组上操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int[][] flipAndInvertImage(int[][] A) {
int columnNumber = A[0].length;
int innerLoopTimes = (columnNumber + 1) / 2;
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < innerLoopTimes; j++) {
int temp = A[i][j] ^ 1;
A[i][j] = A[i][columnNumber - j - 1] ^ 1;
A[i][columnNumber - j - 1] = temp;
}
}
return A;
}
}

执行用时:0ms,内存消耗:36.2MB。

Review

The Two Kinds of Moderate

文章阐述了两种截然不同的温和派:一种是自然的温和,他们本来的观点就是温和派;另一种是有意的温和,他们没有自己的观点,故意在极左和极右之间选择一个温和的观点。

这让我想到当今世界中的杠精。他们没有自己的观点,但是不管你的观点如何,他们总能找到你观点的对立面,然后对你进行无情的抨击。

极端点说,最可怕的事情不是你的观点被整个世界反对,而是一个人本身没有观点。很多时候,观点就是我们意识的载体。而意识,就是我们存在的证明。

对一件事没有观点,要么是自身没有灵魂,要么是认知落后。这才是比较可怕的事情。

Tip

普通索引和唯一索引

查询过程

  • 使用普通索引,查找到满足条件的第一个记录后不会停止。系统会查找下一个记录,直到碰到第一个不符合条件的记录才停止;
  • 使用唯一索引,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

因为 InnoDB 的数据是按照数据页为单位来读写的。所以“使用普通索引查找下一个记录”这个操作的消耗大概率是发生在内存中的,对性能的影响微乎其微。

所以单从查询性能来讲,普通索引和唯一索引差异不大。

更新过程

change buffer:当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式保证这个数据逻辑的正确性。

change buffer 实际上是可以持久化的数据,不仅在内存中有拷贝,也会被写入到磁盘上。将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge。除了访问数据页会触发 merge 外,系统有后台线程会定期 merge,在数据库正常关闭的过程中,也会执行 merge 操作。

索引,如果能够将更新操作先记录在 change buffer 中,减少读磁盘,语句的执行速度会得到明显的提升。

唯一索引的每次更新操作都需要先判断这个操作是否违反唯一性约束,那么对应的数据页会被读入到内存,所以没有必要使用 change buffer 了。

如果要更新的目标页在内存中,两者的执行效率相差无几。

如果要更新的目标页不在内存中:

  • 对于唯一索引来说,需要将数据页读入内存,判断唯一索引是否冲突,没有冲突的话插入记录,语句执行结束;
  • 对于普通索引来说,直接将更新记录在 change buffer 中,语句执行就结束了。

场景:对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。

Share

近些年来,少有事物能够做到人尽皆知。遗憾的是,新型冠状病毒做到了。

但是,除去病毒本身,它背后的人生百态更加耐人寻味。

轻视

一部分人的轻视导致疫情没有在最佳的时间得到控制,一部分人的轻视导致自己、家人甚至是陌生人惨受牵连。

未知的事物,我们应该怀抱敬畏之心。

人血馒头

消息一出,各大网店、药店的口罩瞬间脱销。有趣的是、当我从药店空手走出来的时候,有个人从后面追上来:“哥,要口罩吗?”黄牛的嗅觉,真是灵敏。

随后又爆出新闻,有一些不合格的口罩被售出。

还有更劲爆的消息,甚至还有人回收口罩想要二次销售。

良心这种东西,总是会被利益给吃掉。

利益

什么是对?什么是错?对于人类这种群居生物来说,多数人的利益就是对,少数人的利益就是错。

社会、人心、就是如此。

疫区的人想出去,是为了自己的利益;外面的人想隔离,也是为了自己的利益。想要追求自己的利益本没有错,错在自己的利益和大多数人冲突。

谣言

疫情一出,谣言四起。

始终想不明白造谣的人有何意图。三人成虎,很多人又特别喜欢相信这类谣言,进而推波助澜。

最可怕的事情莫过于,我以为我在做的错的事情是对的。

普通人

我们这样的普通人,最好能够做到不传谣、不信谣、不轻视。在一定程度上,不给他人添乱,也是一种善良。

倘有余力,努力提升自己对真实时态的认识,然后尽可能科普给更多人。

🔲 ⭐

ARTS-12

Algorithm

1295. 统计位数为偶数的数字

题解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int findNumbers(int[] nums) {
int count = 0;
for (int num : nums) {
int bits = 0;
do {
num = num / 10;
bits++;
} while (num != 0);

if (bits % 2 == 0) {
count++;
}
}

return count;
}
}

执行用时:1ms,内存消耗:38.7MB。

Review

Fashionable Problems

作者在许多不同的领域见到了相同的模式:尽管很多人在对应的领域内努力工作,但是仅仅只能探索了很小的一部分可能性,因为他们大都工作在相似的事情上。

即使是最聪明、最优想象力的人们,在决定要做什么时,他们也会出奇地保守。那些从未想象过以任何方式成为主流的人会陷入对主流问题的研究中。

如果你想尝试研究非主流问题,最好的方向之一是去看看哪些人们认为自己已经完全摸透了的领域:文章、演讲、风险投资等。你会在这儿发现一种模式:如果你可以在一个庞大但显然已经淘汰的领域中找到新方法,你发现的事物的价值都会乘以该领域已经覆盖的面积。

避免陷入和其他人做一样的事情的最好的方法是真诚地热爱你所做的事情。这样,即便犯了和其他人相同的错误,你也会认为这很重要并且能够坚持下去。

Tip

数据库索引

作用

索引的出现其实就是为了提高数据查询的效率, 就像书的目录一样.

常见的索引模型

哈希表

  • 特点: 插入快, 等值查询快, 区间查询慢.
  • 适用场景: 只有等值查询的场景.

有序数组

  • 特点: 有序数组在等值查询和范围查询场景中的性能都非常优秀, 但是插入慢.
  • 适用场景: 静态存储引擎.

搜索树

  • 特点: 均衡了读写速度, 相对来说都比较快.
  • 适用场景: 已被广泛应用.

索引类型

  • 主键索: 主键索引的叶子节点存的是整行数据. 在 InnoDB 里, 主键索引也被称为聚簇索引 (clustered index);
  • 非主键索引: 非主键索引的叶子节点存的是主键的值. 在 InnoDB 里, 非主键索引也被称为二级索引 (secondary index);

非主键索引查询到的是索引值, 主键索引查询到的是整行数据, 所以非主键索引的查询需要多扫描一颗索引树. 因此, 我们在应用中应该尽量使用主键查询.

建议

一般情况下, 建议使用自增主键. 原因有二:

  • 自增主键的每次插入都是一条新纪录, 执行追加操作, 不涉及挪动其他记录;
  • 主键长度越小, 普通索引的叶子节点就越小, 普通索引占据的空间也就越小.
    KV 场景下, 可以使用业务字段直接做主键, 需要满足两个条件:
    • 只有一个索引;
    • 该索引必须是唯一索引.

优化

根据非主键索引查询到的主键回到主键索引搜索的过程称为 回表, 回表会增加搜索次数, 导致查询效率降低.

覆盖索引

索引上的字段已经满足了查询需求, 这种索引称之为 覆盖索引. 由于覆盖索引可以减少树的搜索次数, 显著提升查询性能, 所以使用覆盖索引是一个常用的优化手段.

最左前缀原则

B+ 树这种索引结构, 可以利用索引的 “最左前缀” 来定位记录. 这个最左前缀可以是联合索引的最左 N 个字段, 也可以是字符串索引的最左 M 个字符. 所以, 如果通过调整顺序可以少维护一个索引, 那么这个顺序往往就是优先考虑采用的.

索引下推

MySQL 5.6 引入的索引下推优化 (index condition pushdown), 可以在索引遍历过程中, 对索引中包含的字段先做判断, 直接过滤掉不满足条件的记录, 减少回表次数.

Share

之前听了极客时间谭超老师的直播,老师提到一个刷算法题的思路,感觉很是有道理。

做算法题最大的误区:只做一遍。

  • 第一遍

    5 分钟读题 + 思考,不会做不要紧,直接看解法,比较各种解法的优劣。然后背诵、默写好的解法。

  • 第二遍

    自己解题、优化、比较各种解法利弊、比较时间复杂度和空间复杂度。

  • 第三遍

    一天之后 重复做题、专项练习。

  • 第四遍

    一周之后 反复练习相同的题目。

  • 第五遍

    面试前一周恢复性训练。

我自己做题会陷入一种“自己做出来才算是会了”的误区。但谭超老师有句话很有道理:“我们是在学算法,不是在发明算法。”如此说来,自己一直死磕就有点浪费时间了。

☑️ ⭐

ARTS-No.6

Algorithm

27. 移除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
public int removeElement(int[] nums, int val) {
if (nums == null) {
return 0;
}

int insertIndex = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != val) {
nums[insertIndex] = nums[i];
insertIndex++;
}
}

return insertIndex;
}
}

执行用时: 0ms, 内存消耗: 35.3MB.

Review

What is REST — A Simple Explanation for Beginners, Part 2: REST Constraints

RESTful 接口需要满足如下六条约束:

统一接口

统一接口包含以下四个方面:

  1. 发送到服务器的请求必须包含资源标识;
  2. 服务器需要返回足够的信息, 以致于客户端可以操作对应的资源;
  3. 客户端的每一个请求需要提供包含服务器执行操作所需的全部信息; 服务器的每一个响应需要提供客户端需要的所有信息以便理解响应内容;
  4. 超媒体应作为应用程序状态引擎;

客户端 - 服务器分离

客户端和服务器是各自独立的, 它们之间的交互仅能通过客户端的请求和服务端的响应来实现. 服务端不会主动向客户端发送信息.

无状态的

无状态意味着服务端不会记忆调用 API 的用户的任何信息, 每一次独立的请求都包含了服务端执行对应操作需要的所有信息.

分层的系统

客户端和真正提供服务的服务端之间可能有很多类似安全层, 缓存层, 负载均衡层等中间服务, 这些中间层不应该影响客户端和服务器之间的请求和响应, 客户端也不会知道有多少分层.

可缓存的

服务端的响应需要标注自身是否可被缓存. 良好的缓存设计可以减少不必要的请求, 达到节约资源的目的.

按需代码 ( 可选 )

客户端可以向服务端请求能够执行的代码, 代码通常是脚本的形式.

这个约束不作为 Restful 接口的的必要条件.

参考文献

  • 【译】REST的6个约束 — 亚里士朱德
  • 梳理REST API的设计原则 — 动力节点官方账号

Tip

「神器系列」软件终结者,没有它不能做的:uTools

这是一款和 Listary 相似的工具. 可以用作效率启动和文件搜索, 有点在于 uTools 拥有自己的插件系统, 如果插件生态做好的话优势会很明显.

Share

这周接受了将近三个小时的保险推销, 成功从一个保险小小白变成了保险小白. 这里分享一下我了解到的保险基础知识.

保险保障的范围一般是包括三个方面: 身故, 健康和意外.

身故

保障身故的险种称为寿险, 保额取决于被保人所承担的家庭责任. 保额的确定需要考虑当下以及将来父母的赡养费, 子女的抚养费, 房贷和车贷等负担. 假如自己意外身故, 尽可能保证家人正常生活.

健康

保障健康的险种一般包括重疾险, 医疗险和社保.

社保

社保是现代人医疗的基础保障, 最大报销额度平均大概是 15 万元.

医疗险

医疗险是对社保的一个补充, 用来保障社保覆盖不到的范围. 年龄越大, 保费越高, 保期一般是一年, 有停售风险.

重疾险

重疾险用来保障重大疾病以及康复修养期间的收入损失, 目前国内重疾的治疗费用平均为 50 万元, 收入损失一般考虑 1 - 3 年的工作收入. 保额的规划原则大概 = (50 万) + (1 - 3 年工作收入) - (15 万社保报销额度).

意外

意外险用于保障各种意外情况, 比如车祸和意外伤残等.

最后补充一个原则: 保险的主要目的是规避风险, 不是理财. 不要被一些别有用心的分红险给忽悠了.

刚被洗脑, 在此记录. over!

🔲 ⭐

月刊-201907

优秀文章

  • 这十七个学习网站,值得你去浪费时光

    文章总结了一些优秀的学习网站.

  • Java8 lambda表达式10个示例

    关于 Java lambda 表达式的一篇文章.

工具推荐

  • uupoop - 在线 PS 工具

    信息来源: 买不起正版PS?试试这个免费的在线工具!

  • DownGit | github

    Create GitHub Resource Download Link (git-github-direct-zip-directory-folder-file)

  • gitMemory

    一个帮助你可视化查看某一 github 账号近期动态的工具.

  • 犸良

    一个在线制作动效的小工具. 教程

  • mixkit

    一个高质量插画图库, 使用时需要注意版权.

有趣的项目

  • 程序员的婚礼邀请函 | github

    颇具程序员风格的婚礼邀请函.

  • Dollar Street

    足不出户, 阅尽人间百态.

  • Arch 配置教程

    Arch Linux 的一个配置教程.

🔲 ⭐

月刊-201901

精选文章

  • 5分钟经典英文技术演讲1:如何快速掌握新技术 - Kathy Sierra

    如何快速掌握新技术, 除了一些小技巧, 文中还提到了一个很好地观点: 高质量的例子.

    这一点我很赞同, 高质量的例子往往会给人最直观的感受, 这或许是我们开发者努力的一个方向.

    此外, 作者博客中的其他文章也值得阅读, 貌似博主总能以最精简的语言表述最核心的内容. 博客地址: DecodeZ

  • 10000字干货!这可能是最全的英语学习方法了

    作者总结了一些学习英语的心得, 方法和资源, 个人感觉很是受用.

  • 任正非万字采访昨夜刷屏!这20句话让全世界振聋发聩

    这是我第一次认识任正非, 也是我第一次被他的大智慧, 大心胸, 大眼界所折服. 这是一篇值得我们反复品读的文章.

  • 一千个不用 Null 的理由

    文中解释了为什么 Mysql 数据库中不建议使用 Null.

  • BBC曝光:每天10000步,竟是商家的营销骗局?!

    日行一万步来源于日本计步器商家随口编出来的营销骗局. 对于部分人群来说, 日行一万步不仅无益, 还有可能伤及自身.

  • 别再写 bug 了,避免空指针的 5 个案例!

    文中简单列举了一些 Java 编程中避免空指针异常的方法和习惯.

  • 马云后半生的目标:赔钱 | 2018 “马云乡村教师奖” 颁奖晚会

    说实话, 马老师是我最佩服的一个人. 百度推广, 腾讯游戏, 唯有阿里, 改天换地. 阿里巴巴, 淘宝, 支付宝, 天猫, 菜鸟物流, 达摩院, 甚至蚂蚁森林, 无一不是伟大的创举. 在人生最巅峰的时候, 他又洗尽铅华, 投身于教育事业当中.

    文章评论里有位朋友说道: “教育是最廉价的国防”. 这又何尝不是我们追逐更好的生活的的最佳方式呢?

    如果能够更好地改善自己的生活, 对于国家, 已经算是一种贡献了.

工具

  • CODELF

    脑洞清奇的变量命名小工具. 工具再好, 也好不过自身良好的英语素养, 还是老老实实学英语吧.

  • Snapseed

    很强大的手机修图 app, 这里是一篇介绍文章: 手机修图,用这一个App就够了

  • wonderfulsuccess / weixin_crawler

    微信公众号历史文章和阅读数据爬虫.

感悟

  1. 所谓岁月静好, 不过是有在人替你负重前行.
  2. 正常情况下我们认为思想决定行动, 但是大多情况下行动更能影响思维. 所以, 如果想要改变, 那就大胆地行动吧! — 读 [正能量] 有感
❌