《菜鸟程序员成长计划》之团队高效合作【开发规范篇】

1、「 Java开发规范 」10人小团队Java开发规范参考这篇就够了!

2、「 前端开发规范 」10人小团队前端开发规范参考这篇就够了!
3、…

篇幅所限,更多、更体系化的内容请持续关注 《菜鸟程序员成长计划》之团队高效协作 专栏,您的 关注、点赞、收藏 都将是小编持续创作的动力!


一、编程规范

1、好代码的原则

Kent Beck 的简单设计四原则非常好地来指导我们的如何写出优秀的代码,如何有效地判断我们的代码是优秀的。

  • 通过所有测试(Passes its tests):强调的是外部需求,这是代码实现最重要的
  • 尽可能消除重复 (Minimizes duplication):代码的模块架构设计,保证代码的正交性,保证代码更容易修改
  • 尽可能清晰表达 (Maximizes clarity):代码的可阅读性,保证代码是容易阅读的
  • 更少代码元素 (Has fewer elements):保证代码是简洁的,在简洁和表达力之间,我们更看重表达力

以上四个原则的重要程度依次降低, 这组定义被称做简单设计原则。

2、项目命名规范

全部采用小写方式, 以中划线分隔。

正例:mall-management-system / order-service-client / user-api

反例:mall_management-system / mallManagementSystem / orderServiceClient

3、TODO/FIXME 规范

TODO/TBD(to be determined) 注释一般用来描述已知待改进、待补充的修改点,并且加上作者名称。
FIXME 注释一般用来描述已知缺陷,它们都应该有统一风格,方便文本搜索统一处理。如:

// TODO <author-name>: 补充XX处理
// FIXME <author-name>: XX缺陷

4、方法参数规范

无论是 controller,service,manager,dao 亦或是其他的代码,每个方法最多 3 个参数,如果超出 3 个参数的话,要封装成 javabean 对象。

  1. 方便他人调用,降低出错几率。尤其是当参数是同一种类型,仅仅依靠顺序区分,稍有不慎便是灾难性后果,而且排查起来也极其恶心。
  2. 保持代码整洁、清晰度。当一个个方法里充斥着一堆堆参数的时候,再坚强的人,也会身心疲惫。

反例:

/**
* 使用证书加密数据工具方法
*
* @param param
* @param password 加密密码
* @param priCert 私钥
* @param pubCert 公钥
* @return 返回加密后的字符串
*/
public String signEnvelop(JdRequestParam param, String password, String priCert, String pubCert){}

5、注释规范

5-1、注释和代码一样重要

注释是我们披荆斩棘历经磨难翻越需求这座大山时,留下的踪迹和收获的经验教训,这些宝贵的知识除了证明我们曾经存在过,也提醒着后来的人们殷鉴不远、继往开来。

注释除了说明作用、逻辑之外。还有一个很重要的原因:当业务逻辑过于复杂,代码过于庞大的时候,注释就变成了一道道美化环境、分离与整理逻辑思路的路标。这是很重要的一点,它能有效得帮助我们免于陷入代码与业务逻辑的泥沼之中。

正例:

/**
* 开始抽奖方法
* 保存中奖信息、奖励用户积分等
* @param luckDrawDTO
* @return ResponseDTO 返回中奖信息
*/
public ResponseDTO<String> startLuckDraw(LuckDrawDTO luckDrawDTO) {// -------------- 1、校验抽奖活动基本信息 ------------------------xxx伪代码一顿操作// -------------- 2、新增抽奖记录 -------------------------------xxx伪代码一顿操作// -------------- 3、如果需要消耗积分,则扣除钢镚积分 -------------xxx伪代码一顿操作// -------------- 4、获取奖品信息,开始翻滚吧 --------------------xxx伪代码一顿操作return ResponseDTO.succ(luckDrawPrizeVO);
}

5-2、注释和代码的一致性

注释并不是越多越好,当注释过多,维护代码的同时,还需要维护注释,不仅变成了一种负担,也与我们当初添加注释的初衷背道而驰。

