如何设计实施自己的GTD系统,和TTCC日历来提高工作效率。
微信搜索关注《Java学研大本营》,加入读者群,分享更多精彩
介绍
如果您参与多个项目,除了每日、每周、每月例行活动和预定的截止日期之外,您会想要一个日历系统,帮助您从您参与的各种计划中捕获和组织任务,在您的日历中进行有意义的日程安排。然后系统可以在每天、每周、每月的早晨向您发送汇总的议程电子邮件,直到流中的未完成任务完全完成。
Track Things to Completion Calendar(以下简称 TTCC)的灵感来自 David Allen 的 Getting Things Done。GTD 方法,是一种全面的生活方式。它要求您始终如一地遵循组织、审查过程。这个过程涉及大量和持续的努力。如果您已经被日常决策疲劳和数字干扰所困扰,您需要一个系统来为您增强此过程。
Track Things to Completion Calendar 的功能架构如下所示:
跟踪完成日历(TTCC) - 功能架构
案例
-
个人
当我们承担各种个人和专业项目和任务时,我相信我们会考虑雇用某人来检查任务列表,我们想要参与的项目,以及我们每天、每周、每月的例行公事,并帮助我们公平地安排事情到我们的日历。到时候给我们发送每日、每周提醒,说明我们在每项举措中的立场。
-
敏捷
对于 Scrum Master 来说,一项非常大的工作就是每天、每周对项目中尚待完成的内容进行汇总。除了每天、每周和每月提醒团队成员计划和临时任务。
-
技术风险与合规跟踪
Track things to completion 适用的领域之一是安全性和合规性跟踪。不断发现新的安全漏洞,系统需要定期修补或升级。当系统变得庞大和复杂时,漏洞修补的整个状态需要定期跟进和跟踪,直到完成。
为各种技术风险和合规领域准备燃尽报告需要大量的人力。在此报告中,人为错误很可能导致打补丁和升级过程的延误或延迟。
-
容量冗余或容量浪费跟踪
当我们查看跨越本地、云、容器的基础架构系统时,需要在基础架构级别跟踪容量冗余,以便系统不会因容量问题而出现故障。一旦识别出容量问题,就可以自动修复或跟进。
随着公共云和私有云中基础设施配置的简便性,采购和配置基础设施变得很有吸引力。但是在一段时间内,我们需要扫描基础设施资产以扫描和量化浪费或为更优化的基础设施平台构建建议。对我们来说,我们使用 Track things to complete 日历来识别和通知最大的产能浪费者,并为他们提供反馈和建议以优化他们的工作负载。
我是 David Allen 的 Getting Things Done 方法的忠实粉丝。如果我们看一下 GTD 过程中的基本步骤,它会按以下顺序进行:
-
捕捉(收集你的注意力)
-
澄清(处理它的含义)
-
整理(放在该放的地方)
-
反思(经常回顾)
-
参与(简单地做)
TTCC系统基本上增加了上述过程中的一些步骤。当然,不能完全消除的一件事是参与(或简单地做)。如果我们不定期将我们的东西从盘子里移走,它只会堆积成我们无法再组织的混乱。
TTCC系统
TTCC 系统基本上是在后台工作的。但是,您会看到两个 UI 界面。一个当然是安排每日、每周、每月活动的日历。其次是您的每日、每周、每月议程电子邮件或报告。
这就是日历的样子。它基本上是 Angular-Calendar(具有一些后端智能):
下面是我们将收到的每日议程电子邮件的原型。当然,实际输出将根据您订阅的来源以及系统中启用的规划器而有所不同:
上述电子邮件中项目的一般分类如下:
-
截止日期——时间敏感的预定截止日期
-
例程 - 每日、每周、每月重复例程
-
提醒——注意事项
-
Burndowns - 要跟踪的任务直到完成
示例电子邮件模板
如何运作
系统的功能架构在上面的介绍部分中概述。
如前所述,系统的高级流程受到 GTD 系统的启发:
捕获 => 澄清 => 组织 => 反映 => 参与
TTCC 系统提供了实现上述工作流程的增强功能。架构图中概述的 TTCC 工作流程如下:
扫描源 => 生成事件 => 安排到日历中 => 发送通知
让我们看一下每个步骤:
-
扫描来源
这是工作流程中的第一步,各种计划者(下文讨论)扫描不同的系统以识别未完成的任务或行动来源。
-
生成事件
TTCC 系统的第二步,我们的计划者生成日历事件。这些事件可以是重复的(每天/每周/每月),也可以是由于持续时间较长而未决的事情,或者可能是需要跟踪完成的事情等。计划者还为每个任务生成下一步行动的建议。这在某种程度上模仿了自动日记功能,让您了解一天中所有计划外的事情都完成了。我们安排在午夜 00:00 AM 进行此操作,预计到第二天早上的变化最少。
-
安排到日历中
我们的计划者在上面确定的事件被安排到我们的日历系统中。日历系统根据您指定的重复次数(对于例行任务)或根据该任务是否完成(对于一次性或跟踪完成活动)重复事件。
-
发送通知
然后,我们日历的通知系统会按照指定的时间表运行,例如
-
每日早上 6:00 用于每日花名册。
-
每周花名册周一早上 6:00。
-
每月花名册等的日历月第一天早上 6:00
重要模块
为了实现这个系统,我们使用了 Angular-Calendar,Spring boot。为了解耦系统,我们使用 RabbitMq 跨模块发送和同步信息。
让我们看一下系统中的一些重要模块。第一组类是 Planner 类。
Planner 类
在高层,Planner 类实现接口 ICalendarPlanner。
![](https://files.mdnice.com/user/30879/c77ab600-0699-46c9-9800-adede81f5ea1.png)
该接口要求实现类实现以下方法:
-
runAnalyses()
此函数扫描相应的源系统并构建事件列表。
-
buildRecommendations()
此函数将已识别事件列表作为输入,并为每个事件构建建议。它还确定是否可以使用自动化自动纠正其中一些事件。
-
publishCalendarEvents()
此函数最终创建一个 CalendarEvent 以发布到日历系统中。
-
run()
这是这个类的入口点。如您所见,它使用预定注释进行注释,以根据指定的 cron 计划运行。它基本上按顺序运行上述三个功能。
import com.ttcc.calendar.JiraClient;
import com.ttcc.calendar.model.CalendarEvents;
import com.ttcc.calendar.model.Jira;
import com.ttcc.calendar.model.JiraValue;
import com.ttcc.calendar.model.Utility;
import com.ttcc.calendar.service.CalendarEventsDtoService;
import com.ttcc.planner.model.ICalendarPlanner;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component("jiraTasksCalendarPlanner")
@Slf4j
public class JiraTasksCalendarPlanner implements ICalendarPlanner {
private static Logger log = LoggerFactory.getLogger(JiraTasksCalendarPlanner.class);
@Autowired
private CalendarEventsDtoService calendarEventsDtoService;
@Autowired
JiraClient jiraClient;
@Autowired
String jiraProjectFilter;
@Override
@Scheduled(cron = "${cron.expression.jira.tasks.planner}")
public void run() {
try {
List listOfIncidents = this.runAnalyses();
Map listOfRecommendations = this.buildRecommendations(listOfIncidents);
this.publishCalendarEvents(listOfIncidents,listOfRecommendations);
} catch (Exception err) {
log.error(Utility.getStackTraceAsString(err));
}
}
@Override
public List runAnalyses() throws Exception {
return jiraClient.getJiraByProjectFilter(jiraProjectFilter);
}
@Override
public Map buildRecommendations(List listOfIncidents) {
Map<String,String> recommendations=new HashMap<>();
for (Object jiraItem :
listOfIncidents) {
Jira thisJira = (Jira) jiraItem;
//build recommendations for jiraItem
}
return recommendations;
}
@Override
public void publishCalendarEvents(List listOfIncidents, Map listOfRecommendations) {
for (Object jiraItem :
listOfIncidents) {
Jira thisJira = (Jira) jiraItem;
//create calendar event
buildAndSaveCalendarEventFromJira(thisJira);
}
}
private void buildAndSaveCalendarEventFromJira(Jira sourceJira){
CalendarEvents buildData = new CalendarEvents();
LocalDateTime start = LocalDateTime.now(ZoneOffset.UTC).plusHours(2);
LocalDateTime end = start.plusHours(2);
JiraValue jiraValues = sourceJira.getValues().get(0);
buildData.setTitle(jiraValues.getId().toString());
/// Map JIRA Fields to CalendarEvent Fields
///
calendarEventsDtoService.saveCalendarEvent(buildData);
}
}
日历系统
需要注意的一件事是,与一次性事件相比,日历系统如何保存重复事件。在顶部,日历控制器如下所示:
@PostMapping(value = "/save")
public CalendarEvents saveCalendarEvent(@RequestBody CalendarEvents inputCalendarEvents) {
CalendarEvents calendarEvents = calendarEventsDtoService.saveCalendarEvent(inputCalendarEvents);
return calendarEvents;
}
但是,在 calendarEventsDtoService 中,CalendarEvents 根据指定的重复以不同的方式保存。基本上,如果您将 CalendarEvent 标记为“RECURRING_EVENT”,则根据指定的“每日”、“每周”、“每月”或“每年”的重复周期处理重复周期:
@Service
@Slf4j
public class CalendarEventsDtoService {
@Autowired
CalendarEventsRepository rosterCalendarRepo;
public CalendarEvents saveCalendarEvent(final CalendarEvents inputCalendarEvents) {
CalendarEvents calendarEvents = new CalendarEvents();
if ((inputCalendarEvents.getEventType().equalsIgnoreCase(SCHEDULED)) || (!inputCalendarEvents.getEventType().equalsIgnoreCase(RECURRING_EVENT))){
calendarEvents = rosterCalendarRepo.save(inputCalendarEvents);
calendarEvents.setEventId(String.valueOf(calendarEvents.getId()));
rosterCalendarRepo.save(calendarEvents);
} else {
calendarEvents = saveRecurringEventsInDatabase(inputCalendarEvents);
}
return calendarEvents;
}
private CalendarEvents saveRecurringEventsInDatabase(final CalendarEvents inputCalendarEvents) {
CalendarEvents calendarEvents = new CalendarEvents();
switch (inputCalendarEvents.getRecurrenceType()) {
case DAILY:
calendarEvents = processRecurrence(inputCalendarEvents, DAILY_COUNT);
break;
case WEEKLY:
calendarEvents = processRecurrence(inputCalendarEvents, WEEKLY_COUNT);
break;
case MONTHLY:
calendarEvents = processRecurrenceForMonth(inputCalendarEvents, MONTH_COUNT);
break;
case YEARLY:
calendarEvents = processRecurrenceForYear(inputCalendarEvents, YEARLY_COUNT);
break;
}
return calendarEvents;
}
//…Truncated for brevity
每日/每周/每月花名册类
接下来让我们看看我们的花名册类。
如前所述,我们使用 RabbitMq 订阅之前收集的数据,然后相应地处理电子邮件。下面的 CalendarConsumer 类订阅我们的计划者之前发布的数据,并根据指定的时间表对其进行处理:
@Slf4j
@Service
public class CalendarConsumer implements RabbitListenerConfigurer {
@Value("${daily.mail.subject}")
String dailyAgendaSubject;
@Value("${weekly.mail.subject}")
String weeklyAgendaSubject;
@Value("${monthly.mail.subject}")
String monthlyAgendaSubject;
@Value("${statusUpdate.mail.subject}")
String dailyStatusSubject;
@Autowired
RosterMailSender rosterMailSender;
@Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar rabbitListenerEndpointRegistrar) {
}
@RabbitListener(queues = {"${spring.rabbitmq.queue.roster.daily}"})
public void receiveDailyEventAgenda(List<CalendarEvents> calendarEvents) {
log.info("Received message" + calendarEvents);
rosterMailSender.sendRosterEmail(calendarEvents, dailyAgendaSubject, DAILY);
}
@RabbitListener(queues = {"${spring.rabbitmq.queue.roster.weekly}"})
public void receiveWeeklyEventAgenda(List<CalendarEvents> calendarEvents) {
log.info("Received message" + calendarEvents);
rosterMailSender.sendRosterEmail(calendarEvents, weeklyAgendaSubject, WEEKLY);
}
@RabbitListener(queues = {"${spring.rabbitmq.queue.roster.monthly}"})
public void receiveMonthlyEventAgendas(List<CalendarEvents> calendarEvents) {
log.info("Received message" + calendarEvents);
rosterMailSender.sendRosterEmail(calendarEvents, monthlyAgendaSubject, MONTHLY);
}
public void receiveDailyEventAgendas(List<CalendarEvents> calendarEvents) {
rosterMailSender.sendRosterEmail(calendarEvents, dailyAgendaSubject, DAILY);
}
}
结论
在本文中,我们研究了我们为跟踪完成的事情而构建的增强系统之一。该系统在应用于各种用例时很有用。我希望这将有助于任何有兴趣建立一个系统来捕获、组织和跟踪他们的任务完成的人。
推荐书单
《项目驱动零起点学Java》
《项目驱动零起点学Java》共分 13 章,围绕 6 个项目和 258 个代码示例,分别介绍了走进Java 的世界、变量与数据类型、运算符、流程控制、方法、数组、面向对象、异常、常用类、集合、I/O流、多线程、网络编程相关内容。《项目驱动零起点学Java》总结了马士兵老师从事Java培训十余年来经受了市场检验的教研成果,通过6 个项目以及每章的示例和习题,可以帮助读者快速掌握Java 编程的语法以及算法实现。扫描每章提供的二维码可观看相应章节内容的视频讲解。
《项目驱动零起点学Java》贯穿6个完整项目,经过作者多年教学经验提炼而得,项目从小到大、从短到长,可以让读者在练习项目的过程中,快速掌握一系列知识点。
马士兵,马士兵教育创始人,毕业于清华大学,著名IT讲师,所讲课程广受欢迎,学生遍布全球大厂,擅长用简单的语言讲授复杂的问题,擅长项目驱动知识的综合学习。马士兵教育获得在线教育“名课堂”奖、“最受欢迎机构”奖。
赵珊珊,从事多年一线开发,曾为国税、地税税务系统工作。拥有7年一线教学经验,多年线上、线下教育的积累沉淀,培养学员数万名,讲解细致,脉络清晰。
购买链接:https://u.jd.com/XwJWF2r
精彩回顾
微信搜索关注《Java学研大本营》
访问【IT今日热榜】,发现每日技术热点