Skip to main content

Section 12.10 Project Setup, Branches, and Tooling Context

Following the introduction to Git and GitHub (Sections 6A-6E), you should now have the 1213-arraylist-example repository successfully cloned to your local machine and open in VSCode. Please ensure you currently have the main branch checked out, as this branch contains the necessary starter code for implementing your ArrayList<T>. (Refer back to Section 12.8 and Section 12.9 if needed).
Before we dive into the Design Recipe for our implementation, let’s examine the project structure, understand the different Git branches available for reference, and revisit the context of the essential build and test tools being used behind the scenes.

Subsection 12.10.1 Confirming the Project Structure

In your VSCode file explorer, verify you see the standard Java project layout:
1213-arraylist-example/  <-- Your main project folder (cloned)
├── src/                   <-- Source code root
│   ├── ADTs/              <-- Package for Abstract Data Types
│   │   ├── CollectionADT.java
│   │   └── ListADT.java     <-- The interface contract we will implement
│   └── DataStructures/    <-- Package for our implementation
│       └── ArrayList.java <-- **Your primary implementation file** (currently a skeleton on 'main')
├── test/                  <-- Test code root
│   └── DataStructures/    <-- Test package mirrors source package
│       └── ArrayListTest.java <-- **Provided JUnit tests**
├── build.gradle.kts         <-- Gradle Build Script (tooling)
├── settings.gradle.kts      <-- Gradle Settings (tooling)
└── ... (Other Gradle files like gradlew, gradlew.bat, gradle/)
This structure correctly separates the ADT contracts, your implementation code, and the verification tests into distinct packages and source roots (src and test). Your work will primarily be in src/DataStructures/ArrayList.java, using the tests in test/DataStructures/ArrayListTest.java to check your progress.

Subsection 12.10.2 Navigating Project Versions with Git Branches

As mentioned in Section 12.9, Git branches allow a repository to hold multiple versions or snapshots of the project. For the 1213-arraylist-example repository, we use branches to provide specific states corresponding to the completion of different sections in this chapter.
The main branch contains the starter code skeleton. You must do all your implementation work on the main branch.
The other branches are provided purely for your reference – you can checkout them temporarily (as described in Section 6D) to see what the code should look like at various stages or view the final solution. Remember to switch back to main to continue your own work! The available branches include:
  • main: Starter code skeleton (Begin work here!).
  • dr-step-4.1-add-skeletons: Contains commented skeletons for Add methods (End of Sec 12).
  • dr-step-4.2-remove-skeletons: Contains commented skeletons for Remove methods added (End of Sec 13).
  • dr-step-4.3-other-skeletons: All method skeletons complete (End of Sec 14).
  • dr-step-5.1-core-impl: Core methods implemented (End of Sec 15).
  • dr-step-5.2-resizing-impl: Resizing/addLast implemented (End of Sec 16).
  • dr-step-5.3-indexed-impl: Indexed Add/Remove implemented (End of Sec 17).
  • dr-step-5.4-remaining-impl: All methods implemented (pre-refinement) (End of Sec 18).
  • dr-step-5.5-final-refined: Final refined code (End of Sec 19).
Knowing these branches exist can be helpful if you get stuck or want to compare your approach after completing a section.

Subsection 12.10.3 Making Sense of the Project Files: Build and Test Tools

Looking at the file structure, besides the .java files, you see files like build.gradle.kts and ArrayListTest.java. Let’s revisit why these exist and clarify our scope regarding them.

Subsubsection 12.10.3.1 The Build Process Problem and Build Tools (Gradle)

Problem: As we discussed when learning about packages, compiling multiple .java files spread across different packages (ADTs, DataStructures) isn’t as simple as just running javac on one file. The compiler needs to find all the related files (like ListADT.java when compiling ArrayList.java) and handle their dependencies correctly. Furthermore, our tests (ArrayListTest.java) rely on an external library, JUnit. How does our project get access to JUnit’s code, which isn’t part of standard Java? Manually managing compilation paths (classpaths) and downloading library files (dependencies) for even moderately complex projects becomes extremely difficult and error-prone.
Solution: This complex process is automated using build tools. Our project uses Gradle, a popular Java build tool. Gradle reads instructions from configuration files – primarily build.gradle.kts (written in Kotlin script, hence .kts) – which tell it how to perform tasks like:
  • Compiling all source code in the src/ directory, respecting package structures.
  • Automatically downloading and managing required external libraries (dependencies), such as JUnit, from online code repositories (like Maven Central).
  • Compiling the test code in the test/ directory.
  • Running the unit tests using the specified framework (JUnit).
  • (Often) Packaging the compiled code and resources into a distributable format (like a JAR file).
Scope: For this chapter, you do not need to understand the Kotlin script syntax or modify the contents of build.gradle.kts or other Gradle files (like settings.gradle.kts or the gradlew wrapper scripts). It’s important to know that Gradle is the powerful tool working behind the scenes, configured by these files, making it possible for VSCode to easily compile and test this multi-package project that depends on JUnit. We will simply use VSCode’s interface (like the Test Explorer) which triggers Gradle to do the necessary work automatically. Build tool configuration is out of scope.

Subsubsection 12.10.3.2 The Verification Problem and Testing Frameworks (JUnit)

Problem: We need confidence that our ArrayList<T> implementation correctly fulfills the ListADT<T> contract. As we noted earlier, using simple assert statements in a main method becomes unmanageable for testing all the methods and edge cases thoroughly. We need an organized, repeatable, and automated way to verify our code’s behavior.
Solution: This is achieved using unit testing supported by testing frameworks. The file test/DataStructures/ArrayListTest.java contains unit tests specifically designed to check your ArrayList implementation. These tests are written using JUnit (specifically JUnit 5, also known as Jupiter), the framework we mentioned before. JUnit provides features (like the @Test, @BeforeEach, @DisplayName, @Nested annotations you might see if you peek in the file, and static methods from org.junit.jupiter.api.Assertions like assertEquals, assertTrue, assertThrows) that make it easy to structure tests, define individual test cases, and automatically check if your code produces the expected results or throws the correct exceptions.
Scope: The JUnit tests in ArrayListTest.java are provided for you. Your task, which is in scope, is to learn how to run these tests within VSCode (using its Test Explorer, which leverages Gradle and JUnit) and how to interpret the results – green check ✅ means pass, red X ❌ means fail. Failed tests will provide messages indicating what went wrong, guiding you to fix bugs in your ArrayList.java implementation. The process of writing unit tests using JUnit is out of scope for this chapter.
Understanding that these tools (Gradle, JUnit) and file structures (src, test, packages) exist to manage complexity and ensure correctness allows us to focus on our main task: implementing ArrayList.java.
With the project cloned from GitHub, the correct main branch checked out, the file structure confirmed, the available reference branches listed, and the roles of the background build/test tools understood, we are now fully prepared to begin the core task: applying the Design Recipe to implement ArrayList<T>. Let’s start with Step 0.
You have attempted of activities on this page.