diff --git a/config/ClientsSharedConfig.ts b/config/ClientsSharedConfig.ts
index ea55b0c06a35f38773c6744474159514f0687fed..77f1053b62aa98d6703a8d441e583657c24f7f5b 100644
--- a/config/ClientsSharedConfig.ts
+++ b/config/ClientsSharedConfig.ts
@@ -21,28 +21,28 @@ class ClientsSharedConfig {
 
 
     constructor() {
-        this.apiURL = process.env.API_URL || '';
+        this.apiURL = process.env.API_URL ?? '';
 
         this.assignment = {
-            filename   : process.env.ASSIGNMENT_FILENAME || '',
-            neededFiles: JSON.parse(process.env.EXERCISE_NEEDED_FILES || '[]')
+            filename   : process.env.ASSIGNMENT_FILENAME ?? '',
+            neededFiles: JSON.parse(process.env.EXERCISE_NEEDED_FILES ?? '[]')
         };
 
         this.gitlab = {
             dojoAccount: {
-                id      : Number(process.env.GITLAB_DOJO_ACCOUNT_ID) || -1,
-                username: process.env.GITLAB_DOJO_ACCOUNT_USERNAME || ''
+                id      : Number(process.env.GITLAB_DOJO_ACCOUNT_ID ?? -1),
+                username: process.env.GITLAB_DOJO_ACCOUNT_USERNAME ?? ''
             }
         };
 
         this.dockerCompose = {
-            projectName: process.env.DOCKER_COMPOSE_PROJECT_NAME || ''
+            projectName: process.env.DOCKER_COMPOSE_PROJECT_NAME ?? ''
         };
 
-        this.exerciseResultsFolderMaxSizeInBytes = Number(process.env.EXERCISE_RESULTS_FOLDER_MAX_SIZE_IN_BYTES || 0);
+        this.exerciseResultsFolderMaxSizeInBytes = Number(process.env.EXERCISE_RESULTS_FOLDER_MAX_SIZE_IN_BYTES ?? 0);
 
         this.filenames = {
-            results: process.env.EXERCISE_RESULTS_FILENAME || ''
+            results: process.env.EXERCISE_RESULTS_FILENAME ?? ''
         };
     }
 }