首先:大家应该通过清晰的逻辑架构,好的变量命名来提高代码可读性;需要的时候,才辅以注释说明。注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,按需注释。注释内容要简洁、明了、无二义性,信息全面且不冗余。

其次:无论是修改、复制代码时,都要仔细核对注释内容是否正确。只改代码,不改注释是一种不文明行为,破坏了代码与注释的一致性,会让阅读者迷惑、费解,甚至误解。

反例:

// 查询部门
EmployeeDTO employee = employeeDao.listByDeptId(deptId);

5-3、方法注释

方法要尽量通过方法名自解释,不要写无用、信息冗余的方法头,不要写空有格式的方法头注释。

方法头注释内容可选,但不限于:功能说明、返回值,用法、算法实现等等。尤其是对外的方法接口声明,其注释,应当将重要、有用的信息表达清楚。

正例:

/*** 解析转换时间字符串为 LocalDate 时间类* 调用前必须校验字符串格式 否则可能造成解析失败的错误异常** @param dateStr 必须是 yyyy-MM-dd 格式的字符串* @return LocalDate*/
public static LocalDate parseYMD(String dateStr){}

反例:

/*** 校验对象** @param t* @return String*/
public static <T> String checkObj(T t);

反例中出现的问题:

  • 方法注释没有说明具体的作用、使用事项。
  • 参数、返回值,空有格式没内容。这是非常重要一点,任何人调用任何方法之前都需要知道方法对参数的要求,以及返回值是什么。

二、项目规范

1、代码目录结构

统一的目录结构是所有项目的基础。

src                               源码目录
|-- common                            各个项目的通用类库
|-- config                            项目的配置信息
|-- constant                          全局公共常量
|-- handler                           全局处理器
|-- interceptor                       全局连接器
|-- listener                          全局监听器
|-- module                            各个业务
|-- |--- employee                         员工模块
|-- |--- role                             角色模块
|-- |--- login                            登录模块
|-- third                             三方服务,比如redis, oss,微信sdk等等
|-- util                              全局工具类
|-- Application.java                  启动类

2、common 目录规范

common 目录用于存放各个项目通用的项目,但是又可以依照项目进行特定的修改。

src 源码目录
|-- common 各个项目的通用类库
|-- |--- anno          通用注解,比如权限,登录等等
|-- |--- constant      通用常量,比如 ResponseCodeConst
|-- |--- domain        全局的 javabean,比如 BaseEntity,PageParamDTO 等
|-- |--- exception     全局异常,如 BusinessException
|-- |--- json          json 类库,如 LongJsonDeserializer,LongJsonSerializer
|-- |--- swagger       swagger 文档
|-- |--- validator     适合各个项目的通用 validator,如 CheckEnum,CheckBigDecimal 等

3、config 目录规范

config 目录用于存放各个项目通用的项目,但是又可以依照项目进行特定的修改。

src                               源码目录
|-- config                            项目的所有配置信息
|-- |--- MvcConfig                    mvc的相关配置,如interceptor,filter等
|-- |--- DataSourceConfig             数据库连接池的配置
|-- |--- MybatisConfig                mybatis的配置
|-- |--- ....                         其他

4、module 目录规范

module 目录里写项目的各个业务,每个业务一个独立的顶级文件夹,在文件里进行 mvc 的相关划分。
其中,domain 包里存放 entity, dto, vo,bo 等 javabean 对象

src
|-- module                         所有业务模块
|-- |-- role                          角色模块
|-- |-- |--RoleController.java              controller
|-- |-- |--RoleConst.java                   role相关的常量
|-- |-- |--RoleService.java                 service
|-- |-- |--RoleDao.java                     dao
|-- |-- |--domain                           domain
|-- |-- |-- |-- RoleEntity.java                  表对应实体
|-- |-- |-- |-- RoleDTO.java                     dto对象
|-- |-- |-- |-- RoleVO.java                      返回对象
|-- |-- employee                      员工模块
|-- |-- login                         登录模块
|-- |-- email                         邮件模块
|-- |-- ....                          其他

5、 domain 包中的 javabean 命名规范

