Skip to content

πŸš€Your First Assignment: Building a Mini Supply Chain ​

🌐 Management System overview ​

As part of your internship intake, we've crafted a hands-on assignment designed to give you a taste of the challenges we regularly solve at Limax B.V. Your mission is to build a scaled-down version of a Supply Chain Management System focused on mushroom trading. This project should reflect best practices in software development, architecture, and design.

🎯 Assignment Objectives: ​

🍝 Refactor Spaghetti Code to Structured Code: ​

  • ✨ Your task is to refactor a piece of "spaghetti code" that will be provided to you. Your goal is to transform this code into a well-structured, maintainable version.

Key Best Practices to Apply: ​

Best practices
  • πŸ› οΈ SOLID Principles: Ensure your code adheres to Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion principles.
  • πŸ“ Code Readability: Your code should be easy to read and understand, following proper naming conventions and code commenting.
  • πŸ’‘ DRY (Don't Repeat Yourself): Eliminate code repetition by modularizing your code effectively.

Take a look at this video for a better understanding of these principles:

πŸ› οΈ Create an Extensible Codebase: ​

  • The end result of your refactoring should be a codebase that can be easily extended for more complex features in the future.
    • πŸ—οΈ Structure your code in an N-tier architecture for easy extension.
    • πŸ“‘ Make sure your code is prepared for the seamless addition of JPA annotations and other metadata as needed.

πŸ“ RESTful API Features: ​

  • With your refactored, best-practice-compliant code, you should be able to:
    • πŸ„ Implement CRUD operations for managing articles that deal with different types of mushrooms.
    • πŸ‘¨β€πŸŒΎ Develop CRUD operations for farmers and their mushroom supplies.
    • πŸ—“οΈ Add a scheduling feature for planning mushroom pickups from farmers.

πŸ•’ Estimated Time and Workload: ​

  • πŸ—“οΈ The assignment is estimated to take approximately 8 to 12 hours in total. However, these estimates can fluctuate depending on your prior experience, expertise, and familiarity with the technologies and principles involved.
  • ⏳ It's perfectly okay if you take more or less time than estimated; the focus is on the quality and effectiveness of your solution.
  • πŸ“š This assignment is designed to be small and manageable enough to complete alongside your regular studies.

πŸ“ž Clarifications & Support: ​

  • 🀝 If you get really stuck, a one-on-one meeting with Limax, acting as the project owner, can be scheduled. This can also be in the form of an email.
  • πŸ•΅οΈβ€β™€οΈ We expect you to be proactive and investigate the assignment on your own. Ingenuity and creative problem-solving are encouraged, provided you stick to core Object-Oriented Design (OOD) principles.

πŸŽ“ Evaluation Criteria: ​

  • 🧠 This assignment is an evaluation tool to gauge your cognitive abilities, problem-solving skills, and technical proficiency. Successful completion will help us determine your compatibility with Limax's objectives.
  • 🎨 Be creative and think outside the box. There is not a single correct answer to this assignment. We are looking for your problem-solving skills and how you approach the task at hand. Good luck!

πŸ€– AI: ​

  • πŸ“ The usage of AI, like ChatGPT, is allowed. However, you must write the code. We will ask you to explain parts of the code to verify.
  • πŸ§‘β€πŸ« When using AI, be open about how you used it, why you used it, and what parts of the code were created with AI assistance.
  • πŸ†˜ We see the value of AI in the development process, but still are looking for your problem-solving skills and how you approach the task at hand. If AI wrote all or most of your code, we will figure it out soon enough.

πŸ’»Technical Requirements: ​

  • β˜• Language: Java
  • 🌱 Framework: Spring Boot
  • πŸ—„οΈ Database: Use any in-memory database like H2 for simplicity
  • βœ… Tests: Unit and Integration tests are required
  • 🌳 Version Control: Git

πŸ“¦Deliverables: ​

  • πŸ“˜ A GitHub repository containing your project code and a README file that explains how to run it, the design choices you made, and why.
  • πŸ“ A document explaining how you refactored the spaghetti code, with before-and-after code snippets (A flow-diagram for example with PlantUML️ 🌿).
  • πŸ“„ Documentation is always good to have, but since this is just an assignment to test some of your skills, there is no need to make this too extensive.

πŸ”§ Refactor code snippet ​

The provided Java code snippet is a simplified representation of a system that handles different tasks related to mushroom farming. It's intended to mimic some basic functionalities like article management, farmer management, and scheduling. However, the code is not well-organized and violates several best practices.

Here are some key features and issues with the code:

  • Entities and Operations: The code has lists for articles, farmers, and schedules, along with a Map for inventory. These could represent potential entities in a more structured system.
  • Conditional Complexity: The run() method contains deeply nested if statements, making it hard to read and maintain. This is an example of what we generally term "spaghetti code."
  • Modular Design Lacking: Although there are private methods like processWestLocation, processEastLocation, etc., they are not abstracted well enough to be reusable or extendable.
  • Global State: The code utilizes class-level variables for state information like userType, isWeekend, isActiveUser, etc. This could potentially lead to issues in a more complex, multi-threaded environment.
  • Code Readability: There's a lack of comments and documentation, and the method names could be more descriptive to understand their functionality without diving into their implementations.
  • SOLID Principles: The code does not adhere to SOLID principles. For instance, the run method has multiple responsibilities.

By taking on this assignment, you will demonstrate your ability to recognize code smells, refactor legacy code, and ensure it aligns with industry best practices. Given that you'll be working on a project in microservice architecture, these skills will be invaluable.

java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Main {
   List<String> articles = new ArrayList<>();
   List<String> farmers = new ArrayList<>();
   List<String> schedules = new ArrayList<>();
   Map<String, Integer> inventory = new HashMap<>();
   boolean hasSpecialPermission = true;
   String userType = "regular";
   boolean isWeekend = false;
   boolean isActiveUser = true;
   boolean isHighPriority = true;
   String location = "west";

   public static void main(String[] args) {
      Main example = new Main();
      example.run();
   }

   public void run() {
      String newArticle = "Shiitake";
      String newFarmer = "John";
      String newSchedule = "2023-10-26";
      int articleQuantity = 10;

      if (hasSpecialPermission) {
         if (userType.equals("regular")) {
            if (isHighPriority) {
               articles.add(newArticle + "-HP");
            } else {
               if (!isWeekend) {
                  if (isActiveUser) {
                     if (location.equals("west")) {
                        processWestLocation(newArticle, newFarmer, newSchedule, articleQuantity);
                     } else {
                        if (location.equals("east")) {
                           processEastLocation(newArticle, newFarmer, articleQuantity);
                        }
                     }
                  }
               } else {
                  processWeekend(newArticle, newFarmer);
               }
            }
         } else {
            processNonRegularUsers(newArticle, newFarmer, newSchedule);
         }
      }

      displayOutput();
   }

   private void processWestLocation(String newArticle, String newFarmer, String newSchedule, int articleQuantity) {
      if (!articles.contains(newArticle) && !farmers.contains(newFarmer)) {
         articles.add(newArticle);
         farmers.add(newFarmer);
         if (!schedules.contains(newSchedule)) {
            schedules.add(newSchedule);
            if (inventory.containsKey(newArticle)) {
               inventory.put(newArticle, inventory.get(newArticle) + articleQuantity);
            } else {
               inventory.put(newArticle, articleQuantity);
            }
         }
      }
   }

   private void processEastLocation(String newArticle, String newFarmer, int articleQuantity) {
      if (!articles.contains(newArticle)) {
         articles.add(newArticle);
         if (!farmers.contains(newFarmer)) {
            farmers.add(newFarmer + "-east");
         }
         if (inventory.containsKey(newArticle)) {
            inventory.put(newArticle, inventory.get(newArticle) - articleQuantity);
         }
      }
   }

   private void processWeekend(String newArticle, String newFarmer) {
      articles.add(newArticle + "-weekend");
      farmers.add(newFarmer + "-weekend");
   }

   private void processNonRegularUsers(String newArticle, String newFarmer, String newSchedule) {
      articles.add(newArticle + "-NR");
      farmers.add(newFarmer + "-NR");
      schedules.add(newSchedule + "-NR");
   }

   private void displayOutput() {
      // Display logic same as before
      System.out.println("Articles:");
      for (String article : articles) {
         System.out.println(article);
      }

      System.out.println("Farmers:");
      for (String farmer : farmers) {
         System.out.println(farmer);
      }

      System.out.println("Schedules:");
      for (String schedule : schedules) {
         System.out.println(schedule);
      }

      System.out.println("Inventory:");
      for (Map.Entry<String, Integer> entry : inventory.entrySet()) {
         System.out.println(entry.getKey() + ": " + entry.getValue());
      }
   }
}

Challenge yourself to unravel the complexities of the code and reimagine its structure. Your unique approach to deconstructing and then reconstructing the logic is key. Consider design patterns that might enhance readability and scalability, and don't hesitate to break apart monolithic blocks into cohesive, loosely coupled units.