Wikipedia

Resultados de la b煤squeda

viernes, 3 de diciembre de 2021

Handling dates in Spring: The right way

In this post I want to show you what — in my opinion —  is a nice way to handle dates within your Spring Boot application. Suitable both for business needs as well as for unit testing.

Usually we find situations in which dates are spawned simply with LocalDateTime.now() or — to make things worse  using the old API new Date(). This makes testing difficult since there's no easy way to control these scenarios for unit or integration testing.

A better approach would be to relay on a utility class in order to give the user the representation of what now means in certain context. Then again, we need either to do some obscure work to handle static methods in unit test — if you're wondering, there are several frameworks, being powermock the most known  or provide the functionality in that class for that purpose. Which in turn could lead to a usage of a test method — God forbids — within production code!

I would give you a clue: There's a mechanism that you're been using for quite a long time that's really handy for this situation... I think you might have guessed by now. YES! it's dependency injection!

Here's a simple class definition to show this approach:


In order for to be fully operational within a Spring context, you'll need to create the following configuration as well:



As you may have guessed, this Spring component will allow us to inject in every other component that we need to get what is the current date. It will also allow us to mock its methods easily with tools like Mockito.

In order to illustrate this, let's imagine that we need to code a feature that needs to validate if a credit card is expired or not. It should also tell us if the card is soon to expire if we're within the actual expiration month. To make this thing more interesting I will use TDD to build the code piece by piece.

Now, for simplicity this will be the class definition for the card:

public class Card {
private String cardholderName;
private String cardNumber;
private LocalDate expirationDate;
}
Let's create our CardExpirationService that will be the responsible for the logic regarding the expiration. After that, let's create the test class as well with the help of an IDE.

We can already start building the first scenario. I'm going to start with a non expired card. We create a non expired card, that is, a card that has an expiration date greater than a month from what we consider "now". Remember, we're doing this in a TDD way, so here's as far as I can get for my test code:

Let the IDE create the method for me so I can go back to the test again. And write the necessary assertion. Lest assume we want to get a "VALID" string for this scenario. The final test looks like this:
@Test
void shouldGetValidCard() {
LocalDate threeMonthsFromNow = LocalDate.now().plusMonths(3);
Card validCard = new Card(threeMonthsFromNow);

String result = cardExpirationService.validateExpiration(validCard);

Assertions.assertEquals("VALID", result);
}
No, if we run it, we'll get an error, of course, so it's time to move to the production code once again. Basically we'll check if the expiration date is in the future, so we write something like this:
public String validateExpiration(Card card) {

LocalDate today = LocalDate.now();
if (today.isBefore(card.getExpirationDate())) {
return "VALID";
}

return null;
}
Now, we run the test and we should have a neat green check! Let's write the next scenario. I'll choose the already expired scenario this time:
@Test
void shouldGetExpiredCard() {
LocalDate yesterday = LocalDate.now().minusDays(1);
Card expiredCard = new Card(yesterday);

String result = cardExpirationService.validateExpiration(expiredCard);

Assertions.assertEquals("EXPIRED", result);
}
Run this test and we should get an error again. It's time to go back to the production code and see what's wrong. The next obvious choice for us this time is to add an else clause and return from there. It should look similar to this:
public String validateExpiration(Card card) {

LocalDate today = LocalDate.now();
if (today.isBefore(card.getExpirationDate())) {
return "VALID";
} else {
return "EXPIRED";
}
}
And with no surprise, the tests are green again! Sweet! Now, let's tackle down the last scenario. A card that is soon to be expired:
@Test
void shouldGetSoonToBeExpiredCard() {
LocalDate oneDayBeforeEndOfMonth = LocalDate.now().plusMonths(1).minusDays(1);
Card soonToExpireCard = new Card(oneDayBeforeEndOfMonth);

String result = cardExpirationService.validateExpiration(soonToExpireCard);

Assertions.assertEquals("EXPIRES_SOON", result);
}
If we run the tests at this point we should get an error stating that:
Expected :EXPIRES_SOON
Actual :VALID
Time to go back to the production code and see what's wrong. So, for the time being, this particular case still represents a valid card. So we have to so something inside that branch. It may look like this:
public String validateExpiration(Card card) {

LocalDate today = LocalDate.now();
if (today.isBefore(card.getExpirationDate())) {
long daysToExpire = ChronoUnit.DAYS.between(today, card.getExpirationDate());
if (daysToExpire <= today.getMonth().maxLength()) {
return "EXPIRES_SOON";
}
return "VALID";
} else {
return "EXPIRED";
}
}
At this point all the tests shall pass. But so far we just covered an imaginary scenario that rarely ever happens in real life. What happens in reality is that we have to deploy this code within some other service possibly across multiple timezones. The integration test you write based on mocked data will start failing — when, all of a sudden, all cards are expired —. If we think about it, the class CardExpirationService somehow knows what day is it today, and that's not a responsibility of the class. Think of yourself, you just don't know what time is, do you? You go to your smartwatch — or a grandfather's clock— to exactly know what the time is. So let's do the same for this class. Let's give the chance to look at our controlled clock. The whole class should look like this:
public class CardExpirationService {

private final BusinessDateUtils businessDateUtils;

public CardExpirationService(BusinessDateUtils businessDateUtils) {
this.businessDateUtils = businessDateUtils;
}

public String validateExpiration(Card card) {

LocalDate today = businessDateUtils.getCurrentDate();
LocalDate expirationDate = card.getExpirationDate();

if (today.isBefore(expirationDate)) {
long daysToExpire = ChronoUnit.DAYS.between(today, expirationDate);
if (daysToExpire <= today.getMonth().maxLength()) {
return "EXPIRES_SOON";
}
return "VALID";
} else {
return "EXPIRED";
}
}
}
And we can perfectly control what now is from our unit test using a mocking framework, or, in this case — and for the sake of simplicity — I just wrote a custom implementation for the BusinessDateUtils interface. The test class should look like this:
class CardExpirationServiceTest {

private static final LocalDate now = LocalDate.of(2020, 4, 21);

private CardExpirationService cardExpirationService;

@BeforeEach
void setUp() {
BusinessDateUtils businessDateUtils = new TestBusinessDateUtils(now);

cardExpirationService = new CardExpirationService(businessDateUtils);
}

@Test
void shouldGetValidCard() {
LocalDate threeMonthsFromNow = now.plusMonths(3);
Card validCard = new Card(threeMonthsFromNow);

String result = cardExpirationService.validateExpiration(validCard);

Assertions.assertEquals("VALID", result);
}

@Test
void shouldGetExpiredCard() {
LocalDate yesterday = now.minusDays(1);
Card expiredCard = new Card(yesterday);

String result = cardExpirationService.validateExpiration(expiredCard);

Assertions.assertEquals("EXPIRED", result);
}

@Test
void shouldGetSoonToBeExpiredCard() {
LocalDate withinTheMonth = now.plusDays(3);
Card soonToExpireCard = new Card(withinTheMonth);

String result = cardExpirationService.validateExpiration(soonToExpireCard);

Assertions.assertEquals("EXPIRES_SOON", result);
}

}

As you can imagine, and with a little bit of Spring magic you can set a custom clock for your integration and/or unit tests with just a few lines of code 馃槃

And yes, of course, now that we have the unit tests in place we can add a few more scenarios for edge cases and do a little bit of refactor on the production code to make it cleaner 馃槈

Hope you find this useful and see you next time!


s谩bado, 27 de noviembre de 2021

Architecture diagrams made easy

When you're starting a new project it's crucial that you are able to understand quickly how the systems that you'll be working on connect to each other and the general idea behind their architecture. Then on a deeper level, you'll need to understand how the components of those systems works together.

A code generated container diagram

Often happens that they give you a general architecture diagram that's really neat but it doesn't tell you exactly what you need to know in order to be able to do your job.

Other times you have to implement or refactor some features that alter the way things are connected at the moment and you have to re-route them or connect to other systems.

On rare occasions, you start a brand new project in which you are responsible to define how the components of the particular software you're trying to build connects to one another.

Throughout the years I had the chance to experiment all of the aforementioned situations. In some of them I had more documentation at hand and in others... well... let's say that it had some room for improvement in that area.

At the time I was working for Southwest Airlines the diagrams (sequence, modules, etc) were made using WebSequenceDiagrams and/or Microsoft Visio. They looked really neat and everything. But there were a few problems from my point of view: 

  • When the diagrams were done then the cost of updating them was really high. You needed to copy the source file if it was in Visio and change them using drag & drop with the mouse. A hideous task for a software developer.
  • For some additional features it was necessary to have a premium account.
  • The tooling was different from the everyday one.
  • It was complicated to version them.
  • Collaboration was limited.
