Skip to content

The April Shower and Two Additional Tasks

It is 5 pm in the afternoon. Not many people are around anymore. It has a peaceful impression as opposed to the chaotic vibe that this room always has. There is no sound of fast raging keyboard typing or footsteps rushing from one corner to another. Just the tranquil sound of raindrops outside. Most engineers just want enjoy the spare time they are finally allowed after a tiring week and go home as soon as office hours end. Some choose to stay in the office's entertainment facility on the upper floor to enjoy some free time and avoid heavy traffic on Friday afternoon.

However, there are still some people in the work zone. Alex is sitting at his desk, sleeping. Maya has been standing beside him for some minutes now. Maybe she is hesitant to wake him up or finds his sleeping face amusing and decided just to watch him. On the other side, Emory's standing by the window, gazing far away into the rain. If more people are in the room, they may discover this unusual sight. The two most tireless employees are relaxing and enjoying themselves is not something most employees here think they will ever see in their time here.

As the downpour continues, something deep down in Emory has emerged again, something they have kept alone maybe from the very beginning. Emory is not keen to show this kind of face in front of everyone. This quiet office room without many people around may be the only reason Emory does not mind. They are playing with their fingers, knocking on the window. Gently, but enough to tell something is bothering them in their memory's lane.

It was several years back. A similar feeling but a different place. Emory was looking outside the windows, surrounded by April's heavy shower. The rain was so heavy that all Emory could hear were the sounds of water clashing with the ground. It stayed like that until noises from the other corner of the room faintly reached them. Emory ignored it and kept their attention on the rain. The noise became more and more apparent to the point Emory couldn't ignore it anymore.

There was someone in the corner of the room, looking somewhat desperate. Emory could tell easily from their typing rhythm they were hopelessly trying to complete whatever they were working with. They were so focused that they didn't immediately realize Emory's presence.

"Ah, Emory. Why are you still here?"

"That's my line. " Emory replied. " Is that additional tasks? "

"Yeah. Mana asked me to do it since I was free. "

"Doesn't look additional to me. " The sound in Emory's voice brought a nonchalant atmosphere; it was almost as if Emory pitied them. Emory did not pursue the topic, and they went back to work, though. Emory felt a bit of a disappointment. Emory was hoping they would ask for help but instead, what Emory got was silent treatment for 3 minutes. Just that, Emory decided to leave the room. Emory walked slowly, still hoping that the desperate junior would beg them for help.

However, the reality was the opposite of what Emory wanted. Emory's junior was staying there and keeping the problem for themselves. Dejected, Emory rushed back to the desk and forced their way to the screen.

"Show me the task requirement, let me help you. "

" Ah. I can't bother your rest time with my task..."

" Just let me do it! "

Emory brutally took control of the keyboard to see the issue's description, ignoring the complaint from their junior co-worker. Emory's eyes were focused on the screen, one hand on the keyboard, and the other resisted the helpless co-worker's push.

" Okay. This was not a big problem for me. I can do this quickly. I will take these two tasks. " Emory walked back to their desk, still ignoring their junior's ramblings and turned on the computer.

Emory started browsing through the codebase and writing down some essential requirements notes. That co-worker, however, was still hesitant to let Emory take on some of their tasks. They ran as soon as Emory assigned themself as the assignee in the repository's board.

" Just to be clear, it's not like I am doing this for you. I, myself, decided to help you. So don't misunderstand it. Hmpf! "

The helpless co-worker looked confused. They obviously didn't know how to react to that. Maybe they were feeling a bit awkward; they then stopped complaining and willingly walked back to their desk.

" I feel it's wrong for Mana to give you all the responsibilities near the weekend. So please, just accept my help this time. Okay? " Emory said. Their voice was so soft that it almost sounded like a whisper.

"Sorry. Did you say something? "

"Nothing. Nothing at all. Hmpf! "

Issue Description

Emory took these two tasks explained below. Please read it carefully and design a maintainable solution based on the requirements.

Text Editor (Decorator Pattern)

Your task is to implement two endpoints of a REST API-based Text Editor application.

  1. /api/text/list?author=<Author name>, GET Request with Author name is the name of the owner of the said note.

Sample Response of GET request to /api/text/list?author=Emory

1
2
3
4
5
6
[
    {
        "content": "#############\n#############\n#############\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus.#############\n#############\n#############\n \n  by:  Emory",
        "author": "Emory"
    }
]

If there is no author with that name, the endpoint should return an empty list.

1
[]
  1. /api/text/create POST Add new text to the application.

Request Body:

1
2
3
4
5
6
7
{
    "content" : "<Text content>",
    "author" : "<Author name>",
    "settings" : [
"Option1", "option2", "option3"
    ]
}

The text settings are the modifier to the text. The output of this request should using these modifier from this settings. The valid settings are listed below:

  1. line-break Add line break (#############\n) at the beginning and the end of the text content.
  2. author-in-content: Add the name of the author (by <Author name>) in the text content.
  3. shifter Shift the text content by 1, using Caesar Cipher. See example below. You can use TextChipperUtils to shift the text.

Examples Request and Response

Request 1:

1
2
3
4
5
6
7
{
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus.",
    "author": "Emory",
    "settings": [
        "line-break"
    ]
}

Response:

1
2
3
4
{
    "content": "#############\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus.#############\n",
    "author": "Emory"
}

Request 2:

1
2
3
4
5
{
    "content" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus.",
    "author" : "Emory",
    "settings" : ["author-in-content"]
}

Response:

1
2
3
4
{
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus. \n  by:  Emory",
    "author": "Emory"
}

Request 3:

1
2
3
4
5
{
    "content" : "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus.",
    "author" : "Emory",
    "settings" : ["shifter"]
}

Response:

1
2
3
4
{
    "content": "Mpsfn jqtvn epmps tju bnfua dpotfdufuvs bejqjtdjoh fmjuI Ovod bd bmjrvbn nbttbI avtdf wfofobujt vsob tfe qvsvt nbyjnvt nbuujtI Nbvsjt ojtj vsoba gbdjmjtjt fu bsdv gbdjmjtjta vmusjdft jnqfsejfu ejbnI Nbvsjt vmmbndpsqfs fsbu mpsfna fhfu vmusjdft ovmmb fggjdjuvs wfmI Jo je mvduvt boufI Npscj hsbwjeb tbqjfo bu tvtdjqju wfijdvmbI ^vsbcjuvs nbhob nbttba tpmmjdjuvejo bd ftu wjubfa qibsfusb ifoesfsju ojciI Ovod vu bouf dpnnpepa jbdvmjt ejbn tju bnfua npmmjt njI Jo jo nbttb wfm mjhvmb vmusjdft ejhojttjn b qsfujvn ufmmvtI",
    "author": "Emory"
}

Request 4: The settings can be customized and called multiple times

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ac aliquam massa. Fusce venenatis urna sed purus maximus mattis. Mauris nisi urna, facilisis et arcu facilisis, ultrices imperdiet diam. Mauris ullamcorper erat lorem, eget ultrices nulla efficitur vel. In id luctus ante. Morbi gravida sapien at suscipit vehicula. Curabitur magna massa, sollicitudin ac est vitae, pharetra hendrerit nibh. Nunc ut ante commodo, iaculis diam sit amet, mollis mi. In in massa vel ligula ultrices dignissim a pretium tellus.",
    "author": "Emory",
    "settings": [
        "shifter",
        "author-in-content",
        "shifter",
        "author-in-content",
        "line-break"
    ]
}

Response

1
2
3
4
{
    "content": "#############\nNqtgo kruwo fqnqt ukv cogvb eqpugevgvwt cfkrkuekpi gnkvJ Pwpe ce cnkswco ocuucJ bwueg xgpgpcvku wtpc ugf rwtwu oczkowu ocvvkuJ Ocwtku pkuk wtpcb hceknkuku gv ctew hceknkukub wnvtkegu korgtfkgv fkcoJ Ocwtku wnncoeqtrgt gtcv nqtgob gigv wnvtkegu pwnnc ghhkekvwt xgnJ Kp kf nwevwu cpvgJ Oqtdk itcxkfc ucrkgp cv uwuekrkv xgjkewncJ _wtcdkvwt ocipc ocuucb uqnnkekvwfkp ce guv xkvcgb rjctgvtc jgpftgtkv pkdjJ Pwpe wv cpvg eqooqfqb kcewnku fkco ukv cogvb oqnnku okJ Kp kp ocuuc xgn nkiwnc wnvtkegu fkipkuuko c rtgvkwo vgnnwuJ Y  czU  `npsz \n  by:  Emory#############\n",
    "author": "Emory"
}

You also need to handle if the settings are not valid (not listed above)

Task

  • Implement all endpoints listed above (you need to analyze the requirement and design a correct implementation of Decorator pattern)
  • Add unit tests and reach more than 80% code coverage for Text Editor application

Gitlabo (Adapter Pattern)

Getting Started