1) javabean 的整体要求:

  • 不得有任何的业务逻辑或者计算
  • 基本数据类型必须使用包装类型(Integer, Double、Boolean 等)
  • 不允许有任何的默认值
  • 每个属性必须添加注释,并且必须使用多行注释。
  • 必须使用 lombok 简化 getter/setter 方法
  • 建议对象使用 lombok@Builder ,@AllArgsConstructor,同时使用这两个注解,简化对象构造方法以及set方法。

正例:

@Builder
@NoArgsConstructor
@Data
public class DemoDTO {private String name;private Integer age;
}// 使用示例:DemoDTO demo = DemoDTO.builder().name("yeqiu").age(66).build();

2)数据对象;XxxxEntity,要求:

  • Entity 为结尾(阿里是为 DO 为结尾)
  • Xxxx 与数据库表名保持一致
  • 类中字段要与数据库字段保持一致,不能缺失或者多余
  • 类中的每个字段添加注释,并与数据库注释保持一致
  • 不允许有组合
  • 项目内的日期类型必须统一,建议使用 java.util.Date,java.sql.Timestamp,java.time.LocalDateTime 其中只一。

3)传输对象;XxxxDTO,要求:

  • 不可以继承自 Entity
  • DTO 可以继承、组合其他 DTO,VO,BO 等对象
  • DTO 只能用于前端、RPC 的请求参数

3)视图对象;XxxxVO,要求:

  • 不可继承自 Entity
  • VO 可以继承、组合其他 DTO,VO,BO 等对象
  • VO 只能用于返回前端、rpc 的业务数据封装对象

4)业务对象 BO,要求:

  • 不可以继承自 Entity
  • BO 对象只能用于 service,manager,dao 层,不得用于 controller

三、MVC 规范

1、整体分层

  • controller 层
  • service 层
  • manager 层
  • dao 层

2、 controller 层规范

1) 只允许在 method 上添加 RequestMapping 注解,不允许加在 class 上(为了方便的查找 url,放到 url 不能一次性查找出来)

正例:

@RestController
public class DepartmentController {@GetMapping("/department/list")public ResponseDTO<List<DepartmentVO>> listDepartment() {return departmentService.listDepartment();}

反例:

@RequestMapping ("/department")
public class DepartmentController {@GetMapping("/list")public ResponseDTO<List<DepartmentVO>> listDepartment() {return departmentService.listDepartment();}

2)不推荐使用 rest 命名 url, 只能使用 get/post 方法。url 命名上规范如下:

虽然 Rest 大法好,但是有时并不能一眼根据 url 看出来是什么操作,所以我们选择了后者,这个没有对与错,只有哪个更适合我们的团队。

/业务模块/子模块/动作

正例:

GET  /department/get/{id}      查询某个部门详细信息
POST /department/query         复杂查询
POST /department/add           添加部门
POST /department/update        更新部门
GET  /department/delete/{id}   删除部门

3)每个方法必须添加 swagger 文档注解 @ApiOperation ,并填写接口描述信息,描述最后必须加上作者信息 @author 哪吒

正例:

    @ApiOperation("更新部门信息 @author 哪吒")@PostMapping("/department/update")public ResponseDTO<String> updateDepartment(@Valid @RequestBody DeptUpdateDTO deptUpdateDTO) {return departmentService.updateDepartment(deptUpdateDTO);}

4)controller 负责协同和委派业务,充当路由的角色,每个方法要保持简洁:

  • 不做任何的业务逻辑操作
  • 不做任何的参数、业务校验,参数校验只允许使用@Valid 注解做简单的校验
  • 不做任何的数据组合、拼装、赋值等操作

正例:

    @ApiOperation("添加部门 @author 哪吒")@PostMapping("/department/add")public ResponseDTO<String> addDepartment(@Valid @RequestBody DepartmentCreateDTO departmentCreateDTO) {return departmentService.addDepartment(departmentCreateDTO);}

5)只能在 controller 层获取当前请求用户,并传递给 service 层。