diff --git a/helpers/Dojo/AssignmentValidator.ts b/helpers/Dojo/AssignmentValidator.ts
index 6ecec2ccefd9f71051d4334a9f5c20c51d35cce1..a45d61d23f7f60ac7502523ae87994df47b23789 100644
--- a/helpers/Dojo/AssignmentValidator.ts
+++ b/helpers/Dojo/AssignmentValidator.ts
@@ -17,6 +17,9 @@ const execAsync = util.promisify(exec);
 
 
 class AssignmentValidator {
+    private readonly folderAssignment: string;
+    private readonly doDown: boolean;
+
     readonly events: TypedEmitter<AssignmentValidatorEvents> = new TypedEmitter<AssignmentValidatorEvents>();
 
     public displayableLogs: string = '';
@@ -30,7 +33,13 @@ class AssignmentValidator {
     private currentStep: string = 'NOT_RUNNING';
     private currentSubStep: string = 'NOT_RUNNING';
 
-    constructor(private folderAssignment: string) {
+    private dockerComposeFile!: DojoDockerCompose;
+    private assignmentFile!: AssignmentFile;
+
+    constructor(folderAssignment: string, doDown: boolean = false) {
+        this.folderAssignment = folderAssignment;
+        this.doDown = doDown;
+
         this.events.on('logs', (log: string, _error: boolean, displayable: boolean) => {
             this.allLogs += log;
             this.displayableLogs += displayable ? log : '';
@@ -77,212 +86,224 @@ class AssignmentValidator {
         this.finished(false, code);
     }
 
-    run(doDown: boolean = false) {
-        (async () => {
-            let dockerComposeFile: DojoDockerCompose;
-            let assignmentFile: AssignmentFile;
+    /**
+     * Step 1: Check requirements
+     * -   Check if Docker daemon is running
+     * -   Check if required files exists
+     * @private
+     */
+    private async checkRequirements() {
+        this.newStep('REQUIREMENTS_CHECKING', 'Please wait while we are checking requirements...');
 
 
-            /*
-             //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 1: Check requirements
-             -   Check if Docker daemon is running
-             -   Check if required files exists
-             */
-            {
-                this.newStep('REQUIREMENTS_CHECKING', 'Please wait while we are checking requirements...');
+        // Check requirements
+        this.newSubStep('DOCKER_RUNNING', 'Checking if Docker daemon is running');
+        try {
+            await execAsync(`docker ps`);
+        } catch ( error ) {
+            this.emitError(`Docker daemon isn't running`, `Some requirements are not satisfied.`, AssignmentCheckerError.DOCKER_DAEMON_NOT_RUNNING);
+            throw new Error();
+        }
+        this.endSubStep('Docker daemon is running', false);
 
 
-                // Check requirements
-                this.newSubStep('DOCKER_RUNNING', 'Checking if Docker daemon is running');
-                try {
-                    await execAsync(`docker ps`);
-                } catch ( error ) {
-                    this.emitError(`Docker daemon isn't running`, `Some requirements are not satisfied.`, AssignmentCheckerError.DOCKER_DAEMON_NOT_RUNNING);
-                    return;
-                }
-                this.endSubStep('Docker daemon is running', false);
+        // Check if required files exists
+        this.newSubStep('REQUIRED_FILES_EXISTS', 'Checking if required files exists');
+        const files = fs.readdirSync(this.folderAssignment);
+        const missingFiles = ClientsSharedConfig.assignment.neededFiles.map((file: string): [ string, boolean ] => [ file, files.includes(file) ]).filter((file: [ string, boolean ]) => !file[1]);
 
+        if ( missingFiles.length > 0 ) {
+            this.emitError(`The exercise folder is missing the following files: ${ missingFiles.map((file: [ string, boolean ]) => file[0]).join(', ') }`, 'Some requirements are not satisfied', AssignmentCheckerError.REQUIRED_FILES_MISSING);
+            throw new Error();
+        }
+        this.endSubStep('All required files exists', false);
 
-                // Check if required files exists
-                this.newSubStep('REQUIRED_FILES_EXISTS', 'Checking if required files exists');
-                const files = fs.readdirSync(this.folderAssignment);
-                const missingFiles = ClientsSharedConfig.assignment.neededFiles.map((file: string): [ string, boolean ] => [ file, files.includes(file) ]).filter((file: [ string, boolean ]) => !file[1]);
 
-                if ( missingFiles.length > 0 ) {
-                    this.emitError(`The exercise folder is missing the following files: ${ missingFiles.map((file: [ string, boolean ]) => file[0]).join(', ') }`, 'Some requirements are not satisfied', AssignmentCheckerError.REQUIRED_FILES_MISSING);
-                    return;
-                }
-                this.endSubStep('All required files exists', false);
+        this.endStep('All requirements are satisfied', false);
+    }
 
+    /**
+     * Step 2: dojo_assignment.json file validation
+     * -   Structure validation
+     * -   Immutable files validation (Check if exists and if the given type is correct)
+     * @private
+     */
+    private dojoAssignmentFileValidation() {
+        this.newStep('ASSIGNMENT_FILE_VALIDATION', 'Please wait while we are validating dojo_assignment.json file...');
+
+        const assignmentFileValidationError = `${ ClientsSharedConfig.assignment.filename } file is invalid`;
+
+        // Structure validation
+        this.newSubStep('ASSIGNMENT_FILE_SCHEMA_VALIDATION', 'Validating dojo_assignment.json file schema');
+        const validationResults = SharedAssignmentHelper.validateDescriptionFile(path.join(this.folderAssignment, ClientsSharedConfig.assignment.filename));
+        if ( !validationResults.isValid ) {
+            this.emitError(`dojo_assignment.json file schema is invalid.\nHere are the errors:\n${ validationResults.error }`, assignmentFileValidationError, AssignmentCheckerError.ASSIGNMENT_FILE_SCHEMA_ERROR);
+            throw new Error();
+        }
+        this.assignmentFile = validationResults.content!;
+        this.endSubStep('dojo_assignment.json file schema is valid', false);
+
+
+        // Immutable files validation (Check if exists and if the given type is correct)
+        this.newSubStep('ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', 'Validating immutable files');
+        for ( const immutable of this.assignmentFile.immutable ) {
+            const immutablePath = path.join(this.folderAssignment, immutable.path);
+            if ( !fs.existsSync(immutablePath) ) {
+                this.emitError(`Immutable path not found: ${ immutable.path }`, assignmentFileValidationError, AssignmentCheckerError.IMMUTABLE_PATH_NOT_FOUND);
+                throw new Error();
+            }
 
-                this.endStep('All requirements are satisfied', false);
+            const isDirectory = fs.lstatSync(immutablePath).isDirectory();
+            if ( isDirectory && !immutable.isDirectory ) {
+                this.emitError(`Immutable (${ immutable.path }) is declared as a file but is a directory.`, assignmentFileValidationError, AssignmentCheckerError.IMMUTABLE_PATH_IS_NOT_DIRECTORY);
+                throw new Error();
+            } else if ( !isDirectory && immutable.isDirectory === true ) {
+                this.emitError(`Immutable (${ immutable.path }) is declared as a directory but is a file.`, assignmentFileValidationError, AssignmentCheckerError.IMMUTABLE_PATH_IS_DIRECTORY);
+                throw new Error();
             }
+        }
+        this.endSubStep('Immutable files are valid', false);
 
 
-            /*
-             //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 2: dojo_assignment.json file validation
-             -   Structure validation
-             -   Immutable files validation (Check if exists and if the given type is correct)
-             */
-            {
-                this.newStep('ASSIGNMENT_FILE_VALIDATION', 'Please wait while we are validating dojo_assignment.json file...');
-
-
-                // Structure validation
-                this.newSubStep('ASSIGNMENT_FILE_SCHEMA_VALIDATION', 'Validating dojo_assignment.json file schema');
-                const validationResults = SharedAssignmentHelper.validateDescriptionFile(path.join(this.folderAssignment, ClientsSharedConfig.assignment.filename));
-                if ( !validationResults.isValid ) {
-                    this.emitError(`dojo_assignment.json file schema is invalid.\nHere are the errors:\n${ validationResults.error }`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.ASSIGNMENT_FILE_SCHEMA_ERROR);
-                    return;
-                }
-                assignmentFile = validationResults.content!;
-                this.endSubStep('dojo_assignment.json file schema is valid', false);
-
-
-                // Immutable files validation (Check if exists and if the given type is correct)
-                this.newSubStep('ASSIGNMENT_FILE_IMMUTABLES_VALIDATION', 'Validating immutable files');
-                for ( const immutable of validationResults.content!.immutable ) {
-                    const immutablePath = path.join(this.folderAssignment, immutable.path);
-                    if ( !fs.existsSync(immutablePath) ) {
-                        this.emitError(`Immutable path not found: ${ immutable.path }`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_NOT_FOUND);
-                        return;
-                    }
-
-                    const isDirectory = fs.lstatSync(immutablePath).isDirectory();
-                    if ( isDirectory && !immutable.isDirectory ) {
-                        this.emitError(`Immutable (${ immutable.path }) is declared as a file but is a directory.`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_IS_NOT_DIRECTORY);
-                        return;
-                    } else if ( !isDirectory && immutable.isDirectory === true ) {
-                        this.emitError(`Immutable (${ immutable.path }) is declared as a directory but is a file.`, 'dojo_assignment.json file is invalid', AssignmentCheckerError.IMMUTABLE_PATH_IS_DIRECTORY);
-                        return;
-                    }
-                }
-                this.endSubStep('Immutable files are valid', false);
-
-
-                this.endStep('dojo_assignment.json file is valid', false);
-            }
+        this.endStep('dojo_assignment.json file is valid', false);
+    }
 
+    /**
+     * Step 3: Docker Compose file validation
+     * -   Global validation
+     * -   Validation of the containers and volumes named in dojo_assignment.json
+     * @private
+     */
+    private async dockerComposeFileValidation() {
+        this.newStep('DOCKER_COMPOSE_VALIDATION', 'Please wait while we are validating docker compose file...');
+
+        const composeFileValidationError = `Docker compose file is invalid`;
+
+        // Global validation
+        this.newSubStep('DOCKER_COMPOSE_STRUCTURE_VALIDATION', 'Docker compose file structure validation');
+        try {
+            this.dockerComposeFile = YAML.parse(fs.readFileSync(path.join(this.folderAssignment, 'docker-compose.yml'), 'utf8')) as DojoDockerCompose;
+        } catch ( error ) {
+            this.emitError(`Docker compose file yaml structure is invalid.`, composeFileValidationError, AssignmentCheckerError.COMPOSE_FILE_YAML_ERROR);
+            throw new Error();
+        }
+
+        try {
+            await new Promise<void>((resolve, reject) => {
+                const dockerComposeValidation = spawn(`docker compose -f docker-compose.yml config --quiet`, {
+                    cwd  : this.folderAssignment,
+                    shell: true
+                });
+
+                dockerComposeValidation.on('exit', code => {
+                    code !== null && code === 0 ? resolve() : reject(code);
+                });
+            });
+        } catch ( error ) {
+            this.emitError(`Docker compose file structure is invalid.`, composeFileValidationError, AssignmentCheckerError.COMPOSE_FILE_SCHEMA_ERROR);
+            throw new Error();
+        }
+        this.endSubStep('Docker compose file structure is valid', false);
+
+
+        // Validation of the containers and volumes named in dojo_assignment.json
+        this.newSubStep('DOCKER_COMPOSE_CONTENT_VALIDATION', 'Docker compose file content validation');
+        if ( !(this.assignmentFile.result.container in this.dockerComposeFile.services) ) {
+            this.emitError(`Container specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, composeFileValidationError, AssignmentCheckerError.COMPOSE_FILE_CONTAINER_MISSING);
+            throw new Error();
+        }
+        if ( this.assignmentFile.result.volume && (!this.dockerComposeFile.volumes || !(this.assignmentFile.result.volume in this.dockerComposeFile.volumes)) ) {
+            this.emitError(`Volume specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, composeFileValidationError, AssignmentCheckerError.COMPOSE_FILE_VOLUME_MISSING);
+            throw new Error();
+        }
+        this.endSubStep('Docker compose file content is valid', false);
+
+
+        this.endStep('Docker compose file is valid', false);
+    }
+
+    /**
+     * Step 4: Dockerfiles validation
+     * -   Check if file exists
+     * -   TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint
+     * @private
+     */
+    private dockerfilesValidation() {
+        this.newStep('DOCKERFILE_VALIDATION', 'Please wait while we are validating dockerfiles...');
 
-            /*
-             //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 3: Docker Compose file validation
-             -   Global validation
-             -   Validation of the containers and volumes named in dojo_assignment.json
-             */
-            {
-                this.newStep('DOCKER_COMPOSE_VALIDATION', 'Please wait while we are validating docker compose file...');
-
-
-                // Global validation
-                this.newSubStep('DOCKER_COMPOSE_STRUCTURE_VALIDATION', 'Docker compose file structure validation');
-                try {
-                    dockerComposeFile = YAML.parse(fs.readFileSync(path.join(this.folderAssignment, 'docker-compose.yml'), 'utf8')) as DojoDockerCompose;
-                } catch ( error ) {
-                    this.emitError(`Docker compose file yaml structure is invalid.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_YAML_ERROR);
-                    return;
-                }
-
-                try {
-                    await new Promise<void>((resolve, reject) => {
-                        const dockerComposeValidation = spawn(`docker compose -f docker-compose.yml config --quiet`, {
-                            cwd  : this.folderAssignment,
-                            shell: true
-                        });
-
-                        dockerComposeValidation.on('exit', (code) => {
-                            code !== null && code == 0 ? resolve() : reject();
-                        });
-                    });
-                } catch ( error ) {
-                    this.emitError(`Docker compose file structure is invalid.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_SCHEMA_ERROR);
-                    return;
-                }
-                this.endSubStep('Docker compose file structure is valid', false);
-
-
-                // Validation of the containers and volumes named in dojo_assignment.json
-                this.newSubStep('DOCKER_COMPOSE_CONTENT_VALIDATION', 'Docker compose file content validation');
-                if ( !(assignmentFile.result.container in dockerComposeFile!.services) ) {
-                    this.emitError(`Container specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_CONTAINER_MISSING);
-                    return;
-                }
-                if ( assignmentFile.result.volume && (!dockerComposeFile!.volumes || !(assignmentFile.result.volume in dockerComposeFile!.volumes)) ) {
-                    this.emitError(`Volume specified in ${ ClientsSharedConfig.assignment.filename } is missing from compose file.`, 'Docker compose file is invalid', AssignmentCheckerError.COMPOSE_FILE_VOLUME_MISSING);
-                    return;
-                }
-                this.endSubStep('Docker compose file content is valid', false);
-
-
-                this.endStep('Docker compose file is valid', false);
-            }
 
+        this.newSubStep('DOCKERFILE_EXIST', 'Docker compose file content validation');
+        const dockerfilesPaths = Object.values(this.dockerComposeFile.services).filter(service => service.build).map(service => path.join(this.folderAssignment, service.build!.context ?? '', service.build!.dockerfile!));
+        const filesNotFound = dockerfilesPaths.filter(dockerfilePath => !fs.existsSync(dockerfilePath));
+        if ( filesNotFound.length > 0 ) {
+            this.emitError(`Dockerfiles not found: ${ filesNotFound.join(', ') }`, 'Dockerfiles are invalid', AssignmentCheckerError.DOCKERFILE_NOT_FOUND);
+            throw new Error();
+        }
+        this.endSubStep('Docker compose file content is valid', false);
 
-            /*
-             //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 4: Dockerfiles validation
-             -   Check if file exists
-             -   TODO - Dockerfile structure linter - Issue #51 - https://github.com/hadolint/hadolint
-             */
-            {
-                this.newStep('DOCKERFILE_VALIDATION', 'Please wait while we are validating dockerfiles...');
 
+        this.endStep('Dockerfiles are valid', false);
+    }
 
-                this.newSubStep('DOCKERFILE_EXIST', 'Docker compose file content validation');
-                const dockerfilesPaths = Object.values(dockerComposeFile!.services).filter((service) => service.build).map((service) => path.join(this.folderAssignment, service.build!.context ?? '', service.build!.dockerfile!));
-                const filesNotFound = dockerfilesPaths.filter((dockerfilePath) => !fs.existsSync(dockerfilePath));
-                if ( filesNotFound.length > 0 ) {
-                    this.emitError(`Dockerfiles not found: ${ filesNotFound.join(', ') }`, 'Dockerfiles are invalid', AssignmentCheckerError.DOCKERFILE_NOT_FOUND);
-                    return;
-                }
-                this.endSubStep('Docker compose file content is valid', false);
+    /**
+     * Step 5: Run
+     * -   Make a run of the assignment (If the return code is 0, the assignment is not valid because it means that there no need of modification for succeed the exercise)
+     * @private
+     */
+    private async runAssignment() {
+        this.newStep('ASSIGNMENT_RUN', 'Please wait while we are running the assignment...');
 
 
-                this.endStep('Dockerfiles are valid', false);
-            }
+        const exerciseDockerCompose = new ExerciseDockerCompose(ClientsSharedConfig.dockerCompose.projectName, this.assignmentFile, this.folderAssignment);
 
+        try {
+            await new Promise<void>((resolve, reject) => {
+                exerciseDockerCompose.events.on('logs', (log: string, error: boolean, displayable: boolean) => {
+                    this.log(log, error, displayable);
+                });
 
-            /*
-             //////////////////////////////////////////////////////////////////////////////////////////////////////////// Step 5: Run
-             -   Make a run of the assignment (If the return code is 0, the assignment is not valid because it means that there no need of modification for succeed the exercise)
-             */
-            {
-                this.newStep('ASSIGNMENT_RUN', 'Please wait while we are running the assignment...');
+                exerciseDockerCompose.events.on('step', (name: string, message: string) => {
+                    this.newSubStep(name, message);
+                });
 
+                exerciseDockerCompose.events.on('endStep', (_stepName: string, message: string, error: boolean) => {
+                    this.endSubStep(message, error);
+                });
 
-                const exerciseDockerCompose = new ExerciseDockerCompose(ClientsSharedConfig.dockerCompose.projectName, assignmentFile, this.folderAssignment);
+                exerciseDockerCompose.events.on('finished', (_success: boolean, exitCode: number) => {
+                    exitCode !== 0 ? resolve() : reject(exitCode);
+                });
 
-                try {
-                    await new Promise<void>((resolve, reject) => {
-                        exerciseDockerCompose.events.on('logs', (log: string, error: boolean, displayable: boolean) => {
-                            this.log(log, error, displayable);
-                        });
+                exerciseDockerCompose.run(this.doDown);
+            });
+        } catch ( error ) {
+            this.fatalErrorMessage = 'Assignment is already solved';
+            this.endStep(this.fatalErrorMessage, true);
+            this.finished(false, AssignmentCheckerError.COMPOSE_RUN_SUCCESSFULLY);
+            throw new Error();
+        }
 
-                        exerciseDockerCompose.events.on('step', (name: string, message: string) => {
-                            this.newSubStep(name, message);
-                        });
 
-                        exerciseDockerCompose.events.on('endStep', (stepName: string, message: string, error: boolean) => {
-                            this.endSubStep(message, error);
-                        });
+        this.endStep('Assignment run successfully', false);
+    }
 
-                        exerciseDockerCompose.events.on('finished', (success: boolean, exitCode: number) => {
-                            exitCode != 0 ? resolve() : reject();
-                        });
+    run() {
+        (async () => {
+            try {
+                await this.checkRequirements();
 
-                        exerciseDockerCompose.run(doDown);
-                    });
-                } catch ( error ) {
-                    this.fatalErrorMessage = 'Assignment is already solved';
-                    this.endStep(this.fatalErrorMessage, true);
-                    this.finished(false, AssignmentCheckerError.COMPOSE_RUN_SUCCESSFULLY);
-                    return;
-                }
+                this.dojoAssignmentFileValidation();
 
+                await this.dockerComposeFileValidation();
 
-                this.endStep('Assignment run successfully', false);
-            }
+                this.dockerfilesValidation();
 
+                await this.runAssignment();
 
-            this.finished(true, 0);
+                this.finished(true, 0);
+            } catch ( error ) {
+                return;
+            }
         })();
     }
 }
diff --git a/helpers/Dojo/ClientsSharedAssignmentHelper.ts b/helpers/Dojo/ClientsSharedAssignmentHelper.ts
index c47d2b4d0ff9eec6019b387429dcc8c00c031825..9c0eb460ac75a392c00af9c515b691979479eb2a 100644
--- a/helpers/Dojo/ClientsSharedAssignmentHelper.ts
+++ b/helpers/Dojo/ClientsSharedAssignmentHelper.ts
@@ -6,7 +6,8 @@ import AssignmentValidator from './AssignmentValidator';
 
 class ClientsSharedAssignmentHelper {
     displayExecutionResults(validator: AssignmentValidator, successMessage: string, Style: { INFO: chalk.Chalk, SUCCESS: chalk.Chalk, FAILURE: chalk.Chalk }) {
-        const finalLogGlobalResult = `${ Style.INFO('Global result') } : ${ validator.success ? Style.SUCCESS(`${ Icon.SUCCESS } Success`) : Style.FAILURE(`${ Icon.FAILURE } Failure`) }`;
+        const globalResult = validator.success ? Style.SUCCESS(`${ Icon.SUCCESS } Success`) : Style.FAILURE(`${ Icon.FAILURE } Failure`);
+        const finalLogGlobalResult = `${ Style.INFO('Global result') } : ${ globalResult }`;
 
         const finalLogSuccessMessage = validator.success ? `${ successMessage }` : '';
         const finalLogErrorMessage = !validator.success ? `${ Style.INFO('Error message') } :\n${ Style.FAILURE(validator.fatalErrorMessage) }` : '';
diff --git a/helpers/Dojo/ClientsSharedExerciseHelper.ts b/helpers/Dojo/ClientsSharedExerciseHelper.ts
index dd8b173f49f911c55759b01042ad1b48e8409b57..740b7695bf484dbb9e0c54bfa0f21bd902926c6a 100644
--- a/helpers/Dojo/ClientsSharedExerciseHelper.ts
+++ b/helpers/Dojo/ClientsSharedExerciseHelper.ts
@@ -5,27 +5,31 @@ import Icon                from '../../../shared/types/Icon';
 
 
 class ClientsSharedExerciseHelper {
-    displayExecutionResults(exerciseResults: ExerciseResultsFile, containerExitCode: number, Style: { INFO: chalk.Chalk, SUCCESS: chalk.Chalk, FAILURE: chalk.Chalk }, additionalText: string = '') {
-        const finalLogGlobalResult = `${ Style.INFO('Global result: ') }${ exerciseResults.success ? Style.SUCCESS(`${ Icon.SUCCESS } Success`) : Style.FAILURE(`${ Icon.FAILURE } Failure`) }`;
 
-        const finalLogExecutionExitCode = `${ Style.INFO('Execution exit code: ') }${ (containerExitCode == 0 ? Style.SUCCESS : Style.FAILURE)(containerExitCode) }`;
+    private getOtherInformations(exerciseResults: ExerciseResultsFile, Style: { INFO: chalk.Chalk, SUCCESS: chalk.Chalk, FAILURE: chalk.Chalk }) {
+        return exerciseResults.otherInformations ? [ '', ...exerciseResults.otherInformations.map(information => {
+            const informationTitle = Style.INFO(`${ information.icon && information.icon !== '' ? Icon[information.icon] + ' ' : '' }${ information.name }: `);
+            const informationItems = typeof information.itemsOrInformations == 'string' ? information.itemsOrInformations : information.itemsOrInformations.map(item => `- ${ item }`).join('\n');
 
-        const finalLogResultNumbers = exerciseResults.successfulTests || exerciseResults.failedTests ? `\n\n${ Style.INFO(Style.SUCCESS('Tests passed: ')) }${ exerciseResults.successfulTests ?? '--' }\n${ Style.INFO(Style.FAILURE('Tests failed: ')) }${ exerciseResults.failedTests ?? '--' }` : '';
+            return `${ informationTitle }\n${ informationItems }`;
+        }) ].join('\n\n') : '';
+    }
 
-        const finalLogSuccessResultDetails = (exerciseResults.successfulTestsList ?? []).map(testName => `- ${ Icon.SUCCESS } ${ testName }`).join('\n');
-        const finalLogFailedResultDetails = (exerciseResults.failedTestsList ?? []).map(testName => `- ${ Icon.FAILURE } ${ testName }`).join('\n');
-        const finalLogResultDetails = exerciseResults.successfulTestsList || exerciseResults.failedTestsList ? `\n\n${ Style.INFO('Tests: ') }${ finalLogSuccessResultDetails != '' ? '\n' + finalLogSuccessResultDetails : '' }${ finalLogFailedResultDetails != '' ? '\n' + finalLogFailedResultDetails : '' }` : '';
+    displayExecutionResults(exerciseResults: ExerciseResultsFile, containerExitCode: number, Style: { INFO: chalk.Chalk, SUCCESS: chalk.Chalk, FAILURE: chalk.Chalk }, additionalText: string = '') {
+        const globalResult = exerciseResults.success ? Style.SUCCESS(`${ Icon.SUCCESS } Success`) : Style.FAILURE(`${ Icon.FAILURE } Failure`);
+        const finalLogGlobalResult = `${ Style.INFO('Global result: ') }${ globalResult }`;
+
+        const finalLogExecutionExitCode = `${ Style.INFO('Execution exit code: ') }${ (containerExitCode === 0 ? Style.SUCCESS : Style.FAILURE)(containerExitCode) }`;
 
-        let finalLogInformations = '';
-        if ( exerciseResults.otherInformations ) {
-            finalLogInformations = [ '', ...exerciseResults.otherInformations.map(information => {
-                const informationTitle = Style.INFO(`${ information.icon && information.icon != '' ? Icon[information.icon] + ' ' : '' }${ information.name }: `);
-                const informationItems = typeof information.itemsOrInformations == 'string' ? information.itemsOrInformations : information.itemsOrInformations.map(item => `- ${ item }`).join('\n');
+        const finalLogResultNumbers = exerciseResults.successfulTests || exerciseResults.failedTests ? `\n\n${ Style.INFO(Style.SUCCESS('Tests passed: ')) }${ exerciseResults.successfulTests ?? '--' }\n${ Style.INFO(Style.FAILURE('Tests failed: ')) }${ exerciseResults.failedTests ?? '--' }` : '';
 
-                return `${ informationTitle }\n${ informationItems }`;
-            }) ].join('\n\n');
-        }
+        let finalLogSuccessResultDetails = (exerciseResults.successfulTestsList ?? []).map(testName => `- ${ Icon.SUCCESS } ${ testName }`).join('\n');
+        finalLogSuccessResultDetails = finalLogSuccessResultDetails !== '' ? '\n' + finalLogSuccessResultDetails : '';
+        let finalLogFailedResultDetails = (exerciseResults.failedTestsList ?? []).map(testName => `- ${ Icon.FAILURE } ${ testName }`).join('\n');
+        finalLogFailedResultDetails = finalLogFailedResultDetails !== '' ? '\n' + finalLogFailedResultDetails : '';
+        const finalLogResultDetails = exerciseResults.successfulTestsList || exerciseResults.failedTestsList ? `\n\n${ Style.INFO('Tests: ') }${ finalLogSuccessResultDetails }${ finalLogFailedResultDetails }` : '';
 
+        const finalLogInformations = this.getOtherInformations(exerciseResults, Style);
 
         console.log(boxen(`${ finalLogGlobalResult }\n\n${ finalLogExecutionExitCode }${ finalLogResultNumbers }${ finalLogResultDetails }${ finalLogInformations }${ additionalText }`, {
             title         : 'Results',
diff --git a/helpers/Dojo/DojoBackendHelper.ts b/helpers/Dojo/DojoBackendHelper.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c682bfb71fdd895a6d3761fea6694754542074ee
--- /dev/null
+++ b/helpers/Dojo/DojoBackendHelper.ts
@@ -0,0 +1,28 @@
+import ApiRoute            from '../../types/Dojo/ApiRoute';
+import ClientsSharedConfig from '../../config/ClientsSharedConfig';
+
+
+class DojoBackendHelper {
+    public getApiUrl(route: ApiRoute, options?: Partial<{ assignmentNameOrUrl: string, exerciseIdOrUrl: string, gitlabProjectId: string }>): string {
+        const url = `${ ClientsSharedConfig.apiURL }${ route }`;
+
+        if ( options ) {
+            if ( options.assignmentNameOrUrl ) {
+                return url.replace('{{assignmentNameOrUrl}}', encodeURIComponent(options.assignmentNameOrUrl));
+            }
+
+            if ( options.exerciseIdOrUrl ) {
+                return url.replace('{{exerciseIdOrUrl}}', encodeURIComponent(options.exerciseIdOrUrl));
+            }
+
+            if ( options.gitlabProjectId ) {
+                return url.replace('{{gitlabProjectId}}', encodeURIComponent(options.gitlabProjectId));
+            }
+        }
+
+        return url;
+    }
+}
+
+
+export default new DojoBackendHelper();
\ No newline at end of file
diff --git a/helpers/Dojo/ExerciseDockerCompose.ts b/helpers/Dojo/ExerciseDockerCompose.ts
index ad033438c57eb8918aff6bc7278b8197ecc585ac..64d60c38346bee7ed44cc242e3ca6d79ed6c093e 100644
--- a/helpers/Dojo/ExerciseDockerCompose.ts
+++ b/helpers/Dojo/ExerciseDockerCompose.ts
@@ -18,7 +18,17 @@ class ExerciseDockerCompose {
 
     private currentStep: string = 'NOT_RUNNING';
 
-    constructor(private projectName: string, private assignmentFile: AssignmentFile, private executionFolder: string, private composeFileOverride: Array<string> = []) {
+    private readonly projectName: string;
+    private readonly assignmentFile: AssignmentFile;
+    private readonly executionFolder: string;
+    private readonly composeFileOverride: Array<string> = [];
+
+    constructor(projectName: string, assignmentFile: AssignmentFile, executionFolder: string, composeFileOverride: Array<string> = []) {
+        this.projectName = projectName;
+        this.assignmentFile = assignmentFile;
+        this.executionFolder = executionFolder;
+        this.composeFileOverride = composeFileOverride;
+
         this.events.on('logs', (log: string, _error: boolean, displayable: boolean) => {
             this.allLogs += log;
             this.displayableLogs += displayable ? log : '';
@@ -49,15 +59,15 @@ class ExerciseDockerCompose {
     }
 
     private registerChildProcess(childProcess: ChildProcessWithoutNullStreams, resolve: (value: (number | PromiseLike<number>)) => void, reject: (reason?: unknown) => void, displayable: boolean, rejectIfCodeIsNotZero: boolean) {
-        childProcess.stdout.on('data', (data) => {
+        childProcess.stdout.on('data', data => {
             this.log(data.toString(), false, displayable);
         });
 
-        childProcess.stderr.on('data', (data) => {
+        childProcess.stderr.on('data', data => {
             this.log(data.toString(), true, displayable);
         });
 
-        childProcess.on('exit', (code) => {
+        childProcess.on('exit', code => {
             code === null || (rejectIfCodeIsNotZero && code !== 0) ? reject(code) : resolve(code);
         });
     }
@@ -66,7 +76,8 @@ class ExerciseDockerCompose {
         (async () => {
             let containerExitCode: number = -1;
 
-            const dockerComposeCommand = `docker compose --project-name ${ this.projectName } --progress plain --file docker-compose.yml ${ this.composeFileOverride.map((file) => `--file "${ file }"`).join(' ') }`;
+            const filesOverrideArguments = this.composeFileOverride.map(file => `--file "${ file }"`).join(' ');
+            const dockerComposeCommand = `docker compose --project-name ${ this.projectName } --progress plain --file docker-compose.yml ${ filesOverrideArguments }`;
 
             // Run the service
             {
diff --git a/helpers/Dojo/ExerciseResultsSanitizerAndValidator.ts b/helpers/Dojo/ExerciseResultsSanitizerAndValidator.ts
index 8a1ec41c241c1e3c757726723dd7509440689b12..38ffa923fd74d191787e20ebf832adc9e6325bec 100644
--- a/helpers/Dojo/ExerciseResultsSanitizerAndValidator.ts
+++ b/helpers/Dojo/ExerciseResultsSanitizerAndValidator.ts
@@ -17,7 +17,15 @@ class ExerciseResultsSanitizerAndValidator {
 
     private resultsFilePath: string = '';
 
-    constructor(private folderResultsDojo: string, private folderResultsExercise: string, private containerExitCode: number) { }
+    private readonly folderResultsDojo: string;
+    private readonly folderResultsExercise: string;
+    private readonly containerExitCode: number;
+
+    constructor(folderResultsDojo: string, folderResultsExercise: string, containerExitCode: number) {
+        this.folderResultsDojo = folderResultsDojo;
+        this.folderResultsExercise = folderResultsExercise;
+        this.containerExitCode = containerExitCode;
+    }
 
     private async resultsFileSanitization() {
         this.events.emit('step', 'RESULTS_FILE_SANITIZATION', 'Sanitizing results file');
@@ -33,11 +41,11 @@ class ExerciseResultsSanitizerAndValidator {
         this.events.emit('endStep', 'RESULTS_FILE_SANITIZATION', 'Results file sanitized', false);
     }
 
-    private async resultsFileProvided(path: string): Promise<boolean> {
+    private async resultsFileProvided(resultFilePath: string): Promise<boolean> {
         // Results file schema validation
         {
             this.events.emit('step', 'VALIDATE_RESULTS_FILE', 'Validating results file schema');
-            const validationResults = Json5FileValidator.validateFile(ExerciseResultsFile, path);
+            const validationResults = Json5FileValidator.validateFile(ExerciseResultsFile, resultFilePath);
             if ( !validationResults.isValid ) {
                 this.events.emit('endStep', 'VALIDATE_RESULTS_FILE', `Results file is not valid. Here are the errors :\n${ validationResults.error }`, true);
                 this.events.emit('finished', false, ExerciseCheckerError.EXERCISE_RESULTS_FILE_SCHEMA_NOT_VALID);
diff --git a/models/Exercise.ts b/models/Exercise.ts
index 710314ee1d377a117650fe1ced9ec171de104638..b8a2b83b02d763effa7516905028fd760da37cf7 100644
--- a/models/Exercise.ts
+++ b/models/Exercise.ts
@@ -1,5 +1,5 @@
 import GitlabRepository from '../../shared/types/Gitlab/GitlabRepository';
-import { CommitSchema } from '@gitbeaker/rest';
+import * as Gitlab      from '@gitbeaker/rest';
 import User             from './User';
 import Assignment       from './Assignment';
 
@@ -18,7 +18,7 @@ interface Exercise {
     assignment: Assignment | undefined;
 
     isCorrection: boolean;
-    correctionCommit: CommitSchema | undefined;
+    correctionCommit: Gitlab.CommitSchema | undefined;
 }
 
 
diff --git a/types/Dojo/ApiRoute.ts b/types/Dojo/ApiRoute.ts
index 53e3f9f59129ce7eecef1c82d9ecd6a0ab28db27..8e4969b6de34599ca29e803ca6fbcd3a3c91d799 100644
--- a/types/Dojo/ApiRoute.ts
+++ b/types/Dojo/ApiRoute.ts
@@ -2,16 +2,16 @@ enum ApiRoute {
     LOGIN                        = '/login',
     REFRESH_TOKENS               = '/refresh_tokens',
     TEST_SESSION                 = '/test_session',
-    GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{id}}/checkTemplateAccess',
-    ASSIGNMENT_GET               = '/assignments/{{nameOrUrl}}',
+    GITLAB_CHECK_TEMPLATE_ACCESS = '/gitlab/project/{{gitlabProjectId}}/checkTemplateAccess',
+    ASSIGNMENT_GET               = '/assignments/{{assignmentNameOrUrl}}',
     ASSIGNMENT_CREATE            = '/assignments',
-    ASSIGNMENT_PUBLISH           = '/assignments/{{nameOrUrl}}/publish',
-    ASSIGNMENT_UNPUBLISH         = '/assignments/{{nameOrUrl}}/unpublish',
+    ASSIGNMENT_PUBLISH           = '/assignments/{{assignmentNameOrUrl}}/publish',
+    ASSIGNMENT_UNPUBLISH         = '/assignments/{{assignmentNameOrUrl}}/unpublish',
     ASSIGNMENT_CORRECTION_LINK   = '/assignments/{{assignmentNameOrUrl}}/corrections',
     ASSIGNMENT_CORRECTION_UPDATE = '/assignments/{{assignmentNameOrUrl}}/corrections/{{exerciseIdOrUrl}}',
-    EXERCISE_CREATE              = '/assignments/{{nameOrUrl}}/exercises',
-    EXERCISE_ASSIGNMENT          = '/exercises/{{id}}/assignment',
-    EXERCISE_RESULTS             = '/exercises/{{id}}/results'
+    EXERCISE_CREATE              = '/assignments/{{assignmentNameOrUrl}}/exercises',
+    EXERCISE_ASSIGNMENT          = '/exercises/{{exerciseIdOrUrl}}/assignment',
+    EXERCISE_RESULTS             = '/exercises/{{exerciseIdOrUrl}}/results'
 }