【山竹记账】项目介绍

大纲链接 §

[toc]


如何做技术选型

要好招聘

  • 提高程序员的可替代性(真相令人悲伤)

要好用

  • 自己公司用过或认识的人用过,反馈不错

要有长期维护者

  • 付费维护者 > 免费维护者 > 兼职维护者 > KPI 维护者
  • github star 上万
  • 大公司背景

无政治利益冲突,无商业风险

  • nginx 俄

是否要考虑「用得人多不多」

  • 只要满足一定规模即可,不一定要很多人用

是否要考虑「有大公司背景」

  • YUl、Silverlight、Flash、AngularJS1 已停止维护
  • 所以大公司背景并不能保证什么,尽量参考林迪效应

项目架构

需求、架构、编程语言、核心技术概念

核心需求 Vue3 + TSX

  • 记账
  • 云同步
  • 可视图标
  • 非商业项目,轻业务,重技术

架构

  • Nginx 分发请求
    • 静态文件 /index.htmlstyle-xxx.cssmain-xxx.js
    • api请求 api/v1/resources
    • 单页面App 重定向路由 /tagsrecords/newindex.html
  • 前端页面
    • 通过 router 路径展示对应视图 views
    • pinia 做状态管理
    • views -> components -> hooks -> axios -> ajax
    • 请求后端 JWT、View(JSON) 数据
    • Vite 打包构建开发
  • 后端 Ruby/Go
    • Controller
    • Model <- PostgreSql
    • View(JSON)
  • 使用 docker 镜像

项目用到的编程语言

  • Ruby
  • TypeScript JavaScript(ES6+)

记笔记,做项目


Ruby 简易教程

Ruby的类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class User
  def initialize(name)
    @name = name
  end

  def hi target
    p "Hi #{target}, I am #{@name}"
  end
end

u1 = User.new 'Alice'
u1.hi 'Bob'
p u1
u1.hi 'Charlie'

def add a, b
  a + b
end
p add 1, 2
  • 类 实例化
  • 函数(方法) 可不加括号调用,参数不一致会报错,多参数间用逗号
    • 函数最后一行不需要写 return,不强制自动默认隐式返回
    • if分支时需要写
  • 插入字符串用 双引号

Ruby的数组

 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
# 太啰嗦了
even_numbers = []
[1,2,3,4,5,6].each do |n|
  # even_numbers << n if n.even?
  if n.even?
    even_numbers << n
  end
end
p even_numbers

# 简写一 if语句-句尾if,只会在if成立的时候才运行前面的语句
even_numbers = [1,2,3,4,5,6].select do |n|
  n.even?
end
p even_numbers

# 简写二 简写 do |n|...end
even_numbers = [1,2,3,4,5,6].select { |n| n.even? }

# 简写三 简写当前作用域参数
even_numbers = [1,2,3,4,5,6].select { &:even? }

# 简写四 简写连续数字的数组
even_numbers = [1..6].select { &:even? }
# 就地操作
even_numbers = [1,2,3,4,5,6].select! { &:even? }

# Range转数组就地操作
even_numbers = (1..6).to_a
even_numbers.select! { &:even? }
  • select 语句有返回值,可以直接赋值,相当于jsfilter
  • do |n|...end代码块(相当于函数体)
    • 可以简写为 { |n| ... }
    • 简写当前作用域参数 |n| n.even? -> &:even?&表示当前,类似 SASS 语法

Javascript 简易教程

声明变量

  • 99%只用const
  • 尽量不用 let
  • 绝对不用 var

函数

单行函数

1
2
3
4
const a = n => n + 1
const b = (a, b) => a + b
const c = (a, b, c) => [a, b, c]
const d = (name, age) => ({ name, age })

多行函数

1
2
3
4
5
const b = (a, b) => {
  console.log('add')
  return a + b
}
// ;(a, b) => (console.log('add'), a + b)
  • 逗号表达式 ;(a, b) => (console.log('add'), a + b)
    • 第一句会执行 console.log('add')
    • 最后一句会返回 a + b

高阶函数

1
2
3
4
5
6
const f = a => b => a + b
f(1)(2)

// 参数是函数
const f2 = fn => fn(1, 2)
f2( (a, b) => a + b )

扩展操作符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const user = {name: 'frank', age: 18}
const user2 = {...user, name: 'jack'}
const user3 = Object.assign(
  {},
  user,
  {name: 'tom'}
)

const call = (fn, ...args) => fn(...args)
call( (a, b) => a + b, 1, 2 )

Typescript 简易教程

声明类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
type Name = string
const str: Name = 'Frank'

type Id = string | number
const id1: Id = '123'
const id2: Id = 456

type Wrong = string & number  // never // 这一般是写错了

type User = {
  name: string,
  age?: number
  readonly id: string | number;
  isOk: boolean
}
const u: User = {
  isOk: false,
  id: 123,
  name: 'frank'
}
u.id = '444'

type Dir = '东' | '南' | '西' | '北'
const d: Dir = '酉' // 不可分配给变量类型 Dir
  • 简单类型别名不可写 &
  • 联合类型 string | number

声明类型 II

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
type A = {
  t: 'a'
  specialForA: string
}
type B = {
  t: 'b'
  specialForB: number
}
type Target1 = A | B
type Target2 = A & B // never

// 报错
const c1: Target1 = {
  t: 'b'
  specialForA: 'hi' // 不存在于类型 B 中
  // specialForB: 123 // 满足
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
type A = {
  ta: 'a'
  specialForA: string
}
type B = {
  tb: 'b'
  specialForB: number
}
// 属性必须全部满足
type C = A & B
const c2: C = {
  ta: 'a',
  tb: 'b',
  specialForA: 'hi',
  specialForB: 123
}
1
2
3
4
5
6
7
8
9
type A = {
  t: 'a'
  specialForA: string
}
type B = {
  // t: 'b'
  specialForB: number
}
type Target3 = A & B

只用来声明对象的 interface

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
interface User {
  readonly id: number | string
  name: string
  age?: number
}
interface UserWithDog extends User {
  dog: string
}
const u1: UserWithDog = {
  name: 'frank',
  age: 18,
  id: 1,
  dog: 'hi'
} 
  • 可以描述 对象 和 函数 等复杂类型
  • 可以继承

泛型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
interface User {
  readonly id: number | string
  name: string
  age?: number
}
interface UserWithPet<T> extends User {
  pet: T
}
type Cat = 'Cat'
const u2: UserWithPet<Cat> = {
  name: 'frank',
  age: 18,
  id: 1,
  pet: 'Cat'
} 

前端选择 Vue3 + TSX

优点

  • 语法像 React 体验更好,灵活

缺点

  • 无法使用vue模板的性能优化,包括
    • 静态提升、修补标记、树结构打平、加速SSR激活

前端依赖包管理器技巧

  • 锁死版本号 npm config set save-prefix=''

  • 先打包pnpm build生成dist
  • 再运行pnpm serve

保险使用pnpm

1
2
3
4
5
// .bashrc
alias npm=pnpm

# 破除
\npm --version

docker 速学

  • docker network create network1
  • 38eda56ac8822aaf9fa4d1331301376acb31d8e7e0d04631e4e00c255428d4cb

排期

  • 基于历史经验排期
  • 精细
  • 留好 buffer

部分软件

统计代码 分类行数

  • cloc
  • tokei

·完待续·

参考文章

相关文章


  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名