因为获取当前请求用户是从 ThreadLocal 里获取取的,在 service、manager、dao 层极有可能是其他非 request 线程调用,会出现 null 的情况,尽量避免

    @ApiOperation("添加员工 @author yandanyang")@PostMapping("/employee/add")public ResponseDTO<String> addEmployee(@Valid @RequestBody EmployeeAddDTO employeeAddDTO) {LoginTokenBO requestToken = SmartRequestTokenUtil.getRequestUser();return employeeService.addEmployee(employeeAddDTO, requestToken);}

3、 service 层规范

1)合理拆分 service 文件,如果业务较大,请拆分为多个 service。

如订单业务,所有业务都写到 OrderService 中会导致文件过大,故需要进行拆分如下:

  • OrderQueryService 订单查询业务
  • OrderCreateService 订单新建业务
  • OrderDeliverService 订单发货业务
  • OrderValidatorService 订单验证业务

2)谨慎处理 @Transactional 事务注解的使用,不要简单对 service 的方法添加个 @Transactional 注解就觉得万事大吉了。应当合并对数据库的操作,尽量减少添加了@Transactional方法内的业务逻辑。
@Transactional 注解内的 rollbackFor 值必须使用异常的基类 Throwable.class

对于@Transactional 注解,当 spring 遇到该注解时,会自动从数据库连接池中获取 connection,并开启事务然后绑定到 ThreadLocal 上,如果业务并没有进入到最终的 操作数据库环节,那么就没有必要获取连接并开启事务,应该直接将 connection 返回给数据库连接池,供其他使用(比较难以讲解清楚,如果不懂的话就主动去问)。

反例:

    @Transactional(rollbackFor = Throwable.class)public ResponseDTO<String> upOrDown(Long departmentId, Long swapId) {// 验证 1DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);if (departmentEntity == null) {return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);}// 验证 2DepartmentEntity swapEntity = departmentDao.selectById(swapId);if (swapEntity == null) {return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);}// 验证 3Long count = employeeDao.countByDepartmentId(departmentId)if (count != null && count > 0) {return ResponseDTO.wrap(DepartmentResponseCodeConst.EXIST_EMPLOYEE);}// 操作数据库 4Long departmentSort = departmentEntity.getSort();departmentEntity.setSort(swapEntity.getSort());departmentDao.updateById(departmentEntity);swapEntity.setSort(departmentSort);departmentDao.updateById(swapEntity);return ResponseDTO.succ();}

以上代码前三步都是使用 connection 进行验证操作,由于方法上有@Transactional 注解,所以这三个验证都是使用的同一个 connection。

若对于复杂业务、复杂的验证逻辑,会导致整个验证过程始终占用该 connection 连接,占用时间可能会很长,直至方法结束,connection 才会交还给数据库连接池。

对于复杂业务的不可预计的情况,长时间占用同一个 connection 连接不是好的事情,应该尽量缩短占用时间。

正例:

    DepartmentService.javapublic ResponseDTO<String> upOrDown(Long departmentId, Long swapId) {DepartmentEntity departmentEntity = departmentDao.selectById(departmentId);if (departmentEntity == null) {return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);}DepartmentEntity swapEntity = departmentDao.selectById(swapId);if (swapEntity == null) {return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS);}Long count = employeeDao.countByDepartmentId(departmentId)if (count != null && count > 0) {return ResponseDTO.wrap(DepartmentResponseCodeConst.EXIST_EMPLOYEE);}departmentManager.upOrDown(departmentSort,swapEntity);return ResponseDTO.succ();}DepartmentManager.java@Transactional(rollbackFor = Throwable.class)public void upOrDown(DepartmentEntity departmentEntity ,DepartmentEntity swapEntity){Long departmentSort = departmentEntity.getSort();departmentEntity.setSort(swapEntity.getSort());departmentDao.updateById(departmentEntity);swapEntity.setSort(departmentSort);departmentDao.updateById(swapEntity);}

将数据在 service 层准备好,然后传递给 manager 层,由 manager 层添加@Transactional 进行数据库操作。

3)需要注意的是:注解 @Transactional 事务在类的内部方法调用是不会生效的

反例:如果发生异常,saveData方法上的事务注解并不会起作用

