What's going on guys? Assalamualaikum. And welcome to Amigoscode. In this video
I want to talk to you about 10 spring and spring boot common
mistakes that I see lots of beginners and
even experienced developers do. So in here I do have
this class where basically it's a test controller and I want to
go through ten mistakes that you should definitely avoid.
So number one in here is leaking into tunnels when I
mean leaking internals. Have a look at this controller in here.
So here we have Customer and then getCustomer.
Nice and simple, right? So I can send a request here
and this will give me a customer back. Now the issue here
is that if you look into this customer, this right here
is an entity, meaning that this class right here will be mapped
onto your database and then you can have a repository and perform all the
CRUD operations on it. But the internals here that you are leaking most
of the times are stuff that the client doesn't need to know.
So here for example, have a look. So we have the password.
And in here, so if I scroll down,
you can see that I have here get password.
Now by you basically doing this, you are
leaking internals. I've seen people doing this. So in here,
so get password and then add JSON and then
ignore. So @JsonIgnore. This is fine,
but still totally wrong. Why?
Because this entity right here is meant for
your database. It's the internal of your back
end. And if the internals change,
then basically you're going to have to always make sure that the client
doesn't have exposed information, even though sometimes you might even forget to
add @JsonIgnore, ignore leaking information. So never do
this. And the second mistake that I see is that you
are not using Records. So Java Records, it's something which
was introduced, I think it was Java, I can't
remember to be honest. When was it? Java 16.
Correct me if I'm wrong. Yeah, but you're
not using it. So basically what you would do is instead
of Customer you'd have a record. So here, let me just say record.
And then here I'm going to say customer and then DTO
for example. So data transfer object and or
I can even say response. For example. So customer and then response.
And then inside here I can say now. So here string
and then maybe Name for example, right? And let's say that I just want to
return the name. So now you can see that basically
this now is what the client receives. So what
I would do is I would map basically the
entity onto a class. So this is an
Immutable class. So before Records, what people used to do was having
a class and then here they would say Customer and then Response.
And inside of the customer response you'd have string
or private final string. And the name and then
you have getters constructors and yara, yara, yara, yara. But you don't need
none of that with records. Yeah,
so records is something very powerful and you should be
using the other mistake that I see is
that you are not so this is mistake number three.
Someone's calling me 1 second. So this
is mistake number three and that is not using
dependency injection correctly. Why am I it's like this.
So not using dependency injection correctly.
So usually what you do is you have private and then customer
repository and then basically within the constructor
you would initialize this to new and then yada, but don't do
this yet, this is wrong. Okay? So what you should be doing is
using dependency injection. So in here
so what you do is basically you remove all of this right here
and then basically add the constructor. And the beauty
of this is that you let Spring take care of
the objects for you, right? So you don't have to manage anything
and that is managed for you, right?
So basically now you can basically have one instance.
So the default is that beans, they are singleton, right? So which
means that they are reused all over the shop. So instead
of basically creating a brand new instance, if you were to do new
all the time within the constructor yeah, so never do this,
right? Then I also seen so I also seen that usually
people don't have this in here. So people don't have this
and they just leave it as is, right? So they
just leave it as is and this actually works. But don't
do this. Literally don't do this. Yeah, and also I've seen people
have the setter. So here setter and then the customer repository.
So setter injection basically setter injection versus
controller injection. So don't do this because when it comes to
testing you are in big trouble, right? So if you want to
mock dependencies you won't be able to do so. So never do
this. And basically, so if I control Z in here,
always use dependency injection. And also I've seen people still
using auto wired and they say oh, why this is not
needed. Basically it's not needed anymore. Yeah, so this is before, so now it's not
needed. Cool. The fourth mistake is
separation of concern. So if we look into this class
right here, so it's acting as a controller, meaning that it
basically bridges the gap between the clients and
the back end server. But if we look in here,
look at this. So get customer here we have
access to the repository, find by ID or else throw,
right? So this is basically wrong.
The job of the controller is to handle Http
requests. Then you have service classes which basically
perform business logic and then you have repositories which
basically interact with any data source of your choice.
So here this class, we are mixing the whole world and we
don't want to do that, right? So even also have a look. Customer response
in here. And actually this should have been like that, right? So before and
then basically you map. So map basically
here I can say get and then username,
for example. So I meant to do this before in here,
right? So basically so if I get rid of this
so here you can see that I even have this record which
should be in its own file, right? So here
we are mixing both things. So don't
ever do this, right? So if you want to learn more about building
well organized and structured applications, check out my latest
full stack course where I teach all of this. Literally every
single thing that I'm covering here I teach you so that you can build a
full stack application from the ground up.
And currently there's a 10% off on the website.
So definitely go check it out. The fifth
thing which I also need to mention is lack
of error handling. So here, have a look.
Customer Repository Find and then here, new runtime exception.
Like what is this? Right? So if you know about Http
status codes, you know that. So if I try and basically run this Http
request through IntelliJ yes, so if I send the request
now, you can see that it works, right? But we're getting
a 500. 500. But this is wrong,
right? 500 is not an internal server.
500 means internal server error. Something went wrong with our
logic and the customer is not the one to blame for.
But here we're saying hey,
something happened with our server, something happened with our server.
Basically we can't handle the request but it's not the case, right? So the
client sent an ID which is not present. So in
this scenario, what we want to return back is
a client response error. So it would be a
four or four. Now, the way to do this is by
basically having your own exceptions. And I've seen people doing
this all different ways, but basically in
here so this is the new UI, which I'm still not quite
sure how to close this. Yes, and the services.
So basically what you would do so the best thing to do is
for you to have so in here I've got exception and
in here I've got this API error. And at this point I can
construct the exact payload that I want clients to look at.
So here I've got a path message and status code.
But more important, I've got this default exception handler which
basically is responsible for handling all different
types of exceptions. So here resource not found.
Exception. Insufficient authentication.
Exception. And here you can see that I'm populating the correct
response status code. And the same for bad credentials,
unauthorized exception. This is a default.
And if you want to catch, for example so here if you want to
catch this runtime exception, all you do,
you just duplicate this and then you say right, so you
could even actually have it here as well. So basically runtime
exception if you want to combine these two together, right? So this is a
much better way of handling your exceptions. If you're not sure, don't you
worry because I do cover this on the full stack course as
I've said. So the other thing that I want to
talk to you about is testing. And this is big,
right? So this is big. So I've seen people basically so if
I go here and test, basically so
here we learn about testing and whatnot you need to basically understand all the annotations
that come with testing because your tests, they should run
fast. And also you have to make sure that you only test the unit itself
instead of the entire world. And application context
as well is something that you have to be aware because when testing,
you don't want to load the entire application context. So this is where all the
beans are managed for you. So you need to be aware of data
JPA test. Also if you're doing stuff with JDBC,
so there's an appropriate annotation for it in here. So have
a look. Actually, sorry, here is even better
because what I've done, actually I've constructed the JDBC template
myself instead of loading the entire context.
So here, have a look, data source. And I can build this with
test containers, which is basically a way for you to test
your SQL queries and repositories and all that stuff
with a real database or actually with a database that
you're going to use in production and not age two.
So this is, again, it's a big thing that I've seen people do
using H two for testing. Don't do that and I can record
a video on it if you want, just feel free to let me know.
And one more thing actually, so with testing,
so I've seen that. So if I go to it,
so, integration testing, so people are using this
all over the shop for all tests. This is wrong, this is wrong.
Okay, so we have to be really careful. So here I can
actually run all tests. And the cool thing actually, I'm actually
testing the whole thing, unit testing as well as integration testing,
right? So if you want to learn how to basically test this
or actually external dependencies, there's a nice way where you can
have a fake implementation and then with your configuration,
you say, right, so basically with property
or environment variables, actually you can say, right, so here I'm going
to mock. And then basically you return the fake implementation and then you
can use that in your integration testing and in
environments where you don't have access to, for example AWS, right. So testing
is something that you should and must learn how
to test because otherwise it will cause you big,
big trouble. Trust me, this one is serious.
I'm not even joking. Okay, cool. The other thing that I want to talk to
you about is not using annotation validation,
right? So here, if I go back to the what
is it? Test controller. So test oops,
so test controller in here, have a look. So this test
controller I'm getting, for example, let's say that I'm storing a customer,
for example, right? So here, let's just say that this was a
customer. So let's just create one of these. So duplicate this
and then let's just say request, and this
would be the request, for example, right? So this is not real code that
works, but I'm just demonstrating what's happening here. So if I
remove that and then say void, for example. Now what I've seen
a lot is that people usually get the payload from
the client and then they pass on to the service and then they'll do,
for example, let's say that this is a service class if and
then customer request name, and then dot
is empty for example, right? But this would fail because if the
name is empty, then you'll throw null pointer exception and then that's
it, right? So if you have more fields that you want to
validate that they should be empty or they should be between
a range, then you'd have a bunch of if statements,
but you don't want to do that. Okay? So what you do is you basically
use so this annotation right here. So here I can say at
and then non null, for example in here.
So now this right here basically now
allows me to remove all if statements
and I can say, right? So in order for me to receive the
request, it has to be a valid. So valid
at and then valid and then
request actually, so I think it's validated,
so validated request, right? So there's some more other stuff
that you have to do. And then what you do is within
the exception handler, you can then capture that exception
and then transform it into a payload that a client
can understand and say, hey, oh, okay, cool. So I've missed the
name, so the name must be present, okay, instead of
you having all of those if statements. And the last two things
that I want to talk to you about are the fact that one,
you don't log enough. So if I have my controller
here so you're not using loggers. So loggers,
it's very important that you understand when to debug or
info or warnings. So you need to understand basically what
to debug but also don't log frequently because you
can actually impact the response round trip and you don't want that,
right? Because it's all I o intensive tasks.
It can be right at times if it's many logs, right?
And the other thing is, so if you are still stuck in the past
and using XML to build spring applications,
please stop and enroll
to my brand new course where I teach you how to build
a full stack application from the ground up. This is pretty much it.
Let me know about these mistakes. Have you done
some of these? Have you learned something new? And yeah,
if there's anything that you want me to teach you next, comment down below.
As always. Smash the like button. Literally go on
smash. And I'll catch you in the next one.