Before you can begin the tasks related to Adapter Pattern practical, you need to create personal access tokens from GitLab CSUI and GitHub. You can open the following pages to create the tokens: GitLab CSUI, GitHub. The minimum scope required for each token is read-only access to the APIs related to users data. Once you obtained the tokens, write them into application.properties file in the corresponding variable, i.e. gitlab.token and github.token.

Mandatory Tasks

Your mandatory tasks in Adapter Pattern practical is focused on creating a new adapter class and completing getActivities(String username) method in ApiActivityController class along with the associated test suite. Specifically, these are the tasks you need to complete:

  • Create an adapter that makes GHEventInfo objects compatible with the expected data type that will be returned as HTTP response
  • Combine the activities data from GitLab and GitHub. This is possible once you have created the adapter for data coming from GitHub.
  • Return the combined data streams to the client.
  • Make sure the tests still pass after you completed ApiActivityController.
    • You may adjust the test code to mirror the changes you made in the controller.

Since the controller uses Spring WebFlux and follows reactive-style programming, you need to recall the concepts of asynchronous programming and read Spring WebFlux documentation.

Additional Tasks

If you want extra challenges, there are some additional tasks that you can try to solve. Here is the list of the additional tasks:

  • Implement the methods in service and controller layers that will return the list of activities in given timeframe from GitHub.
  • Ensure the integration test suite, i.e. ApiActivityControllerWebTest, still pass after you finished the previous task, i.e. returning list of activities in given timeframe from GitHub.
  • Maintain the line coverage to stay above 65% after you finished the practical.

    P.S. It is very challenging to test the methods from GitHub API library that return paged results. You need to use advanced mocking techniques in order to test them.

Emory's Choice

It was some years ago. Emory couldn't really remember exactly. Some years after that day Emory helped a helpless junior. Honesty was something of a challenge for Emory, as they didn't particularly like the idea of opening up to people.

It was the same April shower and the same quiet Friday afternoon. Emory spent their time looking at the raindrops, as usual. Until they felt it was so quiet. No sound of anyone typing in the corner. Though some minutes ago Emory heard someone still working on something. For a moment, Emory thought they might had gone to the restroom and choosed to ignored it. 10 minutes passed and they still haven't come back. 20 minutes, 30 minutes. Emory's curiosity got the better of them.

It didn't take that long before Emory found their location. Emory was ready to throw their long list of excuses if they asked. However, fate wasn't so kind this time. Emory was standing, dejected, and empty. Emory looked at their former junior co-worker soulless body. Emory didn't know how to respond.

"It's a lie, isn't it?" They were trembling and crying. Emory was screaming for help. They took the body looking for some glimpse of hope of survival. Emory ran to the lower floor. No one was there. Emory didn't want to gave up just yet. They ran and ran again. This time to the entertainment area in the upper floor. No one was there. Emory kept running and running through out the building, but no one was anywhere.

"Why..."

Emory asked a question to no one in particular. For themselves or maybe for their surroundings. For treating the co-worker cruelly. Maybe they wouldn't have died this way if it wasn't because of their harsh enviroment. But that also not quite right. In fact, they blamed themselves the death of their co-worker.

Emory kept crying, until they realized something wasn't quite right. Emory turned to the corner of the room. There was someone else that shouldn't be there. Who are they? But, without hesitation Emory asked them for help.

They shook their head. "I can't save them." They replied. "Not in this world..." The mysterious figures explained some nonsense, something out of this world. They offered Emory to go to another world where they could save the poor Emory's junior. What was that? Did they just say magic and another world? This just didn't make any sense. But, something about this person bothered Emory. They had very strong presence. Something that convinced Emory they didn't just talk nonsense. They really had the power to do so. Then, without hesitation, Emory accepted their proposal. They were entering a world from which they will never return. They might choose to embrace it, or fight it, but they couldn't change it nor can they go back. However, if that was what it would take to save them, Emory would willingly accept it.


"Emory, it's 6 PM. Why are you still here?"

Emory turns their head towards you, breaking their long memory journey, or maybe you can say a nightmare. However, it is not a nightmare, it is the reality, Emory's past that they want to forget.

You realize something different with Emory. But as soon as Emory is aware of your realization of the situation, they try to brush it off.

"Nothing. Let's go home. But, There is somewhere I want to go first." Emory smiles. You have never seen that kind of smile before.

Emory walks a bit slower, just behind you. You feel a bit of awkwardness. You can't see their face, but you know what kind of face Emory's making.

After all what they've been through, Emory feels a bit of relief.

I am glad you have a second chance here and above all, a better place. I am so glad...


Last update: 2022-04-27 14:04:02
Created: 2022-04-27 13:43:39
Back to top