@Service
public class OrderService{public void createOrder(OrderCreateDTO createDTO){this.saveData(createDTO);}@Transactional(rollbackFor = Throwable.class)public void saveData(OrderCreateDTO createDTO){orderDao.insert(createDTO);}
}

Spring采用动态代理(AOP)实现对bean的管理和切片,它为我们的每个class生成一个代理对象。只有在代理对象之间进行调用时,可以触发切面逻辑。而在同一个class中,方法A调用方法B,调用的是原对象的方法,而不通过代理对象。所以Spring无法拦截到这次调用,也就无法通过注解保证事务了。简单来说,在同一个类中的方法调用,不会被方法拦截器拦截到,因此事务不会起作用。

解决方案:

  1. 可以将方法放入另一个类,如新增 manager层,通过spring注入,这样符合了在对象之间调用的条件。
  2. 启动类添加 @EnableAspectJAutoProxy(exposeProxy = true),方法内使用AopContext.currentProxy()获得代理类,使用事务。
SpringBootApplication.java@EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication
public class SpringBootApplication {}OrderService.javapublic void createOrder(OrderCreateDTO createDTO){OrderService orderService = (OrderService)AopContext.currentProxy();orderService.saveData(createDTO);
}

4)service是具体的业务处理逻辑服务层,尽量避免将web层某些参数传递到service中。

反例:

public ResponseDTO<String> handlePinganRequest(HttpServletRequest request){InputStreamReader inputStreamReader = new InputStreamReader(request.getInputStream(), "GBK");BufferedReader reader = new BufferedReader(inputStreamReader);StringBuilder sb = new StringBuilder();String str;while ((str = reader.readLine()) != null) {sb.append(str);}if(!JSON.isValid(msg)){return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM);}PinganMsgDTO PinganMsgDTO = JSON.parseObject(msg,PinganMsgDTO.class);// 示例结束
}

反例中出现的问题:

  • 反例中把 HttpServletRequest 传递到service中,是为了获取Request流中的字符信息,然后才是真正的业务处理。按照分层的初衷:将代码、业务逻辑解耦,正确的做法应该是handlePinganRequest方法将String字符作为参数直接处理业务,将从Request中获取字符的操作放入controller中。
  • 另一个坏处是不方便做单元测试,还得一个new一个HttpServletRequest并制造一个InputStream,然而这样做并不能模拟到真实的业务情景及数据。

4、 manager 层规范

manager 层的作用(引自《阿里 java 手册》):

  • 对第三方平台封装的层,预处理返回结果及转化异常信息;
  • 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理;
  • 与 DAO 层交互,对多个 DAO 的组合复用。

5、 dao 层规范

优先使用 mybatis-plus 框架。如果需要多个数据源操作的,可以选择使用 SmartDb 框架。

1)所有 Dao 继承自 BaseMapper

2)禁止使用 Mybatis-plus 的 Wrapper 条件构建器

3)禁止直接在 mybatis xml 中写死常量,应从 dao 中传入到 xml 中

3)建议不要使用星号 * 代替所有字段

正例:

    NoticeDao.javaInteger noticeCount(@Param("sendStatus") Integer sendStatus);
---------------------------------------------NoticeMapper.xml<select id="noticeCount" resultType="integer">selectcount(1)from t_noticewheresend_status = #{sendStatus}</select>

反例:

    NoticeDao.javaInteger noticeCount();
---------------------------------------------NoticeMapper.xml<select id="noticeCount" resultType="integer">selectcount(1)from t_noticewheresend_status = 0</select>

3)dao层方法命名规范

  • 获取单个对象的方法用 get 做前缀。
  • 获取多个对象的方法用 list 做前缀。
  • 获取统计值的方法用 count 做前缀。
  • 插入的方法用 save/insert 做前缀。
  • 删除的方法用 remove/delete 做前缀。
  • 修改的方法用 update 做前缀。

建议:dao层方法命名尽量以sql语义命名,避免与业务关联。

正例:

List<PerformanceDTO> listByMonthAndItemId(@Param("month") String month, @Param("itemId") Integer itemId);

反例:

List<PerformanceDTO> getInternalData(@Param("month") String month, @Param("itemId") Integer itemId);

