Chris Geihsler
@seejee
SYNC
SYNC
ACTIONS
Student::Create
Student::ReassignSchool
Classroom::AddStudentToClassroom
Error::ValidationError
Teacher::Update
School::Deactivate
Error::WontAddStudentToClassroom
Error::CantMoveSchool
AcrossCustomers
class Student
# 1100 lines
def update_from_clever(clever_student)
# 100 lines
end
end
module CleverUtils
# 500 lines
def create_student(clever_student)
# 50 lines
end
end
class Sync::Student
def sync(clever_student)
student = find_student(clever_student)
if student.nil?
create(student, clever_student)
else
update(student, clever_student)
end
end
# more methods
end
class Student
#
# a little smaller
#
end
module CleverUtils
#
# a little smaller
#
end
class Sync::Classroom
def update(classroom, clever_classroom)
# do some update stuff
if !classroom.students.include?(student)
classroom.add_student(student)
end
end
end
class Sync::Classroom
def update(classroom, clever_classroom)
actions = []
# generate some actions
actions
end
end
# new
actions <<
Actions::AddStudentToClassroom.new(
student_id: student.id
classroom_id: classroom.id
)
# original
classroom.add_student(student)
class Actions::AddStudentToClassroom
attr_reader :student_id, :classroom_id
def invoke
student = Student.find(student_id)
classroom = Classroom.find(classroom_id)
classroom.add_student(student)
end
end
# original
def sync_students
clever_students.each do |clever_student|
Sync::Student.new.sync(clever_student)
end
end
# new
def sync_students
actions =
clever_students.flat_map { |clever_student|
Sync::Student.new.sync(clever_student)
}
actions.each do |action|
action.invoke
end
end
id | type | payload | invoked_at |
1 | action | #JSON | 2015-05-05 |
2 | action | #JSON | NULL |
3 | error | #JSON | NULL |
class Actions::AddStudentToClassroom
attr_reader :student_id, :classroom_id
def to_json
{
_class: 'AddStudentToClassroom',
student_id: student_id,
classroom_id: classroom_id
}
end
end
def sync_students
actions =
clever_students.map { |clever_student|
Sync::Student.new.sync(clever_student)
}
save_actions(actions)
invoke_pending_actions
end
class Synchronizer
def sync
save_actions(sync_schools)
invoke_pending_actions
save_actions(sync_teachers)
invoke_pending_actions
save_actions(sync_students)
invoke_pending_actions
save_actions(sync_classrooms)
invoke_pending_actions
end
end
class Synchronizer
def sync
save_actions(sync_schools)
save_actions(sync_teachers)
save_actions(sync_students)
save_actions(sync_classrooms)
end
def invoke
invoke_pending_actions
end
end
Student::Create
Classroom::Create
actions <<
Actions::AddStudentToClassroom.new(
student_id: student.id
classroom_id: classroom.id
)
class EntityReference
def to_json
[
{ field: 'id' , value: XXXX},
{ field: 'clever_id', value: YYYY}
]
end
def find
end
def ==(other)
end
end
# new
if !current_student_refs.include?(student_ref)
actions <<
Actions::AddStudentToClassroom.new(
student_ref: student_ref
classroom_ref: classroom_ref
)
end
# original
if !classroom.students.include?(student)
actions <<
Actions::AddStudentToClassroom.new(
student_id: student.id
classroom_id: classroom.id
)
end
class Actions::AddStudentToClassroom
attr_reader :student_ref, :classroom_ref
def invoke
student = student_ref.find
classroom = classroom_ref.find
classroom.add_student(student)
end
end
if student.school == classroom.school
Actions::AddStudentToClassroom.new(
student_ref: student_ref
classroom_ref: classroom_ref
)
else
Errors::WontAssignClassroom.new(
student_ref: student_ref
classroom_ref: classroom_ref
)
end
Student::Update
Student::ReassignSchool
Student
if student.school == classroom.school
Actions::AddStudentToClassroom.new(
student_ref: student_ref
classroom_ref: classroom_ref
)
else
Errors::WontAssignClassroom.new(
student_ref: student_ref
classroom_ref: classroom_ref
)
end
Student::Update
Student::ReassignSchool
Student
Pending Student State
class Data::Student
:attributes,
:school_ref,
:classroom_refs
end
def pending_state_for(student_ref)
initial_state =
if student_ref.exists?
extract_state(student_ref.find)
else
empty
end
pending_actions_for(student_ref)
.reduce(initial_state) { |state, action|
action.apply(state)
}
end
class Actions::Student::ReassignSchool
attr_reader :student_ref, :school_ref
def apply(current_state)
current_state.merge(
school_ref: school_ref
)
end
def invoke
student.reassign_school(school)
end
end
class EntityReference
end
class Data::Student
:attributes,
:school_ref,
:classroom_refs
end
class Sync::Clever::Student
def find_entity(clever_student)
EntityReference.new(clever_id: clever_student.id)
end
def extract(clever_student)
Data::Student.new(
attributes: {
first_name: clever_student[:first_name],
last_name: clever_student[:last_name],
},
school_ref: ...
)
end
end
if will_too_much_stuff_change?(pending_actions)
reject_changes
pause_syncing
notify_support
end
Chris Geihsler
@seejee