General
后端需要做参数校验
代码风格和Api设计风格的一致性大于正确性
- 一致的代码风格使团队所有成员都能快速理解代码
新成员加入时学习曲线更低
减少"这是谁写的代码?"这类困惑
- 长期成本考量
修复风格不一致的代价往往高于修复逻辑错误
风格混乱的代码库会持续产生维护成本
一致性差的代码在重构时风险更高
- 认知负荷理论
开发者大脑需要处理的风格差异越少,越能专注于业务逻辑
减少风格争议让团队把精力放在真正重要的架构问题上
数据入库时间应由后端记录
- 除非特殊情况,数据进入数据库的时间记录应是后端插入数据的时间
- 前端传来的时间是不可信的,比如两条数据传一样的时间,错误的时间等等情况
- 特别是有需要使用时间排序的情况
在对Api修改的时候,要注意兼容情况,避免breaking change
- 在对Api进行修改的时候,如改变Api的signature或在behavior时,要尽量避免breaking change,需要兼容老版本
索引
对于查询字段,注意加索引
对于唯一的字段,考虑加唯一索引
多线程
尽量优先使用线程安全工具,避免直接使用锁
- 在现代多线程编程中,直接使用锁(如synchronized、ReentrantLock等)虽然能解决问题,但会带来一些潜在风险和维护成本。更好的做法是优先使用线程安全的集合和其他封装好的并发工具
ConcurrentDictionary<TKey, TValue>
ConcurrentQueue<T>
ConcurrentStack<T>
ConcurrentBag<T>
BlockingCollection<T>
- c# 原子操作 (System.Threading.Interlocked)
Interlocked.Increment(ref counter);
Interlocked.Decrement(ref counter);
Interlocked.Exchange(ref value, newValue);
Interlocked.CompareExchange(ref value, newValue, comparand);
- C# 任务并行库 (Task Parallel Library, TPL)
Parallel.For(0, 100, i => {
});
Parallel.ForEach(collection, item => {
});
var results = data.AsParallel()
.Where(x => x > 0)
.Select(x => Process(x))
.ToList();
Task.Run(() => {
});
var task1 = Task.Run(() => DoWork1());
var task2 = Task.Run(() => DoWork2());
Task.WaitAll(task1, task2);
SemaphoreSlim
ReaderWriterLockSlim
ManualResetEventSlim
async Task<int> GetDataAsync()
{
var data = await httpClient.GetStringAsync(url);
return ProcessData(data);
}
注意线程的使用数量
- 在使用多线程的时候,需要预估和注意线程的数量. 过多的线程数量会导致资源紧张问题
- 比如一个发送消息的代码, 当taskNum过于大的时候,会导致大量的线程被创建,消耗资源
解决方案
- 思考是否真的需要多线程,可否不用
- 使用信号量控制线程数量
- 使用线程池控制线程数量
public void Run(int taskNum)
{
var producerTasks = new Task[taskNum];
for (int i = 0; i < producerTasks.Length; i++)
{
int producerId = i + 1;
producerTasks[i] = Task.Run(() => ProducerThread(producerId));
}
}