记录第一次带后端团队
在过去的一个半月里我第一次作为后端开发组长角色参与公司项目从0到1的开发,记录这一次开发的经历。
1、背景介绍
首先说明一下背景。我所在的公司是做智慧社区相关业务,开发的项目是系统升级工具,方便公司实施同事安装和升级系统。
参与后端开发一共四个人,包括我在内。其他三个同事有一个是应届生、两个做大数据的。按照公司的技术规划,对内项目开发节奏要短平快,用Python语言完成,对外的项目一律用Java语言完成。
项目经过正常开发生命周期,包括需求采集、产品设计、系统设计、详细设计、编码、测试等过程。其中详细设计就是针对接口做的详细设计,一共用时3天完成,设计了45个功能点,包括40个接口和5个初始化准备工作。编码用时计划为3周。最终在时间点之内完成了相关的开发。
我在这次开发过程中担任的是组长的角色,主要的任务包括:
(1)项目框架的搭建。本次开发是一个从0到1的过程,在此之前并没有Python项目的框架。
(2)关键技术的实现。包括通用接口,复杂的技术点。
(3)任务分配。所有接口根据任务量分配给指定的成员,完成最多的接口开发。
2、项目框架搭建
Python做web开发常用的项目框架其实并不是很多,我的候选项有三个:
Django 前后端不分离框架、Flask 最容易上手的框架、FastAPI 异步高性能框架。
对比这三个框架,我从业务逻辑、公司技术栈、复杂度等三个角度出发,选择了Flask。
业务逻辑
业务逻辑对性能并没有特别要求,就是通过接口调用运维的ansible脚本,没有高并发,计算密集等任务,所以三个都能满足。
技术栈
公司技术栈是前后端分离,所以Django这种前后端不分离的框架并不适合,虽然Django也可以做纯后端开发(防杠)。
复杂程度
复杂度来说肯定是Flask最简单。Django号称大而全,配置复杂。FastAPI是异步框架,需要学习异步编程,虽然用来做同步框架也很丝滑,但是学习成本需要增加很多。其他三个同事都没有做过Python项目,所以尽量减少学习成本。
经过这三个方向的衡量,最终确定了Flask框架,搭配peewee orm数据库框架。核心的技术包括:
(1)web框架 Flask
(2)数据库ORM框架 peewee
(3)数据库 sqlite
(4)运维脚本执行模块 subprocess
(5)WSGI服务 Gunicorn
(6)代码检查工具pre-commit
在编码前我已经准备好完整的项目框架,写好了数据库CRUD接口的demo,后续开发过程同事模仿相关接口,一定程度上提高了开发效率。
3、关键技术实现
带团队开发并且是带领成员第一次做Python项目,自然要将有挑战的任务安排给自己。在关键技术的实现上挑选三个有代表性的讲解。三个分别是:系统命令执行通用接口、流式日志、sqlite 多线程写问题解决。
系统命令通用接口
项目主要用于公司开发的其他系统安装和升级,因此需要调用运维人员用ansible编写的相关脚本。调用的ansible脚本格式如下:
ansible-playbook 03.mysql.yml
ansible-playbook 08.zk.yml
需要到指定的路径下执行如上的命令。在详细设计阶段就知道需要使用Python调用系统命令的工具,所以就让应届生同事调研了subprocess模块,输出相关文档。一来是给新人一个学习方向,再则借这个机会熟悉项目需要的技术。
在开发阶段根据对相关模块的理解,完成了通用接口的开发。写通用接口切忌朝令夕改,依赖它的代码也要随之变化。一两次还能接受,次数多估计要被问候祖宗了。所以该接口实现程度不仅仅是写完,而且是自己亲自调用,确认没有问题才宣告完成。
在没有完成之前耐着性子调试,直到没有任何问题才在群里告诉其他开发人员。整个系统中需要大量的调用该命令执行脚本,最终也都比较顺利的完成,没有因为接口造成的bug。
流式日志
按照产品的设计,当一个组件在安装时需要在web页面上展示日志,并且日志的格式要和终端中安装日志一样,也就是一行一行的滚动打印。产品对日志的要求是全量滚动展示,刷新页面要能够再次全量展示出来。为了实现该功能,调研了三个方案:
一、定时刷新。缺点:日志有几万行,每一次读取全部日志给前端,前端会卡顿,而且打印也不连续,体验不好。
二、websocket。可以完成后端向前端的主动推送,但是刷新页面并不会从头开始推送。
三、流式响应。可以将大块文件切分成小块分批传给前端,刷新页面时会再次从头开始推送,符合要求。
经过对比最终使用了流式响应,也就是ChatGPT那种响应的方式。但是需要解决一个问题:什么时候结束推送?因为安装一边向文件中写入日志,流式日志一边读出日志,如果日志已经读完了安装还没结束,那这个时候肯定需要等待而不是停止响应。
解决办法是在安装完成之后插入标记字符,当流式日志读取到标记字符时就表明结束了,没有读取到标记字符则等待。核心代码如下:
def log_flow():query = request.valueslog_path = query["log_path"]def generate():with open(log_path, "r") as f:while True:chunk = f.read(800)if not chunk or chunk.isspace():time.sleep(0.1)if chunk == 800 * "-":breakcontent = json.dumps({"content": chunk})yield f"event: message\ndata: {content}\n\n"time.sleep(0.05)return Flask_response(generate(), mimetype="text/event-stream"
效果:
sqlite3 多线程写问题
在数据库存储这一块,领导钦定用sqlite3,咱也据理力争过用MySQL,but无效。领导说该项目只需要一个轻量的数据库即可,sqlite3轻量,所以就很合适。而且其他项目中已经使用的非常成熟了。好吧,既然领导坚持,我也只能硬着头皮上了。
开始还没问题,到了项目开发中后期就发现问题了,接口经常报错:
File "/home/ljk/.virtualenvs/idt_dev/lib/Python3.8/site-packages/peewee.py", line 3246, in execute_sql
cursor.execute(sql, params or ())
File "/home/ljk/.virtualenvs/idt_dev/lib/Python3.8/site-packages/peewee.py", line 3014, in __exit__
reraise(new_type, new_type(exc_value, *exc_args), traceback)
File "/home/ljk/.virtualenvs/idt_dev/lib/Python3.8/site-packages/peewee.py", line 192, in reraise
raise value.with_traceback(tb)
File "/home/ljk/.virtualenvs/idt_dev/lib/Python3.8/site-packages/peewee.py", line 3246, in execute_sql
cursor.execute(sql, params or ())
peewee.OperationalError: database is locked
查询之后发现是sqlite3不支持多线程写。sqlite3支持事务,是用库锁来完成的。当一个写入开始后,整个数据库都加锁了,再次有写操作就会报错。
这个问题首先从技术上是不好解决的,sqlite3的架构设计就是如此,还能让它支持多线程写吗?只能通过业务逻辑解决。经过一次会议讨论之后,得出几个解决方法:
- 分库。将写操作分到不同的库里完成。既然写操作会锁库,那就分出不同的库,就能避免锁库的问题。
- 全局写队列。将所有的写放到一个消息队列里面,将多线程的写变成串行的写。
- 全局写标识。所有的写操作开始前判断是否有可写标识,能写入就写入,否则接口返回,告诉前端数据库繁忙。
经过投票,大家一致决定用第三种方式实现,技术难度最小,代码侵入性最少。因为第三种方案是我提出来的,所以最终由我来完成。具体的过程可参见另一篇文档《peewee操作sqlite锁表问题分析》。
最终是解决了该问题,虽然不是优雅,但是在目前的时间成本和风险控制上局部是最优解了。后续将调研peewee这个ORM框架提供的sqliteQueueDatabase实现写队列。
摘录于peewee扩展插件playhouse:
SqliteQueueDatabase可作为常规SqliteDatabase。如果你想简单点 read and write 从访问sqlite数据库多线程.
SQLite在任何给定的时间只允许一个连接写入数据库。因此,如果您有一个多线程应用程序(例如Web服务器)需要写入数据库,当一个或多个尝试写入的线程无法获取锁时,您可能会偶尔看到错误。
SqliteQueueDatabase 旨在通过一个长期存在的连接发送所有写查询,从而简化操作。好处是,您可以看到多个线程在向数据库写入时没有冲突或超时。但是,缺点是您不能发出包含多个查询的写事务——本质上,所有写操作都在自动提交模式下运行。
4、个人感受
第一次带团队开发,才明白很多事情。
做项目的主人公
第一真正理解什么叫主人公意识。各种文章都说要对项目有主人公意识才能成长更快。我感觉只有站在这样一个位置上才能感受到这种意识。
项目进度的第一责任人就是你,项目中出现了大大小小的问题都是找你。领导会问题项目进度如何,有没有阻塞,能不能按期完成?队员会问这个校验框架是否ok?这个语法有没有问题?测试会找你说这个bug该给谁的?所以你必须对这个项目了如指掌,小到代码的一个配置项,大到工程进度的把控。开发过程中有任何问题都得及时顶上,组长就是一块砖,哪里需要哪里搬~
团队和谐
再说说团队的和谐。以前做一个小开发,只要完成自己的任务就可以了,团队的氛围影响我写代码的速度吗?带团队开发就不一样。团队中有各种特点的同事,有埋头苦干不汇报进度的、有能力强脾气差的、有脾气好进度慢的。总之各种性格的人都会存在。
本次开发中就遇到了一个能力强脾气差的,看到技术上小问题就直接群里开怼,谁不是热血小青年?第一次遇到这种情况可想而知。领导不得不为此找我们谈话一两次,甚至惊动了大部门领导。那段时间团队氛围特别差,没有人说话。我也不敢多说什么,害怕气氛更差,项目不能如期完成,到那个时候不是我的问题也变成我的问题了。所以只能选择忍一忍,尽量回避分歧。好在领导的谈话起到很大的作用,该安抚的安抚,该批评的批评,后来也没有发生语言的冲突,顺利按期完成项目。
5、总结
第一次带团队做项目对我来说是一次挑战和提高。从技术层面讲让我以后面对技术选型时能以更高的角度看待问题;从个人角度讲这是一次难得的机会让我负责开发团队,对接测试团队、前端团队、运维团队等。这对我的沟通交流都是一次锻炼。
最后,希望下一次做的更好,让所有组员都能有一些进步。
开发工具推荐
原理是将开发过程中某些重复出现的场景、流程,具象化成一个个组件、api、数据库接口,避免了重复造轮子。因而极大的提高了程序员的生产效率。
官网:www.jnpfsoft.com/?csdn,如果你有闲暇时间,可以做个知识拓展。
这是一个基于Java Boot/.Net Core构建的简单、跨平台快速开发框架。前后端封装了上千个常用类,方便扩展;集成了代码生成器,支持前后端业务代码生成,满足快速开发,提升工作效率;框架集成了表单、报表、图表、大屏等各种常用的Demo方便直接使用;后端框架支持Vue2、Vue3。
为了支撑更高技术要求的应用开发,从数据库建模、Web API构建到页面设计,与传统软件开发几乎没有差异,只是通过低代码可视化模式,减少了构建“增删改查”功能的重复劳动。
相关文章:

记录第一次带后端团队
在过去的一个半月里我第一次作为后端开发组长角色参与公司项目从0到1的开发,记录这一次开发的经历。 1、背景介绍 首先说明一下背景。我所在的公司是做智慧社区相关业务,开发的项目是系统升级工具,方便公司实施同事安装和升级系统。 参与后…...
Python文件操作(02):读文件
一、读文本文件 打开文件读文件内容关闭文件 1、在读取文件内容后进行解码操作 """ 1. 打开文件- 路径:相对路径:当前项目(读文件.py)所在的目录下查找需要读取的文件绝对路径:文件--右键--Copy Pat…...

Flink(java版)
watermark 时间语义和 watermark 注意:数据进入flink的时间:如果用这个作为时间语义就不存在问题,但是开发中往往会用处理时间 作为时间语义这里就需要考虑延时的问题。 如上图,数据从kafka中获取出来,从多个分区中获取…...
什么是动态组件以及使用场景
文章目录 一、vue中的动态组件是什么?有什么用?二、使用demo1.tab页签中的使用2.模拟新闻页demo 三、用keep-alive包裹,保持状态总结 一、vue中的动态组件是什么?有什么用? 动态组件指可以动态切换组件的显示和隐藏。…...

CRM销售管理系统如何提高销售效率
CRM销售管理系统是帮助企业对销售活动进行管理、执行和优化的软件系统。它可以帮助企业提高销售效率,提高客户转化率,实现企业的业绩增长。那么,CRM销售管理系统好用吗? CRM销售管理系统的功能 线索管理: CRM系统可…...

纯小白安卓刷机1
文章目录 常见的英文意思刷机是什么?为什么要刷机?什么是BL锁(BootLoader锁)?我的机能够刷机吗?什么是Boot镜像/分区?什么是Recovery镜像/分区(缩写为rec)?什…...

C高级day4循环语句
1,思维导图 运行结果为: 运行结果为:...

Linux 操作系统云服务器安装部署 Tomcat 服务器详细教程
Tomcat 基本概述 Tomcat 服务器是Apache软件基金会(Apache Software Foundation)的 Jakarta 项目中的一个核心项目,由 Apache、Sun 和其他一些公司及个人共同开发而成。它是一个免费的开放源代码的 Web 应用服务器,属于轻量级应用…...

【易盾点选】
拿官网的点选做个例子吧,比较省事,水一篇~ 官网的接口目前都改成V3了,多了个dt参数,以及加密的一个函数也变动了下 点选坐标在这,加密函数未变,用逗号拼接 整个加密里的函数变了,直接重新…...
vue中打印指定dom元素
和window.print()效果一样,调出打印窗口,只是当前使用的插件是vue-print-nb 官网地址:vue-print-nb vue2中使用 安装插件 npm install vue-print-nb --save导入插件 import Print from vue-print-nb // 全局使用 Vue.use(Print);//or// 单…...

OpenCV(三十六):霍夫直线检测
1.检测直线的霍夫变换原理 2.检测直线函数HoughLines() 检测直线流程: Step1:将参数空间的坐标轴离散化。 Step2:将图像中每个非0像素通过映射关系求取在参数空间通过的方格 Step3:统计参数空间内每个方格出现的次数,选取次数大于某一值的方格作为表示直线的方格…...

文心一言 VS 讯飞星火 VS chatgpt (91)-- 算法导论8.3 4题
四、用go语言,说明如何在 O(n) 时间内,对 0 到 n 3 − 1 n^3-1 n3−1 区间内的n个整数进行排序。 文心一言: 在 O(n) 时间内对 0 到 n^3-1 区间内的 n 个整数进行排序,可以使用基数排序(Radix Sort)算法…...

keep-alive缓存三级及三级以上路由
需求需要缓存这个出入记录,当tab切换时不重新加载,当刷新页面时,或把这个关闭在重新打开时重新加载如图: (我这里用的是芋道源码的前端框架) keep-alive 1、include 包含页面组件name的这些组件页面,会被…...

vite vue项目 运行时 \esbuild\esbuild.exe 缺失 错误码 errno: -4058, code: ‘ENOENT‘,
vite vue项目运行 npm run dev 报错某个模块启动文件丢失信息 D:\PengYe_code\2\vite-vue3-admin>npm run dev> vite-vue3-admin1.0.2 dev > vitenode:events:504throw er; // Unhandled error event^Error: spawn D:\PengYe_code\2\vite-vue3-admin\node_modules\vi…...
favicon.ico网站图标不显示问题 Failed to load resource: net::ERR_FILE_NOT_FOU
上述问题主要由于网站的小图标无法显示导致的:可以检查如下部分: 1、是否存在一个favicon.ico文件在根目录下 2、如果存在,看是否写的相对路径:改为绝对路径 <link rel"shortcut icon" href"../favicon.ico&quo…...

微服务·架构组件之服务注册与发现-Nacos
微服务组件架构之服务注册与发现之Nacos Nacos服务注册与发现流程 服务注册:Nacos 客户端会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自身的元数据,比如ip地址、端口等信息。 Nacos Server接收到注册请求后,就会…...

Linux驱动【day2】
mychrdev.c: #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include<linux/uaccess.h> #include<linux/io.h> #include"head.h" unsigned int major; // 保存主设备号 char kbuf[128]{0}; unsigned int…...

4、Nginx 配置实例-反向代理
文章目录 4、nginx 配置实例-反向代理4.1 反向代理实例一4.1.1 实验代码 4.3 反向代理实例二4.3.1 实验代码 【尚硅谷】尚硅谷Nginx教程由浅入深 志不强者智不达;言不信者行不果。 4、nginx 配置实例-反向代理 4.1 反向代理实例一 实现效果:使用 nginx…...

2023年世界机器人大会回顾
1、前记: 本次记录是我自己去世界机器人博览会参观的一些感受,所有回顾为个人感兴趣部分的机器人产品分享。整个参观下来最大的感受就是科学技术、特别是机器人技术和人工智能毫无疑问地、广泛的应用在我们日常生活的方方面面,在安全巡检、特…...

Mac系统 AndroidStudio Missing essential plugin:org.jetbrains.android报错
打开Android Studio,提示 Missing essential plugin:org.jetbrains.android错误,产生的原因是Kotlin被禁用。 解决的方法是删除disabled_plugins.txt,Mac OS对应的路径为: /Users/xzh/Library/Application Support/Google/AndroidStudio202…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...