No notes available for this episode.
Transcribed by Rugo Obi
payment.js , which is this file here - all it does is just
require this PayPal file you were looking at a second ago - and then
admin.js with admin specific stuff. I think this is what-you-can-see-is-what-you-get editor and some Rail stuff.
So we're opening up the
orders/edit page and you can see here there's a bit of code,
payment file, that’s the
So, I'm still within the
orders/edit file right here, and I'm going to look for the bit for actually paying. So, "Click Below To Pay Securely", that looks about right, and then there's this
div tag generated via Rails, that's unimportant. What's important here is all the data attributes that are created.
There are five different data attributes:
@payment is an instance variable passed from the controller. Let's have a look at what that is.
I've opened up the
orders_controller and I'm in the
edit action here. If we go down nine lines, we see this
payment variable, and what's happening here is, it calls
PayPalGateway.new, passes in
order and then generates the
I'll go into that file briefly and take a look. It’s not on the path, I don't know why, and
PaypalGateway, yeah, here we go.
And this generates a big old block of JSON and then calls to JSON there to ensure there are no encoding issues.
You want to be careful to use good methods to transform your objects in your backend language to JSON, otherwise, there can be issues with single quotes, that kind of thing.
Anyway, I generate this glob of JSON in the controller here, and then pass it to the
view, via the
You can see on this line here,
paymentDetails, that I use the
JSON.parse functionality with
paypalButton grabs by ID of
#paypal_button, a particular element.
If we go into the
edit file again here, you can see there is the
div with the id
paypal_button, so they match.
And then there was this function,
dataset. This grabs all the data attributes, so there were five of them as you saw over in the
edit file here, and it grabs them all.
Another thing I like to do in my no-framework framework, is to define very simple reusable functions like
get that have no external dependencies.
Then I have variants like
getJSON and so on, and they tend to bring these functions back and forth between codebase and keep improving them and so on and this is a basic library that I use to make writing code a bit faster.
So, this has a bunch of tax calculators -about 10 of them, I can't remember- and you can see some of them in action here.
You choose a year, you choose your income, and then your particular county, then it gives you what your tax is and you can calculate it again.
There are a bunch of other ones, some of them are more complicated. I think the income tax one is fairly involved, but essentially they all have a similar kind of structure.
The main entry point for this particular codebase was the
resources/js/init.js file. You can see that at the bottom of the screen.
And the structure is similar to in the last video, in the sense that there's polyfills included first, then I include some regular JS files, like
stripeIntegration one here, and then I include a separate file for each particular calculator.
The architecture however differs to my previous codebase.
Let me show you how by going into one of these files. This one is for the church tax, that's the calculator we saw on screen a moment ago. And let's go down 11 lines and look at this key piece of architecture.
What I'm doing is attaching to the
window object and the browser, and a key called
kirchenRechner, and then that has a function called
calculate, which is mapped to a function in terms of this file,
So, this does pollute the global namespace in the sense that if there's another piece of code that uses
KirchenSteuer as a name, then it will clash. But I find that to be very unlikely given that this is in German, that's quite a rare word, but this is a risk that this particular piece of code takes.
Perhaps a safer way to have done this would have been to name the app first, 'xyz', and then make this a property, a sub-property of 'xyz'.
However, and this brings me to a more general point, I tend to think the fear of namespace clashing is a little bit overwrought for small codebases. And the architectural complexity that I'd have to add in order to avoid that, didn't seem justified given that there were junior programmers in the team who mightn’t be able to understand it and so on.
So, therefore, I just went with the simplest thing that would work, and there were no issues. This isn't mission-critical code either, so I'm not particularly worried about an error case causing damage.
The next thing to look at is how this particular piece of functionality, i.e, the calculation of the tax, gets connected to the frontend.
So I'm going to search for that particular object and then you'll see that there are some
view files. For example,
resources/views/calculator/kirchen.blade, and then I have a
form, and then I simply attach to the
So, what is the flow of input to output within this particular function for doing the calculator action?
Let me scroll this to the top of the screen, and you can see there's just 22 lines here because it calls out to other functions which do the work. So it calls
What I mean by that is that there are
divs with the results of previous calculations, and it just resets them between each calculation. This is an external function because it's shared between all the calculators.
Then it grabs the form that this was called on from
event.target, and then there are two functions here but the more important one is the inner one. There’s a function I have called
getInputFromForm, and I pass it the
Let's have a look at that particular function.
The key way it does that is using the form data API to create that object.
So let's find the form element here and look at the various types of input.
So we have a
select input here with
name=tax_year. This will become a property
tax_year within the results, and will have as its value, the
option that's selected.
And then for this next input,
checkbox, with the name
income _time_frequency, this will also appear as a key and value in the results. And even if the form differs or whatever, it will still work, and this is really nice because I don't have to do a lot of the boilerplate.
Let me go through the rest of this now.
So we have this function here,
doRawCalculation that takes this
userInput object generated from the form data. And
doRawCalculation calls a third-party API, so it takes a while for the results to come back.
church_tax- from the big glob of results.
This creates a more lean input and leads to less issues.
Then there's a function I have
addMonthlyResults, which basically translates yearly results into monthly results. Then I have
localizeValues into the German way of showing decimals, which is with a comma instead of with a decimal point like we do around here in the English-speaking world.
And down here, we have a final bit to
displayResultsOnPage, and if there's an error to
.catch, and then call the
displayErrorOnPage once that error is caught.
Let's take a look at the function definition of
The main thing to look at here is
It takes a bunch of
I'm going to go into the definition. The documentation here describes it pretty well. So you can see some imaginary input that's passed to it, and what it does is finds the elements on page with ids:
pension being the key here, and
output being the... not prefix -- but suffix, and then it puts a value inside that particular id. So it'll put '40' there, and '20' into
insurance_output, and so on.
It also gives some warnings in developer mode about when there are issues, such as an id not being found.
Big picture, why do I like this function?
Again, it's to do with coupling and division of resources in a team.
Because it simply requires simple HTML ids on the page, for example,
Let me show you that in action real quick.
So we have the
kirchen.blade thing, and we have this
church_tax_result field, essentially it's just a
span , and the results of my calculation will get inserted in there when the results come in. It's as simple as that.
If there were 20 or 30 fields on the page, which there are for much more complicated types of tax, like income tax, then very little code is required to populate the entire page with results.
This is something else I really like.
Returning to the
displayResultsOnPage function, we see something else.
There's heavy use of a
hide and an
unhide function. This just manipulates the CSS and either shows certain large elements or hides them from view.
For example, when we're showing results on screen, we hide the
calculator_input, i.e, the form where the user inputs the information to be calculated, but we unhide the
The inverse thing happens when we
resetResultsAreas or something like the inverse, it's a bit more complicated.
This code obviously isn't perfect, and it does not scale very far, but it's sufficient for the purposes required.
I don't believe in calling in a framework for every single codebase, sometimes things are more easily and more quickly done by going back to basics and I believe that this project was a case where this was justified.