Table of Contents
Home
Good day! Welcome to the website of Advanced Programming course at the Faculty of Computer Science Universitas Indonesia.
This course is the last leg of foundational programming courses for computer science students at the Faculty of Computer Science Universitas Indonesia. It aims to teach the advanced techniques in software construction based on the best practices and emerging topics in the industry. In addition to lecture and practicals, this course provides an environment for students to develop their skills in collaborative work and implementing medium-sized software project.
The topics of the course will include: object-oriented analysis & design, object-oriented principles, test-driven development, software packaging & deployment, scalability, design patterns, continuous integration, concurrency, high-level networking, and basics in cloud technology.
After successfully completing this course, students should be able to:
- Specify, design, implement, and test software components as part of a bigger software.
- Understand and be able to use the features in a modern programming languages such as Java and Python.
- Conduct good practices in programming as team members such as project management and version control.
The complete description of the course and the schedules can be checked on SCELE LMS for Regular (Indonesian) class and International (English) class.
Current Students
The problem sets for weekly practicals can be found at Regular 2022 and KKI 2022. All source code artefacts related to weekly practicals, exercises, and group projects need to be stored at GitLab CSUI.
Current Instructors
The following is the list of instructors that teach Advanced Programming course on academic year 2022:
- Daya Adianto, M.Kom.
- Rian Fitriansyah, M.Sc.
- Muhammad Anwar Ma'sum, M.Kom.
- Ichlasul Affan, M.Kom.
- Gladhi Guarddin, M.Kom.
Past Instructors
- Dr. Ade Azurat
- Hadaiq Rolis, M.Kom.
- Hafiyyan Sayyid Fadhlillah, M.Kom.
KKI 2022 ↵
International Class 2022
Welcome to Advanced Programming 2021/2022 International Program course page. Some information regarding the course can be found on this page. We also publish the weekly practicals on this page. Please do check this page regularly.
Course Instructor
Course Schedules
Every Tuesday and Thursday at 13:00 - 14:40.
Assistants
- Adrika Novrialdi, S.Kom. (AN) - Teaching Assistant Coordinator.
- Fardhan D. Sudjono, S.Kom. (DS) - Deputy Teaching Assistant Coordinator International Program.
- Nadhif A.P. (NAP).
Interview Exam Guideline
Before attending the scheduled interview exam, make sure to do the following preparation:
- Ensure your camera is working.
- Have your IDE and shell (terminal) ready. Close unnecessary apps to free up computation resources for your IDE.
- Fork the codebase template
into your personal subgroup in
AdvProg/kki-2022/student
namespace. - Clone the forked codebase into your local development machine and load it as a new project in your IDE.
- Let the IDE finish indexing the JDK, project dependencies, and the codebase. This might take a while, especially if your local development machine is still using non-SSD harddisk.
- Verify the codebase can be compiled and tested by executing Gradle task named
check
ortest
. - Do not make further changes to the forked repository until the interview exam begin.
Once you have completed all the preparatory tasks, you are hopefully ready to begin the programming tasks in the upcoming interview exam.
During the interview exam, your tasks is roughly as follows:
- Turn on your camera and share the whole screen from the beginning of the exam.
- Work on the designated case study. The proctor will assign you a case study.
- Read the case study description. You will have 5 minutes to read and ask questions about the case study.
- Start working on the programming tasks. You will have 15 - 20 minutes to finish the programming tasks.
- At the end of programming tasks, make sure you have pushed the latest commits to GitLab CSUI.
We hope this guideline can prepare you in facing the interview exam. See you soon!
Practical Guideline
Each practical consists of a problem specification and template code.
You need to git clone
the template code from the Advanced Programming Practical repository in Gitlab CSUI.
You also need to create a new project in your subgroup for each practical.
Doing the Practical
First, do an initial push to your practical repository's master
branch.
Create a new branch and draft merge request.
Please choose a branch name that represents your task in that practical.
If there are tasks with entirely different features, you may create two separate branches and merge requests.
The base of each branch created is the master
branch.
Create some group labels that you can use in your issues and merge requests later.
You may need some labels, such as Todo
, Doing
, Refactor
, and In-Review
.
Please assign yourself as the assignee of the merge request.
Submission
Please assign the In-Review
label to your merge request.
Assign your TA as the reviewer of the merge request.
Make sure you have done this before the practical submission deadline.
That Time I was sent to another world to become a Software Engineer
Prelude
Your eyes continue to wander abstractly around the room, you’re drenched in sweat, your legs cannot stop shaking. In front of you are several middle-aged men, whispering to each other. Occasionally their eyes would take a sharp gaze at you. That is until one of them stood up and called your name.
"I'm sorry, but our company has decided not to go through with you." Spoke one of the men. You didn’t hear anything he said after that. Emptiness fills you, but strangely enough, you feel relieved.
After a few times of going through the same cycle: Arriving full of hope, followed by a long and convoluted process, only to get hurt by a piercing, sugar-coated response, hearing even the slightest bit of painful yet comely sentence as that must be met with joy. "At least they didn’t tell me to wait." You thought. After the gut-wrenching experience, all you want is assurance, and at least you got it today.
You step out of the building with the same mood as before. You peer long into the distance, away from the busy street of the capital city, still with your lonely heart. Even after many long and annoying attempts have steeled your resolve, somewhere inside, you had hoped that today would be different, that your search would finally be over.
As you take another step, rain pours over the crowded street of the night, driving you to run for shelter at the worst possible time.
Until suddenly, the rain stopped. You can see tiny droplets floating in the air. All the cars, the people, the entire city, frozen solid. It’s as if time has stopped. What is happening? Is this a dream? Many questions went through your mind, but there’s simply nothing that could answer them…. At least that’s what you thought.
"It's all real. What do you think? Beautiful, isn’t it?"
A voice echoes from beside you. The myriad of questions written on your face suddenly got their answers. The person smiled in a way that you’ve never seen before. You know that their smile is hollow, yet you don’t feel animosity coming from it. But one thing you’re sure of is that you’ve never seen that kind of smile on a person’s smile before. “Are they even human?” You thought. Even if that’s true, they’re no one ordinary.
“What are you?” Those are the first words that slipped your mouth after seeing their cold expression and ominous presence. If this happened to anyone else, they’ll probably utter the same thing. But they, no, “it”, did not answer you. It merely countered your question with another.
“You’re looking for a job, right?” That thing then stopped right in front of you, pulling out a piece of paper before continuing. “Work for my company, in a different world.” Said the creature with a grin.
The creature went to explain after that. You don’t understand much of what it is saying. A different world, magic, a modern parallel existence to our own. Meanwhile, it kept going on and on, paying no heed to your confusion. Of course, there are lots of things going through your head. Why does it know you’re searching for a job? Why you? Does magic really exist? And many others, yet none can come out. You kept listening. Even if you can’t follow what’s going on, it seems that you can’t help but listen. Are you swayed by its charisma? Or does it have some sort of power to force you to tune into it? Both of your questions go unanswered.
“So, you must be interested, no?”
Either from its powers or you just feel hopeless from the barrage of rejections, you gladly accepted. It welcomed your answer with a satisfied look.
“Ah, that’s right, I haven’t given you my name.” It bowed slightly. “I am R̵͇̗̈̅̇̐̚e̸̪̯͖̠͍͊̂̋͗͝y̷̧̗͚͚͑͒̔̓a̸̩͕̎̏͌l̴̞̔̄͒̍̕l̵̡̬̱̹̇̈́̐͋͜͝e̵̲͆͒.”
You cannot hear its name. As if something had prevented you from knowing it.
“Ah, then call me 0. Not everyone can hear my name. Alright, without further ado, let’s take you into my world.”
And with that, R̵͇̗̈̅̇̐̚e̸̪̯͖̠͍͊̂̋͗͝y̷̧̗͚͚͑͒̔̓a̸̩͕̎̏͌l̴̞̔̄͒̍̕l̵̡̬̱̹̇̈́̐͋͜͝e̵̲͆͒ sent you into another world. You’ve never felt so uncertain before when the journey began. An amount that would never be possible before accepting 0’s contract. With an unsteady footstep forward, you looked back cynically, to yourself, a few minutes in the past. “I’m sorry, our company has decided to not hire you.” Spoke one of the men. The rest of his words feel foreign to you. Emptiness surrounds you, but strangely enough, you feel relieved.
A fun first day? You must be joking
You sat down in a room after one of your superiors showed you around your new workplace. There’s nothing out of place. Even though you know that this world is not yours, fundamentally, it’s the exact same. At least from seeing your work and living quarters.
When you hear the word “Another world”, many things go through your mind. A place where magic, mythical creatures, and other things that defy logic would be in abundance. A modern society where most of its populace are office workers would never be your guess. Yet what you’re witnessing now is the exact opposite. Despite all that, you feel relieved. “I guess I don’t need to change my lifestyle.” You thought.
“Sorry, did you wait long?”
You peered towards the voice. You see your superior standing with a couple of other people. Some of them are smiling, but with a seemingly forced one. Still, you need to recognize their efforts. They wore badges with their names and “Software Engineer” written on it. They must be your co-workers then.
“These are your team members. You’ll be working together with them.” Said your superior. He then gave you a couple sheets of paper before heading back to his room. “They’ll explain your job in this division. Good luck.”
Just like that, he left your vision, leaving you with a somewhat confused expression. Ever since you met him, he has always acted cold. Only speaking when it’s necessary. You wondered if he knows about 0. If so, you have a few things you want to ask him yourself. But 0 forbids you from talking about it or that you came from another world. Even if he didn’t, you doubt your superior will answer anyway.
“Don’t mind him. He’s a man of few words.” Said one of your co-workers, as if you’ve been saying what you’re thinking out loud.
“Ah, no problem.” You retorted with a small laugh to mask your dissatisfaction.
“I’m Rory, Rory Auden. Call me Rory. And over there is Emory, Riley, and Alex.” Rory introduced each member of the team to you. “And now I shall explain what our division does.”
“Our sub-division focuses on the backend. Well, sometimes the frontend guys require extra manpower, so we often need to dabble in that too.” Rory said with an uneasy laugh. You can tell Rory is not thrilled whenever that happens.
“So, because of that,” Rory pauses while going through files on their computer. “As a new member of our division, I would like to ask you to make a full-stack application to keep your edge, just a precaution.” They continued.
First Task
“I’m not going to hold your hands on this one. But I’ll explain some things you may need to know.”
Rory shows you a document, a “requirements” of sort of the application they want you to make. It seems simple enough, but there’s one problem.
“This web framework… Spring Boot?”
“Bingo.” Answered Rory, confirming your suspicions. “I’m asking you to make that application with Spring Boot. Good luck.”
“Wait!” You shouted. Rory only gave you a wave and left you with no idea of what to do. You can only stare at the document with feelings of resignation.
“Do you need some help?” Touted another co-worker coming towards you.
“Ah, yeah, somewhat. I’m not familiar with Spring Boot. You’re Emory, right?”
Emory nodded. “I can guide you. What do you usually work with?”
“Django and Laravel. But I’m more confident in my Django abilities.” You responded.
Emory suddenly pulled you away into their room and locked the door as soon as you mentioned that.
“What are you doing?” You stare at Emory with bewilderment, only to be met with the same expressionless face.
“You’re from another world, aren’t you?”
Emory’s question made you panic. 0 warned you to not tell anyone about it. Even so, on your first day of work, your secret has been exposed.
“Calm down. I came from the same world as yours.” Emory seemed to notice your inner turmoil and tried to calm you down. “Don’t worry, the people of this world won’t know that. I noticed from your way of pronouncing foreign terms in this world’s language. The translation power of “it” is not perfect. I recommend you learn the native tongue.”
You’re stumped after hearing Emory’s explanation. You can only react with a simple nod. You see that other people can tell of others from their world easily. That may be something you need to keep a note of.
“If you got that, let’s start helping you with spring boot and maybe the version control we use here, Git. What did you use back then?” Emory brings you to the table and started explaining.
“TFS.” You replied.
“I’m glad you’ve worked with version control before. At least you’re not a FOVC user.” Sneered Emory.
“FOVC?”
“Flash-disk Oriented Version Controlling. A few lunatic companies also used Google Drive™ for their version control. Be glad that your experience was with TFS.” Added Emory.
Spring Boot Basic
Note: Please prepare your environment before continuing to the next step.
- IntelliJ Ultimate
- Git
Supplementary tutorials are also available on SCeLe. Please keep in mind that the tutorial below is made with IntelliJ Idea Ultimate.
Creating a Spring Boot Project
“Try opening Spring Initializr
on the new project
menu on your IDE. Fill it with what I wrote here.”
Emory showed you a few configurations they used to make a Spring Project. “Of course, you can pick whatever location you want. Use a project SDK with the same or higher version of Java than you picked. You can also do this outside of your IDE by visiting Spring Initializr .”
“You’ll get the following application structure.” Emory showed you the structure you get from using Spring Initializr
.
“I’ll explain some folders you need to know.”
- The
src
folder has two important sub-folders:main
andtest
. As the name goes,test
will be where your test files go andmain
will be where your main application goes. \ Themain
folder will also contain two other folders,java
which includes your java code andresources
which contains your other assets for the web, like static files, HTML templates, and configuration inside ofapplication.properties
. Some of the configurations you know from Django, like database, are in that file on Spring. gitignore
is a file that contains all the other file names that you don’t want to commit on your version control.-
Gradle files. There are four important ones:
build.gradle
,gradlew
,gradlew.bat
, andsettings.gradle
. You probably don’t need to mess withgradlew
and the bat file. So we’ll focus onbuild.gradle
andsettings.gradle
-
The
build. gradle
file contains Gradle tasks, application information, configurations, plugins, and dependencies. The Java version used can also be controlled in this file. In Python, you might be used to putting dependencies on ‘requirements.txt’ or ‘Pipfile’. But on Spring Boot or other Gradle-based apps, it’s usually in ‘build.gradle’. - The
settings.gradle
is where the Gradle module is configured. In this case, you can see the name of the module. For advanced use, like on a multi-module Gradle project, you will use this file to activate sub-modules.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Basics of Model-View-Controller on Spring Boot
“Are you familiar with the Model-View-Controller or MVC?” Emory continued their explanation of the structure design and its effects on the application.
“I have experience with MVT before in Django.” You replied.
Emory looked relieved. “Okay, so this shouldn’t be that long.” They added.
“Model-View-Template or MVT on Django is fundamentally a derivative of MVC.
The design pattern is created to suit its use on Django.
The difference lies in the view
part, ironic because they have the same name, right? View on Django contains business logic that also manages requests and responses of the application.
View on MVC is a layer that manages the display of the app.
On Django, that’s the job of the Template
part. Long story short, MVT’s View
is Controller
and Template
is View
on MVC.
This is extremely simplified, I know. Up next, I’ll tell you what each layer does.”
Model
is a layer that represents data and business logic.Controller
is a layer that manages requests and responses of the application. Ideally, this layer shouldn’t contain any business logic. It should focus on processing requests from users and returning the appropriate responses.View
is a layer that manages the display. In web applications, this layer contains files that bridge HTML files and static files like CSS and JavaScript. In reality, theController
layer also works together with this layer to serve the proper pages.
In Spring Boot itself, there are also a few extra layers to increase the maintainability and clarity of each layer.
You can see that the Model
layer has quite a big role.
In order to make the Model
layer have one specific job, it is divided into two other layers:
- The
Service
layer exclusively manages business logic. - The
Repository
layer exclusively manages data processing
And just like that, the Model
layer’s job is only to represent data.
Basics of Requests and Responses on Spring Boot
“Next up, let’s try making a simple web application.” Emory started typing on their IDE. “Try arranging some packages like this. Each package will represent a layer on Spring Boot’s MVC.”
“We’ll start by making a Controller. A controller in spring boot is a class that is given a @Controller
annotation.
Try making a simple controller that returns an HTML page first.”
Create a BaseController
class inside the controller
package.
Fill it with the code shown below.
Try to not write import statements manually.
Take the advantage of your IDE.
“Spring Boot now views the BaseController
class as a Controller.
A Controller class usually has a few methods.
These methods will represent a few different URLs.
The method index in the BaseController
class is an example.
That method has the @RequestMapping
annotation.
This tells Spring Boot that it handles an endpoint.
There are a few parameters that you need to know, method
and path
.
The method
parameter describes which HTTP Method the method itself will accept.
In this case, it’s GET
. The path
parameter, on the other hand, describes the URL that it will handle.
The method’s name itself doesn’t actually do anything, but try to give it a proper name that describes what it’s supposed to do.
Lastly is the return type of a Controller’s method.
Every single one returns a string.
This string you return will be a name of an HTML file you have in resources/template.
You can see here the index method returns home
, meanwhile the template folder does not contain a home.html
file.
So we need to create it.”
Make a home.html
file in resources/template
Fill it as such:
Now try running the application. Open Tutorial0Application
and click the run button.
If there’s no problem, the IDE’s command line will look like such:
And the result will be as such:
“Now try adding two other methods in BaseController
.”
Emory points at the @GetMapping
notation on both methods.
You noticed it’s different from the @RequestMapping
you used on the index
method.
“Did you realize something?”
You nodded. “Is GetMapping
a RequestMapping
that accepts the HTTP method GET
?”
Like always, Emory confirms your guess with her gestures. “We wrote it this way so it’s more concise. “But besides that, there are other uses for RequestMapping
called URL Grouping.
It’ll let you group a bunch of URLs with the same prefix, such as student/create
with student/list
.
You will need to utilize this in the application you were asked to make.”
In the two other methods, there are also two other annotations and a model
parameter as an argument of it.
"Next, let’s use RequestParam
and PathVariable
.
These two parameters are important to handle the URL mapping.
Maybe it’ll be easier to show you an example.
Because we have these methods, there’s a slight change we need to make to the HTML file.
Try changing it like this!"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
"th:if
and th:unless
are if and else statements in the Thymeleaf templating engine.
Since you used Django, I’m sure you are familiar with these terms, right? Here you can see that there’s a check done to the variable name
.
You may notice that this is a variable that the model
parameter puts.
Pay attention to model.addAttribute(“name”, name);
.
Basically, model
contains key-value pairs.
In our case, the HTML calls on the key value name
, and it returns a Java object as a value which happens to also be called name.
Surely you’ve used dictionary on Django before for something like this.
So, you can just think of this model
here as a dictionary on Spring Boot.
Also, bear in mind that this model
isn't the same model as the one in MVC."
Now try to rerun the app and open http://localhost:8080/greet?name=Emory
, you should see the following result:
You can substitute Emory with whatever you want. Try changing Emory to your own name and see the result.
“Compare the result with this.” Emory urged you to open http://localhost:8080/greet/Emory
“Any difference?” Emory asked.
You can see a few differences in the URL pattern used.
“I’ll answer based on what I see.” You started. “The first one is the use of RequestParam
, noted by ?paramName
, or in this case, ?name
.
Another one is the PathVariable
noted by the /greet/{variableName}
, or in this case, name
.”
Emory didn’t say anything, but they look satisfied with you. You take that as a sign that you were right.
“At this point, you’ve created a basic function on Spring Boot. It may be about time that you start committing your progress to git.”
Right now, your Spring folder from Spring Initializr
isn’t considered a git folder yet. To designate a folder as a git folder, use the command:
1 |
|
You can check what things have been done (in this case, what has been added to the folder outside of the ones in ‘gitignore’) to a git folder with the command:
1 |
|
To add a file to git, use:
1 |
|
If you want to add all files to git, you can use the following command. Just make sure everything in ‘git status’ is what you want to add. The best practice is to add and commit in as small of a chunk as possible. You will learn how to do this later.
1 |
|
You can use git status
again to check which files have been added to git.
Then, you just need to commit your addition with the following command:
1 |
|
For now, do a commit with the message “initial commit” as shown below:
1 |
|
First Task Implementation
Emory analyzes the documents Rory gave you. They look uninterested to the point of boredom. After a few seconds of flipping the pages back and forth, they returned it to you.
“Rory always gives the same task to every new recruit.” Emory lamented.
“Okay. As you can see, this application is a prototype of a teaching assistant information system. This application is made for a small university at the outskirts of Prediff.”
“Prediff is an outlaw town west of the trade city of Yukginia, right?” You asked. Emory only nodded slightly.
“With that said, Rory only asked to make a simple version of that app. Luckily, Rory also gave you the detailed requirements. You’re asked to make a page that could create a new ‘Student’ and show it on another page. You also need to repeat that for ‘Course’. I’ll help you make the ‘Student’ page, but I want you to make ‘Course’ on your own. It just so happens that only I can help you this far.”
“Thank you so much.” You’re very thankful that Emory agrees to help you finish your task. At least you still have a kind senior among your other co-workers.
1 2 3 4 5 6 7 8 9 |
|
First, we need to change the requirements into code.
The easiest step is to make the model or core of the application first.
Make a Student
class inside the model package.
But before you do that, let’s make a new branch on git.
“The reason why we should make a new branch is as I said earlier, we should make each of our changes focused and minimal.
We also want long-lived branches, like master
, to only be used for mature codes.
Maybe you can find other usages from branching.
I’m serious, I will ask this later.”
Make a new branch called task-implementation-student
with the command:
1 |
|
Or in this case:
1 |
|
After that, you can start on the model like so:
Generate setter and getter. On IntelliJ, you may use right-click -> generate -> setter and getter or use the alt+insert shortcut (On Linux and Windows). Try using the shortcut now on your machine.
“Ah, speaking of which, to reduce boiler code, we will use Lombok. If you remember, it’s part of the dependencies I asked you to put in the beginning. Delete the setter and getter you’ve generated and replace it with the following code.”
The next step is to make the Repository
layer.
“I taught you the simple version of model
and repository
. In truth, you would want to integrate both layers with the database. Let’s make a simple 'database' with the following data structure.”
This class is essentially a regular Java class.
We haven’t used the Repository
feature that connects it to the Spring Boot database.
The main thing you need to note is the @Repository
annotation.
Simply put, it serves the same purpose as @Controller
, showing that a class is a repository. By tagging this class as a repository, it will become a Bean
that will be used a lot in Spring Boot.
Next, create a service of Student
. First, make the interface StudentService
inside the service package, fill it as such:
“So, do you remember there are some things you need to check on the Student
business process? There’s a need for validation. Let’s make an exception in case there’s a duplicate Student
name. Make a new package called exception
and make a class called DuplicateStudentnameException
.”
1 2 3 4 5 6 7 8 |
|
Now that the preparation is done create an implementation of the StudentService
interface. Make another class, StudentServiceImpl
, inside the Service
package.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
“Pay attention to @Service
and @Autowired
. I’m sure you can guess what @Service
does at this point. Let’s focus on @Autowired
.
@Autowired
is a dependency injection mechanism on Spring Boot. In this case, we didn’t explicitly initialize StudentRepository
. @Autowired
tells Spring to make an instance of StudentRepository
. This is only possible on a Bean
. Remember that previously we gave the @Repository
annotation to StudentRepository
.
That turns it into a bean that can utilize @Autowired
for its initialization process. After this, you will see the same for StudentService
on the controller.
Now let’s make an implementation of the StudentController
class inside the Controller package.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
“I’m not going to explain everything again. I’m sure you’re now quite familiar with a lot of these codes. Our focus this time is to make a form for Student
. Pay attention to the createStudentPage
and createStudentPost
methods.
But, before that, let’s make an implementation for studentList.html
and createStudent.html
.”
studentList.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
createStudent.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
The Student
creation process is divided into two methods, represented by the aforementioned methods.
The createStudentPage
method has an HTTP GET method and serves to direct users to the form page of Student
.
While the createStudentPost
method has an HTTP POST method and serves to submit the form to the backend.
The form submission process is also split into two parts that you need to know.
Take a look at the createStudentPage
method!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
"Now try doing another add and commit. But let's utilize a feature in our IDE."
Open the git
menu on IntelliJ and open commit. The following window will show up:
You can see the list of files given is the same as what you get from doing git status
.
The changes
window on your IDE might be different. Maybe you find that the files you made haven't been added yet. If so, please check the unversioned files
section.
Pick files related to the Student
implementation that we have done, and now we're going to write a commit message.
Write down Implement student page
inside the commit message text box and click commit. There may be a warning sometimes. For the purposes of this exercise, proceed with commit anyway if a prompt does show up.
You need to follow a few rules in writing a commit message. Try reading the following article, How to Write Git Commit Message, to learn more about the rules.
Some Advanced Git
Emory were looking at your program for a few moments.
“Alright, I don’t see any problem.” They commented. “Now, try pushing it to your repository. Oh, and don’t forget to push the master
branch first. I assume you know how to make a repository on Gitlab and how to configure your local git (hint: git remote
). Give it a descriptive name.”
Switch to the master branch. You can use the GUI inside IntelliJ or do it through the command line.
1 |
|
Push your commits. You may also use the GUI inside the git menu on IntelliJ or use git push
on the command line.
Go back to the task-implementation-student
branch and make another push. Look up Merge Request
for git.
Make a merge request to the master branch from the task-implementation-student
branch. Try merging and watch what happens. You will be asked to explain this later.
“Now, let’s simulate the use of ‘git reset’ and ‘git revert’.”
Git Reset
Make a MockStudentServiceImpl
inside the Service package and fill it as such:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
StudentService
type. This causes Spring to not know which bean to use. You can fix this problem by changing @Autowired
on StudentController
to a @Qualifier
and explicitly choosing StudentServiceImpl
.
But for the purpose of this tutorial, we want to fix the issue by turning our repository into a previous commit version with git reset
.
You can learn more about Qualifier
to understand how to handle two conflicting bean types.
As usual, you can use the IDE’s built-in feature to do this, but it’s best if you learn how in a command line first. (Hint: Try clicking on the git menu on the bottom left part of your IDE to explore other git features)
Run the following command to see what commits you have done:
1 |
|
The command line should look like this:
While the IDE should look like this:
We’re going to solve this by using the command line. For the IDE solution, please try it yourself.
You know that your application works on the Implement Student Page
commit.
Now let’s do a git reset
back to that commit. Copy the commit has from the Implement Student Page
commit. Note: Your commit hash will be different from the given image.
The basic git reset syntax is as follows:
1 |
|
Example (Again, this is an example. Your commit hash will be different. Do not copy-paste the following example. Copy the hash from your git log
instead)
1 |
|
Now, if you do git log
again, you can see that your MockStudentService
commit is gone. Try rerunning the application to make sure it works. (Pay attention to the --hard argument. Is there any other option? Do your own research!)
Git Revert
Create a new branch called simulation-revert
.
Re-add the MockStudentServiceImpl
again as in the previous section.
Do a git add
, git commit
, and git push
.
Try simulating git reset
again and do a push.
You will find that said push is denied by git. This is because your remote repository does not have a commit ahead of your local repository.
You cannot do a push unless you use git push –force
(For the love of god, don’t do try this at home).
In this state, it’s better to use git revert
.
First, do a git pull
to get the changes that you’ve done to your remote repository.
Open the git log
again. Contrary to git reset
, we’re not going back to a commit where the problem has not yet arisen, but we’re canceling a problematic commit.
As such, copy your MockStudentService
implementation commit’s hash.
Do:
1 |
|
Example:
1 |
|
You will be asked to do a commit message. Fill it with a good description.
The result will look as such:
You can see the revert process adds a new commit that cancels the previous commit. Do another push and come back to the task-implementation-student
branch.
End of Your First Day
“How was it?” Asked Emory. They look like they finished their task today. Her cold eyes contrasted the close attention they gave you. You’re still trying to complete your remaining tasks to implement the Course
page.
“Not so bad.” You commented.
“Okay then, good luck.” Emory looks indifferent. They started packing their belongings. Emory is going home, you thought. “Don’t forget the things I’ve taught you. Rory and the boss might want to evaluate everything, from your code quality to git discipline.”
Emory then walks toward your desk, pulls up a chair, and sits beside you. You stare at Emory with confusion.
“I’m going to rest up here for a bit. Poke me if you have any questions.” Mentioned them.
“Ah, thank you.”
“Don’t be too long now. I’ll be taking you around the city.” Followed Emory, still emotionless as ever, their actions directly oppose their cold tone. “It’s been a long time since I’ve met someone from my world. I would like to know what’s been happening out there.” They continued.
“Roger.” You responded.
Your first day ended with a short trip to a few places with your ice-cold senior. Their face continues to be impassive, though you feel like their mood slightly improved from when you first met them. You smiled. This wasn’t a bad way to end your first day. You made small talks with Emory under the dimly lit moon. About this world, about 0, and about other people from your world. If possible, you would like to meet them all. Their stories, whether they have any regrets leaving, or maybe whether they want to come back if given a chance.
This is the start of your story. You who have been sent to another world to work.
Tasks
- Read the entire tutorial
- Do everything the tutorial asks
- Implement
Course
feature according to the requirement
Hints
- You can follow how the
Student
feature is implemented to work on theCourse
feature - Make sure you follow a good Git discipline for
Course
- Make sure you take note of every single time this tutorial tells you to study up on something. You will be asked about them on the demonstration session later
Suppose You Want to Prove That Your Code is Working and Start Writing a Unit Test for Your Program
You gaze through the window lazily, watching the rain fall and ignoring everything else. You've been like this for the past 10 minutes. Instead of words, doodles find their way onto the paper you should be working on. You've tried to start writing, but you lose motivation a couple of seconds in. This cycle repeats itself.
The weather had been awful since the morning. The office's mood was not so good either. You had seen nothing but gloom. The manager had a fierce debate with Rory about the team performance. Riley, as usual, came 1 minute before work time, not making Rory's mood any better either. You could clearly see the annoyance on their face. On the other hand, Alex... On second thought, forget him, he just flexed his wet clothing from the harsh morning's rain. You couldn't understand why he was so proud of it. As if it wasn't bad enough, just after you sat in your chair, an email popped up. It was from Rory. They told you that the tests you have written aren't good enough. They didn't cover every case possible, Rory explained. Even worse, the email they sent also asked you to do more work.
It was as if Rory asked you to do better in the subsequent work. You took a piece of paper and started writing possible test cases, hoping this time it would be enough to satisfy your ill-tempered team leader. But the more you tried to write, the more hopeless it got. You realized the possibilities are too much to cover. Some cases were meaningless, and some needed to be covered. However, you couldn't give a proper argument as to why some were more meaningful than others. Somehow you found yourself in this endless loop.
Now, you try to look at the paper you have ignored for the last 10 minutes. It is a mess no matter how you look at it. You revert back to a 'no thoughts, head empty' state. The doodles on the paper do not represent anything at the moment. They are purely frustrations, a byproduct of your inability to discover the solution. You then decide to look back at the water drops outside. With that, the loop is restored.
You focus on the relaxing sounds of the rain, so much that you don't realize a pair of eyes has been looking at you. Surprised, you start to look toward the subject. Emory is sitting on the empty chair next to yours, looking bored and, as usual, without any trace of expression.
" How long have you been there?" you ask. " For 5 minutes, I think. "
The conversation ends there. You and Emory simply stare at each other without uttering a single word. This awkward situation lasts for several seconds before Emory starts to ask:
" Is there something wrong? You just sigh at the paper, then laugh like a maniac, then look sad, and gaze away at the window. " " Did I really do all that? " Emory nods. " Did Rory ask you to write tests again? " " It's scary that you are always able to guess my problem every time.." " So, what is the problem?"
You then explain everything to Emory. The whole thing takes you about 3 minutes, and Emory's best response is just a harsh comment:
"Yeah, I can guess since your past tests are not that good. " They say.
It definitely hurts your pride to hear that. The comments from Rory is bad enough and hearing this from Emory does not help you at all.
" I can help you, though. " " Really? " " But... " Emory stops there, pointing at the clock beside your table. " You owe me lunch. Again. "
Input Space Partitioning
"This is a concept I learned in my university back in our homeworld. It's called Input Space Partitioning. I can see you have understood that writing every possible case is not feasible. For example, data types such as String and Integer have infinite possible combinations. There is no way to cover all of that. But you can build a model that represents the test cases you want to make. This model will guide you in creating concrete test cases by choosing a representation of the input domain. " Emory takes a paper from your desk before further explaining the concept.
" Input Space is simply a domain, a space of possible input to the program. For example, integers input may be a positive number, negative number or a zero. String can be a length of three or simply called non-zero input, a length of 1 like the character 'a' or even an empty string. In general it's all possible input for the program. The problem is the possibilities are limitless. That's what happened. This is the problem you were facing. The next question is, 'how about not inputting all the possibilities?' Just the good enough number of test cases to cover most of the input space? The answer to that question is here" Emory starts to write the concept on the paper. Then Emory writes a sample program to demonstrate the concept.
"Input Space is simply a domain, a space of possible input to the program. For example, integers input may be a positive number, negative number or a zero. String can be a length of three or simply called non-zero input, a length of 1 like character a or even an empty string. In general it's all possible input for the program. The problem is the possibilities are limitless. That's what happened. This is the problem you were facing. The next question is, 'how about not inputting all the possibilities?' Just a good enough number of test cases to cover most of the input space? The answer to that question is here" You start to write the concept on the board. You write a sample program to demonstrate the concept.
1 2 3 |
|
"Suppose you want to test this code. Both inputs are integers. Which means we will work with the input space of integers. How many integers are present in this input space?"
"Infinity. From minus infinity to plus infinity" you replied.
"Correct."
Input Space | Positive Integer | Negative Integer | Zero |
---|---|---|---|
Example Value | 7 | -30 | 0 |
"Like what I have said earlier. Integers can be categorized as positive integers, negative integers and a zero. Now look at this table!" Emory is pointing at the table on the paper they just wrote earlier.
"We can choose the sample value of each category with this method and then create test cases using three values. This three value has represented the large amount of space on the integer domain. So we can create tests as follows."
1 2 3 4 5 6 |
|
You are impressed, but you have a question to ask. "This concept is truly fascinating. But how can we use this concept for a more complex system? Can you give me more examples?"
Emory responds silently. They take another piece of paper. " This time I am thinking to show you the example of Palindrome checking to demonstrate another concept of ISP. "
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
"Now we have this method that tests whether a string is a palindrome or not. Input is a string. So we will work on the input space of string. When I showed you the example of integers, you might realize that I divide the input as types of integer values. This is called characteristics, and in this case, the characteristics of integers are their relation to 0. How we create the 'characteristic' is free, and will depend on context. For this palindrome example I will create two characteristics. One is similar to the example of integer earlier, is created based on string properties of length on the their relation to 0. Another is considering the behaviour of the program itself. In this context we know the program can detect a palindrome. So we can create another characteristic: The properties of string in their relation to palindrome. Look at this table."
Characteristic | Block 1 | Block 2 | Block 3 |
---|---|---|---|
Relation to length | 0/Empty String | Exactly 1 | More than 1 |
Palindrome | Palindrome True | Palindrome False |
"So with this characteristic, we can create test cases. One thing to remember about creating a characteristic is a block value can't also be a member of another block in the same characteristic and it must hold a complete member of that characteristic, the completeness. For example the characteristic of length. A string can't have length of 0, 1 and more than 1 string at the same time. The second block also holds this property. A string can't be both palindrome and not a palindrome at the same time. Both hold all possibilities of the characteristic, so It is also a complete partition. "
"Now let's create the test cases from these two characteristics. A block from a characteristic must be paired with all blocks from another characteristic. Look at this example. "
Palindrome True (B1) | Palindrome False (B2) | ||
---|---|---|---|
0/Empty String (A1) | "" | (Infeasible) | |
Exactly 1 (A2) | a | (Infeasible) | |
More than 1 (A3) | abba | Lost |
You stop Emory's explanation and raise a question. " What is the meaning of Infeasible you wrote in the third column on the first and second row?"
"Simpy they don't exist." Emory replied. " All empty string by definition is a palindrome. And so does a string with length 1. Meanwhile you can create a number of examples of the third pair. " Emory stops and take another piece of paper to write.
1 2 3 4 5 6 7 8 |
|
"I want to show you one final example of ISP" Emory then proceeds to browse your computer to check for a suitable codebase. "I think this one will work," they think.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
create
method.
"As I said earlier, there are two ways to create a test requirements: Natural characteristics of the input space, like my first example. Or you can choose to create the characteristic from your knowledge of the method like my second example. As the program you test get more complex, you will use the latter more often. I will give you an example. "
Characteristic | block 1 | block 2 |
---|---|---|
Name Duplication | Duplicate (A1) | Not Duplicate (A2) |
Data content | Empty (B1) | Not Empty (B2) |
Name charset | ASCII standard (C1) | Non ASCII standard (C2) |
"I created three characteristics: Name duplication, data content, and name charset. Name duplication is refer to the possibility of duplicate name that prevented in validateName
method. We also need to check two conditions of the database to ensure both condition's output is correct. The last one is to check the case user will input non-standard characters. Such as specific language characters.
As you can see, I didn't use specific domain at all. Instead, I used the knowledge of the method to derive the charactristics and blocks. This mechanism to derive the characteristics is called Functional-based approach. The previous example that used the input specific domain is called interface-based approach. Now let's create the test requirements. "
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
"Do you undertand what I have taught you until now?" Emory asks, as they want to confirm your mastery of the subject.
"I have one more question. "
"Go on. "
"So, a block needs to be paired with all other blocks?"
"Correct. This rule knowns as 'Pair Wise'. There are some other coverage criteria in Input Space Partitioning. You can learn about them if you like. I usually use pair wise."
You are relieved. "This is indeed a good way to reduce the test cases and create quality test cases." you said.
"Now, shall we apply this concept to our system?" Emory proposes.
"Of course. Let's begin."
Writing Unit Test with JUnit 5
“Now we have the concept, let’s work on the system. Can you tell me, what system do I need to test first?” After a quick break, you are ready to test the system. However since this is not a system you have known before, you need to find out the behaviour of the system. You then read the email sent by Rory to take a look at the codebase and some general information about the system.
From what you know, this application has two very basic functions. It can show the list of registered adventurers and it can register a new adventurer to the system. Business logic is located in the service
package. There is one model used in this system and belongs to the model
package. To control and communicate with the frontend, there is one controller
class. Rory said that you should start with the business logic first. So it means you need to test the service
package.
Now you know what to do. As you know, you can generate the test class using the IDE assisted feature. If you are using IntelliJ, you can press Alt+Enter
on the class name to open the sub-menu. Choose Create Test
. Select JUnit 5
as the testing library. You can do some experiments with JUnit to test the application.
Tasks
- Read this document to understand the requirements.
- Document the process of creating Input Space Partitioning of all methods available in
AdventurerRegistrationServiceImpl
class. - Create characteristic and test case value candidates similar to the example provided in this document (see: Palindrome and StudentService), which is in tabular format.
- Write your documentation in README.md.
- Create JUnit 5 unit tests based on the test cases you have created.
Hints
- You may try to run the application first to understand the behaviour.
- Do some research about JUnit 5.
- Use the IDE assisted feature to help you create and run the test.
- In the process of creating characteristics for Input Space Partitioning, the input domain can be related to the method you want to test, not just the input value. Example in the palindrome there are 2 blocks, one representing input space of the string and the other one representing possible outcome of the method. You can try to apply the same strategy here.
References
Suppose You Want to Improve The Code Quality of Your Program and List All The Issues Exists and Have a Nice Dashboard of It
Prelude
You woke up to the blaring and painful sound of your alarm. You recognize this tune, it's your third layer in case you slept through the first two. You purposely made it the worst thing posisble to hear, sorting algorithm, though it doesn't sound as bad now that you've grown accustomed to it. "I should really change them.". You haven't really browsed the music of this world all that much, maybe they'll be better. But nevermind that, now you have to force yourself out of the bed.
You went to the kitchen and made some tea. As you take a sip, you realized that you used salt instead of sugar. "Geh, what a bad start." As you continued your morning routine, small but annoying things kept happening. You ran out of shampoo, one of your socks is missing, and your favorite website got blocked by the local government. "Something bad is gonna happen today, won't it? I'm starting to think I'm cursed." You uttered to yourself as you leave for work.
The heavy mood of the office strikes immediately after you arrived. Everyone seems a little busier than usual. Occassionally you would see people running from one corner to another. The thought doesn't concern you, though, as whether there is a problem or not for you, you will deal with it in front of a computer anyway. As you entered your division's office, your eyes landed on Emory. They look... rather normal, surprisingly. Maybe Emory works well under pressure. "I should greet Emory." You thought, but not long after another person came and took your chance. Alas, you concede and retreated back to your desk.
You turned on your PC, everything works fine. You have your tasks for today already laid out on your desk, Rory must've put them earlier. You read and thought it was odd that today's task was just minute things. "There must be a catch here somewhere." You thought. You took a quick glance up at your monitor, and then it dawned on you. "One of those days, huh?" You stare at the timeout errors on all in-house tools the company offer. No one is going to get much done except locally. You begin your shift and type away at your keyboard.
Distress
"Do you, uhh... have some time?" A faint voice broke your concentration. You turned your head. It was one of your co-workers, you remember them from your first day but you don't think you've spoken to them since. "What can I do for you, err..." You stopped mid sentence, you don't remember their name. "Riley. It's okay, barely anyone remembers my name around here." They seem to be the self-deprecating type. While you don't necessarily have a problem, it might be a pain to deal with whatever Riley is going to bring up.
"Riley, okay. Is there a problem?" You continued. "No... I mean, yes! Umm, not really your problem, but..." They paused and seemed to think for a while. "Is it related to why the server is so slow today?" You fire a blind guess. Riley's face lit up, it seems that you've hit the bullseye. "Actually, yes! You see, one of our engineers... Uhh, 'left', a short while ago. They were in charge of the job management system in the company and it seems like that somehow they sabotaged the codebase. It seems to be extremely inefficient and slow now."
Straight out of an action movie, you thought. Actually, is there hollywood equivalent here? Your mind wonders a little bit before Riley interrupted. "So, I was tasked with fixing it but I don't actually know what to do. The code is a mess and I don't think I can completely rewrite it from scratch...". You seem to get the gist of it, Riley wants you to help identify and fix the problem together. If you get it done quick, your tasks can be finished in no time. But there's still a question lingering on your mind.
"Any reason why you asked me in particular?" You don't exactly have much expertise either, and if anything, you're the newest member of the team. "Emory seems to be... warm, to you. So I thought maybe they could also help us." Warm? In what world are those expressionless face 'warm'? Maybe Riley grew so accustomed to it that they can tell the slightest bit of difference. Now that you think about it, Riley is the person you saw at Emory's desk this morning. You guess they might have asked before.
But regardless, you do feel like the only other person you've really interacted with is Emory, so there wasn't a choice to begin with. "Alright, I'll try." You said as you rise from your chair. "...! Thank you!" Contrary to Emory, Riley's face is so honest with their emotions. You felt a sense of refreshment, maybe today won't be so bad after all.
Conflict
"What?" Emory asked you with their usual cold stare. You plopped down them the document Riley gave you earlier. "I've been told someone sabotaged this company service today. That's why we're all working extremely slow right now." You continued. "Yeah. And what about it?" Emory uttered while typing away, seemingly ignoring you. Again, Riley, in what world is this 'warm'? "I thought I could take a look at it, maybe I know something." You replied. Emory stopped for a second. "That's Riley's job, not yours. Don't you have your own tasks today?" Her tone might have slightly changed, but it's really hard to tell.
"Well, if I help Riley maybe we'll get back to speed quicker. So I don't have to slave away at my task for hours on end too." This time Emory did not say anything. You feel a sense of tension, did you say something wrong? It's hard to tell over that steel mask of theirs. "Umm, so-..." Before you can finish your sentence, Emory interjects. "I gave you access, do you what you want." This time you can tell Emory's tone changed. It might be rude to ask more, but you're not sure if you could do it either, so there's only one way.
"You did say that I can bother you again anytime, right? Can I ask for help along the way, or...?" You asked with a timid intonnation. "Why don't you ask Riley instead, there's a reason that that is her task. You're the one helping her, so why are you asking for my help anyway?" Does Emory have a personal vendetta against Riley or something? You have to pick your words carefully, getting Emory's help will be important to your success, you formulated a sentence and prepared for the worst.
"You're a great teacher, Emory. I'm not extremely bright, yet you got me to understand foreign concepts easily. Your tutelage drives me to want to explore a lot more, that's why I want to try my hands at this. It seems like the perfect opportunity to hone my skill and prove that I'm useful to everyone." You took a deep breath and continued. "However, I know my own limitations. I do not have the necessary knowledge yet. But with your kind guidance, I'm sure even someone like me could be a part of something greater. So please, Emory."
You cringed, you've never tried so hard to sway another person before, let alone deliver praises. It is as embrassing as people say, but what you say aren't lies. You took a glance at Emory. "Heh." A weird sound came out of their mouth. Did they just chuckle? The stoic Emory just chuckled at you, how are you ever going to live this down. You feel your confidence dropping, but then...
"Flattery won't get you anywhere with me, but I suppose you're right. This will be a good learning opportunity for you." Emory said with her normal tone, maybe this is the 'warm' Riley mentioned. "Very well, I shall teach you something. But you have to learn how to utilize it yourself." Emory gets up and started walking to your desk. You breathe a sigh of relief. "Come on, we don't have all day."
Sonarqube
Emory took over your PC. "Are you familiar with any code quality measuring tools?". You tried to remember if you've used any in the past. Maybe you did, but alas, you shook your head. "Alright then, let's use my solution." Emory opens your browser then typed something in the address bar. "Meet SonarQube." Emory points at the screen. "SonarQube gives you a dashboard and metrics to measure your code quality. When you push new code to the repository, SonarScan will measure the quality of your code. SonarQube also lists all the issues and recommendations to fix them."
"This tool will help you fix the application. The big problems are fairly obvious, you don't need SonarQube for them as they're more of a system wide problem. I've marked most but it's possible that there may be more you can do. You will need to use SonarQube for the little ones, though." Emory paused and checks if you're still listening. "I'll give you a quick rundown."
Setting Up SonarQube
- Log in to SonarQube CSUI with your GitLab CSUI account
- Create a new project by clicking on the + next to your profile
- Set up the project credentials. To make it unique, set up the name with the following format:
advprog-practice-[NPM]
- Generate a token, which will be used in the GitLab's CI pipeline environment with the name
SONAR_TOKEN
. Keep the generated value. You will need it for later. Set up the project as a Java project using Gradle.
- Configure sonar in build.gradle file and add a sonar job in the gitlab-ci.yml file (Example provided below)
Add the sonar configuration in build.gradle.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Add the sonar
stages in gitlab-ci
1 2 3 4 |
|
Add sonarCheck
job in the gitlab-ci
1 2 3 4 5 6 |
|
- Configure your Gitlab CS repository by adding the SONAR_TOKEN from earlier
- Push the code and see the pipeline!
- You’ll see the status of your code at SonarQube CSUI
Code Smells
"Now, you are familiar with code smells, no?" Emory interjects with a question. "If I recall correctly, code smells are any violation of fundamental design principles that decrease the overall quality of the code. Is that right?" Emory gave you a little nod. "After you think you're done with problems that SonarQube can find, see if you can fix any of the ones I marked. Each mark also have their hints, but in case you need extra material, you can go here."
Emory begins typing another site. "Go to this site if you feel stuck, it should have everything you need." You seem to recognize a few, but you feel the need to review all of them. Emory stands up and start walking away, you assume back to their desk. "...And yes, you can bother me any time. Good luck." Emory then disappears from your sight. Below that emotionless face is still a kind heart, you thought to yourself.
More knowledgable than ever before, you set out to complete your task.
TODO
- Set up the SonarQube
- Resolve as many as possible Issues in Sonar Dashboard
- Answer this question in README.md (or any extension you more prefer)
- Why do we need SonarQube for refactoring? What does SonarQube offer?
- What is the relationship between SonarQube Quality Gate and Clean Code?
- Suppose you asked to deal with a technical issue within the program. What will you prioritize when implementing the fixes? The performance or the code quality?
Bonus
- Resolve as many TODO as you can. Make sure to write what you think is the problem with each TODO and how you solved them
- Make the quality gate of SonarQube reaches A
- Answer this question in the same file as README.md:
- Is SonarQube the only way to solve the problem? Is there any different way to solve the problem? (hint: Software Quality metrics)
Another one down
It's almost the end of the day when you're done fixing the problems in SonarQube. It was quite the challenge, but nothing as dire as the next thing that comes across your mind. You completely forgot about your own task today, you scramble to find the document, but it's nowhere to be seen. You kept searching until a familiar faint voice calls out to you.
"Umm, excuse me..." You looked towards the source of the voice and sure enough, it's Riley. "I was going to fix the application with you... But I heard your speech earlier, and it amazed me how motivated you are, so I thought I'd help finish your task instead." While it's mostly mundane tasks, it saved you from going overtime today. "Thanks, sorry I forgot to fetch you. Emory kind of took over, so." You feel bad taking all the credit to yourself, but Riley doesn't seem to mind.
"Not at all, you're my savior! Thank you so much for today!" Riley jumped and hugged you. You're not used to this kind of skinskip, but you're more surprised that someone so timid can be so daring, in the workplace no less. "Alright then, I'll catch you tomorrow!" Riley trots back to their desk, leaving you stunned, but not entirely unhappy. "That... might be enough for a bit." You uttered to yourself.
Another job well done. You feel satisfied with todays work as you step out of the building. "Maybe life like this isn't so bad after all". You gaze into the night sky as you walk. Your co-workers might be eccentrict, but they're nice people, at least. As you got back home, you reached into your pocket and felt a cold shiver down your spine. You took off your jacket and sure enough, there was a hole with your keys nowhere in sight.
"I'm starting to think I'm cursed."
Suppose You Want to Use Multiple Requests at The Same Time without Inconsistency Issues
Emory's eyes are locked onto their monitor. It is as if Emory is looking at the screen, but at the same time it is like they are looking through it. For the last 30 minutes, the following sequence of events have been repeating: First, Emory would type something, click the mouse, and look hopefully at the monitor awaiting some sort of result. Sometimes the outcome is the rather preferable one, relieving them from the nightmare that has haunted them many times. That is not always the case. Emory's expression, as usual, does not change much. It's still the same cold expression you are familiar with. However, you know something within Emory has changed. Having to work with Emory for months has given you the ability to read Emory like a book. You can tell what they are thinking purely through perceiving their face and tension. Each has a different meaning. They must have a problem right now. As you take a peek at their monitor, your body shivers. It's the prototype application you have just completed. This is clearly not a good sign.
"Could you come here for a second?" The voice coming from Emory's desk made you tremble.
Seconds ago, you realized how bad the situation you are in, and now it's getting worse and worse. Riley, who supposedly has been sitting beside you a moment ago, is now gone without a trace.
"Also, bring Riley here.I know you are there." Emory added. You hear a crash in other room as you hear Emory's command. You can imagine Riley had tried to run away from the responsibility. This can't get any worse right... You silently wish. At least you are not facing the wrath of your coworker alone.
"Can you see my screen?" Emory asks you to see the screen, while Riley slowly shuffles towards Emory's desk.
You see a bunch of duplicated entries accross the screen. Emory then executes several other operations for five more times. Sometimes the entries are working as intended, and in others some entries are duplicated. It's not consistent. You take a guess on the source of the problem.
"Isn't this a race condition?"
"So, you do know." Emory replies. "The test did pass, but there is a bug in multithreading. It wasn't there in the last version. What happened?"
"Riley and I had an idea that time. So we proposed a prototype that utilized multithreading to do parallel job. So I think that's the cause. "
Emory sighs. "You should asked me or Alex for a review first. "
"We are so sorry. We thought we need to make it quick. But..We will take the responsibility! " Riley exclaims. They who always have kept their mouth shut finally starts to talk. You think Riley, the original proposer of the idea felt responsible. After all, you only coded what Riley asked.
Emory then boots their IDE and opens the aforementioned problematic code. They look at it for some minutes before taking out a piece of paper.
"Let's fix it." Emory suggested."It might be you and Riley's fault here. Normally that is the case. Our manager will see it like that. But.. I dislike that kind of system."
You and Riley are surprised to hear Emory's words. Both of you expected scolding from the team lead for ignoring their authority because of the urgency for the change. On the contrary, Emory is willing to help.
"I think a mistake made by a member of the team is the responsibility of the team. Don't be surprised. As I said before, I hate the idea of blaming just one person."
That line, and also that attitude. You have seen time and time again, and that is what you admire about Emory. It's not fear that Emory uses to rule. It's responsibility and respect.
"Shall we start?" Riley proposes.
Emory does not respond, as usual. They simply turn their eyes to the monitor and starts writing out some possible problems.
The Race Condition and Critical Section
"As you have guessed, this problem is called the race condition. Basically, multiple threads are trying to operate on a section at the same time. The program normally guarantees the correctness based on the correct order of execution. That's not the case with the race condition. Since multiple threads are accessing the same part at the same time, we can't really say for sure what the execution order is like at that point. " Emory starts to explain the state of the program right now. The condition known as the race condition is a well known concurrency issue.
"The tests can't detect them and I also don't know where the issue is coming from. How can we spot the source of problem?" Riley asked.
"I think the use of an unsafe thread operation is the source. " You try to answer.
Emory writes something on the paper as they comment on your statement just now. "If it is an atomic operation, it's easy to spot. I believe you and Riley know about critical sections. It's a section where the multi thread access breaks their operation and data integrity. Most of the time it's related to data access and data write. "
"So it's like two or more threads are writing data at the same time or there is a thread who tries to read data from an incomplete operation by the other thread. That data might be rolled back by the other thread but that one thread might have already used the incomplete data on their operation. "
"So a solution would be identifying the critical section and limit the access to that section? "
"Correct. " Emory replies. "It's called synchronization. This concept simply only allows one thread to access a critical section at one time. After the operation is finished, that section is released and other threads will able to work on it. The process repeats until all threads' operations are finished. "
"There are some possibility of the critical section in our application. We might need to analyze it and try it one by one. "
"It's sounds like exhausting work, but it's what it is. "
Emory stands up and walks in the direction of the other room, leaving you with a curious Riley. "I will talk to Rory." Emory says. "Can I leave this matter to you?"
"I will go with you. " You propose. Seeing your superior take the responsibility of your own mistake, you can't sit still here while imagining what would happen to Emory in the other room.
"Stay here. " Emory rejects your intention and walks away, leaving you feeling devastated.
"Let's fix this problem as soon as possible. " Riley suggests. Riley walks to their table without looking at you. They must feel even worse than you. After all it's their idea that led to this mess. Knowing what kind of person Emory is, you could imagine how many times this has happened before. You didn't want to rely on Emory's kindness forever. You have always wanted to help them. That cold superior that have saved you time and time again since the first day you have been here. You can't do anything about this situation except fix your own mess.
Work Allocation System
Like the previous application you helped fix, this application creates new jobs and divides them based on the competence needed. However, this application creates multiple jobs at once, allowing for increased productivity. It also utilizes multi-threading on job service to handle multiple jobs at once. This is likely where the application failed.
There are several job types available to be created, they are:
- Coding Jobs
- Design Jobs
- Security Jobs
You can create new jobs at /employee-list/ by clicking the "add another job" button. Select the category and the name you want then press add.
Each job type can only be solved by certain employees with the following rule
- Frontend employees can only do coding and design jobs
- Backend employees can only do coding and security jobs
- Fullstack employees can do everything, be it coding, design, and security.
As such, to test the application, you need to check it with coding jobs to make sure it all goes well. The order of the job does not matter in this case, but it is important to not have duplication nor have a job missing from the list.
Tasks
- Identify the critical section. Write your argument why the said section is the critical section in
README.md
- Fix the concurrency issue(s) and describe your solution in the
README.md
- Make sure there are no other concurrency issues
- Please answer these questions in the
README.md
- What is concurrency control?
- Using your own words, explain what is the critical section?
- What is race condition? In this practice, what is causing the race condition? Explain other concurrency issues that you know besides race condition.
Optional Tasks
- Fix some code quality issues in the program
- Testing: add some tests for the service package. Currently, not all methods have tests.
Hints
- The order of the input doesn't matter. However, make sure no duplicate entries or inconsistent data presents.
Is It Wrong to Pick Up Girls at the Public Cafeteria Near the Office?
"It's always fix this, fix that, deploy this, deploy that. They give me trash documentation and expect me to understand? Do they think I'm psychic or something?"
You listen to Alex complain about things you don't understand while walking together. It is lunchtime, and Alex has invited you to check out the public cafeteria he often frequents. You have never been there and so decide to take him up on his offer.
The Office does have a store and a small cafeteria, but you rarely see anyone you know eat there. You often see Emory eating lunch at their desk, eyes glued on their monitor. It seems that your team does not particularly enjoy the food there.
The two of you arrive at the Shopping District where the Cafeteria is located. It is pretty packed at this hour, but the variety is overwhelming. You and Alex check out the vendors available.
"You're still pretty new here so you might not understand my pain, but working with development ready code made by someone else, especially if they don't know how to make proper documentation, is a pain in the--"
"Alex? Is that you?"
A girl calls out to him. You notice Alex turn red and attempt to hide his face. The girl in front of you appears to be oblivious to it, though.
"A friend of yours?" You inquire. Alex seems unsure of how to answer.
"Ah. Nice to meet you. My name is Maya."
"Err, she works at our Front End department. It's natural that you haven't met her yet since you haven't worked on projects with our other teams." Alex tells you. That's true, you haven't really gotten to know anyone aside from your team. Does everyone like eating here?
"Do you want to eat together?" Maya asks Alex.
You can hear Alex scream internally. He nods at the proposal. Way to go, Alex. He glances at you. You exchange between looking at Alex and Maya. The girl invites you too.
After quick consideration, you decide to leave them alone and get some take-out to eat at the Office instead.
Keeping a High Profile
Alex and Maya order some noodles from a vendor and find a place to sit. Alex isn't sure on what to talk about, but Maya starts a topic about the new programmer and eases the conversation in.
"So they joined not too long ago, huh? No wonder I didn't recognize them."
"Yeah. They're doing pretty good. Thanks to my tutoring of course."
The girl chuckles. The truth is Alex is probably the least involved member in their endeavors thus far.
"So, um, earlier, were you complaining about our current project?"
"WHA!? You heard that?"
"You were making quite the fuss, and I just happened to overhear a little bit. Sorry..." "Ah, no, that's fine. Well, you're not wrong."
Alex and Maya are currently working on the same application, albeit from different perspectives. It is a simple grammar application, and is currently able to use an API to retrieve the synonyms and antonyms of a word. There are currently no major problems in the application, but Alex's next task is to prepare profiling tools to check the metrics of said application.
"Why do we even need to profile this application? There's only like what, two separate functionalities that probably don't even take that long to run."
"But I'm pretty sure in the last daily check-in, this was going to be a test setup before we begin profiling the more complicated functions, was it not?" Maya explains.
"Oh, was it?" Alex had not paid attention during that meeting.
"So how do you set-up the environment for profiling, anyway?" Maya asks with genuine intrigue. Alex finds it a chance to show off his knowledge to the girl.
"You know how we're using SpringBoot for the backend, right? SpringBoot has a built in metrics system that we can access
with the actuator endpoint, and all we need to do is add a single dependency to the build.gradle
." Alex runs his mouth.
The dependency Alex mentions is implementation 'org.springframework.boot:spring-boot-starter-actuator'
and this must
be added to the build.gradle
for you to run the /actuator
endpoint.
"Uh-huh. Add some dependency in the build dot griggle, got it."
"Gradle. Anyway, we're going to be using something called Prometheus."
"Prometheus like the Greek god Prometheus? The one who stole fire and gave it to the humans?"
"Yes but this Prometheus steals metrics from our application and gives it to us" Alex jokes. "It is an open-source system for monitoring."
Alex explains that anyone can just download Prometheus and instantly run it
on localhost:9090
. But for it to actually read the metrics from the application, there are several steps to do first:
- Add the
'io.micrometer:micrometer-registry-prometheus'
dependency to thebuild.gradle
- Expose metric endpoints by adding
management.endpoints.web.exposure.include=*
in theapplication.properties
file
These two steps should allow you to see Prometheus metrics in /actuator/prometheus
endpoint. But for the Prometheus to
listen in to the Spring Boot project's metrics itself, one more step is necessary:
- Edit the
prometheus.yml
file available in the downloaded Prometheus folder so that it listens to your Spring Boot project's metrics endpoint. (For this practice, deployment is not necessary. Reading metrics locally is enough.)
"Once that's set up, you just access the metrics through Prometheus!"
"With queries and stuff?"
"Yup. Spring MVC comes with several default metrics. Say we call the synonym function a couple of times. We can try
querying the http_server_requests_count
metric to see how many times it was called, among other queries."
"We can also use Grafana to display our metrics. There's this really nice dashboard template called JVM Micrometer dashboard, and we can use it to display metrics with our Prometheus source."
Alex goes on a tangent
about Grafana and how it can
be used to display metrics, using many available preset dashboards to monitor infrastructure and architecture of
applications. It generally runs on localhost:3000
, and you'll need to set it up so that it will listen to your
Prometheus data source in localhost:9090
.
Once you have logged in and set up your data source, you can make a panel and try querying the same Prometheus queries as before.
You can also create or import a dashboard for monitoring. Try importing the JVM Micrometer Dashboard and understand the data it displays.
Alex wraps up his explanation and Maya lightly claps her hands.
"Well? How was that?"
"Very informative. You really like talking about technical stuff, don't you?"
"Ah well... It's really all I can talk about. Pretty lame, huh."
"I think it's pretty cool."
Alex's heart skips a beat. Is that just an off-hand remark, or does it have any meaning behind it? Alex can't help but wonder. He looks at Maya with an expression of disbelief, to whom she responds with an innocent grin.
"Your food's getting cold."
They finish their lunch and return to the office without much small talk. Alex had offered to pay for his coworker but was quickly shot down as she insisted the company was more than enough. Either way for Alex, today was a win in his book. He may need to work on a way to impress people that does not involve technical lectures, though.
Tasks
- Succesfully open the
/actuator
endpoint - Install Prometheus, run it locally at
localhost:9090
- Configure your project to display Prometheus endpoint at
/actuator/prometheus
- Configure your local Prometheus to listen in on your Spring Boot project
- Try to query some default metrics from Prometheus and display it using Graph in Prometheus. (Minimum:
count
,max
,sum
) - Set up Grafana in your localhost, and display your Prometheus data on it (using custom panel and JVM Micrometer Dashboard)
- Write the answer in the README file, and answer the following questions:
- What does software profiling mean and why do we do it?
- What is Prometheus? What is Grafana?
- How do you set up Grafana to display your Prometheus data on it?
- According to your findings based on the profiling process, what will you say about the application at current state?
- How do you interpret the findings? Answer this along with a screenshot of a graph query result from your Grafana/Prometheus dashboard.
- What new things did you learn from this tutorial?
Suppose You Want to Help Out Your Senior by Taking Responsibility and Modifying Some Code Using Asynchronous Programming
It's 8 o' clock in the morning. The door you've opened time and time again stood before you. It was just a normal office door, but there was much more to it. A feeling you couldn't describe. You then asked yourself, "is it because I am starting to feel attached to it?" You acknowledged the idea as you opened the door for several seconds. A part of you still denied that possibility as the truth.
As you entered the room, seeing the folks run wild in the middle of the room, you began to smile. "I might attached to this office after all." Bitter the fact may be, you accepted it. For some reason you were started to feel something about these people and this world. After all, it has almost been a year since you arrived and worked for this company.
You hated some of your workmates at first. Your first impression for most of them were bad. Besides Emory, you were unable to mention a single good thing about them. However, as time goes on, your impression changed. They were not as bad what you imagined.
You sat at your office desk and noticed something was wrong. It might be the regular morning chaos, but something was different. It felt very different from the mess you normally experience everyday. As you gazed through the mayhem, you noticed what it was.
"Where is Emory?" You wondered.
"If you're looking for Emory, they've fallen sick." An answer to your inquiry came a second later. You saw Alex standing there, looking like he's been to hell and back, and back to hell again, and back. Worried, you asked him.
"Are you alright?"
"HECK NO" He didn't even hesitate to answer. His voice erupted with pain. He was also out of breath. You looked at the clock. It's not even time for your daily stand up, yet Alex is already dead.
"The whole building lost its structure when it lost its foundation. That's what Emory means to us I guess.They are this team's leader after all." Alex's voice was getting softer and softer as he spoke. The whole morning has always been a big mess even when Emory's arround. However, losing its captain, the ship had no direction at all.
Alex continued to speak. "No one in our team can code as fast and as accurate as Emory. I might be fast but not accurate. Even worse, I don't possess the same leadership skills as Emory. " You knew Emory's ability very well. Hearing such things coming from Alex was also a shock. He had always been a prideful man. You couldn't imagine just a few minutes without Emory could lead to this mayhem.
It made sense after all. As the sprint deadline got closer, and with a lot of hard stuff being handled by Emory, their absence meant a lot. There was a need to change priorities and resource allocation.
"Can I help with something? I don't have that many tasks left, so I think I can handle more."
Alex seemed pleased with your initiative. "You will? That's great. " Alex showed a task left by Emory. He began to explain the job you need to do. "I belive you quite familiar with this application. If I recall, you are the one that implemented the PDF exporter in this application. "
"Yes. I did that one." you replied.
"That saves time, then."
Anyway, I will remind you some basic features of the application. This is a guild management system requested by a town called Luneburg. It's a little town in the east of Literra empire. This application lists some kind of information about guilds in Luneburg. It has a lot of data stored in json
format. The good news is it is immutable. The bad news is it's so slow, although it's just a read-only app. "
"So you believe there is something wrong with the IO process? " You guessed.
It seems like that it was the most obvious thing, so Alex just answered it quickly. "There should be more than one source of data, so I think some parts of IO process could be converted to an asynchronous call. To help you enable the asynchronous process in Spring Boot, you can modify the code to match this snippet. But, I leave the rest to you. Thank you so much, and don't forget to write the tests!" Alex then ran away after briefly explaining everything. You were a bit annoyed by his attitude after worrying about him. At least he showed you how to enable the asynchronous process.
After you saw the application's code, you knew you needed to work on the service layer of the application. From the information you got from Alex, you knew it should be something related to IO process. There are should be a part of the IO process that can be ran as parallel process. So as not to waste anymore time, you then proceeded to work on the program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Guild Information System
This application serves as a list of all guild members on the realm. The list itself is quite long, so the system has automatically paginated into neat looking pages which you can control and search through using the tools given. It also provides a way to look into the details of each members and turn the list itself into a portable PDF file.
There are 3 endpoints to this app:
- List of all guild members
- Details of each members
- Generate PDF of the list
The main list can be accessed at "/guilds/members". With this, you can do a multitude of things including filtering certain roles, change your sort bys, go to different pages, and control entries. Filtering roles refreshes the page, but the others do not. Maybe you can use this knowledge in the future, so make sure to look at how it's created.
Details of each member can be accesed at "/guilds/member/detail?id=x" where x is the id of the member. Of course you can visit this page by simply clicking at the name of a member. To export pdf, you may access "/guilds/members/exportpdf" or click the export pdf button on the main screen. This will create a pdf which you may then save.
As is the norm, the problem with this app lies within these 3 endpoints. Make sure to read the code thoroughly and figure out what each does!
The Side of Me I don't Want You to See
"You seem close with Emory. Could you visit their apartment?"
"Huh?" You are puzzled by the request. You didn't even try to look at your conversation partner.
That's the only answer you got. This whole day had been nothing but a living hell. The fact you need to get on Emory's level and helped Alex to replace Emory had taken everything from you. Accompanied by the slow and relaxing jazz music, you gazed at him. You saw Alex and Maya sitting beside you. Not far from them, Riley was also enjoying their drink. After a while you gave a proper response.
"Is this a joke?" you replied. But there was no response other than a serious look from Alex. You knew he was dead serious. Riley, who supposed to not bother your conversation with Alex, also looked interested. With that, you were sent to Emory's place.
You weren't bothered with the smug look on Alex and Maya's eyes when you accepted the request. It was just a visit to a sick coworker. You didn't think much of it until you saw the look of Emory when they opened the apartment door. A moment of awkwardness. The both of you were startled. You by their look and Emory by your sudden arrival. The silence lasted for more than a minutes before Emory let you in.
Your eyes couldn't help admire the unit. This is the first time you had come to their place. Everything was so clean and neat. Judging from how Emory arranged their work desk, this is really no suprise.
"Please don't look around too much..."
"I am sorry."
Emory's cracking voice suddenly made you stop. They were still as cold as always, but something was different. Somehow their sick and weak voice possessed much more emotion than usual.
You then humored Emory with small talk, telling them how your team was worried about their condition. You tried several approaches, each with different questions. Somehow it always ended with Emory apologizing. It was not something you expected to happen. You never imagined Emory could be docile like this. Was this really Emory? No cold stares or dismissing gestures. They always answered properly and even sometimes laughed. This Emory was so sweet, it made you wonder whether they are the same person.
Two hours filled with awkward yet strangely cozy moments had passed, and it was about time for you to leave. You were glad to see Emory's condition was getting better. It seemed like Emory was also happy to see you. But as you announced your departure and tried to turn toward the front door, Emory stops you by grabbing your jacket.
"Don't leave me alone.." Emory raised their voice a bit. Her voice cracked, but was driven by strong emotion. You were left with no choice but to stay, and only left after making sure Emory had fallen asleep. It wasn't so bad after all. This was something you couldn't see everyday. Might as well enjoy it while it lasted. A side of Emory you were sure they never wanted you to see. This might be a story you would never forget.
Tasks
- Identify the part of the service you need to refactor to asynchronous. All service method always return a
CompleteableFuture
. Your task is to find which part of the method that might be better to run as parallel process. You can use the help of other tools like profiler (see practical-4) to find the said segment(s) - Explain your decision and reasoning in
README.md
- Write tests for service and repository packages. Achieved at least 90% line coverage for both service and repository.
The End of The Year, Deployment, and The 12Factors App
It's finally that time of the year again. No matter where your eyes were looking at, everything was covered by a thick white blanket. The cold slowly pierced your skin as you moved. Even a litte touch felt like a sharp blade. The further you walked, the more painful it became. The office door seemed so far away. You really wished you were in your bed, covered by a warm blanket and accompanied by a glass of piping hot tea right now. In reality, you were sitting at your desk.
Although all your tasks were done, you still needed to remain present at the office until the deployment is complete. It was a peaceful and relaxing day for you and the rest of the backend team, except for Alex. He was still busy with the deployment related stuff. He had a rather stiff expression since this morning. The loud sound of the keyboard's typing reverberated in your ears. Every few minutes, he gave a long sigh. As if something disappointed him every so often. You didn't even need to ask what's wrong. His face told you everything you needed to know.
"Is there something wrong with the codebase? " That line was simply courtesy. You knew something was wrong. Alex glared coldly at you, as if it wasn't cold enough. He stopped for some seconds before gesturing for you to look at his monitor.
"I really need to teach you guys something about the 12Factors App. It is always a pain to deploy your codebase."
Something made you regret your decision to chat with him. But, it has already happened so you decided to stay. Alex then started to speak, explaining the list of problems in his monitor.
"I believe you are familiar with 12Factors App?"
"No." You responded quickly. Alex looked annoyed. After taking a deep breath he accepted the fact and continued.
"It seems we need to start from zero."
You didn't know exactly whether he had the time for all of this knowing the deadline was near, but you listened anyway.
"Since we will use a third party service as our deployment platform this time, I want to show you a methodology that is widely used to develop and deploy such an application. It’s called 12Factor. Yeah normally we won’t need to follow this methodology, as the client also seems not to care much about it, but I want give my best and show them an app built by best practices. After all, they might change the deployment platform in the future. Following this best practice is for our best interests in case that happens."
Alex revealed his plan on the monitor. It listed everything, starting from the current codebase until the development platform and what improvements should be done.
“ We will use Heroku as a deployment platform. Until now we've used a development environment to develop and when the deployment stage was coming, I just changed some settings to match the production environment and deployed them manually. However we can automatically deploy a new version of our application using CI job. Heroku, fortunately, supports it as well. But, deployment is only a small part of our concern right now. Here, look. “
A list of problems showed up. The problems were not bugs or a faults in the program, but it is a list of issues of 12Factors that are not yet fulfilled by the current application.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
"I don't understand." You replied.
"Yeah I expected that. "
"Thank you."
Alex looked even more irritated. You expected him to stop, but instead he began to explain more and more things to you. If you hadn't regretted your decision to initiated a talk with him earlier, now you definitely would. However, this is knowledge you never heard of before. You found it interesting. So you didn't try to run away.
Alex took about half an hour to explain everything. After you showed good understanding, Alex seemed satisfied. But as soon as he glanced at the clock, a frown returned to his face.
Alex was an interesting person. He seemed like he didn't care about your team. He wasn't a good leader either. He even admitted that himself. However, once you've discussed something that gained his full attention, he would immerse himself in it, ignoring everything else. Maybe only the presence of Maya, the frontend team lead, may be able to bring him back to the reality.
"Can I help refactor the codebase?" You then decided to help him out since he took his time to explain everything. You also had understood the task you need to do in order to complete the 12Factor, so it won't take too much effort to complete. After all you had completed all the tasks given to you.
"Sure. That will help me a lot." He simply replied.
Codebase
Any application should have exactly one codebase. At the moment, The application has one environment, that is development environment. The codebase constraint restricts the application without regarding the number of servers that run the application. This means every server that runs the application must use the same codebase.
Checklist
- Create a branch named “staging”.
- Create a Heroku account if you still don’t have one.
- Create a Heroku app named “trade-system-< NPM> -production” where
is your student identification number ( also eponymously known as NPM). This will be your production environment. Ex: trade-system-20012233434-production - Create another Heroku app named “trade-system-< NPM >-staging” where
is the same value from before. This will be your staging environment. - Create Heroku Postgres instances for both servers.
- Deploy the application to both servers. You must deploy the code from the “master” branch to the production environment and deploy the code from the “staging” branch to the staging environment. (Hint: You might want to solve the “Build, release, run” constraint’s task to do this)
Config
The application configuration in application.properties needs to not include sensitive information like database username, password. Their values has to be taken from environment variables.
Checklist
- Analyze all variables in the application.properties. List all dangerous variables that store sensitive information.
- Make environment variables to store sensitive information
- Refactor application.properties to use the environment variables.
Build Release and Run
Application deployment should be separated into three stages: build, release, run.
Build stage is when “transformation” of the application’s code into executable files is done. Release stage is when the application’s code that already passed the build stage is sent to the deployment’s environment (for example: staging and deployment). Run stage is when the application’s code that passed the release stage is run (in the designed environment in release stage). Your job is to make the deployment flow into these stages.
Checklist
- Create build and release stages into your practical-6’s “.gitlab-ci.yml”. Make sure to differentiate release stages for staging and production environments.
- Add a new job to deploy your practical-6 application.
- Make sure not to expose sensitive information related to your Heroku apps and account. (Hint: Satisfy the Config constraint)
Port Binding
As a web application it is common sense that it will run on port 80. But this time you want the service to serve at 8089. It also makes the application have an universal port.
Checklist
- Change the port at application.properties
Dev/Prod parity
At the current state, the application will run smoothly in a local development environment. It will not run at Gitlab or Heroku. Provide the each environment (refers to staging and production at point 1) the variable needed to run the application. At the current state, the application has been using the same database driver as the production. You just need to make sure the data sources are correctly configured. In the ideal condition, the OS that runs the application should be the same in all environments. But you will assess this issue later.
Checklist
- Provide all the variables needed in the repository as well in Heroku.
Logs
The last thing you need to do is to implement a logging system. During production, we don’t always want all the system’s
information to be displayed. Say we print out every little detail using System.out.println()
. Sometimes we don’t want
this information to leak, or sometimes it returns a simple confirm message which isn’t really necessary. This is bad
granularity. Using a logger, we can control the levels of logging output we want.
There are several ways to implement a logger, either with java.util or an external application. You are not confined to
only one method to log messages to the console. The main point is to treat your logs as event streams, and output
to stdout
. What the environment chooses to do with these event streams are of the environment’s concern. All the
application needs to do is output logs based on the events that are happening within the application.
Checklist
- Implement a logging system for the functions. Make sure it can return an output to stdout. You are allowed to use any logging system you want.
Notes
You need to configure a local PostgreSQL database in order to run the application. You can set the configuration
via application.properties
to match with your local database.
Suppose Something is Dockerizing but It’s Not The Shield Hero Season 2
Festivities Abound
December 31st, New Year's Eve. You never had good memories from your childhood of this date. You've always spent every year alone, watching videos of other people celebrating while you take refuge from the ear-piercing fireworks and hit the bed after Cinderella had lost her magic. Normally you would worry of what to say to your relatives over another year of unemployment, but you couldn't care less about them now.
"Hm? Isn't this place..." You murmur before continuing forward. Your team decided to hold a New Year's party at a pub in the shopping district. Alex insisted that it's the best place to get a drink in town, but now that you're here you think you can figure out his intentions. You walk around until you stumble upon 3 familiar faces.
"Yo, why the long face?" Alex prods you, looking drunk already. Your intuition is spot on as you see Maya sitting beside Alex, calming him down. "Nothing, I never really celebrated New Year's before, so I was just reminiscing a little bit." You reply as you sit down next to Riley. Emory had also been invited, but they declined citing they have stuff to do. Apparently Emory never attended one of these because of "things to do". You order some tea and converse in small talk, mostly dominated by Alex's rambles.
"You know, you don't really talk about yourself. Emory too. Where were you before all this?" inquires Maya. The focus suddenly shifts. You feel a slight shortness of breath before calming yourself with another sip. There's not much you can say. Emory has told you to come up with a believable narrative, but you come up empty. "Oh, well... I've just been out of work for a while now and I would hate to work in retail. Mostly stayed at my place since I don't have relatives nearby."
You feel like telling your true past shouldn't be a problem, as long as you didn't mention about being from another world and all. Alex and Maya gave you a warm smile, but Riley seems to have raised an eyebrow. "You're not in debt or anything, right? It must be hard to survive in this city without a job and family." They say.
You never considered that surviving without financial support in a big city would be that weird, but you didn't account that your parents has always given you some amount at least until you find a job. "Ah yeah, I had a large saving I got from my parents." You casually mention the fact. It is the truth back in your world, and from what you gather, culture here doesn't seem too different. But little did you know that you've just opened pandora's box.
"So you're not from here? Where are you from then? I'm from Praston myself. Getting all the paperwork done to move here was a chore and a half ins't it?" Maya pressed on. At this point you realized that you might have ran your mouth a little bit too much. "Of course that's going to be the next question!" You thought to yourself. Where even is Praston?
Years of social gathering should've prepared you to navigate through minefields like this, but you've barely attended any in the past world, let alone here. Maybe this is the reason Emory doesn't participate in gatherings. You start to scramble for a good answer.
"Oh, the government had this program, and uhh... I applied for it and-"
Ring Ring Ring
Your phone rings. You set your ringtones to silent except for one person, Emory, in case any emergency happened. It's as if they had been watching from the start. The grace of an angel bailing you out of a bad situation...
"Sorry to do this to you, but can you come to the office?"
...into a worse one.
A Not So Happy Carol
You arrived at the dark and desolate office. While normally there are several security personnels, only a few still remained. It's holiday, naturally everyone wants to be with their loved one. You told the others back at the pub that it's an emergency situation and left in a hurry. While you feel bad, this gives you more time to get your story straight and maybe a chance to consult Emory.
As you walk, you began to wonder what's up. Emory never asks for other's help, but why are they working in the first place? You had thought that they're a hard worker, but not to this point. Though you feel happy that Emory would rely on you for once. Your mind starts humouring the idea of them seeing you in a different light, as you have always seen a different side of them recently.
You rushed over to your department and see a familiar yet disheveled face. "How long have you been here?" You asked gently, as if to signal a change of pace. "That doesn't matter. Sorry to intrude on your break. It was supposed to be something I could handle myself, but something came up" Emory grunted. "There are actually two systems that I need to work on, normally I would press on however long it will take..." Emory then paused as if considering something, perhaps the right words?
"But, maybe just this once I would like to also be done in a timely fashion. And I figured a certain someone owes me more than a little bit." They continued.
You start to feel bad, but felt that behind the remark Emory finally found the will to rely on someone. As usual though, they said that with a straight face. So who knows what Emory is really thinking about.
"Of course. I'd be more than happy to be of service. What is the problem?" You asked, Emory did help you get out of a bad situation, albeit indirectly.
"Right, let's get started"
Docker
"So how did you ended up with spending your holiday here?"
You had been wondering what is Emory's motive here. Being in the office outside work hours and above all, during a holiday, was something you can't imagine, even for Emory. There should be a specific reason.
Howver,Emory didn't budge at all and kept on typing. It lasted for a minute or two before Emory decided to give the reply you wanted. Emory gazed at you. But, in the last second Emory decided to change their mind and ignore the question. As if Emory was trying to hide something.
"So what we want to do here is to Dockerize the application we have developed. Is it correct?"
You decided to change the topic after seeing Emory's reluctant reaction to the question, respecting their privacy.
"Yes" Emory replied. Their voice sounded a bit trembling. Maybe the tension from hesitation whether to tell you the truth or not. Then, for a split seconds they looked at you before commented, "I assume you remember what happened with the last application."
"Yeah. There is no way I can forget about it."
Yes. There is no way anyone in the team able to forget it. When your team thought everything is over after the development and the deployment, fate didn't smile at you. Everything was going well in the staging server. More or less, the behaviour in the staging was the same with what you saw in the local environment. But, somehow production server didn't want to see the relief on your team's face and the application failed to deploy miserably. Alex had suspected the root problem was because of multiple java and external other dependencies existed in the server. The management saw the sleepless nights Alex must have endured to make sure the application still deployed on time and they asked for a change in the workflow.
"We will soon need to release the next phase of that application. So we need to do something so the same problem won't happen again. Alex and I proposed that we need to use container in the next deployment. With the use of container we can make the application's enviroment even more isolated with each other. We can even mimic the production server better with container, to comply with Dev/Prod parity factor. "
Emory explained the supposedly technical stuff with a much more neutral tone. You were also relieved that the first question did not bother them that much. But, you also realized. Why did Emory choose to work on that now? In the middle of new year's eve? They could have just done it after the holiday session. Yes, there was no rule from the kingdom that forbids this kind of work behaviour but it's just so unthinkable that some will do it for real. For what purpose? That question raised in your head for some seconds before you answered it yourself. To give the team a bit of rest time in the new year.
Emory then suddenly murmured something. The look on their face changed. The voice was so soft to hear but you could judge what it is. Emory might had seen your face when you realized the intention.
"I just wanted to repay the debt when I was sick. So..." The voice was getting louder, enough for you to hear. You had expected that sort of response. But the situation was becoming more awkward each second and you decided to get over with it.
"I will start to dockerize the backend application. " You tried to avoid a more tactless conversation with working as the alibi.
Dockerizing The Application
"I assume you are bit familiar with Dockerfile
"
"Yes. It's a file with the instruction to build and run the containerized application, isn't it? I have created some when I had Alex to taught me. However, I don't have any experience in dockerizing a more complex application. I believe there is a need for the containers to communicate with another container in this system. "
"Yes." Emory approved your observation. "As you can see we have two Springboot applications here: the trade system and company system. Basically, you can see that the trade system dependent on the company system. On top of that both applications also need their own instance of PostgreSQL database. So basically you need to run four docker images for the backend application. "
"So if I not mistaken, I need to run both instance of the PostgreSQL containers for both application first, then run company system container, and last the trade system. "
"Correct. "
"But how can we make the container communicate with each other? I am sure that database host and service url are not pointing to localhost
anymore. "
"It is pointing to the host of the target container. So it will be the name of the target container. You will need to comply to configuration factor of the 12App to make this possible. "
"In short, we will use environment variables to pass the name of the said container?"
"Yes. One more thing you need to be aware is a container can only access another container if they belong to the same network. "
"Okay. Thank you Emory."
The information provided by Emory was enough to start to work on.
The first step of course to create a Dockerfile
for both application: CompanySystem
and TradeRouteSystem
.
This application structure is a Gradle multi-module consisting two Spring Boot app.
You need to define the Dockerfile
in each module.
Spring Boot with Docker is a good article to start with.
However you need to make some adjustment, e.g. JDK base image.
Create the image for both of the application using docker build.
You can define a network via docker network create
.
A full docs can be found here.
Once done, you can try to create the container instance of the related images using docker container command.
You will need to create the container and start it using the above command.
A container can have some environment variables defined.
You need to utilize these variables to run the container.
An official image such as PostgreSQL has a set of variables defined in their Docker Hub page.
Meanwhile for CompanySystem
and TradeRouteSystem
you can read all set of variables in the README of the repository.
The Clock Strikes 12
You entered the last line of code and pushed the result to the repository, everything seems to check out. You look at the clock and it shows 11:50. The same old memory every year, spending New Year's in a dimly lit room in front a computer. Only this time, you're accompanied by someone else.
"Hm?" You noticed something at the corner of your eye, a figure. A few, actually. And they're not Emory. You have heard of ghost stories on the office before, though you're not the believer type. Suddenly, one of the figure draws closer. You feel chills and prepare for...
"What? You looked like you've just seen a ghost." The figure spoke, but you know this voice. A voice of someone who shouldn't have been here. "Is something wrong?" another figure tapped your shoulder. You cleared your eyes and confirm both source of voices.
"Alex? Riley? What are you guys doing here? Weren't you going to celebrate New Year at the town's square?" You asked in confusion. "Well, we did before someone decided to ditch. Can't you be more grateful? Geez." Alex sneered, he looks pretty pissed.
Now that you look again, a few other computers in the office are turned on. It seems that they also did some work. "Did Emory ask you two?" You inquired. "Ya think? Obviously not. Honestly, we're pretty stumped that Emory asked you. Voodoo magic I tell ya." Alex went on, his speech pattern is a bit weird. Maybe he's still drunk.
"But then-" Before you could respond, Riley interjected. "It's our decision. We can tell from your call that you're going here to help Emory. There's no way we could be partying while knowing that. We're a team."
You did feel like your task went significantly faster in the middle, it must've been because of these two. You feel guilty, but at the same time happy and relieved. The fact that they're here means Emory didn't turn their help down.
You reported to Emory. They didn't mention anything about Alex and Riley, presuming that you had talked to both anyways. "For the record, it would be weird to ask them not to help after I asked for your help." While the tone is the same, you can sense a small sense of embarassment.
You returned to your desk and turned off your computer. Alex and Riley sat on a sofa near a window. You followed them and sat down. Emory walked in with four cups of coffee. Each of you took one without saying a word, everything was silent. You felt like nothing needs to be said, but to bask in the sense of camaraderie.
The clock striked 12. Fireworks started to fire outside, must've been from the Town's Square. The four of you did a little toast and took a sip. It's sweet, perfect for such a good night.
Maybe you can tell Alex and Riley after all, though you wouldn't know how Emory will response if you say that out loud. Why can't you tell people about being from another world anyway? Though you suppose the fear should be enough to keep you from something stupid. Trust is a fickle thing, but surely you'll figure it out.
"Happy new years!" everyone shouted. You're sure that today will be a memory you will recall for years to come.
Checklist
- Create
Dockerfile
for bothTradeRouteSystem
andCompanySystem
. - Create a network for your system
- Create two containers of PostgreSQL that use the network you just created.
- Create containers for both applications. Make sure you can access it via browser (your
localhost
). Make sure it has the same behavior as yourpractice-6
application.
Bonus
You can attempt the following bonus tasks:
Dockerhub
- Create a Docker Hub account
- Push your image to Docker Hub
Docker Compose
There is a way to automate and compose what you have done so far by using docker-compose
. It needs to be installed separately from Docker. Try to run the container using docker-compose
. Make sure it has the same correct behaviour as the container you had run before in the previous section. Please install docker-compose
first before doing this part. Please read more about how to use docker-compose
on your own.
Checklist
- Create
docker-compose.yml
in the rootpractice-7
folder - Make sure the application can run via
docker-compose up
Commence Operation: C.A.C.A.O (Chocolate And Commerce At Once)
The office is lively as usual. The echoing yells of your teammates reverberate around the enclosed office. You sit at your desk, listening to the ramblings of your workmates. The topic this time reminds you of something you've experienced before yet again.
"How do you not know about St. Valentines Day!!??" "Should I be concerned about it?" "Yes!! You should!! It should be a public holiday." "I know of no such thing. You just want a day off. Besides, I can't do anything about it. Orders from above."
Alex seems to be yelling at Emory about something. Usually it's the other way around. What's got him so worked up? Riley appears to be fidgeting in the corner. They seem to want to say something about whatever is being discussed.
Just then, the room door opens. Rory and Maya walk in together. An unusual combination. Maya is holding several papers in her hand, and is likely about to consult us about some project or other. The two ignore the bickering Emory and Alex and approach you to ask about the situation. You explain what you understand so far on the topic of St. Valentines. They both seem to show a reaction of interest, revealed by the glint in their eyes. The two whisper for a bit before silently agreeing on something.
Rory walks over to Riley. You inquire Maya as to what St. Valentines Day really is.
"You don't know? It's a day to remember the valiant efforts of the Great Paladin St. Valentine. Apparently a common practice is to share chocolate with friends and loved ones. At least that's what I remember about it."
The whole concept sounds familiar, except for the whole Great Paladin St. Valentine character, and you don't really feel like inquiring further is necessary. Sharing chocolates though, that piques your interest a little bit.
Rory finishes discussing something with Riley, who's expression changes drastically. She now appears to be pleased somewhat, grinning from ear to ear. Rory cuts in between Emory and Alex, gesturing them to stop and listen.
"I have an idea" Rory proposes. "They didn't give us a holiday, so why don't we give ourselves a holiday?"
"What do you mean?" Emory questions.
"We can work in shifts. Like a half day thing. We've done this before, haven't we?" Rory looks at Alex. "Huh? Oh, yeah. I guess we have. As long as we reach our deadline."
With that said, Rory returns to Emory and suggests the idea of doing a half-day shift tomorrow, with the work distribution too. Rory then beckons Emory and whispers something to them, all secret-like. You can't quite catch what they are saying, but you can see Emory's face grow with interest every passing second.
"Hm. I suppose that's fine. I'm sure I can compromise with our superiors." Emory declares. Alex jumps for joy. The mood in the room changes. It is as if a thick blanket of smoke was wisped away through the window.
"As I have been informed, tomorrow is St. Valentine's Day. Our higher ups did not given us a day leave, but I will permit a half-day leave for everyone in shifts." Emory explains that you, Alex, and Rory will work until noon, and after that will be Riley and Emory, and Maya by extension. A half-day holiday, that doesn't happen very often.
"Are you really allowed to do that though?" Alex wonders. Emory simply shrugs. "We still have a deadline to do, but I do agree resting is also important."
"That said, we still need to talk about our next task first.." Rory reminds everyone and ushers you and Maya over to where everyone else is. Maya obliges and brings their stack of documents with them. You follow them and regroup with everyone else in the middle of the room. Guess it's back to work.
BootShop
"You're aware that we're helping the development of an e-commerce system, yes? It's still in its early stages, though."
You seem to recall a commerce project that had been handed over to your team. Bootshop, is it? A simple e-commerce application with the purpose of democratizing access of commerce through a digitized application. Maya explains the backlog and what is to be expected.
Apparently they need a system where when a customer checks out their carts, they are able to choose a payment method and a courier they prefer. Early development requirements aren't much, and only two payment methods and three couriers are available. The development team has tried several approaches, but haven't found the correct way to do it.
Emory asks about details on the system. Maya picks up a different document and starts flipping pages. "It says here there are two supported payment systems right now. Gold Transfer and ArgentaPay. The customer can choose these options on the checkout page. If you look at the application, it is a page that can be accessed via the cart icon. At the current state, the selection hasn't been added yet. We need to add it later."
"There is also a promo offer we are trying to implement for ArgentaPay. For example, the payment using Gold is treated as is. If the invoices say you need to pay 350G, you need to pay 350G. However, If they use ArgentaPay, they will get a 10% discount for every item they buy." Seems like a good deal, you figure.
"Another thing the customer needs to choose is the delivery method. We are implementing three couriers: AtivexGo, Slossea, and Thunder Cross Split Delivery. AtivexGo will deliver the products in between 10-20 seconds for each item in the cart. Slossea between 20-30 seconds for each item in the cart, and Thunder Cross Split Delivery will send all items in the cart in 30 seconds exactly, all at once. All the courier costs 10G, 5G, and 15G respectively."
Maya then explains about the required dashboard. There will have to be a dashboard to support the reporting of the
status of the items sent by the system. In general, the item has three statuses: ADDED
when the items are for the
first time added to the cart, PROCESSED
after the requests received by the merchants; after the customer checkout,
and DELIVERED
after the items are delivered to the customer. The cart also has status. ADDED
after the customer
chose some items they’d like to buy. If one of the items added has the change of the status, the status on the cart also
changes into PROCESSED
. If all the items in the cart are delivered, has the status changed to DELIVERED
, the cart
status will be changed into COMPLETED
. The page to display all cart transactions you have made can be accessed via the
dashboard on the navigation bar. This mechanism is also not implemented yet.
"Seems like a lot of frontend work to do..." Alex comments. "Don't worry, this is a prototype, so feel free to edit the frontend as you like. The frontend team will be working on the actual web application. You're not expected to create a fully working front-end."
Making Chocolates
"So, why am I doing this again?" Emory asked, inspecting the frilly apron they were given by Maya.
"Hehe, you say that, but you really don't mind, don't you?" Maya retorted.
"Well... I'm not against it."
The two were in Emory's apartment kitchen. Ingredients for simple chocolate chip cookies was prepared on the counter. Alongside Maya and Emory was Riley, who seemed very amped up. They had rolled up their sleeves, equipped their apron, and was ready for battle.
"Do you have any prior experience baking cookies? Or making chocolate?"
"I cook a lot but I've never really made desserts."
"Same here."
Maya had prepared a recipe to follow and began instructing everyone on what to do. Though the other two have no prior experience baking, they followed with no problem as they already had cooking experience. Maya preheated the oven, and they started on the actual cookie batter.
Emory mixed together softened butter, white sugar, eggs, and vanilla extract onto one bowl, creating a buttery mixture. Riley mixes flour, cocoa powder, baking soda, and a pinch of salt into it. Once the batter was well blended, it was time to mix in the chocolate chips and some walnuts.
Maya had readied up cookie sheets, and was carefully pouring teaspoonfuls of batter onto the tray. Once the tray was fully occupied, she
"At this rate we should be ready by lunchtime"
"Don't forget, we have work after this."
"Hahah, very true."
Once the cookies were done, they shared one to taste. The taste was just as expected, very chocolatey. They parceled it up in very cute wrapping paper to make it look presentable, and furnished the final product with a pink bow. The cookies were complete!
It was fulfilling, the process of making cookies. Cooking was something they had done often, but cooking together was a completely new experience. Emory smiles softly at no one in particular. They can only hope their effort would be appreciated by the receiver of this present, they thought as they clutched the bag of cookies close to their heart.
The Task
You will need to assess the requirements from the Boot Shop section. From the requirements you will need to decide what design pattern is needed to solve the problem. You will need Strategy and Observer pattern to solve the problem. Analyse the problem and decide which part needs which design pattern.
-
Write all the requirements in notes.md. Compare the current state of application with the requirements. Write down what you need to change.
-
Write your proposed solution in notes.md, explain why you propose that solution. Explain what part of the solution is using the design pattern and why.
-
Implement the proposed solution. Don't forget to change the credential of the database in
application.properties
Hint
- You may need to change the controller and the view (HTML). Read more about controllers and Thymeleaf.
- You may try to run the application first while reading the Boot Shop section to give you a clearer picture of what the requirements asks.
- You can change the model if needed by your design.
- You might try the application first to understand. Then you can design the changes needed.
- You can change the value of
spring.jpa.hibernate.ddl-auto
to update to retain the value of previous transaction from previous sessions - You may book your TA to discuss the requirements or something you are not sure about.
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.
/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 |
|
If there is no author with that name, the endpoint should return an empty list.
1 |
|
/api/text/create
POST
Add new text to the application.
Request Body:
1 2 3 4 5 6 7 |
|
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:
line-break
Add line break (#############\n
) at the beginning and the end of the text content.author-in-content
: Add the name of the author (by <Author name>
) in the text content.shifter
Shift the text content by 1, using Caesar Cipher. See example below. You can useTextChipperUtils
to shift the text.
Examples Request and Response
Request 1:
1 2 3 4 5 6 7 |
|
Response:
1 2 3 4 |
|
Request 2:
1 2 3 4 5 |
|
Response:
1 2 3 4 |
|
Request 3:
1 2 3 4 5 |
|
Response:
1 2 3 4 |
|
Request 4: The settings can be customized and called multiple times
1 2 3 4 5 6 7 8 9 10 11 |
|
Response
1 2 3 4 |
|
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...
Once Upon a Dream
"What is this? Why are you showing me this?" The train of questions don't stop. Shiny things fly here and there as if they have their own consciousness. They are everywhere. And this place, you have never been here before. But, as soon as you want to launch another question, the intention itself is stopped. You already know the answer.
" These are memories. " The stream of questions ends following that statement. Yet to whom were the previous questions are addressed to? As if you knew you are always in the attention of something entirely different from you; an inhuman presence you can't ignore. The entity that always watches you from far away finally makes its move.
" You will know. Very soon. " They said, and then they walk away just like that.
But there is no need to wait any longer. That question and potentially every question after that has its answer already.
It's my coworker's past memory...
The Dream of the Dreamers
It was an ordinary summer afternoon. The heat left quite the impression, making work feel harder than it should have been. Not the ideal condition for a critical period, you would say. But it was what it was. For Alex, however, it was something he wanted to ignore. After all, it was a big day for Maya. Finally, the time came for her.
" You two look so awkward...What the heck with this mood." Both Maya and Alex just kept staring at each other without saying any words. Kevin scolded Alex and Maya. But, it was just the natural reaction you would expect. The two childhood friends were not used to meeting formally like this. But, after some seconds of silence and finally, both of them just laughed. After all, the day they both had waited and waited for so long was finally here.
Maya had always wanted to become a star. Someone adored by many people that she would like to call fans. Obviously, not a few thought that was a dumb idea by a young girl who didn't know anything about this world. But not Alex, at least. Maya was his only light back then. He always believed, and the day when he could see Maya smile like she always wanted finally was here. However, it was a bit different than what he expected. It was not a pop star or idol unit that Maya always dreamed of. She tried and tried but failed. Somehow, the path they both followed led to this.
" It is finally the first anniversary of Leticia Arianne, and to celebrate, we want to create a giveaway event where Cia's fans can redeem promo and giveaway codes automatically using a website. These codes also can be used to redeem premium membership in the Fu Tube " Leticia's manager initiated the meeting out of the blue. Alex laughed a bit. Alex imagined that she couldn't stand the awkward air between him and Leticia, or should you say, Maya, anymore.
Leticia Arianne, Maya's Vtuber persona, finally made it to the big stage. As someone who always supported her so-called dumb dream joined her as the agency's IT staff. Unfortunately, he rarely got the chance to support her directly. He was a programmer. Most of the time, he wouldn't get near Maya. After all, both he and Maya were busy with their own schedule. So this was a golden opportunity that he had waited for so long to directly support his precious childhood friend.
"May I confirm something? Are the items on the website based on the items provided in the marketplace we have developed before? " Kevin raised his hand. Alex's superior, as usual, took secondary notes apart from Alex's to prevent any misinformation.
"Correct. " Cia's manager nodded. " In the marketplace, Cia's viewers can buy some mech items such as cards, stickers, mousepad etc. With this website, we want to be able to generate codes so the viewer can use the code in that marketplace.
"So basically, with this new system, we want to automate the creation of promo and giveaway codes that were previously manually created and input to the marketplace? " Alex asked a question to Cia's manager, but to his surprise, Cia's manager gestured for Cia to answer that herself.
"Yes. In addition, we can generate random or customized words. However, the code only can be used once. The same code can't be redeemed twice. "
" I see. "
"Is there a fixed number of item and code types on the website? "
" We may add another type of code and item in the near future. We may add something like a voice pack's promo and giveaway codes to celebrate the subscriber's milestones. "
With that information, Alex started to design the system. There are several code types. Every type can be used in merch promos and giveaways but represents different items. There is also a need to be able to add more code types in the future. So it's better to design a system that can generate more code types without changing the existing codebase. Without paying attention to the chit chat after the meeting, Alex focused on creating the codebase. For Alex, he must not fail this job. If there was any task that he couldn't afford to make any single mistake, it must be this. After all, Maya's dream always has been his dream.
Task Description
Your task is to complete a code that match the requirements mentioned above. You need to choose a suitable factory design pattern to solve the problem.
Workflow
There are two main endpoints in this application. One for the agency to generate code and one for viewers to redeem the code.
Final Product Expectation
-
Code generator interface
-
Code generation output
-
Custom Code Generation
-
Redeem Code interface
-
Redeem Code Expected Result
Checklist
- Read the above sections to understand the requirements
- Complete any class with
TODO
comments. You may also need to add new classes to implement the design pattern and change the HTML to make the application functional. - Complete
Code Generation
feature - (Optional) Complete
Redeem
feature so the same code can't be redeemed twice. - Add any tests for any changes and new classes you make.
Hint
- To get the full score, you need to design a maintable code that does not need to change much if there is a need for new type of coupon code or item besides the existing one.
Lost Dreams
The job was successfully done, and Leticia's anniversary was also a big success. However, the fairy tale ended there.
Alex stood in the corner of Maya's bed. The formerly known Leticia was nowhere to be found. Maya's eyes were empty, and her cheerful demeanour had gone long ago. "Is it a sin to have a dream, Alex? " Alex obviously couldn't answer that. He could, but he didn't want to. He couldn't accept it. The hard work she had done since their childhood. The pain and the tears she shed. Is there no meaning to all of that?
You can't make everyone happy. That is something Maya has known since the first time she entered this industry. However, the harassment and her anti, her haters continually spammed her chats every time she streamed on her social media, and she couldn't take it. Her dream had become her nightmare and, little by little was driving her crazy. To prevent any more damage to her mental health, Alex suggested she retire.
The effect wasn't the best Alex hoped. Maya's condition wasn't getting better. She felt so much hatred and anger. To whom? To the antis who ruined her life? Or to her past self for having a dumb dream and didn't listen to anyone? Or, to the cruel fate commanding her life? Alex wasn't sure.
And just like yesterday and several days before, Alex wasn't able to help Maya. Alex felt he was never able to help his only childhood friend. In that kind of time, a certain entity approached him. They offered him and Maya a second chance in life. In another world, that is. Desperate and feeling like there was no other option, he accepted their proposal.
"Please erase her memory and let her choose her own life. " was the last thing Alex requested from the entity, and they responded with a little smile.
" Maya, let's go home. " Alex shows himself in front of Maya's desk. She responds with a warm smile.
" Let's go. "
Alex usually walks a bit faster than Maya. But, as he recalls something from his past, he decides to walk just behind his co-worker and shows a bit of relief.
"Are you happy right now, Maya?"
From Reactive Programming to Your Legacy
You walk through the memory corridor. That's what it's called. Before now, you didn't know anything about this place. A lot of times in the past, unconsciously, you wandered here, peeking a piece of someone's memory. Sometimes it's a beautiful memory. Sometimes it's painful.
Nevertheless, you always adore those memories. They give you meaning and strength. Although you don't understand why you have been given this kind of authority. Maybe so you can try to understand your co-worker. However, something is missing. Why didn't you get the chance to know your own past? As if your knowledge of your past is stopped the day you were transferred to this world. After knowing what happens with your co-worker, you feel something similar may have to you. That question is yet to have an answer.
That night you see Rory, your division manager, alone in her office. It isn't the most beautiful of nights. When you look through the window, all you can see is the pitch-black sky covered by heavy rain. The strong wind knocking on everything in their path accompanied by thunderstorms are the only things you can hear besides. You can easily guess that poor Rory is trapped just like you here. However, Rory doesn't seem to be working or resting in her office. Instead, she looks at the night sky, almost like praying. After a good look, you realize it is not a hopeful prayer. She is definitely scared of something. Her whole body is trembling. Rory holds her necklace still and, a few times, looks at the picture in it. After doing so, she seems more relieved. It was nearly 10 years ago when everything began and ended for Rory, in the middle of the night of a heavy storm.
Stella, The City of The Stars
She was in a hurry to meet with her client, an important figure from Stella. The great city of Stella was the centre of the population. Many problems led to a need for a system to manage many aspects of the town. However, the resources were so limited as the effect of the great war. Rory and her team were the only developers available right now. The condition couldn't be any worse as the weather in Stella wasn't stable either. The heavy rain in the middle of the storm wasn't helping her at all. After all Rory's effort, she still arrived late at the meeting.
"You are late.."
A man in his thirties did not seem impressed. The meeting hadn't started yet, but Eddie still scolded his late co-worker. The government of Stella usually came late to a meeting, so late for some minutes should still do it. But, this man, Eddie, really didn't like the indiscipline act.
"I am sorry. "Rory simply apologized and did not try to argue with her co-worker. She didn't want to make any more trouble after the fuss of her late arrival. Rory then sat silently beside Eddie.
The whole meeting went on without a hitch. The pair then spent some minutes in the meeting room to discuss.
"Property management, huh?" That was the first thing that came out of Eddie's mouth after the meeting.
Stella's government does not have control over many resources. It is mainly because Stella is a city of travellers in the first place. It does not have a native tribe. However, their position is strategic, perfect for trading routes. So the Stella government saw this as an opportunity. They offer residency to outsiders that want to conduct business in Stella. They gain access to many properties that the government sells by applying for residency. Buildings are essential for trading. So this is its main business of Stella.
"Stella's primary business is trading, after all. It's what makes money. So what we want to create here is a system to automate that business process. "Rory replied. Her eyes wandered to Eddie's screen. He's already made some designs of the system. "This is..?"
"My initial system. I guess. "
"Can you explain? "
"Sure! Generally, there are three entities in the system. Proprietor, Property, and License. The Proprietor could be a resident or a guild. Every Proprietor could own 0 or more properties. So, a traveller who wants to buy or rent a property in Stella has to be a resident or affiliated with a guild first. Every property has its own License. Whether it is for occupancy or business. I also have a document of the data design in that suitcase."
"Is that the document Stella's representative gave during the meeting? "
Eddie nodded. "They have created the base endpoints and models for Proprietor. Our task is to complete the remaining two models: Property and License. We will need to create an API for Create, Update, and Read. We won't need DELETE endpoints. You can only update the property owner id field when you update a Property. The License doesn't have an UPDATE endpoint. Add License should be done via property/add-license
, assigning them to a property."
Rory checked the codebase mentioned by Eddie. The codebase was basically a bit familiar, but at the same time, it didn't. "Reactive style.." she mumbled.
"Yeah, it makes us need to use different styles in the development. "
" The Flux
and Mono
? " Rory asked.
"Yeah. Are you familiar with these two? "
Rory only froze in her place for seconds before Eddie understood that his colleague was broken.
" So you didn't know..."
"Yeah. I have never had the experience with web flux after all. "
Eddie sighed. Not so surprising, really. He had expected that but was still disappointed.
" In Reactive style, we do not return an ordinary model or DTO (Data Transfer Object Directly) directly; instead, we return Mono
and Flux
, as you can see. Mono is used when we return a single object, like in getObjectById
or objects returned by CREATE
, UPDATE
, or DELETE
endpoints. Flux is used when we have a stream of objects or a list of objects."
" Ah, I see. "
" Okay, I think we can start to work on the application. Can you help me complete the rest of the application? "
"Sure."
"But, We must hurry up. "Eddie looked outside the window. The storm was getting worse. The face of Eddie and Rory were definitely hopeless. They didn't have the time or the resources to complete the system. "I don't want to stay here for so long. "
"What do you mean? "
"Soon, this city will be destroyed. "
Those are the last words Rory heard from Eddie before her friend went entirely quiet. As she had no other choice, she proceeded to help her colleagues without asking any more questions.
The Requirements Documents and Guidelines
This section is listing all the models you need to create to complete the application. You need to convert the definition to Spring Data Entities first. For instance, BigInt can be translated into Long in the model definition.
Data Definition
- Property
1 2 3 4 5 6
Property id - Big Int - Auto Generated - Primary Key Property Name - Varchar(100) - Not Null Property Type - Varchar (100) - Not Null Description - Text - Not Null Property owner id - Big Int - Nullable Property Base price - Int - Not Null
- License
1 2 3 4 5
License Id - Big Int - Auto Generated - Primary Key IssuedDate - Date - Not Null - Auto Generated - Now validUntil - Date - Not Null Description - text - Not Null property id - Not Null
Read the section above. There are rules you need to follow. Please read it carefully. The application in this practical is in the form of REST Web Service. You can use Postman to assist you doing this practical. You may try to run the application first and access some endpoints provided by Master Robert.
Sample Request to list all Proprietor
Target: http://localhost:8080/proprietor/find-all
Method: Get
Sample Request to create new Resident
Target http://localhost:8080/proprietor/resident/create
Method: Post
Sample Request Body
1 2 3 4 5 6 7 8 |
|
You need to create the Reactive endpoints for the other two entities. Please read carefully the previous section to understand the whole requirements.
Postman
After you analyze the requirements for this particular problem, you realize that you will be using REST API, which means you can't just testing the program's functionality by usual means (such as accessing it on HTML page rendered by browser). This means you need to use another tool for testing the program's functionality. Postman is one of those tools.
Motivation
Contrary to what many programmers in this world think, there are many HTTP Request Methods other than GET
and POST
(the prominent examples are : PUT
, PATCH
, and DELETE
). Unfortunately, requests that use those methods can't be sent by HTML pages rendered by browsers, since HTML only supports GET
and POST
methods.
Postman, unlike HTML, can send such requests. In fact, one of its common uses is to deliver HTTP Request directly to the web services or web applications.
Installation
It's preferable to install Postman in your own computer instead of relying on its web version. As such, you must download the application here.
Creating and Sending Request
As it's stated earlier, one of Postman's common uses is to create HTTP Request and send it directly to the web services or web application.
First, open the Postman application. You will see the program like this:
At the right side of the app, there is a form to create request
To create a request, you must enter the URL of the web service/application alongside its endpoint you want to access.
After that, you need to specify what method to use for that particular request. Just click one of the options you want to choose.
If the endpoint requires you to include information (for example, you need to add data into the service), include said information into the request. You can do it by using request parameters or RequestBody. This tutorial will show you how to include that information using RequestBody written in JSON.
First, to include JSON data into the request body, select "Body" from this particular part of the app:
Next, select the option "raw" from the radio button option and select "JSON" from the dropdown option:
After that, you can write the JSON data you want to include.
After you make such a request, send it by pressing the "Send" button and then wait for Postman to deliver the response.
Examples : These examples will be using this web service that has been used earlier in Practice-6.
This example will show how to access endpoints that need no additional information other than endpoints and the request method alongside its response.
This example will show you how to access endpoints that need some additional information alongside its response.
Notes : While in this example the response is written in JSON, it's not always the case with other web services/applications. Response by the service/application can be written using formats such as JSON, XML, HTML, and no format, in a very rare case.
Creating Collection
Sometimes you need to write your already-given-response request in a separate files, programs, or other things so you can execute it again later for testing some functionality after other request (or perhaps because you forgot to execute one before). You can do it by using one Postman tab by changing the request method, the endpoint, the data inside the request body, and many other things whenever you want to execute different requests. Keeping requests and executing it this way, however, is not very time-efficient. Fortunately, Postman has a feature called Collection.
Collection is a feature in Postman that can be used to store multiple requests that can be executed later. While technically it can be used to store requests regardless of what web service/application of the requests's destination, most of the time, a collection is only used for storing requests from one web service/application. This tutorial will show how to make a collection and use it to store requests.
First, in the left side of the application, you will see the app like this:
Click the "Create Collection" hyperlink and you will see something like this:
For this tutorial, just rename the collection into something else and let other things unchanged.
You can add request to the collection by right-clicking the collection's row bar and left-clicking the "Add Request option"
After you choose to add a request, you can make requests in the same way as explained in the previous section. However, requests stored inside a collection can have a name to differentiate it from other requests.
Just as it's stated earlier, Collection can be used to store requests to be executed later. Those stored requests can be found at the left panel of the Postman application.
You can access the request by left-clicking it and Postman will open a new Postman tab for that request. In that tab, you can modify the request and send the request to the destination just like usual.
Rory Auden
That job was Eddie and Rory's last. Both of them had wandered around the great land of Gothia for years. Doing jobs here and there. While both of them were programmers, they were really adventurers at heart. The wheel of fate had them come to the great city of Stella. Something that they may have regretted. Stella was in a great war. When you play with fire, you should be ready to get burned. An attack from the enemies would come soon enough. That was something they knew they would face. However, they had no money, so this was their only choice.
The storm was one thing; the attack of a nearby kingdom had them scattered. It was too late by the time Eddie and Rory finished the job. In the middle of a great storm, that night Stella was attacked. Both Eddie and Rory were running for their life. They didn't know where to go. Should they have stayed and gotten destroyed by the storm? Or run and get murdered by the attacker. In that condition, they were separated after the eye of the storm enveloped city. Rory was unconscious for hours after being knocked by the strong wind.
The first thing she thought after she awoke was Eddie. She could barely stand and yet still forced her way to find her one and only colleague. She tried to run. Only the debris of the formerly great city was present. She ignored the already destroyed city and thought positively, hoping that Eddie was still alive.
" Eddie! Where are you?" She screamed. Her steps were shaking. She could barely stand and was in grave danger herself. But the only thing on her mind was Eddie. Since the beginning of her journey with no goal, what she had was Eddie. Of course, Eddie was everything for Rory.
" Eddie..." She cried but was still hopeful. Maybe you couldn't say that either. She was desperate but denied everything that might come to her mind. Her body was fragile at the time, but she still forced her way. After hours of searching, she found nothing. She finally collapsed. Her body couldn't take it anymore. But just before she lost consciousness, she found Eddie's necklace. With the last of her strength, she reached out to the necklace.
Years after that, she never knew Eddie's whereabouts. Rory didn't even know whether her partner was still alive or not. Rory's biggest regret is that she didn't get to know Eddie more. The only thing she knew was Eddie came from another world. At the beginning of her journey, she met Eddie. He taught her all the programming knowledge, and they decided to go on an adventure together. Strange at is was, as a wandering programmer. But now, she was alone.
She continued the job as a programmer and found some other people she could call friends. They made a company together. At first, she was only doing jobs blindly. After all, she didn't have any dreams anymore. However, one day, she found there were other people transported from another world. She met Maya, who cried and tried to find someone at that time. Sadly enough, Maya didn't retain her memory of the past and didn't even know the said person's name. She felt looking at her past self when she looked at Maya. Rory couldn't leave her. So Rory took Maya as her stepsister and taught her programming. She then had a new goal. To find and help other people that came from another world. She didn't know why but she felt it was Eddie's legacy. So she gathered them in her company.
"Miss Rory, are you not going home? " You asked after a couple of minutes. Rory appears lost in her thoughts. She doesn't respond and freezes for some seconds and then suddenly laughs.
" Yes, I will," she replied.
Rory then looks at the night sky once again. She is glad that Maya finally found the person she sought years ago. And in her silence, Rory continues to help the people from the other world. So she can prevent the same tragedy happen to them. Before leaving her room, she once again looks like she is praying.
" Are you happy over there, Eddie? "
Checklist
You will need to implement the task using REST Controller and Reactive Web Service. Please follow the structure of the MVC Design Pattern as well. You can use the current project structure or previous practicals as reference to implement the solution.
Checklist
- Read Stella, The City of The Stars, write the requirements (restriction, todo etc) you found in
README.md
- Read The Requirements document and Guidelines section.
- Implement endpoints for Property and License. Please refer to the Stella Property Management Section.
- Test your implementation using postman or similar tools. Read the postman section for more details about Postman
- Create
gitlab-ci.yml
Minimun create: build and test job
Hint
- The basic information you need is in the The Requirements Document and Guidelines
section. Read it first.
- Try to run the application first.
- Don’t forget to change the application.properties
to match your local configuration.
Midterm Interview Exam - Case 1: Backtruckwkwk
Backtruckwkwk is a Web service that allows truck enthusiasts to document witty and interesting (and also, fabulous) decals often found on rear side of a truck. The user can submit the decal along with the details such as the text description, geo-location, and image of the decal.
For the interview exam, the scope of the requirements is simplified. The Web
service only needs to handle text and location description of the decal. Hence,
there is no need to handle and store image. In addition, the data storage can
be handled by an instance of java.util.List
instead of relational database.
Requirements
Estimated reading time: 5 minutes
The Web service shall provide 4 (four) API endpoints:
-
HTTP GET /decal
Return a random decal information.Does not need any parameters in the request payload.
-
HTTP GET /decal/{index}
Return the decal information stored atindex
in the list.There is one parameter named
index
in the path.index
is an integer with possible valid values from0
tosize of list - 1
. -
HTTP POST /decal
Save a new decal information into the list.Does not need any parameters in the request payload. Require the data regarding the decal to be submitted as form data.
-
HTTP PUT /decal/{index}
Replace the decal information stored atindex
in the list with the submitted decal.There is one parameter named
index
in the path.index
is an integer with possible valid values from0
tosize of list - 1
. Require the data regarding the decal to be submitted as form data.
The form data used in delivering data to HTTP POST
and HTTP PUT
endpoints
shall comprise of 2 (two) attributes: description
and location
. Both
attributes are text-based and must present in the request body.
The description
contains user's description of the decal and location
describes the location where the decal was found.
The response must contain a body of JSON data regardless the status of request handling. The JSON data, at minimum, must contain:
- A
status
attribute that describes whether the request was succcessfully handled or not. The possible value is eitherOK
orFAIL
string. - A
data
attribute that contains the JSON string representation of the returned data. It may be empty/null if the backend did not find any relevant data or failed to process the request.
During the interview exam, you will be asked to implement one of the feature above. To give you an idea how the Web service works and behaves, you can access the reference implementation on Heroku.
Programming Tasks
Estimated working time: 10 - 15 minutes
Turn on your camera and share your desktop screen. Ensure that the proctor (in most cases, the lecturer and sometimes the TAs) can monitor your activities during the interview exam. Imagine you are conducting a remote pair programming where the partner needs to observe your work.
Do the tasks in the Mandatory Tasks subsection. If there is some time left after you completed the Mandatory Tasks subsection, you can do the tasks in the Optional Tasks subsection.
Mandatory Tasks
We recommend you to do the mandatory tasks according to the given order. The tasks are sorted based on the required effort and the logical order to complete them.
- Get a designated feature to implement from the proctor.
- Fork the codebase template
into your personal subgroup in
AdvProg/kki-2022/student
namespace. - Clone the fork into your local development machine.
- Implement the designated feature along with the tests code, preferably by following test-driven development methodology.
- Ensure your tests verify the correctness of the main/success flow and at least one possible alternative flow (e.g. input validation error, incomplete input) of the designated feature implementation.
- Update the GitLab CI/CD configuration in the code template to make your
repository on GitLab CSUI:
- Run the test suite for each new commits pushed to the repository on GitLab CSUI.
- Save your changes as Git commit(s) and push the commit(s) to the fork repository on GitLab CSUI.
Optional Tasks
Feel free to do the optional tasks in any order. It is alright if some of the tasks are not completed. The discussion session may ask you to complete the unfinished tasks.
- Implement a simple, HTTP header-based authentication mechanism. For example,
all HTTP requests sent to the endpoint must contain an HTTP header named
X-AdvProg-Auth
with a designated value, e.g.TopSecretKey
. If the HTTP request contain the said header and the value match, then the request can be handled by the handler method. Otherwise, immediately return an appropriate error response.- If time permitting and you would like an extra challenge, create or refactor the tests to verify the authentication mechanism.
- Identify and clean up code smells as many as possible in the codebase.
- Update the GitLab CI/CD configuration in the code template and the project page on GitLab CSUI to make the codebase automatically deployed to Heroku.
- Update Gradle configuration, and GitLab CI/CD configuration in the code template and the project page on GitLab CSUI to make the codebase automatically scanned by SonarScanner and sent the analysis result to SonarQube CSUI.
Discussion
Estimated discussion time: 5 - 10 minutes
The list of possible topics during the discussion is as follows:
-
Development workflow (Git, IDE)
Examples: How do you use Git when working on your course work?; How to merge a branch into another branch?; How do you resolve a merge conflict?
-
Writing and running test
Examples: How do you design the test cases to test a piece of code?; How to measure line coverage?
-
Concurrency
Examples: How to prevent a race condition in implementation level or architectural level?; Describe one example of serialisation technique employed in a programming language/framework of your choice
-
Deployment workflow (GitLab CI/CD, Heroku)
Examples: Describe one or more elements commonly found in a
.gitlab-ci.yml
file; Show how to deploy a codebase to Heroku using Heroku CLI -
Code quality (SonarQube, SonarScanner)
Examples: Mention some code smells that you have encountered throughout this course; What is the responsibility of SonarQube and SonarScanner?
It is also possible that the proctor will ask questions that are not listed above.
Hints
- As mentioned in the requirements, you do not have to set up a database. The most straightforward approach is to use a class from the collection package in Java standard library.
- If you are using Spring Boot, you only need Spring Web in the project dependencies. Do not make the project more complex by adding other dependencies such as Spring Data REST or database connection drivers.
- You already have a collection of code examples that you can adapt to solve this problem. Hence, we do not recommend you to search for tutorials or code snippets through a search engine. You may do so, but we think it is better to spend your time in coding and reuse the available resources. In addition, it is easier to describe and to reason with the code that you wrote by yourself.
Midterm Interview Exam - Case 2: Kuda (Runner) Reporting System
Kuda is an alias of the GitLab Runner server that provides shared CI runner for projects hosted on GitLab CSUI. Due to heavy utilisation and limited resources, the server sometimes experienced issues such as timed out CI jobs. To allow faster response by the administrator in handling issues on CI server, the users can write a report, or issue description, detailing the problem they encounter with the CI server.
For the interview exam, the scope of the requirements is simplified. The Web
service does not need to use relational database to store the issues. It can
be handled by an instance of java.util.List
.
Requirements
Estimated reading time: 5 minutes
The Web service shall provide 4 (four) API endpoints:
-
HTTP GET /issue
Return 5 (five) most recent issues submitted to the reporting system.Does not need any parameters in the request payload.
-
HTTP GET /issue?index={index}
Return the issue stored at positionindex
in the list.There is one parameter named
index
as part of the query string in the URL.index
is an integer with possible valid values from0
tosize of list - 1
. -
HTTP POST /issue
Save a new issue into the list.Does not need any parameters in the request payload. Require the data regarding the issue to be submitted as form data.
-
HTTP DELETE /issue?index={index}
Remove the issue stored at positionindex
in the list with the submitted issue.There is one parameter named
index
as part of the query string in the URL.index
is an integer with possible valid values from0
tosize of list - 1
.
The form data used in delivering data to HTTP POST
endpoint shall comprise of
2 (two) attributes: description
and pipelineUrl
. The request body
only require description
to be present and pipelineUrl
may be empty/unset.
The description
contains the user's description about the CI issue and
pipelineUrl
is the URL to the corresponding GitLab pipeline where the CI
issue was observed.
The response must contain a body of JSON data regardless the status of request handling. The JSON data, at minimum, must contain:
- A
status
attribute that describes whether the request was succcessfully handled or not. The possible value is eitherOK
orFAIL
string. - A
data
attribute that contains the JSON string representation of the returned data. It may be empty/null if the backend did not find any relevant data or failed to process the request. In the case of handlingHTTP DELETE
request, thedata
must be empty.
During the interview exam, you will be asked to implement one of the feature above. To give you an idea how the Web service works and behaves, you can access the reference implementation on Heroku.
Programming Tasks
Estimated working time: 10 - 15 minutes
Turn on your camera and share your desktop screen. Ensure that the proctor (in most cases, the lecturer and sometimes the TAs) can monitor your activities during the interview exam. Imagine you are conducting a remote pair programming where the partner needs to observe your work.
Do the tasks in the Mandatory Tasks subsection. If there is some time left after you completed the Mandatory Tasks subsection, you can do the tasks in the Optional Tasks subsection.
Mandatory Tasks
We recommend you to do the mandatory tasks according to the given order. The tasks are sorted based on the required effort and the logical order to complete them.
- Get a designated feature to implement from the proctor.
- Fork the codebase template
into your personal subgroup in
AdvProg/kki-2022/student
namespace. - Clone the fork into your local development machine.
- Implement the designated feature along with the tests code, preferably by following test-driven development methodology.
- Ensure your tests verify the correctness of the main/success flow and at least one possible alternative flow (e.g. input validation error, incomplete input) of the designated feature implementation.
- Update the GitLab CI/CD configuration in the code template to make your
repository on GitLab CSUI:
- Run the test suite for each new commits pushed to the repository on GitLab CSUI.
- Save your changes as Git commit(s) and push the commit(s) to the fork repository on GitLab CSUI.
Optional Tasks
Feel free to do the tasks in any order. It is alright if some of the tasks are not completed. The discussion session may ask you to complete the unfinished tasks.
- Implement a simple, HTTP header-based authentication mechanism. For example,
all HTTP requests sent to the endpoint must contain an HTTP header named
X-AdvProg-Auth
with a designated value, e.g.TopSecretKey
. If the HTTP request contain the said header and the value match, then the request can be handled by the handler method. Otherwise, immediately return an appropriate error response.- If time permitting and you would like an extra challenge, create or refactor the tests to verify the authentication mechanism.
- Identify and clean up code smells as many as possible in the codebase.
- Update the GitLab CI/CD configuration in the code template and the project page on GitLab CSUI to make the codebase automatically deployed to Heroku.
- Update Gradle configuration, and GitLab CI/CD configuration in the code template and the project page on GitLab CSUI to make the codebase automatically scanned by SonarScanner and sent the analysis result to SonarQube CSUI.
Discussion
Estimated discussion time: 5 - 10 minutes
The list of possible topics during the discussion is as follows:
-
Development workflow (Git, IDE)
Examples: How do you use Git when working on your course work?; How to merge a branch into another branch?; How do you resolve a merge conflict?
-
Writing and running test
Examples: How do you design the test cases to test a piece of code?; How to measure line coverage?
-
Concurrency
Examples: How to prevent a race condition in implementation level or architectural level?; Describe one example of serialisation technique employed in a programming language/framework of your choice
-
Deployment workflow (GitLab CI/CD, Heroku)
Examples: Describe one or more elements commonly found in a
.gitlab-ci.yml
file; Show how to deploy a codebase to Heroku using Heroku CLI -
Code quality (SonarQube, SonarScanner)
Examples: Mention some code smells that you have encountered throughout this course; What is the responsibility of SonarQube and SonarScanner?
It is also possible that the proctor will ask questions that are not listed above.
Hints
- As mentioned in the requirements, you do not have to set up a database. The most straightforward approach is to use a class from the collection package in Java standard library.
- If you are using Spring Boot, you only need Spring Web in the project dependencies. Do not make the project more complex by adding other dependencies such as Spring Data REST or database connection drivers.
- You already have a collection of code examples that you can adapt to solve this problem. Hence, we do not recommend you to search for tutorials or code snippets through a search engine. You may do so, but we think it is better to spend your time in coding and reuse the available resources. In addition, it is easier to describe and to reason with the code that you wrote by yourself.
Midterm Interview Exam - Case 3: SITODO
SITODO (Sistem Informasi TODO List/"TODO List Information System") is a Web application that lets user to store a list of tasks they need to accomplish. The user can manage their list of tasks either through the graphical user interface (GUI) on the Web browser or Web service calls to the available endpoints.
For the interview exam, the scope of the requirements is simplified. You only required to implement REST-like API endpoints specified in Requirements section.
Requirements
Estimated reading time: 5 minutes
The Web service shall provide 2 (two) API endpoints:
-
HTTP POST /api/list
Create a new todo list containing one todo itemThe input JSON data payload must contain a single attribute named
item
that holds the name of task to be inserted into the new todo list. The output response must contain a JSON object nameddata
that holds the newly created todo list with a single item, andstatus
attribute that describes whether the request was successfully handled or not. -
HTTP POST /api/list/{id}
Store a todo item into the todo list with primary key equal toid
.The input and output description are similar to the description in the requirement for
HTTP POST /api/list
endpoint. The output, however, needs to ensure that it contains the existing and new todo items.
The output response must contain a body of JSON data regardless the status of request handling. The JSON data, at minimum, must contain:
- A
status
attribute that describes whether the request was succcessfully handled or not. The possible value is eitherOK
orFAIL
string. - A
data
attribute that contains the JSON string representation of the returned data. It may be empty/null if the backend did not find any relevant data or failed to process the request. In the case of handlingHTTP DELETE
request, thedata
must be empty.
During the interview exam, you will be asked to implement one of the feature above. To give you an idea how the Web service works and behaves, you can access the reference implementation on Heroku.
Programming Tasks
Estimated working time: 10 - 15 minutes
Turn on your camera and share your desktop screen. Ensure that the proctor (in most cases, the lecturer and sometimes the TAs) can monitor your activities during the interview exam. Imagine you are conducting a remote pair programming where the partner needs to observe your work.
Do the tasks in the Mandatory Tasks subsection. If there is some time left after you completed the Mandatory Tasks subsection, you can do the tasks in the Optional Tasks subsection.
Mandatory Tasks
We recommend you to do the mandatory tasks according to the given order. The tasks are sorted based on the required effort and the logical order to complete them.
- Get a designated feature to implement from the proctor.
- Fork the codebase template
into your personal subgroup in
AdvProg/kki-2022/student
namespace. - Clone the fork into your local development machine.
- Implement the designated feature along with the tests code, preferably by following test-driven development methodology.
- Ensure your tests verify the correctness of the main/success flow and at least one possible alternative flow (e.g. input validation error, incomplete input) of the designated feature implementation.
- Update the GitLab CI/CD configuration in the code template to make your
repository on GitLab CSUI:
- Run the test suite for each new commits pushed to the repository on GitLab CSUI.
- Save your changes as Git commit(s) and push the commit(s) to the fork repository on GitLab CSUI.
Optional Tasks
Feel free to do the tasks in any order. It is alright if some of the tasks are not completed. The discussion session may ask you to complete the unfinished tasks.
- Implement a simple, HTTP header-based authentication mechanism. For example,
all HTTP requests sent to the endpoint must contain an HTTP header named
X-AdvProg-Auth
with a designated value, e.g.TopSecretKey
. If the HTTP request contain the said header and the value match, then the request can be handled by the handler method. Otherwise, immediately return an appropriate error response.- If time permitting and you would like an extra challenge, create or refactor the tests to verify the authentication mechanism.
- Identify and clean up code smells as many as possible in the codebase.
- Update the GitLab CI/CD configuration in the code template and the project page on GitLab CSUI to make the codebase automatically deployed to Heroku.
- Update Gradle configuration, and GitLab CI/CD configuration in the code template and the project page on GitLab CSUI to make the codebase automatically scanned by SonarScanner and sent the analysis result to SonarQube CSUI.
Discussion
Estimated discussion time: 5 - 10 minutes
The list of possible topics during the discussion is as follows:
-
Development workflow (Git, IDE)
Examples: How do you use Git when working on your course work?; How to merge a branch into another branch?; How do you resolve a merge conflict?
-
Writing and running test
Examples: How do you design the test cases to test a piece of code?; How to measure line coverage?
-
Concurrency
Examples: How to prevent a race condition in implementation level or architectural level?; Describe one example of serialisation technique employed in a programming language/framework of your choice
-
Deployment workflow (GitLab CI/CD, Heroku)
Examples: Describe one or more elements commonly found in a
.gitlab-ci.yml
file; Show how to deploy a codebase to Heroku using Heroku CLI -
Code quality (SonarQube, SonarScanner)
Examples: Mention some code smells that you have encountered throughout this course; What is the responsibility of SonarQube and SonarScanner?
It is also possible that the proctor will ask questions that are not listed above.
Hints
- As mentioned in the requirements, you do not have to set up a database. The most straightforward approach is to use a class from the collection package in Java standard library.
- If you are using Spring Boot, you only need Spring Web in the project dependencies. Do not make the project more complex by adding other dependencies such as Spring Data REST or database connection drivers.
- You already have a collection of code examples that you can adapt to solve this problem. Hence, we do not recommend you to search for tutorials or code snippets through a search engine. You may do so, but we think it is better to spend your time in coding and reuse the available resources. In addition, it is easier to describe and to reason with the code that you wrote by yourself.
Ended: KKI 2022
Regular 2022 ↵
Regular Class 2022
Selamat datang di Pemrograman lanjut 2021/2022. Halaman di akan memuat informasi terkait dengan perkuliahan. Tutorial mingguan akan di-publish secara berkala di website ini. Harap untuk sering mengecek halaman ini.
Course instructors:
Kelas A
Rian Fitriansyah, M.Sc.
Kelas B
- Muhammad Anwar Ma'sum, M.Kom.
- Ichlasul Affan, M.Kom.
Kelas Blended
Gladhi Guarddin, M.Kom.
Teaching assistants
Kelas A
- Adrika Novrialdi S.Kom (AN) - Koordinator Asisten Dosen
- Asfiolitha Wilmarani (LIT)
- Muhammad Luthfi Fahlevi (LF)
- Rheznandya Erwanto (RE)
- Samuel Tupa Febrian S.Kom (STF)
- Ariasena Cahya (NYA)
Kelas B
- I Gede Aditya (IGA)
- Salman A N (MAN)
- Aji Inisti Udma Wijaya (AI)
- Rifqy Zulkarnaen (RZ)
- Olivia Monica (LIV)
- Fathan M (FM)
Kelas Blended
- Galangkangin Gotera (GGO) - Wakil Koordinator Asisten Dosen Program Studi Reguler
- Dennis A. Walangadi (DNS)
- Nofaldi Fikrul Atmam (PAL)
Guideline Pengerjaan Tutorial
Setiap tutorial akan terdiri dari deskripsi soal dan juga kode template.
Anda akan diminta untuk melakukan git clone
dari template pada repository tutorial Advanced Programming Gitlab CSUI
dan membuat project baru pada subgroup anda.
Pengerjaan Tutorial
Lakukan initial push ke branch master
repository tutorial anda.
Buatlah branch baru beserta Draft Merge Request ke master
dengan nama branch sesuai dengan task apa yang diminta pada tutorial tersebut.
Apabila terdapat dua task dengan fitur berbeda, anda dapat membuat dua branch dan merge request berbeda.
Base setiap branch yang dibuat adalah initial commit dari branch master
.
Buatlah beberapa group label yang dapat digunakan untuk memberikan label merge request yang anda buat.
Beberapa label yang mungkin anda perlukan adalah todo
, doing
, refactor
, dan in-review
.
Assignee dari merge request adalah anda sendiri.
Submission
Tandailah merge request yang anda buat dengan label in-review
.
Assign asdos anda sebagai reviewer pada merge request anda.
Pastikan anda melakukan ini sebelum deadline tutorial.
Aku Dikirim ke Dunia Lain untuk Menjadi Software Engineer
Prelude
Mata anda terus memandang liar mengitari ruangan, keringat dingin membasahi sekujur tubuh anda, dan kaki anda tidak henti-hentinya gemetar. Di hadapan anda ada beberapa pria paruh baya saling berbisik satu sama lain. Terkadang mata mereka tersingkap menatap tajam ke arah anda. Salah satu dari mereka lalu berdiri, memanggil nama anda.
" Mohon maaf perusahaan kami belum bisa menerima anda." Ujar salah satu pria paruh baya itu mengawali penjelasannya. Sisa kata-katanya tidak pernah anda ketahui. Anda merasa dikelilingi kehampaan dan anehnya, rasa lega.
Setelah beberapa kali melihat siklus yang sama: datang penuh harap, mengikuti proses panjang nan berbelit-belit, yang pada akhirnya hanya untuk mendengar sebuah perkataan menusuk bertabur manisan yang terasa menyakitkan. Bahkan mendengar serpisahan keperihan dari kata rupawan yang menggelitik telinga itu harus disambut dengan suka cita. "Untung saja bukan kata: harap menunggu kabar dari kami", pikir anda. Setelah pukulan bertubi-tubi, yang anda harapkan hanya kejelasan. Setidaknya hari ini anda mendapatkannya.
Kaki anda lalu melangkah dari gedung tersebut dengan perasaan yang sama seperti sebelumnya. Menatap jauh dari hiruk pikuk keramaian jalan ibu kota dalam hati anda yang sepi. Meskipun ketegaran sudah anda dapatkan dari sekian kali siklus panjang yang menyebalkan, beberapa bagian dari lubuk hati anda tentu pernah terucap harapan yang berbeda dari yang anda dapatkan hari ini. Beberapa dari diri anda tentu berharap pencarian anda akan berakhir hari ini.
Bersamaan dengan langkah pelan yang anda ambil, hujan membasahi keramaian jalan malam. Anda dipaksa berlari mencari tempat teduh dengan timing terburuk yang bisa anda bayangkan. Namun, di saat tersebut, anda melihat rintikan hujan yang terhenti tepat di mata anda. Kendaraan juga tidak terlihat bergerak dan orang-orang di sekitar anda seolah mematung. Waktu seolah terhenti. Apa yang terjadi? Apa ini sebuah mimpi? Banyak pertanyaan lain yang lalu anda lempar hanya untuk tidak mendapatkan jawaban. Atau itulah yang sempat anda pikirkan.
" Ini adalah kenyataan. Bagaimana? Indah bukan?"
Sebuah suara menggema dari sebelah kanan anda. Dari wajah anda terlukis beberapa pertanyaan yang langsung mendapatkan jawaban dari sumber suara tersebut. Ia tersenyum, sebuah senyum yang tidak pernah anda lihat sebelumnya. Senyumannya kosong, tapi anda tidak merasakan ada niat jahat juga dibaliknya. Hanya saja, wajahnya tidak benar-benar memperlihatkan ekspresi layaknya manusia. Apakah ia manusia? Pikir anda. Apapun itu, ia pastinya bukan orang biasa.
" Anda itu apa?" Kata-kata itu adalah hal pertama yang keluar dari mulut anda. Dari raut wajah yang dingin dan hawa kehadiran yang mencekam. Jika anda menceritakan apa yang anda lihat ke orang lain, mungkin hal yang sama akan dilakukan. Namun, dia-yang-anda-tidak-tahu-apa tidak memberikan jawaban yang anda inginkan. Sebuah pertanyaan dijawab dengan pertanyaan lain.
" Anda sedang mencari pekerjaan bukan?" Makhluk itu berhenti tepat di depan anda dan mengeluarkan sepucuk kertas sebelum melanjutkan pembicaraannya. " Bekerja lah di perusahaan saya, di dunia lain" ajaknya dengan wajah sumringah.
Makluk itu terus berucap banyak hal setelahnya. Banyak hal yang tidak masuk akal. Dunia lain, sihir, dan dunia modern yang tidak duduk di sisi yang sama. Sementara makhluk yang ada di hadapan anda ini terus berceloteh mengenai hal tersebut. Banyak pertanyaan tentunya ingin anda berikan. Kenapa dia tahu anda sedang ingin mencari pekerjaan? Mengapa anda? Sihir, apakah hal seperti itu benar adanya? Banyak lagi pertanyaaan yang ingin anda lemparkan. Namun, tidak satu pun keluar dari mulut anda. Anda terus mendengarkan makhluk itu berbicara, yang meskipun tidak bisa anda pahami, anda tidak bisa tidak mendengarkan. Apakah itu karisma miliknya atau hanya anda tertahan oleh kekuatannya? Dua pertanyaan tersebut juga anda tidak tahu jawabannya.
" Bagaimana, anda pasti tertarik bukan?"
Entah karena terpengaruh kekuatannya, entah karena rasa putus asa yang anda miliki setelah beberapa kali ditolak, anda tanpa berpikir panjang menerimanya. Penerimaan anda disambut oleh wajah puas dari dia-yang-anda-tidak-tahu-apa.
" Ah benar. Saya belum memberikan nama. " Ia membungkukkan tubuhnya sebelum memberikan jawaban. "Saya adalah R̵͇̗̈̅̇̐̚e̸̪̯͖̠͍͊̂̋͗͝y̷̧̗͚͚͑͒̔̓a̸̩͕̎̏͌l̴̞̔̄͒̍̕l̵̡̬̱̹̇̈́̐͋͜͝e̵̲͆͒."
Telinga anda tidak dapat mendengar namanya. Seolah-olah sesuatu menghalangi anda mendengar namanya.
" Oh panggil saja saya 0. Nama saya tidak bisa didengar oleh sembarang orang. Nah, tanpa memperpanjang waktu, mari saya bawa anda ke dunia yang saya maksud."
Dengan begitu anda dikirim oleh R̵͇̗̈̅̇̐̚e̸̪̯͖̠͍͊̂̋͗͝y̷̧̗͚͚͑͒̔̓a̸̩͕̎̏͌l̴̞̔̄͒̍̕l̵̡̬̱̹̇̈́̐͋͜͝e̵̲͆͒ ke dunia lain. Ketika perjalanan dimulai anda merasakan keraguan yang tidak pernah anda rasakan sebelumnya. Keraguan yang tidak anda rasakan ketika belum menerima kontrak dari 0. Dengan langkah kaki goyah anda menatap sinis kebelakang, kepada diri anda yang beberapa menit yang lalu.
Hari Pertama yang Menyenangkan? Anda Pasti Bercanda
Anda duduk di sebuah ruangan setelah salah satu atasan baru anda selesai memperlihatkan tempat kerja anda yang baru. Tidak ada yanga aneh sebenarnya. Walau anda tahu tempat ini ada di dunia yang sama sekali berbeda dengan dunia asal anda, pada dasarnya tidak banyak perbedaan. Setidaknya perusahaan tempat anda bekerja dan distrik tempat anda tinggal saat ini.
Ketika mendengar kata "dunia lain", banyak hal terlintas di pikiran anda. Mungkin hal-hal tidak masuk akal seperti sihir, makhluk-makhluk aneh dapat anda temukan dengan mudah. Tentu saja bukan latar dunia modern dengan sebagian besar penduduknya merupakan seorang karyawan kantoran yang akan anda bayangkan. Keadaan yang anda lihat saat ini adalah kebalikan dari apa yang anda bayangkan akan anda temukan. Walau demikian anda merasakan kelegaan di dada anda. Setidaknya mungkin aku tidak perlu terlalu merubah cara hidupku. Begitu yang anda pikirkan.
"Maaf apa kamu lama menunggu?"
Anda menoleh ke sumber suara. Anda mendapati atasan anda berdiri dengan beberapa orang. Beberapa dari mereka mencoba tersenyum dan jujur terlihat seperti senyum yang dipaksakan. Setidaknya anda dapat mengapresiasi usaha mereka. Pada badge yang mereka kenakan, ada nama dan tulisan software engineer tertulis. Anda dapat membayangkan mereka adalah rekan kerja anda.
"Ini adalah anggota tim yang akan bekerja denganmu." kenal atasan anda. Atasan anda lalu memberikan beberapa lembar kertas sebelum berjalan kembali ke ruangannya. "Mereka akan menjelaskan pekerjaan divisi ini. Selamat bekerja."
Begitu saja dan batang hidung atasan anda tidak terlihat lagi, meninggalkan anda dengan kebingungan terlukis jelas pada ekspresi wajah anda. Sejak anda bertemu dengannya, ia selalu bersikap dingin. Ia hanya bicara sepatah-dua patah kata lalu diam. Anda lalu terpikirkan apakah dia kenal dengan 0. Jika iya, anda ingin menanyakan beberapa hal. Hanya saja 0 telah melarang anda membicarakan soal dia atau pun tentang anda yang berasal dari dunia lain. Kalau pun tidak ada larangan tersebut, anda ragu atasan anda akan mau menerima pertanyaan tersebut.
"Maafkan beliau. Dia memang tidak banyak bicara. " Salah satu dari rekan kerja anda sepertinya membaca ekspresi wajah anda.
"Ah tidak masalah." jawab anda sambil tertawa kecil untuk menyembunyikan rasa kesal yang anda rasakan.
"Namaku Rory. Rory Auden. Tolong panggil aku Rory. Di sana ada Emory, Riley, dan Alex. " Rory memperkenalkan satu per satu anggota tim baru anda. " Aku akan menjelaskan divisi apa ini. "
"Sub-divisi kita adalah tim yang fokus pada bagian backend. Ya walau karena sub-divsi frontend sering kekurangan orang, kita sering harus ikut serta mengurus pekerjaan mereka. " jelas Rory sambil tertawa tak nyaman. Anda langsung dapat menebak betapa kesalnya Rory setiap kali harus melakukan hal tersebut.
"Nah, oleh karena itu," Rory berhenti sebentar sambil membuka file di komputer miliknya. " Sebagai anggota baru divisi ini aku akan memintamu untuk membuat sebuah aplikasi secara full-stack untuk jaga-jaga. " lanjutnya.
Tugas Pertama
"Aku tidak akan membantumu dalam mengerjakan tugas ini. Namun, aku akan menjelaskan beberapa hal yang mungkin kamu perlu pahami."
Rory memperlihatkan berkas yang terlihat seperti requirement aplikasi yang ia minta buat. Aplikasi yang diminta pada dasarnya cukup sederhana, tapi ada satu masalah.
"Web framework ini.. Spring Boot?"
"Betul sekali. " jawab Rory membenarkan dugaan anda. "Aku akan memintamu untuk mencoba membuat aplikasi yang ada pada berkas itu menggunakan Spring Boot. Good luck".
"Tunggu!" tegas anda. Namun, Rory hanya membalasnya dengan ayunan tangan dan meninggalkan anda dalam kebingungan. Anda lalu hanya bisa menatap kertas tersebut dengan kepasrahaan.
"Apa kamu butuh bantuan?" Rekan kerja anda yang lain menghampiri anda.
"Ah, sedikit butuh. Aku tidak terbiasa menggunakan Spring Boot. Namamu tadi Emory? "
Emory mengangguk. "Aku bisa membantumu. Kamu biasa bekerja menggunakan apa?"
"Django, Laravel. Namun, aku paling percaya diri dengan kemampuan Django" jelas anda.
Di saat anda selesai menjelaskan kompetensi anda, Emory tiba-tiba menarik anda ke ruang kerjanya lalu dengan sigap mengunci pintu.
"Apa yang kamu lakukan?" Anda menatap bingung kepada Emory, hanya untuk disambut oleh wajah tanpa ekspresi yang terus ia perlihatkan sejak awal.
"Kamu datang dari dunia lain bukan?"
Sebuah pertanyaan dari Emory cukup membuat anda panik. 0 sudah memperingatkan anda untuk tidak mengatakan bahwa anda datang dari dunia lain. Walau begitu, walau anda sudah tahu, hanya dalam satu hari bekerja, rahasia anda sudah ketahuan.
"Harap tenang. Aku juga berasal dari dunia asalmu." Emory sepertinya melihat wajah panik anda dan berusaha menenangkan anda. "Orang dari dunia ini tidak akan tahu kamu dari dunia lain, tenang saja. Hanya saja, aku yang berasal dari dunia yang sama denganmu akan langsung menyadari rahasiamu dari caramu menyebut istilah asing dari bahasa dunia ini. Kekuatan penerjemahaan dari makhluk-yang-kita-tidak-tahu-apa itu tidak sempurna. Aku sangat menyarankanmu untuk belajar bahasa asli dunia ini. "
Mendengarkan penjelasan Emory anda tidak dapat bereaksi kecuali menganggukkan kepala anda. Orang dunia lain akan dapat mendeteksi orang lain berasal dari dunia tersebut dengan mudah. Itu mungkin adalah hal yang penting untuk anda pahami.
"Jika kamu sudah paham itu, mari aku bantu memahami beberapa hal mengenai Spring Boot dan mungkin version control, Git, yang kita gunakan di sini. Version control apa yang pernah anda gunakan di sana? " Emory kembali membawa anda ke meja kerja anda sambil menjelaskan beberapa hal.
"TFS" jawab anda singkat.
"Aku bersyukur kamu pernah bekerja dengan version control dan bukan menggunakan FOVC atau semacamnya?" sindir Emory.
"FOVC?"
"Flash-disk Oriented Version Controlling. Beberapa perusahaan gila juga menggunakan Google Drive™ untuk version control. Bersyukurlah kamu masih menggunakan TFS untuk pengalaman Version Control-mu. " pungkas Emory lagi.
Basic Spring Boot
Catatan: Harap menyiapkan semua environment sebelum melanjutkan ke bagian selanjutnya.
- IntelliJ Ultimate
- Git
Beberapa tutorial pendukung juga tersedia pada SCeLe. Harap perhatikan tutorial di bawah dibuat pada IntelliJ Idea Ultimate.
Membuat Proyek Spring Boot
"Coba buka Spring Initializr
pada menu new project
IDE-mu. Isikan apa yang aku isikan ini " Emory memperlihatkan beberapa konfigurasi yang ia gunakan untuk membuat Spring Project. "Tentu saja, untuk location silahkan pilih sesukamu.Tolong gunakan project SDK dengan versi yang lebih tinggi atau setidaknya sama dengan versi Java yang dipilih. Selain menggunakan IDE Anda juga dapat membuat proyek ini dengan langsung mengakses Spring Initializr "
"Struktur aplikasi yang akan kamu dapatkan akan seperti ini. " Emory memperlihatkan struktur aplikasi yang didapatkan dari proses pembuatan proyek dari Spring Initializr
. " Aku akan menjelaskan beberapa folder yang perlu dipahami."
- Folder
src
memiliki dua sub-folder penting, yaitumain
dantest
. Seperti namanyatest
akan berisikan kode sumber untuk test yang akan kamu buat. Sementaramain
berisikan kode aplikasi. Foldermain
sendiri berisikan dua folder lain,java
(berisikan kode java) danresources
berisikan aset pendukung aplikasi web, seperti file static, templates (HTML), dan konfigurasi aplikasi dalamapplication.properties
. Beberapa kofigurasi seperti basis data yang kamu kenal di Django berada padasettings.py
. Pada Spring, konfigurasi tersebut ada padaapplication.properties
ini. gitignore
, berisikan file-file yang tidak ingin di-commit pada version control nantinya.-
File-file Gradle. Ada empat file penting:
build.gradle
,gradlew
,gradlew.bat
dansettings.gradle
. Kamu mungkin tidak akan perlu mengotak-atikgradlew
dangradlew.bat
jadi kita fokuskan padabuild.gradle
dansettings.gradle
-
File
build.gradle
berisikan Gradle task, informasi aplikasi, konfigurasi, plugin, dan dependencies. Versi Java yang digunakan juga dapat diatur pada file ini. Jika pada Python kamu mungkin terbiasa meletakkan dependencies padarequirements.txt
atauPipfile
, Spring Boot atau pun aplikasi berbasis Gradle secara umum meletakkan dependencies padabuild.gradle
. - File
settings.gradle
adalah dimana pengaturan module gradle tersebut. Pada kasus ini, kamu dapat melihat nama dari module tersebut. Pada penggunaan lebih lanjut, misalkan pada pengaturan Gradle Multimodule, kamu akan menggunakan file ini untuk mengaktifkan sebuah sub-module.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Dasar Model-View-Controller pada Spring Boot
"Apakah kamu familiar dengan konsep design pattern Model-View-Controller atau mungkin lebih sering disingkat sebagai MVC?" Emory melanjutkan penjelasan pada desain struktur dan peran desain tersebut pada aplikasi.
" Aku pernah bekerja dengan MVT pada Django. " jawab anda.
Emory menampilkan wajah yang sedikit lega. "Kalau begitu seharusnya penjelasan ini tidak akan panjang. " timpalnya.
"Model-View-Template atau MVT pada Django pada dasarnya adalah turunan/derivative dari MVC. Design pattern ini dibuat dan disesuaikan untuk penggunaan pada Django. Perbedaannya adalah ada pada dua nama yang sama, tapi memiliki peran berbeda. View pada Django merupakan logika bisnis dan juga mengatur request dan response aplikasi. Sementara View pada MVC merupakan lapisan yang bertugas untuk tampilan. Pada Django, ini adalah tugas Template. Jika disederhanakan, View adalah Controller pada MVC dan Template adalah View pada MVC. Yah ini adalah penjelasan yang sangat disederhanakan. Selanjutnya, aku akan menjelaskan tugas tiap layer."
Model
adalah layer yang merepresentasikan data dan juga logika bisnis.Controller
adalah lapisan yang mengatur request dan response dari aplikasi. Idealnya, tidak ada program yang mengatur logika bisnis pada lapisan ini. Fokusnya adalah mengelola request dari pengguna dan mengembalikan response yang sesuai.View
adalah tampilan. Sederhananya pada aplikasi web adalah ini adalah file kerja sama antara file HTML dan static file seperti CSS dan JavaScript. Pada kenyataannya, ada kerja sama antara lapisan ini denganController
untuk dapat bekerja dengan semestinya.
Pada Spring Boot sendiri ada sedikit penambahan lapisan untuk meningkatkan
maintainability dan juga memperjelas peran tiap lapisan. Dapat dilihat bahwa lapisan Model
memiliki peran yang cukup luas. Agar tiap lapisan memiliki satu tugas khusus yang jelas, Model
dibagi lagi menjadi dua lapisan:
1. Service
Lapisan yang khusus mengurus logika bisnis.
2. Repository
Lapisan yang khusus mengurus pengelolaan data.
Dengan demikian, Model
hanya akan merepresentasikan data.
Dasar Request dan Response pada Spring Boot
"Selanjutnya ayo kita coba buat sebuah aplikasi web sederhana." Emory mulai mengetikkan beberapa hal pada IDE miliknya. "Coba buat susunan package seperti ini. Setiap package ini akan merepresentasikan sebuah lapisan pada MVC Spring Boot. "
"Untuk langkah pertama mari kita mulai dari membuat Controller. Sebuah Controller di Spring Boot adalah kelas yang diberikan annotasi @Controller
. Coba buat sebuah Controller sederhana yang dapat mengembalikan halaman HTML terlebih dahulu. "
Buat Kelas BaseController
pada package controller
. Isi seperti berikut. Coba untuk tidak melakukan menuliskan import statement secara manual.
"Kelas BaseController
dalam keadaan sekarang sudah dianggap menjadi sebuah Controller oleh Spring Boot. Sebuah kelas Controller biasanya memiliki beberapa method yang setiap method ini akan merepresentasikan URL tertentu. Contohnya adalah method index pada kelas BaseController
. Method tersebut memiliki annotasi @RequestMapping
. Ini adalah annotasi yang menandakan sebuah method akan menangani sebuah endpoint. Ada paramater yang perlu diperhatikan, method
dan path
. Parameter method
merupakan HTTP Method apa yang diterima oleh method tersebut, dalam hal ini GET
. Parameter path
di sisi lain merupakan URL apa yang akan ditangani oleh method tersebut. Nama method sebenarnya tidak ada pengaruhnya pada apapun, tapi tetap usahakan berikan nama yang sesuai dengan apa yang ditangani oleh method tersebut. Terakhir adalah return type dari sebuah controller method. Semuanya mengembalikan string. Nah, string yang dikembalikan ini adalah nama dari html yang ada pada folder resources/template. Dapat dilihat bahwa di sini method tersebut mengembalikan home
, sementara di folder template belum ada file home.html
. Karena belum ada, kita harus membuatnya."
Buat home.html
pada resources/template
Isikan seperti berikut.
Sekarang coba jalan aplikasinya. Buka Tutorial0Application
, klik lambang run.
Jika tidak ada masalah, maka pada command line IDE akan terlihat sebagai berikut
Hasilnya sebagai berikut:
" Sekarang coba tambahkan dua method lagi pada BaseController
"
Emory menggarisbawahi annotasi @GetMapping
pada kedua method contoller tersebut. Anda menyadari ada sedikit perbedaan dengan @RequestMapping
yang digunakan sebelumnya pada method index
.
"Apa kamu menyadari sesuatu?"
Anda menggangguk. "Apakah GetMapping
merupakan RequestMapping
yang memiliki HTTP method POST?"
Seperti biasa, Emory hanya mengiyakan dengan gestur tubuhnya. "Dengan ini penulisan bisa lebih concise. Selain itu, ada kegunaan lain dari RequestMapping
, URL Groupping. Ini akan memungkinkan kamu untuk mengelompokkan URL yang memiliki prefix yang sama, seperti /student/create
dan /student/list
Kamu akan perlu menggunakan ini untuk membuat aplikasi yang diminta tadi."
Pada dua method tersebut ada dua annotasi lain dan juga sebuah parameter model
pada argumen dari method tersebut.
"Selanjutnya mari kita menggunakan RequestParam
dan PathVariable
. Kedua parameter ini penting untuk mengendalikan URL mapping. Mungkin akan lebih mudah untuk langsung memperlihatkan contoh penggunaannya saja. Karena ada method ini, ada sedikit perubahan yang perlu dilakukan pada HTML nya. Coba ubah menjadi seperti berikut!"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
"th:if
dan th:unless
merupakan statement if dan else untuk template engine Thymeleaf. Karena kamu pernah menggunakan Django, aku yakin kamu pernah menggunakan hal semacam ini bukan? Di sini dapat dilihat bahwa pengecekan dilakukan terhadap variabel name. Dapat kamu lihat ini adalah variabel yang dimasukkan oleh parameter model
. Perhatikan model.addAttribute("name", name);
model
pada dasarnya merupakan sebuah pasangan key-value. name
yang dipanggil pada HTML adalah key dan value nya adalah object Java yang kebetulan punya nama name juga.Kamu mungkin biasanya menggunakan sebuah dictionary pada Django untuk keperluan semacam ini bukan? Jadi aku rasa kamu bisa asumsikan model
di sini adalah equivalent dictionary pada Spring Boot. Jadi harap perhatikan model
di sini bukan Model dari M pada MVC."
Sekarang coba jalankan dan buka http://localhost:8080/greet?name=Emory
, harusnya didapatkan hasil sebagai berikut:
Anda bisa menggantikan Emory dengan apapun yang anda inginkan, coba ganti Emory dengan nama anda sendiri dan lihat hasilnya.
" Coba bandingkan dengan yang ini " Anda diminta membuka halaman http://localhost:8080/greet/Emory
"Apa perbedaannya? " tanya Emory.
Anda dapat melihat ada perbedaan pada url pattern yang digunakan.
"Aku akan mencoba menjawab berdasarkan observasiku " jawab anda mengawali jawaban anda. "Aku kasus pertama adalah penggunaan RequestParam
, ditandai dengan ?namaParam
atau dalam kasus ini adalah ?name
. Kasus kedua adalah PathVariable
ditandai dengan /greet/{variableName}
dan lagi-lagi pada kasus ini adalah name
"
Emory tidak mengatakan apapun, tapi wajahnya terlihat puas. Anda menganggap reaksi tersebut sebagai tanda jawaban anda benar.
"Sampai saat ini kamu sudah menyelesaikan suatu fungsi dasar pada Spring Boot. Pada saat ini, sebaiknya kamu mulai commit progress yang sudah dilakukan pada Git"
Saat ini folder proyek Spring dari Spring Initializr
belum dinyatakan sebagai folder git. Untuk membuat sebuah folder menjadi gunakan command:
1 |
|
Silahkan cek, ada perubahan apa dalam folder git (dalam hal ini file-file apa yang belum di-add di luar file yang ada dalam gitignore
) dengan menggunakan
1 |
|
Untuk melakukan add file ke git, gunakan
1 |
|
Jika kamu ingin langsung menambahkan semua file ke git bisa melakukan, tapi pastikan semua file yang ada pada git status
memang file yang ingin ditambahkan. Best practice-nya adalah lakukan add dan commit dengan perubahan seminimal mungkin. Kamu akan mempelajari cara commit seperti ini nantinya.
1 |
|
Kamu bisa menggunakan git status
lagi untuk mengecek file apa saja yang telah di-add.
Selanjutnya lakukan commit dengan perintah:
1 |
|
Untuk saat ini lakukan commit dengan pesan Initial commit
1 |
|
Implementasi Tugas Pertama
Emory menatap berkas yang Rory berikan kepada anda. Wajahnya terlihat tidak tertarik, mungkin terlihat bosan. Setelah beberapa detik membolak-balikkan kertas tersebut ia mengembalikannya pada anda.
"Orang itu selalu memberikan tugas yang sama kepada setiap rekrutan baru" keluhnya.
"Baiklah. Seperti yang kamu lihat, aplikasi ini adalah prototipe aplikasi sistem informasi asisten. Aplikasi ini adalah aplikasi yang dibuat untuk sebuah universitas kecil di pinggiran kota Prediff. "
"Prediff adalah kota liar di barat kota perdagangan Yukginia bukan?" Tanya anda. Emory hanya mengangguk lirih.
"Walau aku bilang begitu, aplikasi yang diminta kepada kamu hanya versi sederhananya. Untungnya, anda juga sudah diberikan requirements detailnya."
Anda diminta membuat sebuah halaman yang dapat membuat Student
baru dan menampilkannya di halaman lain. Begitu juga untuk Course
.
Aku akan membantumu membuat halaman Student
, tapi aku ingin kamu membuat Course
sendiri. Kebetulan hanya aku hanya dapat membantumu sampai di sini."
"Terima kasih banyak" Anda sangat bersyukur Emory bersedia membantu anda menyelesaikan tugas anda. Setidaknya di antara beberapa orang, anda memiliki rekan senior yang dapat membantu anda.
1 2 3 4 5 6 7 8 9 |
|
Pertama, kita harus mengubah requirements tersebut menjadi kode. Salah satu langkah paling mudah adalah membuat model atau core dari aplikasi ini terlebih dahulu. Buat class Student
pada package model. Namun, sebelum itu mari membuat branch baru pada git.
"Alasan pertama mengapa kita membuat branch adalah seperti yang aku bilang tadi adalah changes yang kita buat harus fokus dan minimal. Selain itu, agar long-lived branch seperti master
hanya digunakan oleh kode yang benar-benar siap untuk dimasuki. Mungkin kamu dapat mencari kegunaan lain dari branch. Aku serius, aku akan menanyakan hal ini nantinya. "
Buat branch dengan nama task-implementation-student
dengan perintah:
1 |
|
Atau dalam kasus ini berarti
1 |
|
Setelah ini, mulai bekerja dengan membuat model sebagai berikut:
Lakukan generate setter dan getter.
Pada IntelliJ, dapat menggunakan klik kanan -> generate
-> Setter and Getter
atau menggunakan shorcutalt+insert
(pada Linux dan Windows). Silahkan cek menggunakan klik kanan untuk melihat shorcut pada mesin anda.
"Nah kebetulan, untuk mengurangi boiler code kita akan menggunakan Lombok. Jika kamu ingat itu termasuk dependencies yang aku minta masukkan di awal tadi. Sekarang hapus setter dan getter yang sudah kamu buat, lalu ganti dengan kode di bawah."
Setelah selesai langkah selanjutnya adalah membuat lapisan Repository
.
" Yang aku ajarkan adalah versi yang disederhanakan dari model
dan repository
. Pada kenyataannya, kamu pasti ingin membuat kedua lapisan ini yang terintegrasi dengan basis data. Sementara mari kita buat 'basis data' sederhana menggunakan struktur data. "
Kelas ini pada dasarnya adalah kelas Java biasa. Kita belum mencoba menggunakan fitur Repository
yang terhubung langsung ke basis data dari Spring Boot. Hal utama yang perlu dipahami ada pada annotasi @Repository
.
Sederhananya annotasi mirip seperti @Controller
, berfungsi untuk menandakan bahwa sebuah Kelas adalah Repository. Dengan menandakan bahwa kelas ini adalah repository, kelas tersebut telah menjadi sebuah Bean
yang akan sangat kita gunakan pada Spring Boot.
Selanjutnya buat Service dari Student. Pertama buat interface StudentService
pada package service, isikan sebagai berikut:
"Nah, ingat tadi ada beberapa hal yang perlu dicek pada proses bisnis Student
? Ada keperluan untuk validasi. Mari kita buat sebuah Exception untuk kasus ada input nama Student
yang duplikat. Buat package baru bernama exception
dan buat kelas DuplicateStudentNameException
"
1 2 3 4 5 6 7 8 |
|
Karena persiapan selesai, selanjutnya buat implementasi dari interface StudentService
tadi. Buat kelas StudentServiceImpl
pada package Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
" Perhatikan @Service
dan @Autowired
. Aku yakin pada saat ini kamu sudah bisa menebak apa itu @Service
. Mari kita fokus pada @Autowired
"
@Autowired
merupakan sebuah mekanisme dependency injection
pada Spring Boot. Dalam hal ini dapat dilihat bahwa kita tidak secara eksplisit menuliskan inisialisasi dari StudentRepository
. @AutoWired
membuat Spring dapat membuat sendiri instance dari StudentRepository
. Hal ini dimungkinkan hanya pada sebuah Bean
. Ingat sebelumnya kita telah memberikan annotasi Repository
pada StudentRepository
. Dengan demikian StudentRepository
adalah sebuah bean
dan bisa menggunakan @Autowired
untuk proses inisialisasi. Anda akan melihat hal yang sama untuk StudentService
pada Controller nantinya.
Sekarang, buat implementasi dari Kelas StudentController
pada Package Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
|
"Aku tidak akan menjelaskan semuanya lagi. Aku cukup yakin kamu telah familiar dengan beberapa hal pada kode ini. Fokus kita adalah form untuk membuat student. Perhatikan method createStudentPage
dan createStudentPost
. Namun, sebelum itu mari kita implementasi studentList.html
dan createStudent.html
"
studentList.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
createStudent.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Proses pembuatan Student
dibagi menjadi dua, direpresentasikan oleh 2 method tadi. Method createStudentPage
yang memiliki HTTP Method - Get, merupakan method yang bertugas untuk mengarahkan pengguna ke halaman form untuk membuat Student
.
Sementara createStudentPost
yang memiliki HTTP Method - Post, merupakan method yang bertugas untuk submit form ke backend.
Proses submit form yang terdiri dari dua bagian ini juga perlu diperhatikan.
Perhatikan method createStudentPage
!
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
"Sekarang kembali lakukan add dan commit. Namun, sekarang mari manfaatkan fitur yang tersedia pada IDE"
Buka menu git
pada IntelliJ dan buka commit. Windows berikut akan muncul.
Anda dapat melihat bahwa daftar file tersebut adalah daftar file yang sama dengan apa yang ada pada git status
. Tampilan change
pada IDE anda mungkin berbeda. Anda mungkin akan mendapati file-file yang anda buat belum di-add. Pada kasus tersebut, silahkan cek pada bagian Unversioned Files
.
Pilih file-file terkait dengan implementasi Student
yang sudah kita implementasikan dan kita akan menuliskan pesan commit.
Tulis Implement student page
pada text box commit message, lalu klik Commit. (Terkadang akan ada warning, untuk latihan ini, lanjutkan saja dengan Commit anyway jika ada prompt).
Ada beberapa aturan dalam penulisan commit message yang perlu diikuti. Coba baca artikel berikut, How to Write Git Commit Message, untuk mempelajari lebih lanjut mengenai hal tersebut.
Some Advanced Git
Emory melihat program anda beberapa saat.
"Oke, terlihat tidak masalah" komentarnya. "Sekarang coba push pekerjaan anda ke repository. Oh jangan lupa push pekerjaan pada master
branch terlebih dahulu.Aku mengasumsikan anda paham cara membuat repository pada Gitlab dan melakukan konfigurasi git pada local (hint: git remote
). Berikan nama yang deskriptif."
Pindah ke branch master. Anda dapat menggunakan GUI melalui IntelliJ atau menggunakan command line.
1 |
|
Push pekerjaan anda. Sekali lagi anda dapat menggunakan GUI melalui menu Git pada IntelliJ atau git push
.
Pindah kembali ke branch task-implementation-student
, lakukan push. Pelajari mengenai Merge Request
. Buatlah Merge Request
ke branch master dari branch task-implementation-student
. Coba merge dan amati apa yang terjadi. Anda akan diminta menjelaskan ini nantinya.
"Sekarang kita akan coba melakukan simulasi penggunaan git reset
dan git revert
"
Git Reset
Buat lah kelas MockStudentServiceImpl
pada package Service, isikan sebagai berikut:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
bean
dengan tipe StudentService
. Hal ini membuat Spring tidak tahu bean
mana yang harus digunakan. Anda dapat memperbaiki masalah ini dengan mengganti @Autowired
pada StudentController
dengan @Qualifer
dan secara eksplisit memilih StudentServiceImpl
. Namun, untuk tutorial kali ini, kita akan mencoba menyelesaikan masalah tersebut dengan mengembalikan versi commit kita sebelumnya menggunakan git reset
. Anda dapat mempelajari lebih dalam mengenai Qualifer
untuk memahami bagaimana menangani kasus jika ada dua bean
dengan tipe yang sama.
Seperti biasa anda dapat menggunakan fitur IDE anda untuk melakukan untuk melakukan hal ini, tapi sebaiknya coba pelajari cara menggunakan command line terlebih dahulu. (Hint: silahkan coba menu git pada pojok kiri bawah IDE anda untuk bereksplorasi fitur-fitur git pada IDE anda)
Jalankan perintah berikut untuk melihat ada commit apa saja yang telah anda lakukan:
1 |
|
Tampilan command line
Tampilan IDE
Kita akan coba menyelesaikannya dengan pendekatan command line. Untuk pendekatan IDE, silahkan dicoba sendiri.
Anda dapat lihat aplikasi anda masih dapat bekerja dengan baik pada commit Implement Student Page
.
Sekarang mari lakukan git reset
untuk kembali pada commit tersebut. Copy hash commit dari commit Implement Student Page
. Perhatikan: hash commit yang anda miliki akan berbeda dengan contoh.
Perintah git reset pada dasarnya adalah menggunakan sintaks berikut:
1 |
|
Contoh (Sekali lagi ini contoh. Hash commit anda akan berbeda. Jangan lakukan copy paste contoh berikut. Copy hash dari tampilan git log
anda sendiri)
1 |
|
Ketika anda mencoba membuka git log
anda akan mendapati commit dari MockStudentService
telah hilang. Coba jalankan aplikasi anda kembali dan pastikan aplikasi anda sudah kembali berjalan. (Coba pelajari apa yang dilakukan oleh argument --hard
. Apa ada opsi lain?)
Git Revert
Buat branch baru bernama simulation-revert
.
Kembali lakukan penambahan MockStudentServiceImpl
seperti bagian sebelumnya. Setelah melakukan git add
dan git commit
lanjutkan dengan git push
.
Coba simulasikan git reset
kembali. Coba lakukan push. Anda akan mendapati bahwa push tersebut ditolak oleh git. Hal ini dikarenakan remote repository anda memiliki commit ahead local repository anda. Anda tidak dapat melakukan push kecuali menggunakan git push --force
(For The Love of God, Don't try this at home.)
Dalam keadaan seperti ini, anda akan lebih cocok menggunakan git revert
.
Pertama lakukan, git pull
untuk menarik kembali perubahan yang anda lakukan pada remote repository anda.
Buka kembali git log
anda. Berbeda dengan git reset
yang kita lakukan bukan kembali ke commit dimana masalah ini belum ada, tapi membatalkan perubahan commit yang bermasalah. Dengan demikian, copy hash commit implementasi MockStudentService
anda.
Jalankan:
1 |
|
Contoh
1 |
|
Anda akan diminta melakukan commit. Isikan sesuai dengan deskripsi yang baik
Hasilnya akan terlihat sebagai berikut:
Terlihat bahwa proses revert akan menambahkan commit baru yang membatalkan commit sebelumnya. Lakukan push dan kembali ke branch task-implementation-student
Akhir dari Hari Pertama
"Bagaimana?" tanya Emory. Ia terlihat baru saja menyelesaikan task-nya hari ini. Mata dinginnya berbanding terbalik dengan perhatian yang ia berikan. Anda yang masih berusaha menyelesaikan task tersisa, melakukan implementasi halaman untuk Course
.
"Tidak buruk." komentar anda.
"Jika begitu, semoga beruntung" Emory tidak terlihat tertarik. Ia lalu mengemasi barangnya dan bersiap untuk kembali ke rumahnya, dugaan anda. "Jangan lupa apa yang aku ajarkan. Rory dan bos mungkin akan mengevaluasi semuanya, dari kualitas kode hingga disiplin git. "
Emory lalu berjalan ke arah meja kerja anda, menarik sebuah kursi, dan duduk di samping anda. Anda menatap bingung ke arah Emory.
"Aku akan istirahat di sini sebentar. Jika ada pertanyaan, silahkan ganggu aku." ujarnya.
"Ah terima kasih."
"Cepat selesaikan. Aku akan membawamu keliling kota ini." lanjut Emory seolah tidak ada eksperesi.Tindakannya bertolak belakang dengan nada suaranya yang dingin. "Sudah lama aku tidak melihat orang dari duniaku. Aku rasa aku ingin tahu seperti apa di sana akhir-akhir ini. " ujarnya lagi.
"Baik." jawab anda singkat.
Hari pertama anda diakhiri dengan perjalan singkat ke beberapa tempat bersama senior dingin anda. Wajahnya terus tidak menampakkan eksperi, walau anda dapat merasakan mood-nya yang terlihat lebih ceria dari pertama kali anda bertemu dengannya. Anda tersenyum. Setidaknya bukan cara yang buruk untuk mengakhiri hari pertama anda. Di bawah rembulan kemudian anda terus berbincang dengan Emory. Tentang dunia ini, tentang 0, dan beberapa orang lain dari dunia anda. Jika bisa anda ingin berkenalan dengan mereka. Melihat kisah mereka. Apakah mereka datang tanpa penyesalan atau sebaliknya, jika ada cara untuk kembali, apakah mereka memilih untuk kembali? Di sinilah berawal kisah anda dan mereka yang dikirim untuk bekerja di dunia lain.
Task
- Membaca Tutorial ini
- Menyelesaikan setiap langkah yang diminta pada Tutorial
- Menyelesaikan implementasi
Course
sesuai dengan requirements
Hint
- Anda dapat mempelajari pola dari proses implementasi
Student
untuk implementasiCourse
- Pastikan anda tetap mengikuti disiplin git yang baik untuk menyelesaikan
Course
- Pastikan anda mempelajari bagian yang meminta anda mempelajari sesuatu. Anda akan diminta menjelaskan hal tersebut saat sesi demo nantinya.
Ekspedisi baru (package: pricing)
Deskripsi
PT. DailyNichi adalah sebuah perusahaan besar yang bergerak di bidang informasi. Perusahaan ini bertujuan untuk memberikan update-update terkini di semua hal yang terjadi di dunia ini. Informasi yang disediakan PT DailyNichi mulai dari cuaca hari ini dan event-event yang sedang berlangsung, hingga lokasi real-time dari naga-naga berbahaya. Setelah proses rekruitmen yang berat, anda akhirnya diterima sebagai Software Engineer di PT. DailyNichi. Untuk sementara, anda akan melapor ke direct manager anda, Pak Kai.
Kai gemar sekali bermain game waifu collector untuk melepas penatnya hidup. Secara spesifik, Kai gemar memainkan karakter Alicia karena mekanisme yang menggunakan panah dan gerakan-gerakannya sangat unik. Saking sukanya, dia mulai mencari-cari merchandise Alicia, seperti poster, action figure, sticker, hingga sarung bantal. Pusat merchandise Alicia ada di kota Hoyomi. Sayangnya, kota ini jaraknya cukup jauh dari tempat tinggalnya. Perjalanan ke sana dapat membutuhkan beberapa minggu. Ditambah lagi, ada potensi serangan dari penjarah atau mahluk-mahluk buas di tengah jalan.
Suatu hari, Kai melihat teman anda si Kirigaya membawa pulang life-size figure Asuka. Anda bertanya:
Kai: "Di mana anda membeli itu?"
Kirigaya: "Baru datang tadi pagi via Gajah"
Kai: "Gajah? bukankah kota Incrad pabrik Asuka jaraknya sangat jauh?"
Kirigaya: "Ada perusahaan yang menawarkan jasa ekspedisi dengan gajah. Ekspedisinya dapat dikirimkan dari Incrad ke sini"
Kai: "Oh? berapa bayarnya? bukankah jaraknya sangat jauh dan banyak mahluk buasnya?"
Kirigaya: "Pembayaran cukup terjangkau. Untuk ekspedisi ini, saya membayar berdasarkan berat benda dan juga jarak yang ditempuh. Pengiriman lumayan aman karena gajahnya mengintimidasi"
Mendengar ini, Kai langsung melakukan riset di sektor ekspedisi. Sektor ekspedisi sangat vital di negara ini. Terdapat banyak perusahaan ekspedisi yang masing-masing menawarkan jasa-jasa berbeda, mulai dari jasa pengiriman ekonomis oleh Goblin, hingga jasa premium oleh burung garuda. Kai merupakan seorang karyawan di PT. DailyNichi dan kini menyarankan agar PT. DailyNichi masuk ke dalam sektor ekspedisi. Kebetulan sekali PT. DailyNichi baru mendapatkan rekrut baru yaitu anda. Agar jasa bisa bersaing dengan perusahaan lain, PT. DailyNichi akan menawarkan tiga tipe pengiriman berbeda, yaitu pengiriman kurir kadal, kurir kuda, dan kurir garuda. Ketiga mode pengiriman ditawarkan untuk mengakomodasi berbagai berat paket berbeda. Kurir kadal untuk berat ringan (di bawah 10 kg), kurir kuda untuk berat sedang (10 - 50 kg), dan kurir garuda untuk barang berat (di atas 50 kg). Harga yang perlu di bayar bergantung pada berat barang yang dikirim. Masing-masing tipe pengiriman memiliki harga per-kilogram yang berbeda. Semua pembayaran jasa dilakukan dalam civil credits, e-walletnya PT. DailyNichi.
Kai tahu bahwa pengiriman antar-kota memiliki banyak potensi bahaya. Untuk menjual jasa ekspedisi PT. DailyNichi, Kai ingin ada sistem asuransi. Tujuan sistem ini adalah sebagai "jaminan" bahwa barang-barang berharga yang di kirim akan mendapatkan kompensasi setimpal jika terjadi hal yang tidak diinginkan. Semakin mahal jenis asuransinya, semakin ketat pengawalan dari paket tersebut. Untuk saat ini, direncakan ada tiga tipe asuransi, yaitu asuransi beta untuk barang pasaran (nilai barang di bawah 1.000 civil credits), asuransi alpha untuk barang reguler (nilai barang 1.000 - 50.000 civil credits), dan barang berharga (nilai barang di atas 50.000 civil credits). Setiap asuransi mematok harga tetap, dan asuransi yang lebih tinggi mematok harga yang lebih mahal.
Product Manager (PM) memberikan anda informasi baru mengenai layanan yang akan di buat. Dia mengatakan, khusus untuk kurir Garuda, ada biaya tambahan flat sebesar 2.000 civil credits untuk menggunakan jasanya. Anda sebagai karyawan PT. DailyNichi akan mengimplementasikan jasa ekspedisi ini. Program anda menerima masukan berat dan nilai barang. Untuk setiap masukan, program mengeluarkan civil credits yang harus di bayar jika menggunakan jasa ekspedisi perusahaan.
Penjelasan Kode
Pada core
, tersedia sebuah interface Asuransi
dan Kurir
. Interface Asuransi
memiliki dua buah method:
1. getName()
: mendapatkan nama dari asuransi ini
2. getPrice()
: mendapatkan harga dari asuransi ini (civil credits)
Interface Kurir
memiliki dua buah method:
1. getName()
: mendapatkan nama dari asuransi ini
2. calculatePrice(weight)
: mendapatkan total harga yang harus di bayar untuk barang seberat weight
jika menggunakan kurir ini.
Kode PricingInitializer.java
menginisialisasi informasi Asuransi
dan Kurir
di awal jalannya program.
Hint
Untuk mendapatkan nilai penuh, anda harus mempertimbangkan bagaimana maintainability code anda. Yakni, perubahan kode minimal jika ada penambahan fitur di bawah minimal.
- Ada penambahan tipe asuransi atau jenis kurir baru.
- Ada penambahan layanan baru selain asuransi dan kurir, misalnya ada biaya tambahan untuk jenis packaging barang.
Catatan: fitur-fitur ini tidak diimplementasikan pada tutorial ini.
Tracking Ekspedisi (package: tracking)
Deskripsi
Suatu hari, terjadi suatu diskusi menarik antara Chief Technology Officer (CTO) dan General Manager (GM) perusahaan terkait pengembangan jasa ekspedisi. Diskusi ini terjadi di ruangan tertutup.
CTO: "Bagaimana caranya kita mengejar kompetitor kita yang sudah mulai lebih dulu?"
GM: "Kita minta data riset mereka"
CTO: "Strategi sneak 100 ya :)"
GM: "Bukan, kita 'minta' secara tidak langsung dengan mengamati mereka. Bagaimana kalau beberapa karyawan kita tugaskan untuk kerja di kompetitor?"
CTO: "BONK. Saya punya ide yang lebih bagus. Kita punya divisi lain yang monitor aktivitas-aktivitas naga berbahaya bukan?"
GM: "Benar, kami ada monitor pada semua naga dengan level bahaya terbesar seperti Drago, Fafnir, Kanna Kamui, dan Quetzalcoatl"
CTO: "Kota Trifcester dan Shunard lumayan aktif kegiatan ekspedisinya. Belakangan ini, banyak laporan bahwa Drago sedang aktif di sana. Kabarnya, banyak jasa ekspedisi yang diserang oleh naga raksasa itu"
GM: "Anda berpikir untuk membuka API DragoMonitor kami ke jasa-jasa ekspedisi di Trifcester dan Shunard?"
CTO: "Benar, API itu akan memberi notifikasi tentang kegiatan Drago, seperti saat dia meninggalkan atau pindah lokasi. Kami akan buka APInya agar mereka bisa menghindari Drago"
GM: "Kemudian diam-diam kita rekam dan pelajari gerak-gerik ekspedisi tersebut? Ide yang bagus, mari kita eksekusi"
CTO: "Adalah benar, panggil karyawan baru kita untuk persiapan pembukaan API ini"
Anda dipanggil oleh GM dan CTO untuk menyiapkan API baru ini. Anda sangat senang karena dapat bekerja di projek skala besar yang harus memberikan notifikasi secara real-time. Tipikal korporat, anda hanya diberikan garis besar permintaan aplikasinya saja. Anda belum pernah ke Trifcester maupun Shunard sehingga mulai melakukan studi mandiri. Anda memutuskan bahwa cara terbaik untuk memahami lapangan adalah untuk berangkat ke TKP dengan biaya sendiri. Diketahui bahwa ada 3 rute yang dapat ditempuh untuk bepergian dari Trifcestor ke Shunard (atau sebaliknya), yakni: melewati pegunungan Shefburg Path, melewati rawa Cardham Morass, dan melewati pantai Vottona Edge. API akan memberi notifikasi ke semua yang berlangganan jika Drago sedang berjaga di salah satu tempat, atau jika dia meninggalkan tempat jaganya.
Dibuatlah press release sekaligus pre-register bahwa PT. DailyNichi akan merilis API tersebut dalam waktu dekat
CTO: "Wah, banyak juga ya yang tertarik dengan API kita!"
GM: "Data is the new oil!"
GM: "Eh, ini kok perusahaan Siesta's Agency ikut daftar? mereka bukan di bidang ekspedisi kan?"
PR: "Iya, Siesta's Agency ini salah satu perusahaan bergerak di bidang dragon hunting (pemburu naga)"
CTO: "Waduhh, data kita rusak dong. Apakah kita larang mereka langganan?"
PR: "Jangan, itu bad PR. Kita terpaksa memperbolehkan mereka langganan :("
GM: "Kira-kira buat apa ya mereka langganan sistem ini?"
PR: "BONK. Sudah jelas untuk tahu lokasi Drago sehingga mereka bisa menyerangnya!"
GM: "Ohhh, jadi mereka malah menggunakan API itu untuk hanya pergi ke tempat yang sedang di jaga Drago?"
CTO: "Adalah benar. Yah syukurlah kami tidak perlu mengubah apa-apa di sisi API untuk mengakomodasi ide mereka. Yang penting API kami bisa memberikan lokasi Drago secara terpercaya"
Sisi lain, di perusahaan ekspedisi Raiden's Lightning Express ketika PT. DailyNichi mengumumkan API baru
Terjadi percakapan antara Logistics Manager (LM) dan CEO (Raiden).
LM: "Boss, PT. DailyNichi membuka API baru yang menarik nih"
Raiden: "Apa itu?"
LM: "API notifikasi Drago, boss! Kini kita bisa tahu lokasinya jadi bisa mengambil rute alternatif"
Raiden: "Bagus juga idenya, jadi dari 3 rute yang tersedia, kita bisa lewati dua rute lain yang tidak dijaga Drago ya?"
LM: "Bener boss"
Raiden: "Eh, PT. DailyNichi? Kita bukannya langganan SweetsMonitor juga dari mereka? API yang memberi notifikasi jika sedang ada Sweets Festival di salah satu rute?"
LM: "Bener boss, kurir kami sweet tooth semua boss. Jika sedang ada Sweets Festival, mereka pasti memilih untuk melewati rute tersebut"
Raiden: "Kalau misal rute tempat Sweets Festival sedang dijaga Drago juga gimana?"
LM: "Sejujurnya Drago tidak masalah boss. kurir kami terkenal karena kecepatan pengirimannya. Karyawan kami biasa mampir di Sweets Festival, kemudian akan blitz melewati Drago jika ketemu. Bahkan Drago biasanya tidak sadar jika kurir kami lewat"
Raiden: "Tapi kalau sedang tidak ada Sweets Festival, kurir kami akan menghindari rute yang dijaga Drago kan?"
LM: "Iya boss"
Flow pekerjaan
Pada front-end, akan ada tombol untuk meletakkan Drago dan memulai Sweets festival disemua kemungkinan rute. Ada juga layout untuk setiap pengguna API yang menampilkan rute-rute mana yang dapat dia lalui sekarang. Program dikatakan berhasil apabila tampilan daftar rute-rute yang diambil oleh setiap pengguna API sudah sesuai dengan setiap skenario yang dijelaskan di deskripsi.
Penjelasan Kode
Pada bagian core, ada dua buah interface:
- Interface EventsMonitor untuk menyatakan API-API yang dimiliki oleh PT. DailyNichi (DragoMonitor dan SweetsMonitor)
- Interface RoadUser untuk menyatakan sebuah pengguna API. Dua class yang mengimplementasikannya adalah Courier dan DragoHunter. Fungsionalitas kedua class ini sesuai dengan deskripsi soal.
Semua entitas untuk keperluan lab akan diinisialisasi di TrackingInitializer.java. Hal ini termasuk membuat semua Courier dan DragonHunter, dan memilih kepada siapa saja mereka berlangganan.
Hint
Untuk mendapatkan nilai penuh, anda harus mempertimbangkan bagaimana maintainability code anda. Yakni, perubahan kode minimal jika ada penambahan fitur di bawah minimal.
- Tracking system digunakan oleh kota-kota lain dengan "Drago" nya sendiri.
- Ada lebih dari satu Drago (dua atau lebih rute bisa dijaga Drago).
- Ada penambahan pengguna jalan atau tipe pengguna jalan baru. Seperti Salvager pergi ke lokasi yang baru saja ditinggalkan Drago.
- Bagaimana jika ada Courier lain dengan sifat "aneh" seperti "Raiden's Lightning Express"?
Catatan: fitur-fitur di atas tidak diimplementasikan pada tutorial ini.
So many opportunities!
Section 1: Magic should be fun, isn't it?
Setelah anda bekerja keras mengerjakan aplikasi tracking ekspedisi di tugas anda sebelumnya, anda akhirnya dapat menyelesaikan tugas tersebut dengan baik dan tepat waktu.
Anda kemudian diminta untuk mengunggu hasil evaluasi CTO dan GM mengenai hasil kerja anda. Anda pun duduk di sekitar cafetaria untuk istirahat sejenak dan mengambil sekaleng minuman. Menurut anda, tugas kemarin ternyata cukup menantang untuk dikerjakan. Walaupun demikian, anda yakin bahwa anda telah menyelesaikannya dengan cukup baik. Tak berselang, anda diundang untuk bertemu dengan CTO di ruangannya.
Dengan hati yang gugup, anda masuk ke ruangan CTO dan beliau mempersilahkan anda untuk duduk. "Kami telah mengevaluasi hasil kerja anda," ujar CTO, "dan saya sangat puas dengan hasil kerja anda! Kami mempertimbangkan untuk menggunakan seluruh hasil kerja anda untuk digunakan di production."
Anda menghela nafas dengan lega dan berterima kasih. "Terima kasih banyak, tugas kemarin cukup menantang." Jawab anda dengan rasa gembira. "Cukup seru sekali untuk dikerjakan."
"Nah, karena anda cukup mahir dan menukai tantangan, kami menawarkan kamu untuk ditempatkan di divisi riset kami." Ujar Manajer Inora, "Ini merupakan kesempatan kamu untuk dapat membuat impact yang besar terhadap perusahaan ini. Saya yakin anda akan menyukai divisi tersebut."
"Terdengar menarik, tapi sebelumnya apakah saya boleh tahu apa saja tugas saya di divisi tersebut?" Tanya Anda dengan nada yang menandakan anda kebingungan.
"Boleh saja," Jawab CTO, "kamu dapat menemui manajer divisi riset untuk dapat bertanya langung langsung bersamanya"
Dengan antusias anda menjawab, "Boleh sekali!"
"Baiklah, saya akan menelpon manajernya untuk segera bertemu kamu di ruangannya." Ucap sang CTO.
Kemudian CTO memberikan arahan untuk anda agar dapat sampai ke ruangan Manajer. Dengan mengikuti arahan sang CTO secara perlahan, anda dapat menemukan ruangan manajer divisi riset. Anda kemudian masuk ke ruangan manajer dan menemukan sang manajer sedang berbicara melalui telepon.
Di atas meja terlihat sebuah papan nama bertuliskan "Inora Azerovan - Research Manager" dengan sebuah cangkir disampingnya. Sang manajer kemudian menutup teleponnya sambil memperkenalkan diri.
"Perkenalkan nama saya Inora, saya adalah Research Manager di perusahaan ini." Ucap manajer Inora, "Saya sudah mendengar cerita anda dari CTO, saya rasa anda akan suka bekerja di divisi ini."
"Sebelumnya apakah saya boleh bertanya mengenai pekerjaan saya di divisi ini?" Tanya anda kepada manajer Inora.
"Pertanyaan bagus, sebelumnya apakah anda tertarik dengan praktik sihir?"
Andapun menjawab, "praktik sihir?"
"Tepat sekali!" Jawab Manajer Inora, "Saya kira anda sudah tahu, perusahaan ini mempunyai berbagai anak perusahaan di berbagai bidang."
"Saya pribadi sudah tahu, tapi saya tidak sangka akan menyentuh bagian sihir. Saya masuk ke perusahaan ini hanya sebagai pengembang." Jawab Anda.
"Tidak apa-apa," Ujar Manajer Inora. "Melihat performa kamu di tugas sebelumnya saya sangat yakin anda mampu menangani tugas yang akan saya berikan."
Kamu beprikir sejenak untuk menimbang tawaran dari Manajer Inora.
"Bagaimana?" Tanya Manajer Inora. "Apakah kamu tertarik?"
Anda menjawab dengan percaya diri, "Saya akan coba semampu saya."
"Bagus sekali! Sekarang, mari kita akan pergi ke ruangan riset anda." Ajak Manajer Inora.
Tak lama kemudian seluruh badanmu dikelilingi oleh cahaya kuning. Anda terkejut karena anda dan Manajer Inora tiba-tiba berada di ruangan ramai nan luas.
Task 1: One stick to summon them all
Manajer Inora: "Ini adalah ruangan riset kami, anda akan membantu kami untuk membangun sebuah tongkat."
Anda: "Tongkat sihir?"
Manajer Inora: "Ya memang tongkat sihir, tongkat apa lagi?", jawab Manajer sambil tersenyum. "Kami berencana untuk memproduksi tongkat ini untuk agar bisa men-summon berbagai macam makhluk."
Anda: "Makhluk apa yang bisa di-summon oleh tongkat tersebut?"
Manajer Inora: "Banyak, namun sejauh ini kebutuhan kami hanya terbatas kepada makhluk-makhluk yang sudah familiar, seperti hewan dan tumbuhan. Seluruh makluk hidup dapat di-summon menggunakan sebuah segel kontrak."
Anda: "Segel kontrak?"
Manajer Inora: "Ya, segala macam makhluk hidup dapat diberi segel kontrak sehingga dapat di-summon kapanpun dimanapun. Tentu saja tidak terbatas pada makluk hidup, benda mati juga dapat dipengaruhi menggunakan segel kontrak."
Anda: "Bagaimana sebuah benda mati dapat dipengaruhi oleh sihir?"
Manajer Inora: "Dengan mengatur intensitas mana yang digunakan benda mati tersebut. Tentunya bukan sembarangan benda, hanya alat-alat magic/magic tools yang bisa dipengaruhi."
Anda: "Oohh… Baiklah… Kalau begitu apa yang harus saya perbuat?"
Manajer Inora: "Tugas kamu cukup membuat tongkat melakukan seluruh hal yang telah saya deskripsikan, dan pastikan hal yang dilakukan itu benar."
Anda: "Hoo.. Baiklah kalau begitu. Kira-kira adakah hal dari magic tool ini yang harus saya atasi?"
Manajer Inora: "Pertanyaan yang bagus! Magic tool hanya memberikan segel kontrak. Oleh karena itu, intensitas mananya harus diatur sendiri oleh pemilik tongkat, baik sedikit, menengah, maupun tinggi. Tergantung ukuran benda yang akan di-summon"
Anda: "Kalau begitu, tongkat ajaib in hanya perlu mengatur intensitas dari sebuah magic tool saja?"
Manajer Inora: "Tepat sekali! Tentunya dalam membuat segel kontraknya, anda minimal harus mempunyai satu opsi intensitas mana."
Anda: "Mungkin kembali ke makhluk hidup. Apakah makhluk yang sudah di-summon tidak dapat di-summon lagi kedepannya?"
Manajer Inora: "Tentu saja bisa! Dengan syarat makhluk tersebut di-seal ulang terlebih dahulu. Memangnya jika sudah di-summon, bagaimana caranya di-summon lagi? Tidak bisa bukan?"
Anda: "Oh seperti itu ya, hmm… Bagaimana cara membuat segel kontrak?"
Manajer Inora: "Melalui formulir kontrak tentunya. Formulir kontrak tersebut nantinya akan mengikat terhadap tongkat ajaib secara otomatis. Pengguna cukup cast segel kontrak yang sudah terikat di dalam tongkat, tidak perlu memanggil makhluk familiar atau magic tools secara langsung. Oh iya, saya lupa sampaikan satu hal penting."
Anda: "Apa itu?"
Manajer Inora: "Setiap makhluk dan benda yang terkontrak pada tongkat harus mempunyai semacam riwayat untuk jaminan keamanan perusahaan. Setiap perubahan state pada makhluk dan benda tersebut harus terekam dengan jelas. Selain itu, untuk kemudahan, spell yang di-summon oleh tongkat tersebut agar bisa di-undo"
Anda: "Baiklah, adakah kasus khusus lain yang harus saya kerjakan?"
Manajer Inora: "Saya rasa saya sudah semua saya berikan. Apabila ada hal yang kamu tidak yakin, kamu dapat bertanya langsung ke saya."
Anda: "Baiklah akan saya kerjakan segera."
Manajer Inora: "Bagus, kerjakan tugasmu dengan semangat!"
Sang manajer kemudian meninggalkan anda di sebuah meja dengan sebuah telepon dan sebuah tongkat sihir untuk anda kerjakan.
Additional Feature:
Saat anda mengerjakan tugas, anda sadar bahwa apabila pengguna perlu men-summon berbagai macam makluk sekaligus, maka akan lebih mudah jika urutan spell tersebut disimpan dalam suatu chain spell, sehingga seluruh makhluk dapat di-summon sekaligus secara bertahap. Anda berpikir, jika anda mengimplementasikan fitur ini mungkin manajer akan terkesan dan mungkin anda akan mendapatkan promosi. Setelah berjam-jam memikirkan bagaimana cara untuk implementasi fitur ini, anda mendapat ide untuk menggunakan riwayat pada setiap makhluk/benda. Anda merancang chain Spell agar dapat menyimpan 2–7 spell terakhir yang di-cast pada makhluk/benda. Tentunya chain spell ini dapat di-undo seperti spell normal, agar memenuhi jaminan keamanan perusahaan.
Hint:
- Silahkan ubah class yang sudah tersedia di
core
jika diperlukan, namun tetap ingat design principle yang ingin dicapai. - Silahkan menerapkan best practice yang telah dipelajari. Desain kode akan memperngaruhi penilaian.
- Untuk bonus command: silahkan perhatikan
form_contract.html
baris 68–69 - Alangkah baiknya menjalankan aplikasi terlebih dahulu untuk memahami bagaimana flow yang seharusnya diimplementasikan
- Silahkan bertanya pada asdos jika ada yang kurang jelas.
Screenshot Contoh Tampilan
/control-wand
: Hasil dari eksekusiAbyssal:Summon
,Abyssal:Sealed
,undo
x2;Pogo:Medium
,Pogo:High
,undo
x2
/contract-form
Section 2: Go big or go home!
Telepon di meja anda berbunyi dan anda mengangkat telepon tersebut. "Halo," tanya seseorang dari balik telepon. "Halo, bagaimana akhirnya? Apakah anda tertarik dengan pekerjaan yang ditawarkan divisi riset?"
Anda kemudian mengenali suara tersebut merupakan suara sang CTO, kemudian anda menjawab "Ya, saya sangat tertarik dengan pekerjaan yang ditawarkan." Jawab Anda, "Jadi saya ambil."
"Baiklah," ucap CTO, "Awalnya saya ingin menawarkan anda pekerjaan di bagian lain yang mungkin lebih rileks apabila anda merasa riset terlalu berat."
"Pada bagian apa kalau boleh tahu?" Tanya anda merasa penasaran.
"Fleksibel, anda akan bekerja langsung dibawah pengawasan saya dan bekerja di berbagai bidang perusahaan." Ujar CTO menggunakan nada serius, "perusahaan ini berusaha untuk dapat meraih setiap dunia yang dapat kami raih, baik itu dunia yang penuh sihir, monster, maupun dunia yang dipenuhi berbagai macam makhluk yang belum dikenal. Saya ingin mengajak anda untuk dapat berkeliling dunia untuk memecahkan setiap masalah yang ada di dunia tersebut." Jelas CTO.
Rasa takjub akan tawaran CTO membuat anda terdiam dan kesulitan untuk memberikan respon. "Tapi, karena anda sudah merasa nyaman terhadap divisi ini, saya tidak jadi menerima penawaran kamu."
Anda pun membayakan hal-hal apa saja yang akan dapat dipelajari melalui tawaran tersebut. Anda diam sejenak untuk bepikir untuk mengambil tawaran ini, anda berpikir tawaran ini merupakan kesempatan yang mungkin tidak akan datang kedua kalinya.
"Halo? Anda masih disana?" Tanya CTO memotong jalan pikir anda.
"Oh! Ya!" Jawab anda dengan nada terkejut. "Menurut saya itu tawaran yang sangat menarik."
"Jadi anda ingin mengambil tawaran tersebut?"
"Ya, tapi bagaimana dengan pekerjaan saya dengan Manajer Inora?"
"Jangan khawatir, anda dapat menyelesaikan tugas anda dengan Manajer Inora terlebih dahulu. Untuk sementara ini saya ingin menguji kepandaian anda dalam multitasking."
"Baiklah, apa yang harus saya lakukan?" Tanya anda dengan semangat.
"Kami sedang ada permintaan besar dari negeri Hollowith. Ada dua negara terbesar, Crownvern dan Etherdia, akan saling bertanding di final turnamen ketangkasan. Kedua negara memesan ribuan unit Training Dummy dari kami untuk membantu setiap pemain berlatih."
"Kalau begitu… Apa saja yang kebutuhan Training Dummy? Training apa saja yang diperlukan setiap pemain? Apa saja…"
"Tunggu tunggu!" Potong CTO. "Anda tidak akan membuat Training Dummy anda sendiri. kami sudah mempunyai beberapa unit Traning Dummy tersedia. Saya rasa anda belum mampu mendesain Training Dummy yang cukup kompleks dan tahan banting. Apalagi jika dilakukan bersama tugas dari Manajer Inora yang saya yakin sudah lumayan berat."
"Ah iya, benar juga." Ujar anda, "Tugas dari Manajer Inora sudah lumayan berat untuk dikerjakan. Kalau begitu apa yang harus saya lakukan?"
"Seluruh unit Training Dummy sebenarnya merupakan unit dari turnamen yang sama beberapa tahun lalu. Agar perusahaan dapat menghemat anggaran, maka kami hanya membutuhkan kamu untuk mengecek kondisi setiap Training Dummy."
"Bagaimana caranya saya bisa mengecek kondisi setiap Training Dummy?" Tanya anda kepada sang CTO.
"Dengan menguji setiap training dummy dengan standar prosedur yang sudah tersedia. Anda cukup menjalankan prosedur yang sama untuk setiap Training Dummy yang ada. Perlu diperhatikan bahwa Training Dummy itu memiliki tipe yang berbeda, tergantung pada tipe senjata yang akan digunakan Training Dummy."
"Saya harus menyesuaikan setiap tipe Training Dummy sesuai SOP yang telah ditentukan, begitu kah maksud anda?" Tanya anda kepada CTO.
"Tepat sekali! Detilnya akan saya kirim melalui e-mail anda. Seharusnya ini cukup sederhana untuk anda kerjakan bersama tugas Manajer Inora." Ujar CTO.
"Baiklah, saya akan berusaha sebaik mungkin untuk tidak mengecewakan anda."
Task 2: Gotta go test them all!
Setelah membaca product requirement yang dikirim oleh si CTO, anda mengerti bahwa anda diminta untuk membuat sebuah sistem penyimpanan Training Dummy. Training Dummy adalah sebuah dummy yang digunakan untuk menguji senjata tempur. Training Dummy itu sendiri mempunyai 3 macam sesuai peruntukannya masing-masing: Melee, Ranged, dan Magic.
Karena Training Dummy secara berkala akan disimpan dan digunakan, maka diperlukan sebuah uji kualitas agar Training Dummy dapat digunakan untuk sesi pengujian senjata di kemudian hari. Setiap tipe Training Dummy mempunyai SOP masing-masing. Training Dummy juga boleh dibuang apabila dianggap tidak layak.
SOP terdiri dari:
- Weight Adjustment
- Activation
- Moveset Testing
- Deactivation
Pada tahap Weight Adjustment, Training Dummy dengan tipe Melee harus diberikan armor seberat 20 satuan dan Training Dummy dengan tipe Ranged perlu dirampingkan sebanyak 20% dari berat awal agar mudah digerakkan. Sementara Training Dummy dengan tipe Magic tidak perlu dilakukan Weight Adjustment.
Sebelum dilakukan Moveset Testing, setiap Training Dummy perlu dilakukan aktivasi. Aktivasi dari Training Dummy ini sendiri terdiri dari 2 tahap, yaitu aktivasi Training Dummy itu sendiri diikuti dengan aktivasi senjata. Perlu diperhatikan bahwa senjata yang bertipe Meelee tidak perlu diaktivasi.
Moveset Testing adalah tes yang menguji kinerja dari senjata yang diuji. Pada tes ini, Training Dummy akan melakukan beberapa aksi pada senjata yang dimiliki Dummy. Urutan aksi yang harus dilakukan dummy:
- Attack (2x)
- Buff
- Attack
- Defense
- Attack
- Defense
Setiap aksi dummy juga sudah pasti berbeda-beda, karena tipe senjata yang digunakan berbeda juga. Training Dummy dengan tipe Ranged sama sekali tidak dapat melakukan Defense. Sedangkan Training Dummy dengan tipe Magic selalu melakukan Buff setelah melakukan Attack. Saat Buff, Training Dummy dengan tipe Melee akan melakukan attack.
Seluruh aksi yang dilakukan Training Dummy pada tahap ini akan terekam di log Training Dummy. Training Semua Training Dummy yang sebelumnya diaktivasi kemudian dimatikan untuk disimpan.
That Time You Worked Overtime Because of A Witchcraft Analyst
Part 1 - Linguamorphism for Ancient Grimoires
Part 2 - Logistix Department and The Cave of Abundance
Linguamorphism for Ancient Grimoires
Serombongan Explorer memasukki gedung Omegaware Ltd. saat kamu membeli dosis kafein harianmu pagi ini. Mereka membawa peti-peti besar yang terlihat sepuh dan dekil. Diiringi pandangan ingin tahu dari karyawan lain, rombongan Explorer itu membawa jarahan mereka ke Witchcraft Research Department untuk diteliti.
Pemandangan ini terjadi setidaknya dua minggu sekali di kantormu. Omegaware Ltd. memberangkatkan sekelompok Explorer ke dungeon-dungeon di seluruh negeri untuk mendapatkan barang-barang magis. Hingga kini, kamu tidak yakin bagaimana perusahaan ini mendapatkan keuntungannya, tapi entah bagaimana mereka selalu membayar karyawan-karyawannya dengan baik.
Katanya, bayaran para Explorer adalah yang paling tinggi di antara yang lain. Kamu menganggap fakta ini cukup adil, berhubung mereka berhadapan dengan monster dan gua yang dipenuhi perangkap kuno. Kamu, tentu saja bukan seorang Explorer. Ha! Hal paling mengerikan yang pernah kamu explore adalah dokumentasi Spring Boot, bagaimana kamu mau menghadapi monster? Meski begitu, kamu ini seorang Technological Wizard yang dianggap jago oleh teman-teman departemenmu. Katanya, tidak ada yang menandingi kemampuanmu sejak kamu muncul tiba-tiba dua tahun yang lalu.
Kamu tidak mendengar apa-apa lagi tentang jarahan para Explorer sepanjang hari itu–sampai seorang Witchcraft Analyst bernama Nuule memasuki ruanganmu saat jam kerja hampir habis. Kamu berkomat-kamit pura-pura sibuk supaya Nuule tidak menghampiri kubikelmu.
Berhasil! Nuule ternyata berhenti di kubikel Buulyen, serorang Elf darah campuran yang duduk di seberangmu.
"Kau sudah dengar tentang para Explorer yang baru pulang?" tanya Nuule, secara praktis duduk di meja kubikel Buulyen dan membelakangimu. Ia membawa semacam bundelan kertas tipis yang sudutnya sudah terlipat dan sobek-sobek. Kamu melihat Buulyen mengangguk. "Bagus kalau begitu, ini akan cepat," lanjut Nuule sebelum mengambil napas panjang.
"Mereka menemukan setumpuk peti berisi Grimoire–" Nuule memulai. Grimoire adalah buku sihir yang seringnya berisi
mantra-mantra atau instruksi untuk membuat benda magis. "–dalam Lingua Aeron
."
Buulyen berkedip dua kali, tanpa sadar kamu mengikutinya dan melakukan hal yang sama. Lingua Aeron adalah bahasa yang digunakan oleh peradaban kuno Aeron beberapa milenia yang lalu. Kini, tak ada yang menggunakan maupun mengingatnya lagi. (Legenda mengatakan kalau orang-orang Aeron dulunya adalah pengrajin takhta.)
"Kami perlu kamu membuatkan alat bantu untuk menterjemahkan tumpukan Grimoire itu." Nuule sekarang berbicara cepat sehingga Buulyen tidak punya kesempatan untuk memotongnya. "Ini–" Nuule menyodorkan bundelan kertas yang dibawanya, " adalah buku panduan translasi yang selalu kami gunakan. Semua ada di dalam situ."
Nuule bangkit. "Kami membutuhkan alatnya di hari Senin. Bisa kan? Bisa, ya. Kamu kan hebat." Nuule tertawa, mengacak rambut Buulyen dengan mengesalkan, dan melenggang keluar ruangan.
Rusa keramat! Tapi ini kan hari Jumat!
Buulyen menangkap pandanganmu. "Kau mendengar semuanya kan?" tanyanya.
Khawatir dengan respon apapun yang akan kamu berikan, kamu hanya bisa mengangguk samar dan berharap Buulyen mengartikannya sebagai tidak.
"Oh syukurlah. Dengar, bibinya sepupuku akan menikah besok lusa dan kami harus menyiapkan segalanya. Kau tahu aku darah campuran, kan? Kalau aku tidak membantu, bisa-bisa aku semakin dikucilkan keluarga! Aku tidak mungkin lembur!" Buulyen berbicara cepat seperti saat Nuule berusaha mencegahnya untuk memotong. "Gantikan aku, ya? Ya? Ya? Ya?"
Kalian bertatapan lama sekali selagi kamu menyusun kata-kata untuk menolaknya dengan tegas dan bergaya. Sayangnya, dia mendahuluimu.
"Nanti kubelikan Toffee Caramel Pudding Boba," tambah Buulyen. Kamu menelan ludah. "Dua lusin."
"Deal."
SIAL. Apa yang baru saja kamu katakan? Buulyen melempar buku panduan tadi ke arahmu dan bergegas meninggalkan ruangan untuk menikmati akhir pekannya. Sementara itu, kamu terjebak dalam kubikel ini untuk beberapa jam kedepan (dengan perkiraan optimis) atau semalaman (dengan perkiraan realistis).
Setelah cukup lama berkutat dengan buku panduan itu, kamu akhirnya memulai proses translasinya. Sebuah kalimat dalam
Lingua Aeron terdiri dari beberapa kata, di mana setiap kata dipisahkan dengan karakter 0
. Kamu berpikir untuk
menggunakan alat LinguaTranslator
yang disediakan departemen untuk mengubah setiap kata pada kalimat
menjadi Lingua Latin
(Bahasa manusia) secara terpisah. Akan tetapi, tentu saja pekerjaan ini tidak sesederhana yang
kamu bayangkan. Baru sekali melakukan percobaan translasi, kamu sudah menemukan sebuah keanehan. Kamu mencoba
menerjemahkan kata SCHZM
dengan LinguaTranslator
. Kata tersebut seharusnya berarti magic
, tapi hasil yang kamu
dapat malah vpznt
.
Setelah melanjutkan penelitian, rupanya proses translasinya melibatkan lebih dari satu langkah. Sebelum kata diubah
dengan LinguaTranslator
, ada transformasi khusus yang perlu dilakukan. Kamu menuangkan transformasi pertama ke sebuah
alat bernama Cipher
. Transformasi ini dilakukan dengan memasukkan kata yang disertai setting decode
. Sebagai contoh,
memasukkan SCHZM
dengan setting decode
akan menghasilkan nLdJv
, sementara memasukkan nLdJv
dengan
setting encode
akan menghasilkan SCHZM
.
Selanjutnya, posisi dari setiap huruf dalam kata ini digeser sebanyak 3 posisi ke kanan, jadi dari nLdJv
menjadi dJvnL
. Perhatikan bahwa huruf yang di ujung kanan akan digeser ke posisi awal. Kamu telah membuat alat kedua
bernama Shifter
yang dapat menggeser-geser posisi seberapapun yang dibutuhkan. Barulah setelah mengecek ulang, kamu
mendapati bahwa dJvnL
berhasil ditranslasikan menjadi magic
dengan LinguaTranslator
yang kamu rancang.
Kamu akhirnya berhasil mendapatkan rancangan sebuah alat terjemahan lengkap. Alat ini menerima masukan sebuah kalimat
dalam Lingua Aeron
dan akan menerjemahkannya menjadi Lingua Latin
dengan memanfaatkan bantuan alat-alat yang telah
dibuat. Alat rancanganmu juga harus dapat menerjemahkan secara terbalik dari Lingua Latin
menjadi Lingua Aeron
.
Sebagai contoh, memasukkan =ib0%ZCS_0SCHZM
akan menghasilkan aku cinta magic
, dan memasukkan aku cinta magic
akan
menghasilkan =ib0%ZCS_0SCHZM
.
Masalah translasi ini melibatkan proses yang rumit (mengingat keberadaan buku panduan yang hampir sobek di tanganmu), meski setelah dipikirkan baik-baik sebenarnya cukup sederhana. Witchcraft Research Department hanya membutuhkan alat yang bisa menerjemahkan Lingua Aeron ke Lingua Latin dan sebaliknya.
Karena tidak berniat menghabiskan akhir pekanmu dengan lembur, kamu segera mengerjakan alat penerjemah permintaan Nuule.
Hint
Baca dan pahami setiap tools
yang disediakan. Lihat juga tests nya untuk memahami cara memakai tools bersangkutan.
Tasks
- Membaca dokumen dan memahami deskripsi dan ekspektasi yang diminta soal
- Menerapkan design pattern yang tepat untuk membuat alat translator
- Membuat test cases untuk setiap method yang dilengkapi / dibuat
Logistix Department and The Cave of Abundance
Nuule kembali ke kubikelnya setelah meminta bantuan orang Department of Technological Wizardry. Ia membuka lagi tumpukan Grimoire di mejanya satu per satu. Semuanya usang dan rapuh, dan tidak satupun yang bisa dia baca. Nuule menutup Grimoire satu dan membuka yang lainnya.
Salah satu Grimoire itu memiliki halaman yang terlipat. Nuule membuka lipatan di halaman itu dan menemukan gambar peta tua dan beberapa baris tulisan yang bisa ia baca sebagian. Ia mengenalinya sebagai Lingua Latin, tetapi hurufnya menggunakan huruf kuno. Nuule baru saja menemukan peta menuju Dungeon of Abundance.
Menurut legenda, Dungeon of Abundance penuh dengan harta karun dan barang jarahan yang bisa diklaim oleh siapa saja, tapi tidak pernah ada yang berhasil menemukannya. Bersemangat karena temuan ini, Nuule melaporkan hal tersebut kepada atasannya.
Perusahaan langsung bergerak setelah menemukan peta itu. Semua Explorer yang baru pulang akan langsung diberangkatkan lagi di hari Senin. Omegaware Ltd. juga memutuskan untuk membentuk divisi baru di bidang logistik untuk membawa pulang jarahan para Explorer supaya mereka bisa fokus mengeksplorasi Dungeon of Abundance.
Namun, merekrut karyawan baru akan memakan biaya dan waktu yang lama. Para pejabat Omegaware Ltd. memutuskan untuk
mengisi divisi baru ini secara instan dengan automata Droid
. Perusahaan membutuhkan Droid
yang bisa melakukan
pekerjaan berat, seperti mengangkat barang, menghitung barang, mengirim barang dengan transporter, dan menggunakan
crane.
Beberapa batch pesanan Droid
sudah dibuat. Akan tetapi, para Analyst menemukan bahwa Droid
tidak cost-effective
dan bisa membuat perusahaan merugi bila keseluruhan divisi baru itu hanya berisi Droid
. Akhirnya, perusahaan beralih
ke automata jenis lain, yaitu Golem
dan makhluk Fluid
yang lebih murah.
Pesanan Golem
dan Fluid
telah dibuat juga, tetapi terjadi miskomunikasi dalam prosesnya. Rupanya pesanan automata
itu dibentuk oleh sihir kuno dari Negeri Asnax. Karena sihirnya kuno, para Golem
dan makhluk Fluid
tersebut tidak
bisa mengoperasikan peralatan modern seperti crane dan transporter. Perusahaan akan kembali merugi kalau automata yang
sudah dipesan ini tidak segera diperbaiki. Pasalnya, automata yang telah dipesan tidak bisa mengerjakan satupun
pekerjaan yang dibutuhkan perusahaan.
Karena dikira sudah familiar dengan translasi sihir kuno, Nuule merekomendasikan kamu untuk menjadi penanggung jawab
proyek ini. Kamu diminta perusahaan untuk mengakali Golem
dan Fluid
yang sudah dipesan supaya bisa melakukan semua
pekerjaan yang bisa dikerjakan sebuah Droid
.
Setelah menyerahkan translator buatanmu pada Nuule, kamu menarik napas berat dan kembali untuk mulai mengerjakan proyek
baru ini. Sebuah Droid
, Golem
dan makhluk Fluid
telah berbaris manis di samping kubikelmu ketika kamu tiba. Kamu
meneliti mereka satu per satu berikut dokumen requirement yang diminta perusahaan.
Sebuah Automata harus dapat melakukan action sebagai berikut:
- Mengangkat barang
- Menghitung barang
- Menggunakan Crane
- Mengirim barang menggunakan Transporter
Sebuah Droid
bisa melakukan empat macam aksi, yaitu:
liftItem(item)
countItem(inventory, item)
useTransporter()
useCrane()
Sebuah Golem
bisa melakukan melakukan empat macam aksi, yaitu:
liftItem(item)
: Mengangkatitem
isItem(item1, item2)
: Memberi tahu apakahitem1
sama denganitem2
punch(item)
: Memukulitem
toss(item)
: Melemparitem
Kamu pikir kamu bisa memanfaatkan kemampuan Golem
secara kreatif. Crane bisa digunakan jika lever nya ditekan,
jadi Golem
bisa menonjok lever itu untuk menjalankan crane. Untuk menghitung barang, kamu akan meminta golem untuk
membedakan setiap barang dalam inventori satu per satu untuk kemudian mencatat hasilnya. Terakhir, lemparan Golem
sangat kuat dan akurat sehingga dia bisa melemparkan barang hingga ke tujuan tanpa bantuan transporter (kamu mengetahui
hal ini setelah menyuruhnya melempar beberapa barang aneh ke kubikel Buulyen–seperti gumpalan kertas dan sampah ringan
di sekitar meja kerjamu).
Sebuah Fluid
bisa melakukan empat empat macam aksi, yaitu:
pushItem(item, direction)
: Mendorongitem
ke arahdirection
splitBy(inventory, item)
: Membelah diri setiap kali ia melihatitem
padainventory
merge()
: Menggabungkan kembali fluid yang telah membelah diri menjadi satushapeShift(shape)
: Menjelma diri menjadishape
Fluid
tidak bisa melakukan satupun dari aksi yang diharuskan. Solusi untuk mengakali yang ini lebih rumit. Kamu
pikir, Fluid
bisa mengangkat sebuah barang dengan cara mendorongnya ke atas, efeknya akan sama. Sebuah Fluid
pada
dasarnya tidak bisa berhitung, tetapi ia tahu berapa kali ia telah membelah diri. Kamu tidak perlu menghitung
belahan Fluid
secara manual karena ia akan memberitahumu berapa kali ia telah membelah diri dalam bilangan binary.
Kamu ragu orang-orang di Witchcraft Research Department mengetahui apa-apa tentang binary, jadi kamu harus melakukan
sesuatu tentang itu. Selain itu, Fluid
tidak bisa mengoperasikan crane maupun transporter, tetapi dia bisa menjelma
jadi peralatan yang pernah dilihatnya dan menangani barang sebagai peralatan yang ditirunya. Terakhir, kamu menemukan
bahwa Fluid
tidak bisa melakukan pekerjaan lain dalam bentuk sudah terbelah sehingga perlu menyatukan diri seperti
semula sebelum mengerjakan aksi selanjutnya.
Selesai melakukan pengamatan pada automata di kubikelmu, kamu bersyukur kamu bukan seorang Overseer yang akan mengawasi para automata ini di lapangan. Terutama dengan banyaknya barang yang harus ditangani di Dungeon of Abundance, Overseer yang kebagian nasib buruk itu pasti akan pegal linu. Kamu berpikir untuk melakukan tindakan preventif dengan memastikan semua aktivitas automata tercatat dengan baik. Ini akan menyelamatkanmu dari kerja lembur lainnya jika Nuule mendapatkan keluhan apapun dari para pekerja lapangan.
Kamu kemudian menggulung lengan baju dan meregangkan tangan, bersiap untuk bekerja. Salah satu design pattern yang kamu pelajari terbersit di pikiranmu karena cocok sekali diterapkan untuk proyek ini. Kamu mulai menerapkan pattern tersebut untuk mencegah perusahaan merugi.
Tasks
- Membaca dokumen dan memahami deskripsi dan ekspektasi yang diminta soal
- Melengkapi setiap class yang ditandai
TODO
- Mengimplementasikan design pattern yang tepat dan melengkapi service, controller, dan template agar program dapat digunakan melalui interface web
- Melengapi implementasi fitur
Log
sehingga seluruh rutinitas automata bisa terekam - Membuat test case untuk setiap method yang dilengkapi / dibuat
In Another World, working and simping Using Spring Boot
"Minggu depan anda anda akan bekerja langsung dengan Izumi Sakura untuk sebuah aplikasi perayaan 1 tahun debutnya. Apa anda bersedia?"
Pak Potter berada di depan anda yang sedang beristirahat di pojok ruangan, tersenyum. Tidak biasanya dia memperlihatkan batang hidungnya pada jam istirahat seperti ini. Untuk beberapa saat anda tidak menyadari apa tawaran yang diberikan oleh atasan anda itu. Anda masih dalam lamunan siang saat ini, mencoba benar-benar mengistirahatkan pikiran anda. Namun, saat menydari apa yang ditawarkan oleh Pak Potter, anda tidak dapat menyembunyikan ekspresi wajah anda. Pertanyaan untuk basa basi yang tidak perlu. Bagaimana pun atasan anda sudah mengetahui jawaban anda sebelum menanyakan hal tersebut.
"Tentu saja!" jawab anda singkat. Tawaran yang mudah untuk anda terima tentu saja. Bagaimana pun Izumi Sakura adalah alasan utama anda bekerja pada perusahaan ini.
6 bulan yang lalu anda meninggalkan pekerjaan anda di sebuah perusahaan finance ternama untuk bekerja pada sebuah agensi VTuber. Tentu saja orang-orang melihat keputusan ini sangat konyol. Gaji besar, manfaat banyak, dan terdengar prestisius jika anda boleh berbangga setiap ada yang bertanya dimana anda bekerja. Perusahaan ini begitu besar sampai orang-orang menjulukinya Top Global. Namun, dengan semua hal tersebut anda tetap memilih untuk bekerja di sebuah agensi VTuber. Perusahaannya memang sedang naik daun dengan banyaknya orang yang ingin masuk setiap kali mereka membuka lowongan untuk gen baru. Hanya saja bagaimana pun menjelaskan bahwa anda bekerja pada perusahaan finance tentu lebih mudah daripada di sebuah agensi VTuber. Terlebih, masih banyak orang yang merendahkan kehadiran VTuber itu sendiri.
Sebuah entitas yang ada, tapi tidak ada. Mereka nyata, tapi secara bersamaan tidak nyata. Seolah kehadiran mereka layaknya hantu yang gentayangan. Di balik avatar yang lucu dan keren itu, wajah apa yang mereka simpan? Bagaimana perasaan mereka untuk terus menerus menjadi seseorang yang bukan dirinya? Dan juga, apa mereka tidak sakit? Apa mereka tidak pedih? Apakah mereka tidak takut suara mereka tidak terdengar? Sementara orang-orang terus merendahkan profesi mereka. Itu hanya sebuah fakta menyedihkan yang anda sendiri tidak bisa menerimanya. Karena untuk diri anda sendiri...anda hanya bisa melihat mereka sebagai orang yang sangat anda hormati dengan semua tekanan yang mereka hadapi. Namun, hingga saat itu anda hanya terus melihat mereka sebagai seseorang yang anda hormati dan pandang dari jauh. Setidaknya hingga saat itu.
Sebuah agensi VTuber yang anda ikuti membuka lowongan untuk software engineer. Bagi anda ini adalah kesempatan. Mungkin ini adalah waktu bagi anda untuk bisa mendukung mereka, walau dibalik layar. Bahkan lebih baik, anda juga dibayar. Mendapatkan uang sekaligus mendukung mereka? Ini bukanlah keputusan sulit. Dengan begitu, anda tanpa ragu meninggalkan kehidupan anda saat ini.
【1 YEAR ANNIVERSARY】Giveaway
Promo Code Machine (Problem 1)
Tawaran yang diberikan Pak Potter dengan mudah anda terima. Ini adalah keputusan mudah, begitu yang anda terus bayangkan sejak minggu lalu. Jika pekerjaan biasa anda bisa selesaikan dengan baik, apalagi pekerjaan yang diberikan langsung oleh VTuber kesayangan anda. Itu yang anda rasakan hingga anda menyadari akan bertemu dengan Izumi Sakura secara langsung.
Tentu saja anda sudah mengetahui 'wajah asli' dari Izumi Sakura. Anda sudah bekerja selama 6 bulan di perusahaan ini dan terus mendukungnya dari balik layar. Anda juga sudah biasa mendengarkan suaranya dari stream atau pun saat menguping rapat para talent sebelum Pak Potter menyeret anda menjauh dari ruang rapat. Namun, membayangkan dia akan langsung bicara dengan anda adalah masalah yang sama sekali berbeda.
Dari tadi anda terus duduk tidak tenang di ruangan rapat ini. Kaki dihentakkan, tangan yang terus menerus gemetaran, dan mata yang terus bolak-balik melihat ke arah pintu. Jantung anda juga tidak mau bekerja sama dan semakin memperburuk keadaan yang menurut anda sudah cukup buruk. Bagaimana kalau dia membenciku? Bagaimana kalau aku salah bicara? Pertanyaan-pertanyaan konyol mulai silih berganti menggentayangi pikiran anda. Lalu semuanya berubah dari buruk menjadi sangat buruk ketika anda mendengar suara pintu dibuka.
"Selamat siang.." Anda mendengar suara yang sangat familiar buat anda. Suara yang terus anda dengar dari FuTube tentu saja anda tahu. Dari dulu anda berpikir anda akan senang jika bisa mendengarkannya langsung, bukan melalui pengeras suara gawai anda. Tapi, sepertinya saat ini bukan itu yang anda rasakan. "Tidak", tolak anda dalam hati, "itu juga tidak tepat." Anda merasa terlalu senang hingga reaksi anda seperti ini. Itu adalah jawaban paling logis yang anda dapatkan. Ketika anda puas dengan penjelasan tersebut, anda berhasil mengendalikan tubuh anda kembali.
"Selamat siang" jawab anda. Anda sudah biasa menghadapi klien dengan posisi tinggi. Bertahun-tahun sebagai seorang professional anda telah bertemu dengan berbagai macam klien dengan berbagai posisi. Tekanan seperti ini sudah biasa anda hadapi.
"Mungkin Pak Potter sudah memberitahumu, aku Izumi Sakura. Setidaknya orang dibaliknya..Salam kenal." Ia tersenyum. Meskipun ia bukan Izumi Sakura yang biasa anda lihat menggunakan model VTuber nya, ia tetaplah Izuma Sakura. Kepercayaan diri yang sudah susah payah anda bentuk 10 menit terakhir hilang begitu saja saat menyadari lawan bicara anda bukan klien seperti yang biasa anda hadapi.
Tidak, aku naif. Aku belum pernah menghadapi tekanan seperti ini.... Klien anda memang bukan petinggi perusahaan besar yang sudah menjadi makanan sehari-hari anda pada perusahaan lama anda. Bukan juga pejabat tinggi kerajaan yang anda hadapi untuk menyelesaikan proyek pemerintahaan. Yang ada dihadapan adalah Izumi Sakura sendiri, orang yang selama ini anda dukung karena usaha dan kerja kerasnya walau respon kebanyakan orang belum sepenuhnya positif. Menyadari hal tersebut, rasa panik anda kembali.
Izumi Sakura masih tersenyum di hadapan anda dengan ceria. Di sampingnya manajernya dan Pak Potter juga ikut memasuki ruangan sambil berbincang kecil. Gelak tawa juga beberapa terdengar dari obrolan santai mereka. Ini bukan sesuatu yang biasa anda hadapi di perusahaan lama anda. Tidak ada gelak tawa atau bahkan sekedar obrolan kecil. Kalau ada pun hanya sebuah basa basi. Suasana sebelum rapat dengan klien yang santai seperti ini adalah barang baru buat anda.
"Apakah kamu baik-baik saja?" Entah karena anda lama tidak menjawab sapaannya atau ia menyadari wajah tegang anda, Izumi Sakura melempar pertanyaan kepada anda. Anda menyadari betapa dekatnya anda dengan seorang Izumi Sakura saat ini. Anda yakin jika ada fans yang tahu apa yang terjadi hari ini, nyawa anda tidak akan bertahan lama di luar sana. Menyadari ia telah memanggil anda dua kali, anda lalu memperkenalkan diri.
"Tolong panggil aku Sakura saja." Sakura tertawa kecil mendengar formalitas anda. Pembawaannya begitu santai dan bersahabat. Ia bahkan sempat berbincang beberapa hal remeh dengan anda sebelum manajernya menepuk pundaknya dan menariknya ke bagian lain dari meja untuk memulai rapat.
Beberapa menit terakhir cukup menggelitik anda. Pengalaman professional anda menghadapi beberapa pejabat tinggi kerajaan dan orang-orang penting dari perusahaan lain seolah menguap begitu saja. Entah karena anda tidak memiliki perasaan apa-apa dengan orang-orang tersebut selain klien atau entah karena keadaan santai yang dibawa oleh perusahaan anda saat ini adalah hal baru.
"Seperti yang sudah diberitahukan sebelumnya, kami menginginkan sebuah situs web untuk perayaan 1 tahun debut Izumi Sakura." Manajer Izumi sakura memulai pembicaraan. Ia membuka sebuah desain antarmuka yang telah dibuat sebelumnya. " Pada dasarnya web ini akan digunakan untuk melakukan giveaway sebagai perayaan 1st anniversarry dari Izumi Sakura"
Sakura setelah diberi gestur oleh manajernya, lalu berdiri di samping manajernya. "Kami mengharapkan web ini dapat generasi kode promo dan giveaway secara otomatis untuk beberapa merch yang akan ditawarkan. Selain itu, juga dapat digunakan untuk premium membership di FuTube" terang Sakura memulai penjelasan.
"Sebelumnya kita sudah membuat sebuah marketplace dimana viewer dapat membeli merch dari talent agensi kita seperti baju, mousepad, dll. Viewer dapat menggunakan kode promo untuk diklaim pada marketplace tersebut" Pak Potter sepertinya melihat wajah anda yang terlihat mulai bingung dan mengingatkan anda terhadap aplikasi yang sudah dikembangkan lama.
Penjelasan itu cukup untuk membukakan ide buat anda."Jadi pada dasarnya web ini untuk mengautomasi pembuatan kode promo yang telah dibuat secara manual selama ini?"
Sakura menganggukkan kepala. "Kode promo ini dapat diaplikasikan pada merch dan membership. Nantinya aku juga berencana untuk menambahkan kode promo dan giveaway untuk voice pack. "
Anda lalu berbisik. "Berarti kode promonya ini dapat dibuat secara automatis ataupun custom ya." tanya anda pada Pak Potter di samping anda.
"Sepertinya begitu." jawabnya singkat.
Sembari mendengar penjelasan tersebut, anda mulai membayangkan desain dari aplikasi tersebut. Kode tersebut memiliki beberapa jenis. Setiap jenis sepertinya memiliki kemiripan karakteristik berupa kemampuan untuk digunakan pada promo merch dan giveaway. Selain itu, ada kebutuhan untuk dapat menambahkan tipe kode baru nantinya. Berati sebaiknya desainnya adalah ketika ada jenis redeem code baru, tidak ada perubahan pada yang sudah ada. Sepertinya begitu.
"Apakah ada kebutuhan lain?" Anda sudah mendapatkan sebuah desain, tapi anda ingin memastikan hal lain.
"Tidak ada. Aku rasa cukup" Sakura menjawab dengan ceria. Entah kenapa anda merasa sepertinya ia sadar anda telah menemukan solusi dari aplikasi yang ia inginkan. Seolah ia dapat membaca anda layaknya buku.
"Kalau begitu kami izin dulu. Maaf mengganggu waktu kerjanya. " Sakura lalu keluar ruangan. Ia sempat melambaikan tangan sambil tersenyum ke arah anda. Anda merasakan kehangatan melihat sikapnya. Ramah dan bersahabat. Bagian dari karakternya itu tidaklah palsu. Mengetahui hal tersebut anda merasa lega dan tanpa sadar tersenyum. Anda tidak ingin mengkhianati kerja keras yang sudah dilakukan Izumi Sakura selama ini.
Pak Potter tiba-tiba menepuk pundak anda, mengembalikan anda ke kenyataan. "Sampai kapan kau akan tersenyum-senyum di sana? Ayo kembali bekerja. "
Anda lalu melirik lirih ke Pak Potter. Pak Potter awalnya hanya hanya hening tak merespon lalu tersenyum usil. "Menyerahlah, dia terlalu di atas kelasmu." goda Pak Potter.
"Sudah kubilang bukan seperti itu"
"Seperti apa? Aku tidak bilang apa-apa menyerah tentang apa?"
Muka anda semakin memerah karena godaan Pak Potter. Dalam perjalanan kembali ke ruangan kerja anda terus berdebat tidak kenal akhir dengan Pak Potter mengenai hal tidak jelas hingga kalian akhirnya lelah dan memutuskan untuk kembali diam.
Multiple Claims (Problem 2)
Anda menatap jauh ke jendela pada senja itu. Hujan deras masih mengguyur jalanan yang menyepi, berlindung dari terkaman air yang tidak kenal kasihan. Dalam diri anda, masih ada sejumlah pertanyaan yang terus menerus dilempar hanya untuk tidak terjawab pada akhirnya. Anda terus menerus mempertanyakan sesuatu yang mungkin anda tidak paham apa maknanya. Kenapa ia ada? Apa mungkin karena ini adalah representasi dari kegusaran yang menggerogoti anda? Begitu jawaban itu muncul, kehadirannya anda tolak begitu saja. Anda tidak puas dengan hal tersebut.
Anda lalu mencoba mengintip sekilas ke arah monitor anda, mungkin berharap ada suatu yang lain yang akan diperlihatkan. Harapan hampa tentu saja. Menatap rintikan air pada luar jendela sembari memikirkan sesuatu layaknya seorang filsuf tidak akan membuat anda menjadi filsuf. Bahkan filsuf tidak akan mampu menyelesaikan masalah pada layar anda. Ini terlalu jauh buat mereka.
Dari siang anda terus menerus mencari tahu apa yang salah dengan program yang anda buat untuk Izumi Sakura. Proses generasi kodenya berjalan sempurna. Anda juga yakin kualitas kode nya tidak kalah baik. Hanya saja sesuatu yang anda pikir menjadi suatu perkara yang perlu anda selesaikan ternyata benar terjadi.
Anda sedang mencoba program tersebut dari sisi pengguna. Dari dua tab dari browser anda, anda berusaha mencoba melakukan sebuah klaim kode yang sama dengan waktu tidak jauh berbeda. Seharusnya program anda sudah menghalangi hal kemungkinan klaim kode yang sama. Namun, apa yang anda lihat saat ini membuktikan sebaliknya. Tidak terbayang oleh anda berapa kerugian perusahaan dan mungkin juga mempermalukan seorang Izumi Sakura sendiri karena masalah ini. Tentu anda tidak mau melihat itu semua. Apakah mungkin masalahnya bukan pada logikanya tapi dari sisi prosesnya sendiri? Masuk akal, pikir anda. Prosesnya ditangani secara paralel. Tentu saja setiap proses berpikir mereka belum mengklaim kode yang dimaksud. Setelah diam beberapa saat anda baru sadar akan kemungkinan ini.
"Sampai kapan kau akan menatap jendela? Pekerjaanmu tidak akan selesai dengan sendirinya." Suara Pak Potter menggema dari pintu masuk ruangan. Ia membawa payung ditangan kirinya dan bahkan sudah mengenakan jas hujan. "Cepat selesaikan dan pulanglah." Suaranya kini sedikit melunak, memelas. Ia terdengar seperti pengawas ujian yang tidak sabar menunggu satu peserta yang tak kunjung mengumpulkan jawaban.
Seolah tidak mengindahkan ajakannya anda lalu mulai mengetikkan sesuatu dari proses berpikir panjang yang telah anda lakukan.
"Aku baru saja kembali dari perjalanan panjang Pak Potter." Pak Potter terdengar bingung. Anda tidak dapat melihat wajahnya, tapi anda sudah membayangkan ekspresi apa yang akan dia pasang. "Jika ada dua dunia paralel, apakah kemungkinan akan ada dua jiwa manusia yang sama?" Setelah melemparkan penyataan aneh, sekarang anda melemparkan pertanyaan yang tidak kalah anehnya. "Jawabannya, tidak. Surga selalu membuat manusia yang berbeda meski pada dua dunia paralel sekali pun."
"Apa yang kau bicarakan? Cepatlah selesaikan dan pulang. Kau tahu ini sudah hampir jam 7 malam. " Langkah kaki Pak Potter terdengar menjauh dari telinga anda. Sepertinya Pak tua itu tidak mau terlibat lebih jauh dengan pembicaraan anda. Pak tua Potter yang malang. Mungkin juga sekedar tidak rela melihat uang lembur diberikan kepada pegawai tidak jelas yang dari siang terus menerus berdebat dengan cerminannya sendiri ditemani derasnya hujan. Tapi, bagaimana pun sekarang anda telah menemukan jawbannya.
Flow pekerjaan
Terdapat dua URL endpoint berbeda yang dapat diakses oleh pengguna. Endpoint pertama merupakan endpoint yang digunakan Izumi Sakura dan pihak agensi untuk melakukan generasi code. Endpoint kedua merupakan endpoint yang dapat diakses viewer untuk melakukan redeem code tersebut.
Ekspektasi produk akhir
-
Tampilan code generator
-
Tampilan generasi code
-
Tampilan generasi custom code
-
Tampilan generasi redeem code
-
Tampilan generasi redeem code
Penjelasan kode
- Lombok merupakan sebuah java library yang dapat membantu kita dalam mengurangi infrastructural code seperti getter, setter dan constructor.
- DTO merupakan singkatan dari Data Transfer Object yang merupakan object yang mengangkut data dari suatu proses.
- Anotasi "Data" merupakan anotasi milik lombok dimana class yang ditandai anotasi tersebut akan secara implisit ditambahkan infrastructural code seperti getter dan setter
- Anotasi "RequiredArgsConstructor" merupakan anotasi milik lombok untuk melakukan instansiasi atribut dari suatu class yang memiliki modifier final. (Mirip seperti autowired)
- RedeemCodeUtil digunakan untuk menghasilkan redeem code string sebanyak 18 karakter dari karakter alfanumerik. Anda dapat membuat implementasi generasi redeem code anda sendiri.
Penjelasan lebih lanjut dapat dicek di https://projectlombok.org/features/all
Tasks
- Membaca dokumen dan memahami deskripsi dan ekspektasi yang diminta soal
- Melengkapi setiap class yang ditandai
TODO
dan manambahkan class baru jika diperlukan - Mengimplementasikan design pattern yang tepat dan melengkapi service, controller, dan template agar program dapat digunakan melalui interface web
- Melengapi implementasi fitur
Code Generation
, sehingga giveaway dapat dilakukan - Melengapi implementasi fitur
Redeem
yang dapat menangani kasus permasalahan yang ada pada problem kedua - Membuat test case untuk setiap method yang dilengkapi / dibuat
Hint
- Untuk mendapatkan nilai penuh, buatlah code yang maintainable. Yakni, perubahan kode minimal jika ada suatu penambahan fitur seperti penambahan tipe kupon tersebut selain membership dan merch.
Bonus: Code Coverage
- Buat Code Coverage di atas 80% total.
- Tampilkan Code Coverage pada README.md anda.
Cara untuk Meningkatkan Literasi yang Baik dan Benar
Perulangan 1
Anda duduk sendirian di meja anda. Siang itu matahari bersinar begitu terik, membuat udara luar begitu menyengat. Membayangkan betapa tidak menyenangkan berada di luar, anda memutuskan tetap di kantor dan menyantap makanan mahal dari kafetaria yang tidak begitu enak itu.
Anda melihat ke sekitar. Beberapa meja berantakan yang ditinggal oleh pemiliknya. Mungkin tidak semua. Meja Emory terlihat tetap rapi. Setidaknya membuat anda tahu harus melihat ke mana saat anda bosan melihat ke luar jendela.
"Selamat siang." Seseorang memanggil anda. Anda langsung menoleh pada sumber suara. Seorang gadis seumuran anda berdiri di sana dan tersenyum. Senyuman begitu berkilau hingga anda merasa sedikit takut. Senyuman itu terlihat tidak layaknya manusia, seolah mengingatkan anda pada sesuatu yang tidak ingin anda ingat, tapi anda tidak tahu apa.
"Namaku Alice." Seolah menebak isi pikiran anda, gadis itu memperkenalkan dirinya. Ia begitu mencolok. Entah karena kecantikannya atau gaun gothic loli yang ia kenakan, anda tidak yakin. Yang pasti seorang yang seperti dirinya tidak mungkin tanpa keinginan tertentu. Mengetahui itu anda membalas sapaannya dengan kehati-hatian.
Kehadirannya begitu kuat. Lampu di sekitar Alice terus berkedip-kedip. Semua komputer juga terlihat memperlihatkan layar blue screen. Anda bisa terus menghitung kejadian yang terlihat horor ini sepanjang hari tapi itu tidak akan membantu anda. Anda tidak perlu menjadi seorang penyihir handal untuk tahu bahwa entitas di depan anda ini sangat berbahaya. Sebelum sempat bereaksi, Alice terlihat seperti merapalkan sebuah mantra di depan anda, menghilangkan kesadaran anda.
Perulangan 2
Anda melihat puas setelah keluar dari ruangan atasan anda. Beberapa proyek yang diserahkan kepada anda semua berakhir dengan kesuksean. Mungkin anda dapat berbicara banyak saat ini. Mengenai aplikasi yang dapat mengirimkan barang ke berbagai tempat dengan efektif dan efisien. Atau aplikasi yang dapat mengamati berbagai rute dan keberadaan makluk berbahaya tidak terundang. Mungkin juga mengenai aplikasi pernakan alat sihir dan software engineering. Banyak yang bisa anda bicarakan mengenai itu semua. Namun, waktu tidak memberikan anda kesempatan untuk terlalu lama bersantai. Ada beberapa perkerjaan yang ingin anda selesaikan. Bagaimana pun anda tidak ingin kesuksesan kecil ini merusak reputasi anda.
Perulangan 11
"Sekarang ide bodoh apa lagi yang mereka inginkan? " Buulyen mengeluh di depan anda. Anda tidak terlalu menghiraukannya dan berharap ia cepat pergi. Anda tidak ingin terjebak dalam kekacauan yang bukan menjadi tugas anda lagi. Dengen kebesaran Omegaware Ltd, jumlah sektor bisnis mereka terus berkembang dan tentu saja ide liar akan terus berdatangan.
"Oh ternyata kau di sana." Suara Nuule bergema dari jauh. Keadaan yang tidak ideal menurut anda. Syukurnya ia ingin bertemu dengan Buulyen. Anda lalu memutuskan melarikan diri dari ruangan untuk menghindari masalah.
Perulangan 69
"Apa kau pernah berpikir untuk kembali ke rumah?" Pertanyaan itu bukan sesuatu yang anda pikir akan keluar dari mulut seorang Izumi Sakura. Apa yang ia maksud dengan rumah? Jawaban yang anda harapkan lalu datang tidak lama kemudian.
"Maksudku, dunia asal kita. Aku tahu kau juga datang dari dunia lain." Izumi Sakura masih mempertahankan senyumannya saat mengatakan sesuatu yang anda tahu bukan hanya sensitif tapi juga berisiko. Senyumannya sangat berbeda dari biasanya. Ini bukan senyuman penuh gairah dan semangat. Ini adalah senyum penuh kepedihan dan mungkin rasa sepi. Seolah tahu hujaman pertanyaan muncul di kepala anda, Sakura memperjelas maksudnya. "Jika kau dikirim untuk menjadi software engineer, aku kemari untuk menjadi seorang VTuber."
Pernyataan itu mengejutkan anda. Mungkin pernah terlintas di kepala anda mengenai kemungkinan itu. Bagaimana jika ada orang lain yang dikirim ke dunia ini seperti anda tapi dengan profesi lain? Kemungkinan itu sudah terpikirkan oleh anda, tapi tidak pernah bahkan dalam mimpi terliar anda untuk membayangkan seseorang itu dikirim untuk menjadi VTuber. Fakta bahwa orang tersebut adalah Izumi Sakura hanya semakin memperparah keadaan.
"Aku selalu ingin menjadi VTuber. Tapi, aku tidak pernah berhasil menembus audisi. Sampai suatu hari aku bertemu dengan seseorang misterius yang menawarkanku untuk menjadi VTuber di dunia lain. Aneh bukan?" Suara Izumi Sakura terdengar semakin pelan. Ia mungkin menyimpan jutaan emosi dan tidak tahu harus bercerita pada siapa.
"Maaf telah membicarakan hal aneh. " Saat anda ingin memberikan jawaban Sakura memotong anda. "Kau tidak perlu menjawabnya. Aku senang setidaknya aku punya orang untuk bicara mengenai hal ini. Tolong jangan beritahu siapapun ya" Izumi Sakura meletakkan jari telunjuknya pada mulut anda sambil tertawa kecil. Pada keadaan normal anda akan merasakan kebahagian. Dalam keadaan ini yang anda bayangkan hanya beban mental seperti apa yang dimiliki olehnya. Anda tidak bisa berbuat apa-apa. Jika itu keinginannya, anda hanya dapat menerimanya.
Perulangan 1
Anda perlahan membuka mata anda. Jam dinding memperlihatkan pukul 1 kurang 15 menit. Anda tidak mengingat apa yang terjadi dalam beberapa menit terakhir. Lalu anda merasakan seseorang sedang menusuk pipi anda dengan telunjuknya.
"Cepat bangun dan ikut aku." Emory seperti biasa berkomentar dengan cukup dingin. Tanpa memberikan penjelasan lebih lanjut ia pergi begitu saja dan membuat anda harus setengah berlari untuk mengejarnya.
"Ada klien dari Frostwatch. " ujar Emory yang lalu diam, membuat anda terus berharap ada kelanjutan dari pernyataan tersebut.Tapi ini adalah Emory yang kita bicarakan. Sangat aneh jika ia memberikan penjelasan lebih lanjut tanpa ditanya.
Frostwatch adalah sebuah kota beriklim dingin di pusat Tidaholm, sebuah benua utara. Kota terletak cukup strategis tapi dari apa yang anda dengar cukup tertinggal mengenai teknologi. Mendengar bahwa ada seseorang dari Frostwatch ingin membuat aplikasi tidak pernah terpintas di pikiran anda.
Diskusi antara perusahaan anda dengan delegasi sebuah perusahaan di Frostwatch berlangsung cukup lancar, tapi penuh dengan pembiaraan yang membuat bulu kuduk anda merinding. Ini kali pertama anda berbicara dengan seseorang dari benua utara dan dalam 20 menit diskusi anda langsung berharap tidak bertemu dengan mereka lagi.
"Jadi begitu ide aplikasi yang kami harapkan. Pada dasarnya kami ingin sebuah situs portal berita. Kami merasa orang-orang di Frostwatch masih kurang mendapatkan akses ke informasi. Jadi dengan situs ini kami berharap akses terhadap isu-isu terkini lebih mudah didapatkan. Sumber beritanya didapatkan dari berbagai pengunjung Frostwatch. Penulisnya sendiri kami berencana akan membuka lowongan melalui oprec. Nanti kami akan membuatkan akun untuk penulis-penulis agar mereka dapat mengolah artikel-artikel mereka sendiri. "
Delegasi itu terus menjelaskan harapan aplikasi yang mereka inginkan. Ia membahas bagaimana setiap artikel akan memiliki kategori tertentu. Sejauh ini tidak ada yang aneh dari diskusi yang sedang anda lakukan. Delegasi juga menjelaskan untuk prototipe awal sistem mereka hanya mengharapkan sistem yang simpel terlebih dahulu. Tidak perlu sistem autentikasi untuk sistem awal ini, tapi masih perlu ada informasi mengenai siapa penulis artikel sebagai salah satu field pada basis data sistem ini. Ini dapat dilakukan dengan mudah dengan menambahkan id penulis sebagai salah satu field JSON request. Anda juga sudah membayangkan apa saja yang perlu ada dalam sebuah artikel. Sebuah artikel berisikan judul, isi, waktu artikel tersebut dibuat dan waktu di-update. Hingga saat ini hanya ada pembahasan requirement biasa dari klien anda. Tapi, pembahasan selanjutnya yang menjadi masalah.
"Kami juga ingin kategori ini sespesifik mungkin." Salah satu delegasi yang lain memotong pembicaraan. Wajah delegasi yang dipotong memperlihatkan ketidaksukaan. Namun, ia seperti mencoba bersabar dan membiarkan delegasi lain tersebut berbicara.
"Misalkan kita bisa saja memiliki kategori khusus seperti 'perang dunia', 'perang Gothia Raya', dan 'perang nuklir'.Lalu--"
"Tunggu Rico, ini bukan yang kita bicarakan sebelumnya. " Delegasi yang sepertinya merupakan juru bicara Frostwatch memotong balik delagasi yang sepertinya bernama Rico tadi. "Aku rasa kategori 'perang' cukup untuk menjelaskan semua hal tersebut."
"Tidak, itu akan menjadi tidak menarik Franco." Desis Rico balik. "Jika kita kategorikan sebagai 'perang' saja nanti bisa saja ada kategori seperti 'perang cinta', 'perang ambassador' dan aku rasa itu tidak akan baik. Orang-orang akan merasa kesal dengan model aplikasi seperti itu karena tidak bisa menemukan kategori yang mereka inginkan dengan cepat. "
"Bukannya itu juga menyulitkan pengguna bukan?" Franco mempercepat tempo bicaranya. Rico hanya memangut kesal karena tidak bisa memotong Franco. Franco lalu melanjutkan: "Akan terlalu banyak kategori, sehingga navigasi akan menjadi sulit.
"Bagaimana kalau ada sebuah artikel yang dapat masuk ke lebih dari satu kategori? Saya merasa benda seperti smartphone dapat masuk ke kategori teknologi dan lifestyle. Akan lebih masuk akal kalau kategorinya spesifik. Kita tidak perlu memikirkan kemungkinan ini! Kalau kita buat kategori terlalu umum, terlalu banyak kemungkinan pada kasus artikel semacam ini."
Franco semakin terlihat kesal. Keduanya lalu terus melanjutkan perdebatan mereka. Anda juga bingung bagaimana mulai memisahkan mereka. Pada akhirnya, anda harus mendengarkan apa yang klien inginkan. Namun, bagaimana anda bisa melakukan itu dengan klien sendiri tidak memiliki opini yang konsisten.
"Bagaimana apabila artikel dapat bisa masuk ke lebih dari satu kategori." Emory memotong pekelahian mereka. Keduanya lalu menatap balik ke Emory. "Jadi smartphone dapat masuk ke kedua kategori seperti yang anda katakan."
Keduanya masih menatap bingung. Anda lalu menyadari bahwa memang mereka berasal dari Frostwatch. Mungkin di kepala mereka pengkategorian pada aplikasi layaknya menyimpan berkas artikel secara fisik pada folder tertentu. Jika dianalogikan seperti itu, solusi Emory tadi dan kekhawatiran Rico masuk akal. Tapi hal yang seperti ini tidak berlaku pada aplikasi dengan sistem basis data relational.
"Hal ini dapat kami implementasikan.Tenang saja, desain ini memungkinkan." tambah anda.
Wajah mereka terlihat lebih melunak, tapi masalah mereka tentu saja belum selesai. Ide Emory memang dapat menyelesaikan kemungkinan ada artikel yang masuk ke lebih dari satu kategori, tapi masalah preferensi yang dari tadi mereka bahas tidak akan selesai dengan solusi tersebut. Tapi, Anda menemukan ide untuk menyelesaikan masalah tersebut.
"Untuk kategori bagaimana jika kita buat ada pembedaan kategori? Jadi ada kategori umum dan kategori-kategori spesifik yang termasuk kategori dalamnya. Kategori-kategori spesifik ini kemudian dijadikan sebuah kelompok. Sebagai contoh, kita bisa membuat kategori umum 'perang', dan di dalamnya ada kategori-kategori yang lebih spesifik seperti 'perang dunia', ' perang gothia raya', dll. Jadi ada dua level dalam pengkategorian sebuah artikel."
Keduanya lalu mundur. Sepertinya solusi itu cukup untuk memuaskan mereka. Rapat lalu berakhir dengan tenang. Sekarang anda tinggal memulai pengembangan.
"Aku serahkan frontend padamu ya."
"Serahkan pada kami." Maya, team lead divisi frontend hanya membalas lirih sebelum akhirnya kembali ke ruangan mereka. Emory lalu menepuk pundak anda.
"Inilah kenapa aku membawamu. Aku yakin kau sudah pernah melihat hal serupa dari 'seberang sana'. Selanjutnya aku ingin kamu membantuku menyelesaikan aplikasi ini."
"Dengan senang hati."
Anda lalu juga kembali ke ruangan bersama Emory untuk memulai pekerjaan. Saat anda akan masuk kembali ke ruangan anda, anda merasakan hawa kehadiran seseorang dari belakang anda. Namun, ketika melihat ke belakang, anda tidak mendapati siapa-siapa. Anda kemudian mencoba tidak mempedulikannya sekarang dan kembali berjalan ke ruangan kerja anda.
"Kita akan bertemu lagi.." Gadis itu terkekeh lalu menghilang dari balik kegelapan.
Penjelasan Kode
Pada tutorial ini deliverablenya tidak berbentuk website, melainkan hanya sebuah REST API. Secara sederhana, setiap endpoint mengeluarkan JSON. Dalam mengerjakan tutorial, ada dua konsep baru yang perlu diketahui, yaitu REST Controller dan JPA Repository. Selain itu, ada Postman untuk membantu menguji aplikasi, dan mekanisme Code Coverage
Rest Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Kita lihat di sini ada @RestController
, sebuah anotasi untuk memungkinkan kapabilitas controller untuk melakukan
operasi-operasi REST. Kedua method postCategory
dan getCategory
menerima dan mengembalikan sebuah JSON. Pada
request, ada yang disebut status code.
Method ResponseEntity.ok()
mengembalikan JSON dengan status 200
(OK), dan ResponseEntity(HttpStatus.NOT_FOUND)
mengembalikan dengan status 404
JPA Repository
Berbeda dengan tutorial-tutorial sebelumnya yang menggunakan tempat penyimpanan simulasi, pada tutorial ini kita mempelajari cara menggunakan database sungguhan. JPA Repository merupakan sebuah * Object-relational Mapping* (ORM) pada spring untuk berinteraksi dengan database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Penjelasan anotasi:
- Anotasi
Entity
danTable()
digunakan untuk memberi tahu bahwa class ini akan disimpan di database. - Anotasi
@Column
memberi tahu nama kolom dari setiap atribut pada database. - Anotasi
@GeneratedValue()
memberi tahu bahwa atribut ini akan diisi secara automatis ketika memasukkan ke database
Untuk membuat repositor sebuah @Entity
, cukup buat bean @Repository
yang extends JpaRepository
1 2 3 4 |
|
Nantinya CategoryRepository
sudah dapat digunakan dengan melakukan @Autowire
ke service-service yang membutuhkan.
Concrete class dari CategoryRepository
di mana? silahkan di eksplorasi secara singkat cara kerja JpaRepository
karena akan menambahkan pemahamanmu.
Konfigurasi JPA repository diatur di berkas resources/application.properties
.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Atribut sprint.datasource
mengatur jenis (PostgreSQL, MongoDB, H2) dan credentials (username, password, nama database)
dari DBMS yang digunakan, sedangkan spring.jpa
mengatur setting khusus JPA. Tutorial ini akan menggunakan database
H2, sebuah database in-memory sederhana untuk tujuan pembelajaran.
Konfigurasi spring.jpa.hibernate.ddl-auto=create
akan mereset ulang database setiap aplikasi dijalankan. Silahkan
melakukan eksplorasi tentang ini jika tertarik, namun pada tutorial 5 anda belum perlu mengubah application.properties
.
Postman
Karena aplikasi yang tidak memiliki web, tentu susah untuk membuat request yang memerlukan data, seperti POST dan
PUT. Postman adalah sebuah software gratis untuk menguji sebuah REST API. Pada Postman anda
dapat mengirimkan request ke aplikasi anda. Postman mendukung segala jenis request, seperti GET
, POST
, PUT
,
dan DELETE
. Mohon eksplorasi cara kerja postman.
Berikut kami sediakan sebuah Postman collection yang dapat kalian import untuk mencoba menggunakan bagian Editor dan Category. Gambar di atas memberikan tampilan postman ketika sudah import collection. Bagian kiri memberikan daftar request yang dapat di kirim. Anda bisa mengedit isi dari data yang di kirim pada bagian body di kanan bawah. Ketika klik send, hasil akan dikembalikan di bagian response.
Code Coverage
Code coverage masuk penilaian tutorial ini. Mohon pasang badge code coverage pada semua branch yang dikerjakan.
Tasks
- Memahami deskripsi soal dan mengimplementasikan pekerjaan-pekerjaan yang diminta.
- Memahami
JpaRepository
danRestController
- Menginstall dan memakai Postman. Kemudian, membuat request baru di postman untuk setiap endpoint baru yang dikerjakan
- Memasang badge code coverage di README tutorial
I... didn't sign up for this.
Kamu bekerja di sebuah perusahaan software house dengan reputasi yang sangat baik melihat sekian banyak proyek yang pernah diselesaikan sebelumnya. Ada beberapa proyek yang masih dikembangkan hingga sekarang, termasuk proyek yang kau kerjakan. Yah, bisa dibilang kau merupakan salah satu developer senior di perusahaanmu.
Begitu juga rekanmu, Vincent. Ia merupakan teman kerja dengan pengalaman yang kurang lebih sama denganmu. Vincent memiliki tanggung jawab di proyek yang berbeda denganmu. Dari Vincent, kamu mendengar banyak cerita mengenai orang-orang yang ia temui dan proyek yang ia kerjakan.
Beberapa minggu yang lalu, Vincent bercerita kepadamu bahwa sekarang ia menjadi mentor bagi beberapa developer baru. Mereka bertanggung jawab terhadap suatu proyek yang baru pula, yaitu membuat sebuah pemutar musik. Proyek ini merupakan sebuah investasi oleh seorang earl yang memanfaatkan bagaimana musik merupakan suatu hal yang disenangi banyak orang dari berbagai kalangan, tetapi selera musik orang berbeda-beda.
Beberapa hari dari sekarang, mereka harus menunjukkan progres pengembangan pemutar musik ini ke klien. Namun, karena Vincent sedang izin menghadiri acara keluarganya di luar kota, maka kamu yang akan menggantikannya untuk sementara waktu. Vincent mengabarimu dengan cukup mendadak pada akhir minggu dan terus terang, itu membuatmu sedikit kesal.
Bayangkan apabila kamu sudah menyelesaikan seluruh task yang perlu dikerjakan, tidak ada tetangga yang berisik, cuaca sesuai dengan mood, tampak seperti semuanya damai dan tidak ada gangguan. Semuanya terlihat bagus, kamu merencanakan untuk menghabiskan hari ini dengan bersantai sejenak. Setidaknya itu yang kamu pikirkan pada pagi hari ini. Namun, di akhir hari, kamu berusaha untuk merelakan harimu yang tidak berjalan sesuai rencana.
Ew, this code smells.
Hari pertama saat kamu bertugas sebagai pengganti Vincent, salah satu hal yang perlu kamu lakukan adalah melakukan code review. Menurut Vincent, task yang perlu dilakukan sudah hampir semuanya selesai, tetapi perlu dilakukan sedikit refactoring. Tanpa membuang waktu, kamu pun membuka code yang sudah ada. Namun, ekspresimu berubah menjadi horor ketika melihat program yang perlu kamu perbaiki.
Teleponmu berdering. Layar menunjukkan bahwa rekanmu meneleponmu. Tanpa ragu, kamu pun mengangkatnya dan disambut dengan suara rekanmu yang menanyakan keadaanmu saat ini.
"Aku pikir kau bilang programnya hanya perlu sedikit refactoring," jawabmu singkat.
"Hm? Memang ada apa dengan programnya?"
"...bau."
Setelah hening selama dua detik, kamu mendengar ledakan tawa dari seberang telepon. "Banyak code smell, ya?", sambil bernada sedikit tertawa rekanmu melanjutkan, "Maaf merepotkan, ya. Menurut beberapa rekan kerja kita, sepertinya beberapa proyek sudah menggunakan SonarQube. Coba kau gunakan juga, pasti membantu."
"Hah? Apa lagi itu? Terdengar seperti menambah pekerjaan saja."
"SonarQube itu sebuah tool yang membantumu meningkatkan software quality. Namun, perlu diingat bahwa SonarQube tidak dapat menilai efisiensi dan design pattern yang kamu pakai, sehingga kamu perlu mencari tahu sendiri code smell pada bagian tersebut. Tapi kau coba saja dulu, hal itu akan membantumu dalam merapikan code yang masih bau."
"Hooo... begitu. Baiklah, akan kucoba. Ngomong-ngomong, ini belum di-deploy ya? Apa aku harus men-deploy-nya juga?"
"Ya, tentu saja. Aku yakin kamu sudah tahu apa yang perlu kamu lakukan dan bagaimana caranya, bukan?"
Tentu saja! Kamu adalah developer yang berpengalaman, deployment bukan lagi hal yang asing bagimu. Dengan semangat, kamu pun meyakinkan Vincent soal itu.
"Oh oke, lalu..", belum selesai kamu berbicara, rekanmu berbicara kembali dengan nada buru-buru.
"Maaf, aku tahu kamu memiliki banyak pertanyaan, namun sekarang aku dipanggil ibuku untuk berpergian kembali. Saran dariku, kamu dapat terlebih dahulu mengecek setiap dokumen tersebut. Di sana telah tersedia langkah per langkah mengenai keperluan kamu. Tidak hanya itu, terkadang klien menyisipkan beberapa hal yang perlu kamu lakukan. Coba saja dicek kembali file-nya. Sampai disini saja ya. Byee!"
Bunyi telepon telah terputus. Kamu pun segera kembali fokus ke hal-hal yang perlu kamu kerjakan.
Checklist
- Refactor code di
PlaylistServiceImpl.java
untuk mengurangi code duplication - Refactor (dipisah) template HTML sebelumnya yang digabung (keindahan frontend tidak dinilai).
- Menjalankan analisis kode menggunakan SonarQube
- Memperbaiki code smell berdasarkan hasil SonarQube
- Men-deploy aplikasi ke Heroku
- Menambahkan link aplikasi di
readme.md
Bonus
- Memakai checkstyle. Kalian bisa menginstall plugin checkstyle di Intellij untuk membantu pengecekan di lokal.
- Install checkstyle di gradle dan ditambahkan sebagai
stage
denganallow_failure: true
di.gitlab-ci.yml
.
Notes
- Pastikan telah terinstall PostgreSQL untuk menjalankan program di localhost dan
application.properties
sudah diubah sesuai kebutuhan - Tidak perlu menambahkan test
Referensi
Tutorial SonarQube
Tutorial Deployment Menggunakan Heroku
Tutorial Gitlab Runner (Opsional)
Concurrency and Asynchronous Programming
Running too slow
Kamu merupakan seorang mahasiswa yang sedang menjalankan magang di Tech Wand. Tech Wand merupakan salah satu platform belanja online yang paling baru saja di-release. Segala jual beli akan dilakukan melalui aplikasi sehingga semua aktivitas akan berjalan menggunakan service yang disediakan oleh Tech Wand.
Kamu ditugaskan ke bagian Payment. Vincent merupakan atasanmu yang bekerja untuk mengawasi dan membantu tugas yang diberikan padamu. Kamu yang tidak paham terkait cara kerja belanja online pun menanyakannya kepada Vincent.
“Vincent, apakah kamu dapat menjelaskan alur pembelian?” tanyamu
“Ya bisa, kamu hanya tinggal memilih barang yang ingin dipesan, memasukan alamat pengiriman dan tinggal melakukan pembayaran secara langsung saat barang sudah kamu terima” jawab Vincent
“Apakah terdapat cara pembayaran lain? Bagaimana jika pembeli tidak memiliki uang cash?” tanyamu
“Mudah sekali, kamu hanya tinggal memilih pembayaran melalui Virtual Account. Jangan lupa bahwa kamu harus membayarnya sesuai dengan tagihan agar barangmu dapat dikirimkan secepatnya.” jawab Vincent
“Baiklah, terima kasih atas jawabannya.” jawabmu
“Untuk hari ini kamu pelajari dulu cara kerja, source code dan tech stack yang ada ya! Mungkin besok atau lusa kita aku akan memberikan tugas padamu.” Hari pertama pun berakhir dengan kamu mempelajari flow aplikasi Tech Wand.
WorkTime
Hari keduamu magang dilaksanakan dari rumah. Tiba-tiba teleponmu berdering, layar menunjukkan bahwa Vincent meneleponmu.
“Halo, untuk hari ini sepertinya kita harus melakukan refactoring secepatnya. Aplikasi ini berjalan terlalu lambat. Pelanggan kita akan kabur jika terus seperti ini. Cepat selesaikan hari ini ya! Ini tugas merupakan tugas pertamamu.” Kata Vincent.
"Halo, Aku sudah mempalajari source code yang ada. Kenapa kita tidak migrasi untuk menggunakan third-party seperti Strip untuk menjamin kecepatan pembayarannya?" tanyamu penasaran.
"Kita membuat sistem pembayaran embedded payment agar kontrol situs dapat lebih mudah." Jawab Vincent.
"Alur logika pembayaran sepertinya lebih mengandalkan API luar ya? di sini terlihat dia memanggil API hari libur, API bank, dan API internal. Pemanggilan API kan bisa lama karena ada faktor latency sehingga jika kita tunggu satu per satu bakal menumpuk" Kata kamu sembari membaca kode.
"Bagaimana jika kita memanggil API-APInya secara paralel?" Lanjut kamu
"Ide bagus. Beban server kita tidak akan ada penambahan yang berarti karena API-API ini dijalankan di server lain nantinya" Balas Vincent
"Baik, sebelumnya, bagaimana mekanisme keamanan situs ini?" kamu bertanya kembali.
"Kita memiliki mekanisme AML yang kuat. Setiap kegiatan user akan dicatat untuk keperluan crosscheck nantinya." Jawab Vincent
"Bagaimana sistem KYC nya?" tanya kamu penasaran
"Karena nomor VA unik, sepertinya KYC belum terlalu diperlukan" balas Vincent.
"Tolong bantu aku untuk memperbaiki situs ini ya. Aku ingin melakukan pengecekan lain terhadap aplikasi ini" terus Vincent. Telponpun ditutup. Kamu segera kembali untuk mengecek code dan mencoba untuk mengerjakan tugasmu.
Tasks
- Membaca dokumen dan memahami deskripsi dan ekspektasi yang diminta soal
- Refactor mekanisme pembayaran sehingga membutuhkan maksimal
5000 ms
- Melakukan refactoring agar pemanggilan APi dapat berjalan optimal
Hint
- Untuk mendapatkan nilai maksimal, hindari menggunakan blocking call seperti
CompletableFuture.get()
. Perhatikan bahwaComplatableFuture.get()
bisa blocking dan bisa tidak tergantung penggunaannya. - Pelajari https://www.baeldung.com/java-completablefuture
Microservices
Asisten Dosen
Kamu adalah seorang mahasiswa di universitas ternama di Indonesia. Disana kamu bukanlah mahasiswa biasa, tetapi mahasiswa yang aktif mengikuti kegiatan di kampus, salah satunya adalah menjadi asisten dosen.
Menjadi asisten dosen di mata kuliah ini sering kali diadakan demo terhadap mahasiswanya karena tiap minggunya selalu diadakan pengambilan nilai tutorial. Karena tiap tahunnya mahasiswa fakultas kamu terus bertambah, berimbas pada semakin banyaknya mahasiswa yang harus melakukan demo setiap minggunya. Hal tersebut membuat para asisten dosen mulai kewalahan untuk mengatur waktu demo dengan mahasiswa.
Beberapa waktu yang lalu, ketika kamu sedang melepas penat di perpustakaan fakultas, salah satu dosen pengajar yaitu Pak Vincent tiba-tiba mendatangi kamu. Ketika itu Pak Vincent menyampaikan persoalan yang dihadapi tersebut ke kamu. Beliau juga menyampaikan ide membuat suatu sistem informasi untuk membantu mengatur jadwal kegiatan demo yang dilakukan asisten dosen dengan mahasiswanya. Kemudian untuk membantunya merealisasikan idenya tersebut, Pak Vincent mengajak kamu menjadi salah satu software engineer yang turut ikut serta mengembangkan aplikasi sistem informasi tersebut, dengan harapan para asisten dosen menjadi terbantu dalam menjadwalkan demo dengan mahasiswanya.
Karena tawaran tersebut cukup menarik dan menjanjikan, kamu pun tertarik untuk menerimanya. Untuk mengetahui informasi lebih detailnya kamu menyampaikan beberapa pertanyaan seputar aplikasi tersebut.
“Pada dasarnya aplikasi ini membantu pihak mahasiswa dan asisten dosen untuk menentukan jadwal demo yang sesuai”
“Jadi nantinya mahasiswa dapat booking jadwal ya Pak? ”
“Yup, nantinya mahasiswa dapat memilih jadwal yang diinginkan yang sesuai dengan waktu available nya asdos bersangkutan”
“Oh baik Pak, berarti ini sistemnya nanti mahasiswa sebagai user dapat menentukan jadwal demo pada waktu yang tersedia, sepertinya cukup mudah untuk diimplementasikan hehehe”
“Eits tunggu dulu, ada yang istimewa dengan aplikasi ini, Disini kita tidak hanya menggunakan satu aplikasi, melainkan menggunakan beberapa aplikasi yang lebih kecil yang saling berkomunikasi satu sama lain."
“Wah, kalau boleh tahu kenapa dibuat seperti itu ya Pak? Bukankah lebih mudah jika kita membuat aplikasi besar menjadi satu kesatuan secara langsung”
“Oh belum tentu. Untuk case seperti aplikasi yang kita buat ini, mengingat banyaknya mahasiswa yang akan menggunakannya, dan juga ada kemungkinan untuk dikembangkan di masa yang akan datang, lebih baik kita membagi aplikasi tersebut menjadi beberapa microservice sehingga antar software menjadi lebih low coupling”
“Ohh seperti itu ya, wah saya jadi nambah ilmu baru nih hehehe, Oh iya Pak, by the way nanti microservicenya ada apa saja ya pak?”
“Disini kita menggunakan 2 service terpisah, yaitu asdos-service sebagai produser yang memberikan data semua asisten dosen beserta jadwal ketersediaannya dan booking-service sebagai tempat kita menyimpan data booking yang dibuat oleh mahasiswa. Nantinya sebelum booking-service membuat booking jadwal, kita harus melakukan validasi terlebih dahulu apakah jadwal yang diminta dapat diterima oleh asisten dosen yang bersangkutan”
“Wah keren banget, btw gimana caranya tuh beberapa aplikasi bisa saling berkomunikasi?”
“Aplikasi ini berhubungan satu sama lain menggunakan protokol HTTP REST, dan juga beberapa package yang sudah disediakan oleh bahasa pemrograman tersebut agar aplikasi yang berbeda bisa saling bertukar data dengan baik”
“Oke baik pak saya sudah cukup terbayang bagaimana aplikasi ini nantinya. Mungkin akan saya coba implementasikan terlebih dahulu ya pak.”
“Kamu nanti tidak usah mengerjakan yang bagian asdos ya, kebetulan untuk asdos-service sudah dikerjakan oleh tim saya, kamu bisa fokus mengerjakan yang booking-service saja”
“Baik pak, nanti bagian apa saja ya yang harus saya kerjakan pak?” “Saya ingin nantinya mahasiswa dapat melihat semua asdos yang tersedia sehingga mereka bisa lihat asdos ini available untuk booking kapan”
“Oke pak, berarti untuk yang ini nanti saya harus memanggil asdos-service yang akan mengembalikan list asdos ya pak?” “Yak, betul sekali. Oh iya jangan lupa nanti mahasiswa bisa melakukan booking melalui aplikasi yang dibuat ya, itu fitur utamanya hehe”
“Kalau tidak salah setelah saya cek tadi pak sudah ada api yang menghandle bagian ini ya pak di asdos-service?”
“Betul, jadi kamu cukup memanggil apinya saja sesuai dengan spesifikasi apinya, dan jangan lupa untuk menyimpan hasil booking di database booking-service yaa”
“Baik pak, saya sudah cukup paham apa saja yang harus saya lakukan”
*Pak vincent yeeted from conversation
Task List
- Membuat booking baru melalui booking-service
- Menampilkan seluruh asdos yang tersedia
- Validasi booking yang dilakukan melalui asdos-service
- Implementasi Eureka Service Discovery (Bonus)
Technical Context
- DO NOT Touch
asdos-service
- Pengerjaan dilakukan hanya pada service
booking-service
danservice-registry
Hint
Rest Template
Untuk berkomunikasi antar service kalian dapat memanfaatkan penggunaan Rest Template. Pertama-tama kalian dapat mendeclare sebuah bean rest template pada root application.
Kemudian pada bagian service kalian instantiate object rest template.
Dari sini kalian dapat melakukan pemanggilan http method melalui object restTemplate
Eureka Service Discovery
Eureka service discovery bertujuan untuk mendaftarkan seluruh service kalian, sehingga setiap service dapat berkomunikasi langsung dengan service lainnya tanpa harus mengetahui lokasi dari service tersebut (port dan domain). Setiap service yang terdaftar di eureka server dapat kalian lihat namanya di list eureka.
Pada tutorial ini sudah disediakan module eureka server, setiap service tinggal dihubungkan saja dengan eureka server. Kalian dapat mengakses dashboard eureka setelah menjalankan servicenya di http://localhost:8761
Dari dashboard kalian dapat melihat instance mana saja yang sudah terhubung ke eureka server, untuk menyambungkan service kalian perlu menginisiasi root application kalian untuk mengizinkan service discovery
Kemudian kalian harus menambahkan config pada application.properties tiap tiap servicenya
- spring.application.name merupakan nama aplikasi yang akan kalian register di eureka
- eureka.instance.hostname adalah host dimana eureka di serve
- eureka.client.service-url.defaultZone merupakan endpoint eureka yang menerima koneksi dari service lain
WorldEnd: What do you do at the end of the world? Are you busy? Will you ~~save us~~ profile your application using Prometheus and Grafana?
Hujan April
" Hari yang indah bukan?"
Komentar itu sama sekali tidak masuk akal buat anda. Anda menolehkan kepala anda ke jendela yang sebenarnya bisa anda lihat dari sudut mata anda, hanya untuk memberikan pertanda ke lawan bicara anda. Anda mendongkol dalam hati. Apa maksudmu hari yang indah? Tidakkah kau melihat hujan lebat di luar sana? Jendela padahal hanya 2 jengkal dari matamu? Dan kita jadi diberikan tugas tambahan karena tidak dapat pulang. Namun, setelah menimbang-nimbang anda memutuskan untuk menyimpan kata-kata tersebut dalam hati. Anda yakin Tracy punya maksud lain.
"Apakah kakak membenci hujan?"
Pertanyaan itu sedikit mengagetkan anda tentunya. Sepertinya junior anda menyadari kekesalan anda mengenai cuaca saat ini yang menghalangi anda untuk segera angkat kaki dari kantor. Tanpa melihat wajahnya lagi anda lalu berjalan menjauh dari jendela dengan langkah sendu.
"Waktu bermain-main sudah selesai, kita masih ada task yang harus diselesaikan." desis anda. Tracy hanya diam beberapa saat, sebelum akhirnya mengikuti anda dari belakang. Anda hanya berharap agar dia berhenti bertanya mengenai hujan. Karena pada dasarnya... anda membencinya untuk suatu alasan jauh dalam relung memori anda. Ini adalah perulangan ke-577890 anda dalam dunia ini. Dunia dimana anda hidup sebagai berbagai orang berbeda. Terkadang anda ingat sesuatu dari perulangan sebelumnya, terkadang mereka menghilang begitu saja. Saat ini anda mengingat semuanya, dari perulanagn sebelumnya. Dari pengetahuan anda mengenai software engineering dan mengenai hujan yang membekas dalam luka hati anda.
Profiling, Prometheus, dan Grafana
"Hmm kakak. " Tracy memanggil anda dan hanya sampai di sana. Ia lalu terdiam dan tidak melanjutkan kata-katanya. Keadaan canggung lalu bertahan beberapa detik hingga Tracy kembali membuka mulutnya. "Maaf membuat kakak harus juga ikut mengerjakan task ini. "
Anda tidak serta merta menjawabnya. Anda terus berjalan ke meja kerja anda sebelum membalas Tracy.
"Apakah kamu pernah memasang Profiler sebelumnya?"
Tracy menggelengkan kepalanya. "Sejujurnya... belum. Aku bahkan baru pertama kali mendengarnya tadi."
Ya Tuhan! Aku harus memulai dari sana? Keadaan anda tidak semakin membaik. Anda benar-benar ingin meninggalkan anak itu sekarang juga. Faktanya, jika anda berada dalam keadaan yang sama pada beberapa perulangan yang lampau, anda akan melakukannya tanpa ragu. Namun, saat ini berbeda. Tidak setelah semua itu terjadi dan membayangkan kapan Tracy akan pulang jika anda tidak membantunya. Anda cukup mengenal Tracy dan sudah pasti junior anda itu tidak akan mau pulang hingga task yang diberikan kepadanya selesai. Mengetahui hal tersebut, anda tidak tega meninggalkannya.
"Apakah sekarang kamu sudah tahu?" Setelah melempar pertanyaan tersebut anda lalu berdoa sekuat tenaga berharap keadaan yang sudah buruk ini tidak menjadi sangat buruk.
"Aku sudah sempat membacanya tadi. Yang aku pahami itu adalah suatu alat yang mengambil berbagai informasi dari aplikasi kita."
"Betul." jawab anda lega. Anda setidaknya tidak harus memanggil nama Tuhan satu kali lagi untuk menjaga kewarasan anda sore itu. "Informasi dari profiler bisa kita gunakan untuk berbagai macam hal. Salah satunya untuk mengambil keputusan mengenai scaling. Selain itu hal sederhana seperti mencari sumber masalah pada performa aplikasi juga dapat dilakukan dengan data yang didapat tadi. Kebetulan perusahaan kita menggunakan Prometheus dan Grafana. "
Anda lalu membuka salah satu aplikasi yang sudah pernah anda pasangi Prometheus. Ada beberapa hal yang anda perhatikan sebelum akhirnya anda mulai menjelaskan apa yang harus tracy lakukan.
"Pertama buka build.gradle
lalu tambahkan dependency implementation 'org.springframework.boot:spring-boot-starter-actuator'
"
"Oke, tambahkan dependency baru ke build dot grigle"
"Gradle..."
"Ah maaf.." Tracy tertawa kecil, lalu berhenti setelah melihat wajah anda yang tidak terkesan dengan reaksinya.
Anda menghela nafas panjang. Anak itu benar-benar tidak punya harapan. Tapi, bagaimana pun anda sudah memilih untuk membantu Tracy.
"Oke, coba refresh Gradle dan buka endpoint /actuator
"
Anda lalu meminta Tracy untuk mengunduh Prometheus.
Pada dasarnya setelah diinstall, Prometheus sudah dapat digunakan pada localhost:9090
.
Namun, agar Prometheus dapat mengambil data dari aplikasi masih ada beberapa tahap yang harus dilakukan:
1. Menambahkan 'io.micrometer:micrometer-registry-prometheus'
dependency pada build.gradle
.
2. Expose metriks endpoint dengan menambahkan management.endpoints.web.exposure.include=*
pada application.properties
Dua langkah ini sebenarnya sudah cukup untuk melihat metriks Prometheus pada /actuator/prometheus
. Namun,
pada keadaan ini Prometheus belum bisa membaca endpoint dari aplikasi Spring Boot. Ada satu langkah lagi yang perlu dilakukan:
- Edit
prometheus.yml
pada folder Prometheus agar endpoint yang dibaca oleh Prometheus menunjuk pada aplikasi Spring Boot. (Cukup gunakan localhost, tidak perlu melakukan deployment pada tutorial ini.)
"Setelah semuanya selesai berarti, kita sudah bisa mengakses metriks melalui Prometheus ya?"
"Betul. Kamu bisa mencoba melakukan query beberapa metriks dasar dari Spring Boot. Coba melakukan
query http_server_requests_count
untuk melihat berapa kali sebuah endpoint dipanggil. Kamu juga bisa mencoba beberapa query
lain yang disedikan oleh Prometheus."
"Kita juga dapat menggunakan Grafana untuk memperlihatkan metriks dari aplikasi. Ada sebuah dashboard bernama JVM Micrometer dashboard yang bisa digunakan untuk menampilkan metriks yang berasal dari Prometheus."
Grafana merupakan
hal selanjutnya yang anda jelaskan kepada Tracy. Grafana pada dasarnya dapat digunakan
untuk menampilkan metriks dengan berbagai preset dashboard untuk melakukan monitoring berbagai
infrastruktur dan arsitektur dari aplikasi.
Biasanya Grafana dapat berjalan pada localhost:3000
dan kita perlu untuk menyetel Grafana agar membaca data source dari
Prometheus.
Setelah login dan mengatur data source, kita dapat membuat panel dan melakukan beberapa query Prometheus yang sudah digunakan sebelumnya.
"Selanjutnya aku ingin kamu mencoba membuat JVM Micrometer Dashboard."
"Eh bagaimana caranya meng-import dashboard ya?"
"Coba perhatikan menu dimana kamu menambahkan panel baru. Di bagian bawahnya ada pilihan untuk import. Pilih dari web Grafana dan masukkan link tadi."
"Ah oke. Lalu pilih data source-nya dari Prometheus?"
"Ya. Gunakan data source yang sudah kamu buat sebelumnya. "
Tracy lalu mengikuti instruksi anda dan perlahan menghilang ke dunianya sendiri. Ia seolah terserap oleh layar komputernya dan mengabaikan sekitarnya. Suara ketikan keyboard dan rintik hujan yang tidak mau mengalah menguasai ruang. Di dalam ruangan yang mulai sepi itu anda hanya duduk menatap junior anda yang kesadarannya entah kemana. Anda lalu menghibur diri dengan membuka halaman Issue untuk membaca apa yang menjadi task Tracy. Task junior anda pada dasarnya sudah selesai. Anda cukup heran kenapa dia masih belum memutuskan untuk pulang. Setelah beberapa menit membiarkan Tracy bekerja anda lalu membuka mulut anda.
"Bukannya task mu sudah selesai?" Anda menatap Tracy lekat-lekat. Anak itu hanya menoleh sedikit.
"Ah. Aku ingin mencoba beberapa hal dengan Grafana. " jawabnya singkat.
"Oh. Bagaimana kalau aku berikan sedikit tantangan? Apa kamu tertarik?"
Tracy mengangguk tegas. Wajahnya sudah lelah dan matanya pun sudah memerah. Tidak perlu bertanya lebih lanjut pun anda sudah tahu dia sangat lelah. Tapi, melihat keinginan belajarnya anda akhirnya memutuskan tetap memberikan satu task tambahan.
"Jika aku lihat aplikasi ini adalah pekerjaan anak magang yang masih bermasalah ya? " Aplikasi yang dikembangkan oleh anak magang pada liburan tahun lalu. Anda belum menjadi 'senior Tracy' pada saat itu dan mungkin sedang melanglang buana ke berbagai tempat pada perulangan lain. Namun, anda memiliki informasi, atau mungkin lebih tepat disebut pengetahuan mengenai ingatan dari si 'senior Tracy' ini.
"Benar. Dari tahun lalu perusahaan tidak mempedulikan aplikasi ini. Namun, setelah melihat aplikasi ini sepertinya mereka memustuskan untuk menggunakan aplikasi itu sebagai kelinci percobaan junior engineer atau mungkin anak magang lainnya."
Aplikasi yang malang. Tapi, tindakan yang tidak salah sama sekali. Low risk, high return. Tidak perlu merisiko kan aplikasi working dan tidak perlu membuat studi kasus kecil bodoh untuk digunakan. Anda lalu mencoba aplikasi tersebut. Setelah beberapa kali akses anda lalu menarik kata-kata anda kembali. Pantas saja mereka tidak mempedulikan aplikasi ini untuk beberapa bulan. Response time nya sangat-sangat buruk
"Oke, aku rasa kamu tahu masalah utama aplikasi ini bukan?" Walau sepertinya Tracy sudah tahu, anda hanya ingin memastikan beberapa hal. Mungkin beberapa tips sebelum mungkin pergi.
"Response aplikasi ini benar-benar lambat. Itu yang aku tahu."
"Jika begitu aku menyarankan kamu mencoba beberapa fungsi dari Grafana untuk mencari tahu bagaimana keadaan penggunaan resources aplikasi. Dengan begitu aku rasa kamu akan dengan mudah mengetahui kemungkinan penyebabnya."
"Terima kasih sarannya kak. "
"Sudah kubilang jangan panggil aku kakak.. Itu terdengar aneh." Anda mengambil barang-barang anda membiarkan Tracy berkoceh sendiri mengenai panggilan tersebut.
"Kalau begitu aku pergi dulu."
"Walau di luar tidak ada apa-apa lagi?" Tracy melempar pertanyaan tersebut dengan nada dingin. Suatu hal yang belum pernah anda bayangkan akan keluar dari mulut anak itu.
Anda sama sekali tidak melihat ke Tracy. Saat ini anda tidak dapat membayangkan wajah seperti apa yang diperlihatkan olehnya.
"Kakak tahu kan... Perulangan kakak di sini sudah selesai dan juga dunia yang mensimulasikan hal tesebut..."
Anda hanya diam. Tidak menjawab dan tidak menolak. Bahkan anda tidak kaget dengan reaksi Tracy tersebut. Tidak. Hal itu juga tidak benar. Anda sebenarnya kaget. Tapi, ada hal yang lebih menarik perhatian anda. Rintik hujan lalu terhenti. Suara jam dinding adalah hal terakhir yang menggema sebelum perlahan memudar dan menghilang. Lalu berhenti.
Tasks
Set up
- Unduh
postgresql
- Buat sebuah database di lokal. Misalkan nama database-nya
t9
- Ubah
application.properties
dengan credentials database-mu - Jalankan aplikasi. Akan ada sebuah mekanisme seeding yang berjalan saat aplikasi pertama dijalankan yang akan mengisi database dengan data-data yang banyak. tidak diperbolehkan untuk mengubah kode seeding.
Checklists
- Membaca dokumen ini
- Berhasil membuka endpoint
/actuator
- Install Prometheus, dan menjalankannya pada port
localhost:9090
- Mengatur project agar dapat memperlihatkan data pada
/actuator/prometheus
- Mengatur Prometheus anda agar membaca endpoint dari aplikasi Spring Boot anda
- Coba beberapa query dasar Prometheus dan menampilkannya sebagai graf pada Prometheus. (Minimum:
count
,max
,sum
) - Mengatur Grafana dan dapat menampilkan data Prometheus (menggunakan custom panel dan JVM Micrometer Dashboard)
- Menemukan fitur terlambat dan penyebabnya dengan bantuan profiling
- Tingkatkan performa aplikasi dengan data yang anda dapatkan dari proses Profiling. (Melakukan optimasi pada fitur terlambat)
- Jawablah pertanyaan berikut pada
README.md
:- Bagaimana mengatur Grafana agar menampilkan data Prometheus?
- Berdasarkan hasil Profiling yang anda dapatkan, jelaskan analisis anda terhadap keadaan aplikasi saat ini
- Bagaimana anda mengintepretasikan temuan anda? Jelaskan dan berikan gambar screenshot setiap graph query yang anda dapatkan dari dashboard Prometheus dan Grafana
Notes
-
Beberapa screenshot dijalankan menggunakan docker. Untuk anda yang tidak menggunakan Docker untuk instalasi Prometheus dan Grafana, anda perlu mengarahkan Prometheus dan Grafana ke
localhost
bukanhost.docker.internal
Anda dipersilahkan menggunakan instalasi jenis apapun yang anda inginkan. Namun, tidak disarankan menggunakan docker jika anda belum punya pengalaman sebelumnya dengan docker. -
Anda diperbolehkan untuk mengubah seluruh code base selain bagian models dan seeding selama semua fitur masih berjalan dengan benar.
-
Ingat kembali materi analisis kompleksitas.
WorldEnd Compendium
"Katakan Tracy. Siapa kamu sebenarnya?" Jelas saja pertanyaan itu tidak bermaksud untuk menanyakan identitas. Anda tahu siapa Tracy. Anda sadar siapa dia sebenarnya. Anda telah bertemu dengannya di berbagai perulangan dengan peran yang berbeda-beda. Yang anda tanyakan adalah siapa dia yang asli? Adik anda? Teman masa kecil anda? Rekan anda? Senior anda? Junior anda? Dalam permainan peran dari berbagai perulangan, mana Tracy yang sebenarnya?
"Aku pun tidak tahu..."
Jawaban tersebut tepat seperti bayangan anda. Karena bahkan anda sendiri tidak tahu siapa anda sebenarnya. Anda telah melewati 577890 perulangan. Dari semua perulangan anda tidak tahu pasti mana anda yang asli. Bahkan anda tidak yakin kehidupan anda sebelum dipindahkan ke dunia ini adalah yang asli. Bagaimana kalau itu juga salah satu perulangan yang anda tidak sadari? Kemungkinan itu terjadi tidak 0.
Dalam ratusan ribu perulangan, anda berkali-kali lupa akan perulangan sebelumnya. Lalu teringat pada perulangan lain dan siklus tersebut akan terus berulang. Anda kadang mempertanyakan mengapa anda masih bisa mempertahankan kewarasan anda setelah semua itu. Anda telah hidup dalam 577890 skenario berbeda, sebagai orang berbeda. 577890 hari sebagai manusia berbeda. Terkadang sebagai pria, terkadang wanita. Tapi, yang tidak berubah adalah fakta anda selalu hidup sebagai orang programmer di setiap perulangan. Mengapa begitu? Anda tidak pernah mendapat jawabannya.
Anda menoleh ke samping. Sebuah kehadiran kuat anda rasakan. Anda kemudian memasang sikap siaga. Sebenarnya anda merasakan kehadirannya sejak beberapa menit yang lalu. Kehadirannya sangat kuat, bahkan cukup untuk membuat rintik hujan terhenti.
"Alice..." panggil anda.
Sosok itu menundukkan tubuhnya. Sembari memejamkan matanya ia memberi anda salam. "Selamat malam.." ucapnya.
Tracy tidak kaget melihat sosok Alice walau wajahnya sedikit bergedik ngeri saat saling berpapasan mata dengannya. Ia terus menghentakkan kakinya dan berusaha tidak melihat langsung ke sosok yang supernatural tersebut. Alice sendiri tidak menghiraukannya dan terus berjalan ke arah anda.
"Dalam lebih 1600 tahun anda berjalan di dunia ini, apa yang sudah anda ketahui?"
Anda tidak mau menjawabnya. Anda hanya tahu keputusasaan tak berujung yang terus anda lalui pada berbagai perulangan. Tidak semuanya menyedihkan tentu saja. Beberapa memori indah sempat anda buat dalam beberapa kali kesempatan. Hanya saja anda sudah tidak mengingatnya. Mempertahankan kewarasan dalam sebegitu banyak perulangan jelas bukan perkara mudah. Anda harus picky dalam memilih apa yang perlu anda ingat dan apa yang perlu dilupakan. Wadah anda, jiwa anda tidak mampu menahan beban jika dibiarkan mengingat segalanya.
"Apa aku dapat bertemu dengan mereka lagi?" 'Mereka' yang anda tahu adalah teman. Siapa mereka? Anda tidak bisa menjawab pasti. Yang anda tahu anda telah berjanji kepada mereka untuk kembali. Kemana? Pertanyaan lain yang anda tidak tahu jawabannya. Hingga anda ingat sebuah kata.'Taman'
Alice menatap dingin ketika anda melempar pertanyaan tersebut. Entah ia kecewa karena anda mengabaikan pertanyaannya atau ia tidak suka dengan pertanyaan yang baru anda lempar.
"Jujur, bahkan aku tidak tahu. " jawabnya singkat. Setelah diam beberapa lama, Alice lalu melanjutkan: "Aku pada dasarnya hanya boneka yang ditugaskan untuk mengawasi dan membantu anda."
"Apa itu kehendak dari dunia ini? Apakah itu kenyataan yang harus kami terima?"
"Mengatakan ini adalah kenyataan pada dasarnya juga tidak tepat." balasnya. "Pada dasarnya kalian hanya memainkan peran dari buku ini. WorldEnd Compendium. Aku yakin anda masih mengingat nama tersebut bukan?"
Anda hanya diam. Tentu saja anda tahu mengenai nama benda tersebut. Dalam taman bunga pada dunia asal anda, anda menemukan buku tersebut. Suatu benda yang mungkin seharusnya anda tidak perlu temukan. Itulah hukuman dari mereka yang membuka 'kotak pandora'. Anda tidak yakin asalnya, tapi setelah buku tersebut anda buka, anda terpisah dari teman-teman anda dan dipaksa melewati berbagai skenario dalam perulangan.
"WorldEnd Compendium pada dasarnya bukan suatu benda untuk dimain-mainkan. Benda itu dapat memberikan kekuatan bagi mereka yang berhasil melewati ujiannya. Tidak hanya satu, tapi ada banyak WorldEnd Compendium di dunia asal anda. Koleksi kisah dari dunia yang telah berakhir dan berisikan ujian dari dunia-dunia tersebut. Tidak semuanya mengenai menyelamatkan dunia dari kehancuran masal. Sebagian besar bahkan hanya berisikan kisah remeh, tapi bermakna. Selain itu, jumlahnya besar. WorldEnd Compendium yang kalian buka adalah 1 Juta Kisah Programmer."
"Apa yang ada di halaman terakhir buku itu? "
"Sudah aku katakan: kekuatan. Dalam bentuk apa? Aku tidak tahu. Anda harus mencari tahunya sendiri."
"Bagaimana untuk mereka yang gagal?"
"Mudah. Mereka dikembalikan ke dunia asal. Namun, aku tidak yakin mereka masih utuh. Mereka mungkin sudah tidak waras atau menjadi sesuatu yang tidak manusiawi. Wadah mereka kemungkinan tidak dapat bertahan setelah menerima begitu banyak beban dalam perulangan yang begitu banyak. "
Alice mengatakannya dengan tenang dan dingin. Sesuatu yang menurut anda sangat mengerikan. Keadaan yang bisa dibilang lebih buruk dari kematian. Dia tidak berbohong ketika ia mengatakan bahwa dia adalah boneka. Ia sama sekali tidak memiliki emosi.
"Pertanyaan terakhir. Apa dengan kekuatan itu aku bisa bertemu kembali dengan mereka dan menyelamatkan mereka yang gagal dalam ujian WorldEnd Compendium?"
Alice diam dan lalu berjalan menjauh. "Aku tidak tahu pasti karena aku tidak tahu kekuatan seperti apa yang ditawarkan oleh WorldEnd Compendium anda."
"Kalau begitu, antar aku ke perulangan berikutnya. " tegas anda.
Alice kali ini sedikit bereaksi. Boneka itu terlihat tersenyum.
"Walau anda tidak tahu apa yang menanti anda di ujung jalan?"
"Ini tidak seperti aku punya pilihan lain bukan?"
Tracy berlari ke arah anda. Junior anda itu menatap anda khawatir. "Apa kakak yakin?" Matanya terus berputar kiri dan kanan. Hentakan kakinya yang terus terdengar selama percakapan anda dengan Alice semakin cepat dan keras. Ia jelas tidak tenang.
"Maafkan aku. Aku tidak akan tahu kalau belum mencoba. Aku tidak bisa mengeluh dan berharap orang lain akan menyelamatkanku bukan?"
Pada akhirnya semuanya demi kembali ke kehidupan normal anda. Anda harap-harap cemas tentunya. Satu sisi anda sudah melewati setengah jalan ujian ini, di sisi lain anda menyesali telah mencoba membuka WorldEnd Compendium dan takut akan tidak ada yang menanti di ujung jalan, pada perulangan ke satu juta. Namun, berhenti di sini berarti melewati sesuatu yang lebih buruk dari kematian.
Tracy dengan berat hati melepas anda. Anda lalu menepuk pundak junior anda itu.
"Pastikan tugasmu selesai saat kita bertemu lagi."
Tracy sepertinya berusaha menahan beban dan mencoba tersenyum. Senyum yang berat tapi berusaha jujur.
"Baik" jawabnya.
Anda lalu pergi meninggalkannya dengan maksud untuk kembali. Bukan hanya untuknya. Untuk kembali ke kehidupan normal anda. Perulangan demi perulangan akan anda lalui tapi jika itu berarti anda dapat merebut kembali kehidupan lama anda, anda akan lewati itu semua. Ketika anda melewati pintu ke perulangan selanjutnya anda meningat kembali ketika anda tertawa bersama mereka pada taman bunga itu. Pada taman dengan bunga-bunga red spider lily tumbuh subur di sekitarnya.
fin
Ended: Regular 2022
KKI 2021 ↵
Course Page
Course instructor: Daya Adianto, M.Kom.
Teaching assistants:
- Adrika Novrialdi, S.Kom.
- Fardhan D. Sudjono, S.Kom.
- Jahns Christian Albert, S.Kom.
Course Materials
Check Scele for slides and link to the YouTube streams/videos.
Midterm Exam
Written Exam
The problem set will be delivered through Moodle (Scele) as a Microsoft Word document. Work on the problem set and upload your work as a PDF file in the submission slot on Scele.
Interview Exam
Each student will have at most 30 minutes to implement a simple Web service and discuss the course materials with the proctor. The proctor will assign a case to the exam taker and allocate the first five minutes to peruse the case description. After that, the exam taker will have 15 minutes to implement the case, continued by 10 minutes of discussion.
There are two possible cases: Student Activity Tracker and Employee Clock-In. Both cases are similar in terms of the specifications.
Final Exam
Please check the Final Interview Exam page for further information. In overall, it will be similar to the interview exam during the midterm exam. Each student will be allocated 20 minutes to implement a simple feature from their group project, followed by a 10 minutes of discussion.
Midterm Interview Exam - Case 1: Student Activity Tracker
TL;DR: Read the Specifications and start working on the Programming Tasks. To understand the background, read the problem description from the beginning.
It is very challenging to keep track of student activities during synchronous and asynchronous course activities. Students may have varying pace and schedule when participating in the course. Moreover, students also use multiple learning tools such as GitLab and Moodle (Scele), where each tool may have its way in defining and storing students' activities. The teaching team needs to compile the activity logs by exporting the records from each teaching tool and integrating them into a unified view.
For the interview exam, the scope of the requirements is simplified. Instead of
developing a fully-fledged working system that monitors student activities
across multiple learning tools, the project only requires a single Web service
that lets the user (i.e., the teaching assistant (TA) and lecturer) create an
activity log of a student. The activity logs are stored in an in-memory data
storage such as Java collection (e.g., List
). In addition, there is no
authentication required in the Web service.
For example, the TA noticed that one student made a contribution by increasing
the line coverage of a sample project. The TA can open his or her terminal and
use curl
to send an HTTP POST to the Web service containing the activity log
as form data:
1 2 3 4 5 |
|
Or if the TA prefer to use Python script over curl
:
1 2 3 4 |
|
Both script examples send a form data containing three fields (date
, name
,
description
) to the /activity
endpoint served at https://example.com
.
You are allowed to deploy and run the Web service locally during the exam,
i.e., on localhost
.
Specifications
Estimated reading time: 5 minutes
Develop a Web service with a single endpoint named /activity
that handles an
HTTP POST message containing form data with the following fields:
date
: Date of the activity, written inyyyy-mm-dd
formatname
: Name of the studentdescription
: Description of the activity
If all fields are present and contain valid values, store them as an object in
data storage. Then, return an HTTP 200
response if the activity log is
successfully stored. Otherwise, implement basic error handling. For example,
return an HTTP 400
response if some of the fields are missing.
Programming Tasks
Estimated working time: 10 - 15 minutes
Turn on your camera and share your desktop screen. Ensure that the proctor (in most cases, the lecturer and sometimes the TAs) can monitor your activities during the interview exam. Imagine you are conducting a remote pair programming where the partner needs to observe your work.
Do the tasks in the Mandatory subsection. If there is some time left after you completed the Mandatory subsection, you can do the tasks in the Optional subsection.
Mandatory
We recommend you to do the tasks according to the given order. The tasks are sorted based on the required effort and logical order to complete them.
- Create a new project under your own GitLab subgroup in KKI 2021 group.
- Initialise the Git repository to track your progress.
You can commit and push the initial commit that only contains the starter code at this point.
- Prepare the starter code for building the project. The starter code may
be written in Java (Spring Boot) or any programming language/framework that
you are familiar with.
If you choose to use another programming language/framework, make sure it has support for developing a Web service, writing unit test and can be deployed on Heroku.
- Design a test case that verifies only one of the following:
(1) Checks whether a valid activity log is successfully stored in the data
storage; or (2) Ensures a valid HTTP POST request to
/activity
endpoint will return aHTTP 200
response; or (3) Ensures an invalid HTTP request to/activity
endpoint will return aHTTP 400
response. - Work on the problem set. Write the code to implement the required feature. Do not forget to commit and push your work-in-progress frequently.
- Write a test program using the testing framework provided by the programming language/framework and implements the test case you have designed in the previous problem.
Optional
Feel free to do the tasks in any order. It is alright if some of the tasks are not completed. The discussion session may ask you to complete the unfinished tasks.
- Implement a basic authentication mechanism by checking whether the HTTP
request contains a header named
X-AdvProg-Auth
with the value2021
. If the request is valid, then proceed to store the new activity log. Otherwise, reject the input and return anHTTP 403
response. - Design and implement the test case for verifying the basic authentication mechanism.
- Create a new Heroku app and deploy the local version of the project to Heroku using Heroku CLI.
- Create a new project on SonarQube AdvProg and run SonarScanner that sends the scan result to SonarQube AdvProg.
- Set up a GitLab CI/CD pipeline that automatically runs the test suite
each time a new commit has been pushed to
master
branch.
Discussion
Estimated discussion time: 5 - 10 minutes
The list of possible topics during the discussion is as follows:
- Development workflow (Git, IDE)
Examples: How do you use Git when working on your course work?; How to merge a branch into another branch?; How do you resolve a merge conflict?
- Writing and running test
Examples: How do you design the test cases to test a piece of code?; How to measure line coverage?
- Concurrency
Examples: How to prevent a race condition in implementation level or architectural level?; Describe one example of serialisation technique employed in a programming language/framework of your choice
- Deployment workflow (GitLab CI/CD, Heroku)
Examples: Describe one or more elements commonly found in a
.gitlab-ci.yml
file; Show how to deploy a codebase to Heroku using Heroku CLI - Code quality (SonarQube, SonarScanner)
Examples: Mention some code smells that you have encountered throughout this course; What is the responsibility of SonarQube and SonarScanner?
It is also possible that the proctor will ask questions that are not listed above.
Hints
- As mentioned in the requirements, you do not have to set up a database. The most straightforward approach is to use the collection library provided by the standard library of programming language/framework of your choice.
- If you are using Spring Boot, you only need Spring Web in the project dependencies. Do not make the project more complex by adding other dependencies such as Spring Data REST or database connection drivers.
- You already have a collection of code examples that you can adapt to solve this problem. Hence, we do not recommend you to search for tutorials or code snippets through a search engine. You may do so, but we think it is better to spend your time in coding and reuse the available resources.
Midterm Interview Exam - Case 2: Employee Clock-In
TL;DR: Read the Specifications and start working on the Programming Tasks. To understand the background, read the problem description from the beginning.
Some workplaces use an attendance monitoring system to track the punctuality and presence of their employees. One of the core features is keeping track of employee attendance during workdays. The company would like to know when they start working in a day.
For the interview exam, the scope of the requirements is simplified. The project only requires a single Web service that lets the user clock in their presence by sending an HTTP POST message and store the attendance. In addition, there is no authentication required in the Web service.
For example, suppose that an employee would like to clock in their presence.
He or she can use the terminal and use curl
to send an HTTP POST to the Web
service:
1 2 3 4 5 |
|
Or if the employee prefer to use Python script instead of curl
:
1 2 3 4 |
|
Both script examples send a form data containing three fields (date
, time
,
name
) to the /clock-in
endpoint served at https://example.com
. You are
allowed to deploy and run the Web service locally, i.e., on localhost
.
Specifications
Estimated reading time: 5 minutes
Develop a Web service with a single endpoint named /clock-in
that handles an
HTTP POST message containing form data with the following fields:
date
: Date of the clock-in, written inyyyy-mm-dd
format. E.g.,2021-03-20
time
: Clock-in time, written inhh:mm
format. E.g,16:20
name
: Employee name
If all fields are present and contain valid values, store them as an object in
data storage. Then, return an HTTP 200
response if the clock-in time is
successfully stored. Otherwise, implement basic error handling. For example,
return an HTTP 400
response if some of the fields are missing.
Programming Tasks
Estimated working time: 10 - 15 minutes
Turn on your camera and share your desktop screen. Ensure that the proctor (in most cases, the lecturer and sometimes the TAs) can monitor your activities during the interview exam. Imagine you are conducting a remote pair programming where the partner needs to observe your work.
Do the tasks in the Mandatory subsection. If there is some time left after you completed the Mandatory subsection, you can do the tasks in the Optional subsection.
Mandatory
We recommend you to do the tasks according to the given order. The tasks are sorted based on the required effort and logical order to complete them.
- Create a new project under your own GitLab subgroup in KKI 2021 group.
- Initialise the Git repository to track your progress.
You can commit and push the initial commit that only contains the starter code at this point.
- Prepare the starter code for building the project. The starter code may
be written in Java (Spring Boot) or any programming language/framework that
you are familiar with.
If you choose to use another programming language/framework, make sure it has support for developing a Web service, writing unit test and can be deployed on Heroku.
- Design a test case that verifies only one of the following:
(1) Checks whether valid clock-in data is successfully stored in the data
storage; or (2) Ensures a valid HTTP POST request to
/clock-in
endpoint will return aHTTP 200
response; or (3) Ensures an invalid HTTP request to/clock-in
endpoint will return aHTTP 400
response. - Work on the problem set. Write the code to implement the required feature. Do not forget to commit and push your work-in-progress frequently.
- Write a test program using the testing framework provided by the programming language/framework and implements the test case you have designed in the previous problem.
Optional
Feel free to do the tasks in any order. It is alright if some of the tasks are not completed. The discussion session may ask you to complete the unfinished tasks.
- Implement a basic authentication mechanism by checking whether the HTTP
request contains a header named
X-AdvProg-Auth
with the value2021
. If the request is valid, then proceed to store the new clock-in data. Otherwise, reject the input and return aHTTP 403
response. - Design and implement the test case for verifying the basic authentication mechanism.
- Create a new Heroku app and deploy the local version of the project to Heroku using Heroku CLI.
- Create a new project on SonarQube AdvProg and run SonarScanner that sends the scan result to SonarQube AdvProg.
- Set up a GitLab CI/CD pipeline that automatically runs the test suite
each time a new commit has been pushed to
master
branch.
Discussion
Estimated discussion time: 5 - 10 minutes
The list of possible topics during the discussion is as follows:
- Development workflow (Git, IDE)
Examples: How do you use Git when working on your course work?; How to merge a branch into another branch?; How do you resolve a merge conflict?
- Writing and running test
Examples: How do you design the test cases to test a piece of code?; How to measure line coverage?
- Concurrency
Examples: How to prevent a race condition in implementation level or architectural level?; Describe one example of serialisation technique employed in a programming language/framework of your choice
- Deployment workflow (GitLab CI/CD, Heroku)
Examples: Describe one or more elements commonly found in a
.gitlab-ci.yml
file; Show how to deploy a codebase to Heroku using Heroku CLI - Code quality (SonarQube, SonarScanner)
Examples: Mention some code smells that you have encountered throughout this course; What is the responsibility of SonarQube and SonarScanner?
It is also possible that the proctor will ask questions that are not listed above.
Hints
- As mentioned in the requirements, you do not have to set up a database. The most straightforward approach is to use the collection library provided by the standard library of programming language/framework of your choice.
- If you are using Spring Boot, you only need Spring Web in the project dependencies. Do not make the project more complex by adding other dependencies such as Spring Data REST or database connection drivers.
- You already have a collection of code examples that you can adapt to solve this problem. Hence, we do not recommend you to search for tutorials or code snippets through a search engine. You may do so, but we think it is better to spend your time in coding and reuse the available resources.
Final Interview Exam
The final interview exam will take at most for 30 minutes and comprise of two parts: live coding (20 minutes) and discussion (10 minutes). In the first five minutes of the live coding, the exam taker should describe the new feature that they want to build from their group project. The proctor will decide whether the exam taker can proceed with the proposed new feature or make adjustment to the new feature if similar feature has been implemented by previous exam takers.
The next 15 minutes shall be used for implementing the new feature. The exam taker must activate their camera and share their desktop screen throughout the live coding session. Looking for references on search engine, API documents, or any available source code are allowed. However, be advised that the proctor also take account on the development workflow and the best practices conducted by the exam taker during the live coding. Copy-pasting code from a search result on Google or Stack Overflow without knowing its purpose is frowned upon than reusing code with similar functionality from another module within the project's source code. Even when reusing code, please be aware of readability and maintainbility issues. Strive to have a clean source code at the end of the live coding session.
After the live coding session ends, the exam taker shall proceed to the discussion part. The structure will be similar to the one conducted during the midterm interview exam. The proctor will ask series of questions and the exam taker must answer each question. The questions will cover mainly about the subjects from the midterm exam until the final exam. However, there are chances for the subjects prior to the midterm exam will be asked during the discussion.
Live Coding Specifications
Develop a simple and small enough new feature based on your group project. The criteria for the new feature is as follows:
- It can be implemented by adding and/or modifying at least one Java source code file each from the model- and controller-related modules. You may also want to modify any supporting Java source code files if the new feature needs it, e.g., security-related configuration for RBAC (Role-Based Access Control) or allowable domains in CORS (Cross-Origin Resource Sharing).
- It can be observed and usable when the application is running, hence requiring a new view-related source code file or modifying the existing views.
- It has a test suite that verifies the correctness of the new feature.
- It does not break any of the existing features.
If your group project comprises of two repositories, e.g., Spring Boot as as backend and React as frontend, then the criteria applies only to a component. For example, if you choose to implement the new feature on React frontend, then ensure the addition/modification cover the .JSX/.TSX files that render the component and handle the logic.
Mandatory Tasks
Note: All of the programming tasks must be conducted during the interview exam session.
- Fork the group project's repository into your own GitLab CS subgroup in
KKI 2021 group and assign a descriptive name for the fork repo, e.g.,
fork-interview-final-exam
. - Clone the fork into your development environment.
- Work on the new feature.
- Create the test suite for the new feature.
- Demonstrate the new feature locally and show that the existing features are still working.
- Push the latest state of your work to GitLab CS at the end of the live coding part.
Optional Tasks
- Clean up one or more code smells that are present in the fork repository.
- Ensure the pipeline is working and return pass/"green" status in the fork repository. If the pipeline is not working from the upstream repository, then fix it.
- Deploy the fork repository along with the new feature to your own Heroku account, preferably automated using GitLab CI/CD.
- Run SonarScanner analysis and send the results to SonarQube AdvProg, preferably automated using GitLab CI/CD.