反例中出现的不规范操作:

  • get代表单个查询,批量查询的应该 list 开头。
  • 命名与业务关联,局限了dao方法的使用场景和范围,降低了方法的复用性,造成他人困惑以及重复造轮子。

6、boolean类型的属性命名规范

类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。反例:定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是 isDeleted(),RPC在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

这是阿里巴巴开发手册中的原文,我们团队的规定是:boolean 类型的类属性和数据表字段都统一使用 flag 结尾。虽然使用 isDeleted,is_deleted 从字面语义上更直观,但是比起可能出现的潜在错误,这点牺牲还是值得的。

正例:

deletedFlag,deleted_flag,onlineFlag,online_flag

四、数据库规范

1 建表规范

表必备三字段:id, create_time, update_time

  • id 字段 Long 类型,单表自增,自增长度为 1
  • create_time 字段 datetime 类型,默认值 CURRENT_TIMESTAMP
  • update_time 字段 datetime 类型,默认值 CURRENT_TIMESTAMP, On update CURRENT_TIMESTAMP

2 枚举类表字段注释需要将所有枚举含义进行注释

修改或增加字段的状态描述,必须要及时同步更新注释。
如下表的 sync_status 字段 同步状态 0 未开始 1同步中 2同步成功 3失败

正例:

CREATE TABLE `t_change_data` (`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,`sync_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '同步状态 0 未开始 1同步中 2同步成功 3失败',`sync_time` DATETIME NULL DEFAULT NULL COMMENT '同步时间',`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,`update_time` DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`change_data_id`)
)

反例:

CREATE TABLE `t_change_data` (`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,`sync_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '同步状态 ',`sync_time` DATETIME NULL DEFAULT NULL COMMENT '同步时间',`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,`update_time` DATETIME NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`change_data_id`)
)

3 合理结合业务给表字段添加索引和唯一索引

具体索引规范请参照《阿里巴巴 Java 开发手册》索引规约

五、其他

1、代码提交规范

  • 提交前应该冷静、仔细检查一下,确保没有忘记加入版本控制或不应该提交的文件。
  • 提交前应该先编译一次(idea里ctrl+F9),防止出现编译都报错的情况。
  • 提交前先更新pull一次代码,提交前发生冲突要比提交后发生冲突容易解决的多。
  • 提交前检查代码是否格式化,是否符合代码规范,无用的包引入、变量是否清除等等。
  • 提交时检查注释是否准确简洁的表达出了本次提交的内容。

2、maven项目

  • pom禁止出现相同 groupId,artifactId 的依赖配置。
  • 项目名称应该与 artifactId 保持一致。
  • 定期检查jar包依赖关系,及时排除解决冲突的jar包。

3、保持项目整洁

使用git,必须添加 .gitignore 忽略配置文件。
不要提交与项目无关的内容文件:idea配置、target包等。

参考:本篇内容参考自开源社区,感谢前人的经验和付出,让我们可以有机会站在巨人的肩膀上眺望星辰大海。

「 Java开发规范 」10人小团队Java开发规范参考这篇就够了相关推荐

  1. 10人小团队如何打造支持千人组织的B端产品?

    Agilean 近期参与了广深珠三地的敏捷社区活动,我以知微产品团队为例,分享了如何以10人分布式小团队,打造出一款支持千人组织敏捷运作的产品.话题得到小伙伴们的热烈反馈,因此将内容整理成文,与更多的 ...

  2. 如何带领5人小团队开发软件

    作为一个项目经理,你可能经常面临着如何带领一个小团队高效地开发软件的挑战.在这篇博客中,我将分享一些我的经验和技巧,希望对你有所帮助. 如何明确项目目标和范围,以及团队成员的角色和职责 在开始一个软件 ...

  3. 「GoTeam 招聘时间」金山办公 WPS Go 中高级开发(广州/珠海)

    本期招聘企业--金山办公 WPS   公司简介 金山办公是全球领先的办公软件和服务提供商,主要从事 WPS Office 办公软件产品及服务的设计研发及销售推⼴.著名产品包括 WPS Office 办 ...

  4. 有人爬了一万个购物网站,发现了1818个「年底大促」的商家小伎俩

    本文来自机器之心 禁止未授权二次转载 大家好,我是老表 阅读文本大概需要 7 分钟 机器之心报道 参与:张倩 那些购物网站的坑,你踩过多少? 双十二刚过,问个扎心的问题,你在双十二买的东西真的比平时便 ...

  5. Java架构师的10本小黄书(精华)

    学习的最好途径就是看书",这是我自己学习并且小有了一定的积累之后的第一体会. 概述 很多程序员们往往有看书的冲动,但不知道看哪些书,下面我就给各位Java程序猿们推荐一些好书(每本书的作者会 ...

  6. java web开发学习手册_Java 人必备学习手册开发下载!

    今天给大家分享一套 5000 页的 Java 学习手册,新鲜出炉!此手册内容专注 Java技术,包括 JavaWeb,SSM,Linux,Spring Boot,MyBatis,MySQL,Nginx ...

  7. 「GoTeam 招聘时间」梦映动漫 Golang 开发工程师/高级经理(广州)

    本期招聘企业--梦映动漫   公司简介 广州梦映动漫网络科技有限公司于2016年1月在广州成立,是一家以移动互联网为基础的科技与动漫创作公司.梦映动漫坚信,技艺有高低,梦想无贵贱,人人都应该有权利享受 ...

  8. 两人小团队开发了一款与谷歌竞争的产品

    本文转载自InfoQ Plausible Analytics 是一款轻量级且开源的网站分析工具.它由 Uku Taht 和 Marko Saric 于 2018 年创立,总部设在欧洲,目前月度经常性收 ...

  9. 「 墙裂推荐」互联网人必备GIF制作的14种选择

    生活中可能遇到将自己的操作或者视频转换成 GIF 图分享给别人,今天墙裂推荐 14 个 GIF 制作通道,一起 mark 吧! 本文通过制作 GIF 软件.录制 GIF 软件以及在线制作 GIF 网站 ...

最新文章

  1. Tomcat启动之异常java.lang.IllegalStateException
  2. Openfire3.9.3源代码导入eclipse中开发配置指南
  3. 如何在html中自动生成条形图,html5生成柱状图(条形图)效果的实例代码
  4. On branch master nothing to commit, working tree clean
  5. OpenJudge NOI 1.8 17:最好的草
  6. java可以看懂php代码吗_PHP笔记——java程序员看懂PHP程序
  7. 数据库卡顿 sp_lock和sys.dm_tran_locks的用法
  8. 史玉柱自述:我的十大管理心得
  9. 同一服务器中,同一框架下的不同二级域名之间网站session如何互通
  10. ABAQUS常见错误(一)多根预应力钢绞线
  11. SangforAC(深信服)Web单点登录
  12. python pyz_Python pyzgoubi包_程序模块 - PyPI - Python中文网
  13. iOS传感器:利用磁力计完成一个AR场景应用
  14. Go学习笔记 -- 方法
  15. 杭电oj11页 (c++) 31-40
  16. 【游戏】JavaScript版连连看
  17. Java+MySQL+查询操作
  18. python画风向杆_从u、v分量绘制风速和风向图
  19. 由南非世界杯足球赛的用球“JABULANI”说起
  20. 封装 电流密度 重布线_半导体封装及其制造方法与流程

热门文章

  1. 反编译 AndroidManifest.xml文件
  2. Python 网络爬虫2:第三方库requests 渗透脚本的编写(SQL注入的EXP,主机发现、端口扫描)
  3. 兄弟mfc7220打印没反应_设备操作面板按键无反应
  4. spss20学习之(一)
  5. 企业信息化战略与实施-练习题
  6. idea插件-Spring Assistant
  7. JDBC连接之Oraclel数据库
  8. 互联网晚报 | 9月17日 星期五 | 天猫超市推出“异地订单”优先配送服务;荣耀与微软达成战略合作;百度昆仑芯落地已超2万片...
  9. Linux运维之(九)LNMP环境搭建
  10. 广州大学MFC实验报告——学生成绩管理系统