Skip to content

start exam implementation: with the notate method, driven by test#5

Open
bkuchcik wants to merge 11 commits into
developfrom
feature/a-teacher-notate-a-student
Open

start exam implementation: with the notate method, driven by test#5
bkuchcik wants to merge 11 commits into
developfrom
feature/a-teacher-notate-a-student

Conversation

@bkuchcik
Copy link
Copy Markdown
Owner

@bkuchcik bkuchcik commented Jun 4, 2018

No description provided.

import java.math.BigDecimal

data class Exam(val id: Long) {
fun validateNotation(notation: BigDecimal): Either<InvalidNotationForThisExamException, Unit> =
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In English, this would be a grade :)

fun validateNotation(notation: BigDecimal): Either<InvalidNotationForThisExamException, Unit> =
when (notation) {
in (0.toBigDecimal()..20.toBigDecimal()) -> Either.right(Unit)
else -> Either.left(InvalidNotationForThisExamException("This notation, $notation, is not in bound"))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably call it a GradeOutOfBoundsException

}
}

class InvalidNotationForThisExamException(msg: String?) : RuntimeException(msg)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kotlin exceptions are unchecked, so simply Exception is sufficient unless cross-compatibility with Java is required.

}
}

class NotEvaluatedException(msg: String? = null, throwable: Throwable? = null) : RuntimeException(msg, throwable) No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A default message is probably preferable to null, yes?

else -> Either.left(NotEvaluatedException())
}

fun notate(exam: Exam, note: BigDecimal): Either<InvalidNotationForThisExamException, Student> =
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we grade an exam in English :)

studentsRepository.findStudentById(studentId = 1).flatMap { student ->
examsRepository.findExamById(examId = notateExam.examId).flatMap { exam ->
student.notate(exam, notateExam.note).flatMap { updatedStudent ->
studentsRepository.save(updatedStudent)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are too many levels of abstraction here and it is not clear what this method is doing. Remember the SRP :)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would you remove there is only two call and entity method.
Maybe you do not like flatMap with either, but I don't see how to do it shorter than that

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe by giving up either, but I want to use it to handle errors

Copy link
Copy Markdown

@Hydragyrum Hydragyrum Jun 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly that we jump from a student into an exam into a grade for that exam and student. all the while nesting. Exam doesn't depend on student, so the nesting is odd.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nesting helps to get the values directly. The other solution is to do if(isRight()=> toOption().get()) etc..etc but I really don't like that solution (I tested it)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I searched a lot, and normally the following code is better and compile (I need to check at home)

notateExam.also {
    ForEither<RepositoryException>() extensions {
        tupled(
            studentsRepository.findStudentById(studentId),
            examsRepository.findExamById(examId)
        )
    }.flatMap { (student, exam) ->
        student.notate(exam, note).flatMap { studentsRepository.save(it) }
    }.mapLeft { NotateExamException(throwable = it) }
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not work, please close it, it is useless

class StudentsInteractor(private val studentsRepository: StudentsRepository, private val examsRepository: ExamsRepository) : Students {

override fun notate(notateExam: NotateExam): Either<NotateExamException, Unit> =
studentsRepository.findStudentById(studentId = 1).flatMap { student ->
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your studentId is defined in the notateExam class, we should probably use that otherwise your student 1 will get all the grades

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already noticed it in my comment, but thx

val studentsInteractor = StudentsInteractor(studentRepository, examsRepository)
studentsInteractor.notate20().apply {
it("should notate an existing exam with a note of 20") {
isRight() `should be` true
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual grade isn't checked here. How do we know it's 20?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this test should be deleted because check is done in the last test

typealias Grades = Map<Exam, Grade>

data class Student(val id: Long, val grades: Grades = emptyMap()) {
fun getNotation(exam: Exam): Either<NotEvaluatedException, BigDecimal> =
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops ! get grade !

else -> Either.left(NotEvaluatedException())
}

fun notate(exam: Exam, note: BigDecimal): Either<InvalidNotationForThisExamException, Student> =
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops should be grade not notate

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And a Grade not a BigDecimal

it("should retrieve exam by id") {
verify { examsRepository.findExamById(5) }
}
it("should save student to the repository with the expected notation of 20 for this exam") {
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grade not notation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants