Instructor: So by now, we already refactored a lot.
I'm fully aware of that.
But this is how you do write clean code.
It's a step-by-step process,
which is why I'm showing it in great detail here.
Because that is what you will do ultimately,
when you clean up your own code.
It's about trying out things, being creative,
and moving things around.
And speaking of moving things around,
we now use errors, which is great.
But now we have all that code for creating errors
side by side with code that, for example,
dispatches different process functions
for different transaction methods.
This, again, is mixing different levels of abstraction.
So we should consider splitting our functions.
For example, here in process transactions,
where I check for whether my transactions are empty
to then create an error,
we can create a new function,
which we could name "validateTransactions"
where we get all the transactions.
And then we move this code
where we generate this error into this function.
Then here in process transactions, we can simply call
validateTransactions before we go through this for loop.
The great advantage of this approach
is not just that processTransactions is now slimmer,
though we should forward transactions
to validate transactions function,
but although that because we use real errors,
and we throw this error,
we use a built-in mechanism in the programming language,
which will ensure that this automatically bubbles up.
So it will just bubble through processTransactions,
canceling this function as well,
if an error is generated inside of validateTransactions,
moving up to the next function until it is being handled,
which in this case, it is here.
And this of course, is great.
This here, of course, should be transactions, by the way,
not transaction.
Now, we could argue
that we have mixed levels of abstraction here.
Calling is empty, and then this low level code
of creating the error and adding a code,
and therefore, we could also add another function here,
where we build this error.
You could absolutely do that but I will not do it here.
I think it's too much splitting,
and if you would want such a helper function
which builds an error, I would recommend
that you simply create your own error class,
which you instantiate here.
So I will leave it like this.
Nonetheless, we have some extractions left to do
here for processTransaction.
There we check whether it's not open,
or if it's neither a payment nor a refund.
And we can outsource these validations as well.
So we can add a new function here,
which we name "validateTransaction", for example,
receiving the transaction as a parameter.
And now we could either create
one function for each check here
or we take both checks and put them into the same function.
Which I will do here
because we're doing the same kind of work,
we're validating a transaction, just with different checks,
and therefore having this in one function
makes a lot of sense to me.
And now we can just call validate transaction here
before we then try to process the different transactions.
And again, because validateTransaction froze an error,
if we got an error, this processTransaction,
function execution will be canceled if an error occurs,
and this code will not be executed.
Instead, we move up to the next function above it
until this is being handled,
which in this case is happening here in this for loop.
And that now again, we're more extractions,
which hopefully, overall, help with readability
if you would read this entire code top to bottom.