- 浏览: 524479 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
飞天奔月:
public List<String> gener ...
实践中的重构30_不做油漆匠 -
在世界的中心呼喚愛:
在世界的中心呼喚愛 写道public class A {
...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
在世界的中心呼喚愛 写道在世界的中心呼喚愛 写道在classB ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
在世界的中心呼喚愛 写道在classB的finalize上打断 ...
深入理解ReferenceQueue GC finalize Reference -
在世界的中心呼喚愛:
iteye比较少上,如果可以的话,可以发e-mail交流:ch ...
深入理解ReferenceQueue GC finalize Reference
很少有人可以一遍就写出好的代码。写代码和写文章差不多,大部分人不是天才,需要的是不断的修改,才能使之演化为一段不错的代码。同时,即使是一段原本还算不错的代码,随着时间的推移,受到诸如需求变更,缺陷修复,后期维护等因素的影响,如果不是特别注意的话,也会使其慢慢腐烂。我们能做的,就是持续重构。
以下是一个例子。
原有的代码如下:
该接口的实现如下:
原始的方法实现稍微有点长,在没有bug和需求变更的情况下,一直静静的躺着系统中。直到有一天,不可避免的,需求变更来临了。
新的需求比较简单。
新加入一个参数userId,通过该userId如果可以找到一个UserInfo的话,则返回结果的日期截止点为该UserInfo的最后修改日期。由其他系统保证该修改日期在当前时间之前的某一天。
新的实现如下:
可以看到,新的实现就是在原有的基础上直接修修补补,并没有经过重新设计。
新的实现有以下问题:
1 方法体变的更长了,这个原有的问题更加严重了。
2 UserInfo的定义和使用距离太远了,而在第一行就定义了UserInfo很容易给人一个错觉,该UserInfo和该方法关系很大,但是,实际上,UserInfo只是界定了结果日期的最后截止日期而已。
3 isEquals变量的意义不清晰。
4 补全list大小为7处的代码变得不清晰了。
先来看实现的一个改进,目前最大的问题就是方法体太长,充斥着细节,使其可读性和可维护性降低。解决该问题的思路就是分拆大方法为小方法,提高代码的抽象级别,并且使小方法专注于做一件事情。
新的实现如下:
原始的实现被分拆为3步,得到结果的所有日期,转化为周日期列表的列表,填充null。
同时,在该重构过程中,实现completeWeekListWithNull时发现了一个bug,当结果的列表大小为1的时候,原有的补充null实现是不正确的。意外收获啊,但是也是在情理之中,这也是方法专注干一件事情带来的好处。
当小方法关注于做一个小的事情时,由于关注点比较单一,边界比较清晰,因此更容易产出好的代码。
但是,解决该问题的同时,引入了新的问题。
首先,completeWeekListWithNull方法变长了,有的地方用日期来判断是否需要补充null,有的地方用size来判断是否需要补充null,同样一件事情用不同的方式去做,系统引入了不一致性。保证系统的一致性可以提高代码的可读性和可维护性,避免后来者浪费时间在不一致的理解上。
其次,处理一个list和处理多个list是使用了一个if判断来进行分支处理的。但是处理一个 list和处理多个list在这里真的就是截然不同的两种场景吗?这里的需求也可以描述为把每个list按照自然周用null补齐,而不是,当只有一个list时,怎样怎样,当有多个list时,怎样怎样。用一个简单的需求,简单的实现代替多余的条件判断可以简化代码。
不一致是要去除的,多余的条件判断也是要被替代掉的。
又一轮重构,新的实现如下:
恩,代码和谐多了。
但是又review了几遍后,还是觉得这个代码不应当是定稿。
1 比较明显的,isMonday和isSunday很像,代码又产生了重复。
2 completeWeekListWithNull中对每个子list都补充一遍null感觉比较怪。
3 convertToWeekList看起来还是费劲一些。
这次不是很容易了,经过了一些时间的思考,突然灵机一动,又审视了一遍原始的3步曲,得到结果的所有日期,转化为周日期列表的列表,填充null。convertToWeekList的复杂性在于,处理的是一个无规律的日期列表。如果把3步曲调整一下顺序,变为得到结果的所有日期,填充null,转化为周日期列表的列表。这样一箭双雕,解决了2和3的问题。
最后的实现如下:
当然,这段代码是称不上完美的,但是和最初的版本相比,可以说,通过持续的重构,代码的质量还是得到了一个比较大的提高。
同时,还有一个有趣的现象,引入了多个小方法,代码行数竟然可以没有什么大的增加,这要归功于去除重复和重构过程中发现的更好的实现方案。
以下是一个例子。
原有的代码如下:
public interface DateService { /** * 构建一个按照自然周排好的日期列表(包括最近30天,不包含当日),周时间距离现在越近,在列表中越靠前。 * * <pre> * 保证每个子列表的大小都为7(一个星期的天数),没有日期则以null填充。 * * 例子: * 如果当前时间是2010-09-08(星期3)则构建的列表为: * 第1个subList 2010-09-06(星期1),2010-09-07(星期2),null,null,null,null,null, * 第2个subList 2010-08-30(星期1),2010-08-31(星期2),2010-09-01(星期3),2010-09-02(星期4),2010-09-03(星期5),2010-09-04(星期6),2010-09-05(星期日) * ... * 第n个subList null,null,null,null,date(星期5),date(星期6),date(星期日) * </pre> * * * @return 返回构建好的列表。 * */ public List<List<Date>> getDaysInWeekList(); }
该接口的实现如下:
public class DateServiceImpl implements DateService { private final static int DAYS_RANGE = 30; private final static int DAYS_OF_WEEK = 7; @Override public List<List<Date>> getDaysInWeekList() { List<List<Date>> result = new ArrayList<List<Date>>(); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, -DAYS_RANGE); List<Date> subList = new ArrayList<Date>(); result.add(subList); for (int i = 0; i < DAYS_RANGE; i++) { Date date = calendar.getTime(); List<Date> recentList = result.get(0); if (recentList.isEmpty()) { recentList.add(date); } else { if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { List<Date> newRecentList = new ArrayList<Date>(); newRecentList.add(date); result.add(0, newRecentList); } else { recentList.add(date); } } calendar.add(Calendar.DATE, 1); } // 补全,使每个list大小为7。 List<Date> recentList = result.get(0); int gap = DAYS_OF_WEEK - recentList.size(); for (int i = 0; i < gap; i++) { recentList.add(null); } List<Date> lastList = result.get(result.size() - 1); gap = DAYS_OF_WEEK - lastList.size(); for (int i = 0; i < gap; i++) { lastList.add(0, null); } return result; } }
原始的方法实现稍微有点长,在没有bug和需求变更的情况下,一直静静的躺着系统中。直到有一天,不可避免的,需求变更来临了。
新的需求比较简单。
新加入一个参数userId,通过该userId如果可以找到一个UserInfo的话,则返回结果的日期截止点为该UserInfo的最后修改日期。由其他系统保证该修改日期在当前时间之前的某一天。
新的实现如下:
private final static int DAYS_RANGE = 30; private final static int DAYS_OF_WEEK = 7; private UserService userService; @Override public List<List<Date>> getDaysInWeekList(String userId) { UserInfo userInfo = userService.findUserInfo(userId); List<List<Date>> result = new ArrayList<List<Date>>(); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, -DAYS_RANGE); List<Date> subList = new ArrayList<Date>(); result.add(subList); for (int i = 0; i < DAYS_RANGE; i++) { Date date = calendar.getTime(); List<Date> recentList = result.get(0); if (recentList.isEmpty()) { recentList.add(date); } else { if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { List<Date> newRecentList = new ArrayList<Date>(); newRecentList.add(date); result.add(0, newRecentList); } else { recentList.add(date); } } calendar.add(Calendar.DATE, 1); } // 若可以找到该用户信息。处理特殊情况。 if (null != userInfo) { // 是否需要比较时间,默认true boolean isEquals = true; // 用户修改时间 Date modifyDate = DayUtil.getDayBegin(userInfo.getModifyDate()); for (List<Date> dateList : result) { if (!isEquals) { break; } for (int i = dateList.size() - 1; i >= 0; i--) { // 日历时间 Date date = DayUtil.getDayBegin(dateList.get(i)); // 集合是按日历时间倒序迭代 if (!date.after(modifyDate)) { isEquals = false; break; } else { dateList.remove(i); } } } } // 补全,使每个list大小为7。 List<Date> lastList = result.get(result.size() - 1); int gap = DAYS_OF_WEEK - lastList.size(); for (int i = 0; i < gap; i++) { lastList.add(0, null); } for (List<Date> dateList : result) { int tempGap = DAYS_OF_WEEK - dateList.size(); for (int i = 0; i < tempGap; i++) { dateList.add(null); } } return result; }
可以看到,新的实现就是在原有的基础上直接修修补补,并没有经过重新设计。
新的实现有以下问题:
1 方法体变的更长了,这个原有的问题更加严重了。
2 UserInfo的定义和使用距离太远了,而在第一行就定义了UserInfo很容易给人一个错觉,该UserInfo和该方法关系很大,但是,实际上,UserInfo只是界定了结果日期的最后截止日期而已。
3 isEquals变量的意义不清晰。
4 补全list大小为7处的代码变得不清晰了。
先来看实现的一个改进,目前最大的问题就是方法体太长,充斥着细节,使其可读性和可维护性降低。解决该问题的思路就是分拆大方法为小方法,提高代码的抽象级别,并且使小方法专注于做一件事情。
新的实现如下:
private final static int DAYS_RANGE = 30; private final static int DAYS_OF_WEEK = 7; private UserService userService; @Override public List<List<Date>> getDaysInWeekList(String userId) { List<Date> dayList = getAllowedDateList(userId); if (dayList.isEmpty()) { return new ArrayList<List<Date>>(); } List<List<Date>> weekList = convertToWeekList(dayList); completeWeekListWithNull(weekList); return weekList; } private List<Date> getAllowedDateList(String userId) { Date startDate = DayUtil.getDayBegin(DayUtil.addDays(new Date(), -DAYS_RANGE)); Date endDate = null; UserInfo userInfo = userService.findUserInfo(userId); if (userInfo != null) { endDate = DayUtil.getDayBegin(userInfo.getModifyDate()); } else { endDate = DayUtil.getDayBegin(DayUtil.addDays(new Date(), -1)); } List<Date> list = new ArrayList<Date>(); for (Date tmpDate = startDate; !tmpDate.after(endDate); tmpDate = DayUtil .addDays(tmpDate, 1)) { list.add(tmpDate); } return list; } private List<List<Date>> convertToWeekList(List<Date> dateList) { List<List<Date>> result = new ArrayList<List<Date>>(); result.add(new ArrayList<Date>()); for (Date temDate : dateList) { List<Date> recentWeekList = result.get(0); if (recentWeekList.isEmpty()) { recentWeekList.add(temDate); continue; } if (isMonday(temDate)) { List<Date> newRecentWeekList = new ArrayList<Date>(); newRecentWeekList.add(temDate); result.add(0, newRecentWeekList); } else { recentWeekList.add(temDate); } } return result; } private void completeWeekListWithNull(List<List<Date>> weekList) { int gap = -1; if (weekList.size() == 1) { List<Date> list = weekList.get(0); Date startDate = list.get(0); for (Date temDate = startDate; !isMonday(temDate); temDate = DayUtil .addDays(temDate, -1)) { list.add(0, null); } gap = DAYS_OF_WEEK - list.size(); for (int i = 0; i < gap; i++) { list.add(null); } return; } List<Date> recentList = weekList.get(0); gap = DAYS_OF_WEEK - recentList.size(); for (int i = 0; i < gap; i++) { recentList.add(null); } List<Date> lastList = weekList.get(weekList.size() - 1); gap = DAYS_OF_WEEK - lastList.size(); for (int i = 0; i < gap; i++) { lastList.add(0, null); } } private boolean isMonday(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY; }
原始的实现被分拆为3步,得到结果的所有日期,转化为周日期列表的列表,填充null。
同时,在该重构过程中,实现completeWeekListWithNull时发现了一个bug,当结果的列表大小为1的时候,原有的补充null实现是不正确的。意外收获啊,但是也是在情理之中,这也是方法专注干一件事情带来的好处。
当小方法关注于做一个小的事情时,由于关注点比较单一,边界比较清晰,因此更容易产出好的代码。
但是,解决该问题的同时,引入了新的问题。
首先,completeWeekListWithNull方法变长了,有的地方用日期来判断是否需要补充null,有的地方用size来判断是否需要补充null,同样一件事情用不同的方式去做,系统引入了不一致性。保证系统的一致性可以提高代码的可读性和可维护性,避免后来者浪费时间在不一致的理解上。
其次,处理一个list和处理多个list是使用了一个if判断来进行分支处理的。但是处理一个 list和处理多个list在这里真的就是截然不同的两种场景吗?这里的需求也可以描述为把每个list按照自然周用null补齐,而不是,当只有一个list时,怎样怎样,当有多个list时,怎样怎样。用一个简单的需求,简单的实现代替多余的条件判断可以简化代码。
不一致是要去除的,多余的条件判断也是要被替代掉的。
又一轮重构,新的实现如下:
private void completeWeekListWithNull(List<List<Date>> weekList) { for (List<Date> list : weekList) { completeWeekListToStart(list); completeWeekListToEnd(list); } } private void completeWeekListToStart(List<Date> list) { if (list.size() == DAYS_OF_WEEK) { return; } Date startDate = list.get(0); for (Date temDate = startDate; !isMonday(temDate); temDate = DayUtil .addDays(temDate, -1)) { list.add(0, null); } } private void completeWeekListToEnd(List<Date> list) { if (list.size() == DAYS_OF_WEEK) { return; } Date endDate = list.get(list.size() - 1); for (Date temDate = endDate; !isSunday(temDate); temDate = DayUtil .addDays(temDate, 1)) { list.add(null); } } private boolean isMonday(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY; } private boolean isSunday(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY; }
恩,代码和谐多了。
但是又review了几遍后,还是觉得这个代码不应当是定稿。
1 比较明显的,isMonday和isSunday很像,代码又产生了重复。
2 completeWeekListWithNull中对每个子list都补充一遍null感觉比较怪。
3 convertToWeekList看起来还是费劲一些。
这次不是很容易了,经过了一些时间的思考,突然灵机一动,又审视了一遍原始的3步曲,得到结果的所有日期,转化为周日期列表的列表,填充null。convertToWeekList的复杂性在于,处理的是一个无规律的日期列表。如果把3步曲调整一下顺序,变为得到结果的所有日期,填充null,转化为周日期列表的列表。这样一箭双雕,解决了2和3的问题。
最后的实现如下:
private final static int DAYS_RANGE = 30; private final static int DAYS_OF_WEEK = 7; private UserService userService; @Override public List<List<Date>> getDaysInWeekList(String userId) { List<Date> dayList = getAllowedDateList(userId); if (dayList.isEmpty()) { return new ArrayList<List<Date>>(); } completeDayListWithNull(dayList); List<List<Date>> weekList = convertToWeekList(dayList); return weekList; } private List<Date> getAllowedDateList(String userId) { Date startDate = DayUtil.getDayBegin(DayUtil.addDays(new Date(), -DAYS_RANGE)); Date endDate = null; UserInfo userInfo = userService.findUserInfo(userId); if (userInfo != null) { endDate = DayUtil.getDayBegin(userInfo.getModifyDate()); } else { endDate = DayUtil.getDayBegin(DayUtil.addDays(new Date(), -1)); } List<Date> list = new ArrayList<Date>(); for (Date tmpDate = startDate; !tmpDate.after(endDate); tmpDate = DayUtil .addDays(tmpDate, 1)) { list.add(tmpDate); } return list; } private List<List<Date>> convertToWeekList(List<Date> dateList) { List<List<Date>> result = new ArrayList<List<Date>>(); List<Date> weekList = new ArrayList<Date>(); result.add(0, weekList); for (Date date : dateList) { if (weekList.size() == DAYS_OF_WEEK) { weekList = new ArrayList<Date>(); result.add(0, weekList); } weekList.add(date); } return result; } private void completeDayListWithNull(List<Date> dateList) { completeDayListToMonday(dateList); completeDayListToSunday(dateList); } private void completeDayListToMonday(List<Date> dateList) { Date startDate = dateList.get(0); for (Date temDate = startDate; !isDayOfWeek(temDate, Calendar.MONDAY); temDate = DayUtil .addDays(temDate, -1)) { dateList.add(0, null); } } private void completeDayListToSunday(List<Date> dateList) { Date endDate = dateList.get(dateList.size() - 1); for (Date temDate = endDate; !isDayOfWeek(temDate, Calendar.SUNDAY); temDate = DayUtil .addDays(temDate, 1)) { dateList.add(null); } } private boolean isDayOfWeek(Date date, int dayOfWeek) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return calendar.get(Calendar.DAY_OF_WEEK) == dayOfWeek; }
当然,这段代码是称不上完美的,但是和最初的版本相比,可以说,通过持续的重构,代码的质量还是得到了一个比较大的提高。
同时,还有一个有趣的现象,引入了多个小方法,代码行数竟然可以没有什么大的增加,这要归功于去除重复和重构过程中发现的更好的实现方案。
发表评论
-
实践中的重构32_使用标准的IO操作写法。
2012-07-14 18:42 1360看到这样一段代码,功能为读取一个指定文件的内容然后返回。 ... -
实践中的重构31_结果类两种实现的比较
2011-09-13 19:58 1068在查询接口结果类设计 ... -
实践中的重构30_不做油漆匠
2011-08-15 23:42 1234油漆匠的故事是编程文化中的一个著名故事。本地化如下。 小强毕业 ... -
实践中的重构29_不自动的自动化测试
2011-07-31 18:00 1036测试的精髓之一就是自 ... -
实践中的重构28_小心怀疑类库
2011-07-24 10:25 1038一般而言,类库的使用频率较高,场景较多,隐藏的bug就较少。 ... -
实践中的重构27_不要忘了内存空间
2011-06-06 18:31 1164方法在设计中,一般关注的是方法的功能契约,即方法需要什么样的参 ... -
实践中的重构26_奇怪的接口注释
2011-06-06 16:10 1330最近又看到奇怪的注释。 /** * 用户查询服务。 ... -
实践中的重构25_UT也需要持续重构
2011-05-01 11:20 957UT是个好东西,在对代 ... -
实践中的重构23_详尽的注释未必是好注释
2011-03-20 17:37 1501注释一直是软件开发中的一个老大难问题。 代码中一个注释都没有是 ... -
实践中的重构22_不要垃圾
2011-03-20 13:31 1038Java引入了GC当然很好,减轻了程序员手工管理内存的负担,但 ... -
实践中的重构21_给她一个好名字
2011-03-20 13:03 897名字的重要性实在是再怎么强调都不为过的。 为什么名字这么重要呢 ... -
实践中的重构20_一段可笑的异常处理逻辑
2011-03-06 20:32 1665Code review也是一个充满 ... -
实践中的重构19_脱裤子放屁
2011-03-03 23:17 2014每当看到代码中有一个 ... -
实践中的重构18_不对称的美
2011-02-26 22:30 969一般而言,自然界是以 ... -
实践中的重构17_表驱动法
2011-02-22 00:10 838代码以及初始的单元测试见 http://zhang-xzhi- ... -
实践中的重构16_多即是少
2011-01-16 23:44 1501在编写UT的过程中,随处可见重复,硬编码等等使得代码僵化的代码 ... -
实践中的重构15_null的意义和集合类作为方法结果类型
2011-01-12 22:16 629在编程中,估计null应该是一个很常写的词汇了。 实践中,经常 ... -
实践中的重构14_用方法设计保证正确性
2011-01-04 21:40 989一般来说,方法的调用方遵循方法的契约调用某方法来完成某功能。每 ... -
实践中的重构13_利用递归提高代码的可维护性
2010-12-30 01:38 722有这么一段代码,是用来解析国内的地址信息的。 AddressI ... -
实践中的重构12_不要乱用异常
2010-12-30 00:36 1467code review的时候,发现了如下代码。 /** ...
相关推荐
重构是持续改进代码的基础。抵制重构将带来技术麻烦:忘记代码片段的功能、创建无法测试的代码等等。 而有了重构,使用单元测试、共享代码以及更可靠的无BUG的代码这些最佳实践就显得简单多了。 《31天重构速成》该...
重构是持续改进代码的基础。抵制重构将带来技术麻烦:忘记代码片段的功能、创建无法测试的代码等等。 而有了重构,使用单元测试、共享代码以及更可靠的无bug 的代码这些最佳实践就显得简单多了。 鉴于重构的重要性,...
持续集成是极限编程十二实践之一(1999年KentBeck编写的《解析极限编程》),最初被使用极限编程方法的开发人员所推捧,并在过去的几年中得到广泛应用,成为业界广为人知的软件开发实践。该实践用于解决软件开发过程...
重构的过程:乐趣中不断改进改进 重构的过程:不断的TestCase验证 重构,究竟修炼了什么呢? 重构是一个“永恒的话题”,只要开发在持续,那么重构就会一直伴随着我们。 但是,“重构”本身并不是一个很容易...
同时,他热衷编写代码和开源,涉及软件设计、测试驱动开发、代码重构、遗留代码的维护和持续集成及交付。 内容简介:精益软件开发的目的是,持续高质量的交付价值,通过本次分享,受众可以了解到: 系统化思考:...
第三部分介绍了设计与持续改进代码,如写出更好代码的一些重要原则,建立可测并灵活设计的高级技术,改进已有代码的实践方法—重构技术,改进遗留代码,以及编写和维护测试的指导原则。本书的代码几乎全部用C写成,...
第三部分介绍了设计与持续改进代码,如写出更好代码的 一些重要原则,建立可测并灵活设计的高级技术,改进已有代码的实践方法—重构技术,改进遗留代码,以及 编写和维护测试的指导原则。本书的代码几乎全部用C写成...
第三部分介绍了设计与持续改进代码,如写出更好代码的一些重要原则,建立可测并灵活设计的高级技术,改进已有代码的实践方法—重构技术,改进遗留代码,以及编写和维护测试的指导原则。本书的代码几乎全部用c写成,...
第三部分介绍了设计与持续改进代码,如写出更好代码的一些重要原则,建立可测并灵活设计的高级技术,改进已有代码的实践方法一一重构技术,改进遗留代码,以及编写和维护测试的指导原则。《测试驱动的嵌入式C语言...
QECon全球软件质量&效能大会,规划了一个主会场和多个分会场:云原生工程/质量中台、AI/大数据测试、工程效能、质量保障与管理、测试自动化、需求工程与用户体验、性能测试、架构与代码质量/重构、高效研发体系...
大会聚焦于“数据智能、协同开放、拥抱云化、FinTech质...领域驱动设计在系统重构中的应用实践 基于代码关系网络分析的质效应用实践 软件全供应链安全应用实践 资金安全之核对规则智能推导解决方案 等等文档,共57份。
我们的方法是通过持续集成以及自动重构,通过数据库管理人员(DBA)和应用开发人员的紧密合作。这些技巧在应用开发的各个时期都有效。1敏捷方法学近年来,出现了一种新的软件开发方法学—敏捷方法学。这给数据库设计...
在这本书中,享誉全球的软件开发专家和软件工程大师Robert C.Martin将向您展示如何解决软件开发人员、项目经理及软件项目领导们所面临的最棘手的问题。这本综合性、实用性的敏捷开发和极限编程方面的指南,是由敏捷...
这份资料集结了行业专家的深刻见解和前沿实践,通过系统化的框架和丰富的案例分析,揭示了数字化转型对企业运营、管理和战略决策的深远影响。它不仅涵盖了技术实施的详细步骤,还关注于组织文化、人才发展及业务流程...
2.3 一个团队,一种语言 24 2.4 文档和图 25 2.4.1 书面的设计文档 27 2.4.2 执行的基础 29 2.5 说明性模型 29 第3章 将模型和实现绑定 32 3.1 模型驱动设计 33 3.2 建模范型和工具支持 36 3.3 突出主旨:为...
通过案例分析与最佳实践的分享,这份资料不仅展示了数字化转型的理论框架,更注重于如何将理论落地,如何在变革中保持竞争力,以及如何构建起一个灵活、可持续的数字核心。特别值得一提的是,这份资料强调了数据的...
《敏捷技能修炼:敏捷软件开发与设计的最佳实践》中内容围绕“敏捷式编程”这一主题展开,对每一位敏捷软件开发人员都应该掌握的核心技能和技术进行了深入阐述,总结出了大量最佳实践,提供了一整套最精炼的技术...