That's me making a fool of myself...
 

So when we had to design a new login feature I decided to investigate how can that be done better. I definitely was looking for a tool that you can write the code and it would create the diagrams from it (Just like WebSequenceDiagrams but with versioning and open source). That's when I found PlantUML.

By using that tool it was really easy to maintain architecture diagrams as they where evolving alongside the features or the new requirements that we need to implement. Building a sequence diagram to visualize how particular services should interact had become an enjoyable task for developers and we also had that versioned in our code repository. Even when I had to document a card it was really painless to write a few lines and render the diagram (a sequence diagram for instance) on it just with the use of your favourite IDE.

A few years later when moved to LATAM Airlines project they were using PlantUML as well but they made a huge improvement. On top of PlantUML they decided to use the C4 Model for modeling software architecture. That is exactly what I want to show you in this post.

At this point you may be willing to get your hands dirty and start writing those beautiful diagrams, don't you? Well, the wait is over!

The first thing we need to do is clone this repository so we can have all the templates for the C4 software architecture model as foundation. You may also want to take a look at the README now that you are at it 馃槈

git clone https://github.com/plantuml-stdlib/C4-PlantUML.git

Note: There's no need to clone the repo because you can use directly by importing the web file from your diagram files. Nonetheless I think it's a good idea to take a look at it and play around with the templates.

Let's create our own project folder to start working on it. For simplicity I will call it "diagrams". Create the folder right next to the downloaded repository one.

Now download the PlantUML executable into it by issuing the following command:

wget https://github.com/plantuml/plantuml/releases/download/v1.2021.14/plantuml-1.2021.14.jar
At this moment we can start by creating our first dummy diagram. Copy and paste the following snippet into a dummy.puml file:

 

Now with the following command we'll generate the awesome image file:

java -jar plantuml-1.2021.14.jar .

And after a few seconds you should see a file called "My_First_Diagram.png" in the same folder.

Example diagram
 
I'm feeling that you are starting to think some ways in which you cant start using it in your project by now...
 
If you're using IntelliJ or VS Code there are fantastic plugins that'll render this as you type the code. The plugin for IntelliJ can be found here.

The invitation to start making your own beautiful architecture diagrams by code has been made! I think that with a little bit of scripting you can start adding this diagrams along with your codebase so you'll always have your architecture diagrams clean and updated.

I hope you find this post useful and entertaining 馃榿
 
See you next time!

mi茅rcoles, 24 de noviembre de 2021

Moved to The Netherlands!

It's been seven years since I did my last post in this blog. It's a completely different world now! At least for me many things happened in between: I changed my job, got my engineering degree, got married and moved to The Netherlands!

The last topic is precisely what I want to talk about it in this post.

I'm gonna tell you a little bit of our history on why this movement.

A few years ago, we had the chance to buy really cheap flights and travel to Europe. Since we're from Argentina it was something we really like to do and one of a kind opportunity. I have to give the credits for this to my wonderful wife Roberta because she was the one pushing to find the tickets. I only said the words "buy them" while taking a bus to Buenos Aires during a business trip. We had to make the purchase within a few hours, not much time to decide!

One of the places we stayed at that time was Amsterdam. The moment we arrived at the city centre was a turning point for us. We looked at each other to say:
We have to live here one day!

A tour we took around the canals

Fast forwarding into recent days, we were struggling about what are we supposed to do with our life. Because we knew we wanted to live abroad and we also had a relocation to Chile that got stuck in between bureaucracy and covid restrictions... For that we had the feeling that we were going nowhere...


Enjoying the afternoon

One day my wife found a job posting in Linkedin about a company that offered relocation to The Netherlands. This awesome company is called WAES 馃槈. So I decided to give it a shot. I posted my resume and waited for the recruitment process.
After a few days I got a message requesting for a videocall, which of course I replied. After that nice interview, a coding challenge and a technical interview I was offered a contract with a relocation package for me and my wife! We couldn't believe it!!! Our dream was finally becoming a reality!


So since about a month ago we're happily living in The Netherlands!馃懌


That's it for now so stay tuned! I will create new posts about living here and the whole process I had to go through!

See you soon! Hope in less than seven years... 馃槣

In the meantime, take this cookie 馃榿

A cookie from Van Stapele Koekmakerij