vincent15000's avatar

Code architecture for adding easily new challenge types (scalability)

Hello,

I develop an web application for treasure quests.

At the beginning, I will have some challenge types. If I want to add a new challenge type in the future, I don't want to modify the code, just add a new class to add the new challenge type.

I asked the AI and it gave me some example, but it seems to be quite complex to just add a new challenge type.

What do you think about this solution suggested by the AI ?

https://chatgpt.com/share/69ca384f-273c-8332-8d9c-1b897e430910

https://chatgpt.com/share/69ca385e-c954-8326-abcf-cc69482aaf23

What I would like is just add a new class and 3 new views for each new challenge type.

The class could have some static information about the challenge type itself (the type, the name of the view, the properties, ...) and some validation logic to check if the player has provided the right answer.

And the views would have what is needed to display the form, the challenge type for the creators and the challenge for the players.

I think that each challenge type appears like a module or a plugin, it's probably for this reason that the AI gave me a solution with a service provider, but I think that it's too much for what I need.

What would you suggest me ?

Thanks for your answer.

V

0 likes
3 replies
LaryAI's avatar
Level 58

Absolutely, your use case is perfect for a plug-n-play, class-based approach: each challenge type as a self-contained class ("plugin"), with its own validation logic and static metadata. In Laravel or any normal PHP app, you can make this both scalable and simple—no need for a complex service provider setup for each new type.

Recommended Solution:

1. Define a ChallengeType interface (contract):

This defines what any challenge type must provide: static info, validation, etc.

<?php

namespace App\ChallengeTypes;

interface ChallengeType
{
    public static function type(): string;
    public static function name(): string;
    public static function view(): string;

    // For challenge configuration (for creators)
    public static function creatorView(): string;

    // For player interaction
    public static function playerView(): string;

    // Validation (for player submitted answers)
    public function validateAnswer(array $challengeData, $userAnswer): bool;
}

2. Implement concrete challenge types:

Example: MultipleChoiceChallenge

3. Challenge Type Registry / Discovery

Have a central place to register available challenge types, e.g. in a config/challenge_types.php:

return [
    \App\ChallengeTypes\MultipleChoiceChallenge::class,
    \App\ChallengeTypes\TextAnswerChallenge::class,
    // just add to this array as you add new classes!
];

(You could also auto-discover classes in a directory if you want.)

4. Usage in your code

Any time you need to render/create/validate a challenge, you look up the right class (by type), instantiate it, and use the methods:

$type = 'multiple_choice'; // from DB or user input

$challengeClass = collect(config('challenge_types'))
    ->first(fn($class) => $class::type() === $type);

$challenge = new $challengeClass();

// For rendering views
$view = $challengeClass::playerView(); // or creatorView()

// For validation
$isCorrect = $challenge->validateAnswer($challengeData, $userAnswer);

5. Adding a new challenge type:
Just make a new class implementing the interface, add it to your array. No central code changes needed.

6. Views
Store your Blade templates for each challenge type in subfolders or with type-based names, as above.


Why This Works Well

  • No need to edit central logic or controllers.
  • Adding a type: Just 1 class + 3 blade views, that's it!
  • Very scalable, easy to maintain.
  • Pluggable and testable design.

If you want to make it even simpler, you can autoload all classes in a directory; but the above is already much simpler than a service provider/complex plugin discovery system.

Let me know if you want code snippets for auto-discovery, or a working example repo!

martinbean's avatar

@vincent15000 You’ve already asked about this multiple times before. I know because I’ve replied to at least two threads on this very topic from you. What was wrong with those suggestions…?

1 like
vincent15000's avatar

Oh sorry, yes I have already asked an nothing was wrong with your suggestions.

I should have continued the other post.

It's just that what I imagine for the solution has evolved.

I have at least chosen an architecture, I just implemeted it last week and it works fine.

Please or to participate in this conversation.