lundi 26 avril 2021

Design pattern that handles multiple steps

So I have a complicated onboarding process that does several steps. I created a class that handles the process but I've added a few more steps and I'd like to refactor this into something a bit more manageable. I refactored to use Laravel's pipeline, but feel this may not be the best refactor due to the output needing to be modified before each step.

Here is an example before and after with some pseudo code.

before
class OnboardingClass {
    public $user;
    public $conversation;

    public function create($firstName, $lastName, $email){

        // Step 1
        $user = User::create();
        
        // Step 2
        $conversation = Conversation::create(); // store information for new user + existing user
        
        // Step 3
        $conversation->messages()->create(); // store a message on the conversation

        // Step 4
        // Send api request to analytics
        
        // Step 5
        // Send api request to other service

        return $this;
    }
}
after
class OnboardingClass{
    public $user;
    public $conversation;

    public function create($firstName, $lastName, $email){
        $data = ['first_name' => $firstName, ...]; // form data

        $pipeline = app(Pipeline::Class);
        
        $pipeline->send($data)
            ->through([
                CreateUser::class,
                CreateNewUserConversation::class,
                AddWelcomeMessageToConversation::class,
                ...
            ])->then(function($data){
                // set all properties returned from last class in pipeline.
                $this->user = $data['user'];
                $this->conversation = $data['conversation'];
            });

        return $this;
    }
}

Now within each class I modify the previous data and output a modified version something like this

class CreateUser implements Pipe {
    public function handle($data, Closure $next) {
        // do some stuff
        $user = User::create():
    
        return $next([
            'user' => $user,
            'other' => 'something else'
        ]);
    }
}

In my controller I am simply calling the create method.

class someController() {
    public function store($request){
        $onboarding = app(OnboardingClass::class);
        $onboarding->create('John', 'Doe', 'john@example.com');
    }
}

So the first pipe receives the raw form fields and outputs what the second pipe needs to get the job done in its class, then the next class outputs the data required by the next class, so on and so forth. The data that comes into each pipe is not the same each time and you cannot modify the order.

Feels a bit weird and I'm sure there is a cleaner way to handle this.

Any design pattern I can utilize to clean this up a bit?

Aucun commentaire:

Enregistrer un commentaire