diff --git a/src/Collection/EventCollection.php b/src/Collection/EventCollection.php
deleted file mode 100644
index 7a6357d..0000000
--- a/src/Collection/EventCollection.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Collection;
-
-use Illuminate\Support\Arr;
-use Illuminate\Support\Collection;
-
-final class EventCollection extends Collection
-{
-    public function excludeEventHosts(): self
-    {
-        return (new self($this->items))->filter(function (array $rsvp): bool {
-            return !$rsvp['member']['event_context']['host'];
-        });
-    }
-}
diff --git a/src/Collection/RsvpCollection.php b/src/Collection/RsvpCollection.php
new file mode 100644
index 0000000..a164821
--- /dev/null
+++ b/src/Collection/RsvpCollection.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Collection;
+
+use Illuminate\Support\Arr;
+use Illuminate\Support\Collection;
+
+final class RsvpCollection extends Collection
+{
+    private const RESPONSE_ATTENDING = 'yes';
+
+    public function excludeEventHosts(): self
+    {
+        return (new self($this->items))->filter(
+            function (array $rsvp): bool {
+                return !$rsvp['member']['event_context']['host'];
+            }
+        );
+    }
+
+    public function onlyAttending(): self
+    {
+        return (new self($this->items))->filter(
+            function (array $rsvp): bool {
+                return $rsvp['response'] == self::RESPONSE_ATTENDING;
+            }
+        );
+    }
+
+    public function getNames(): self
+    {
+        return (new self($this->items))->pluck('member.name')->sort();
+    }
+}
diff --git a/src/Command/GetRaffleWinnerCommand.php b/src/Command/GetRaffleWinnerCommand.php
index 27fb28c..c95a1d1 100644
--- a/src/Command/GetRaffleWinnerCommand.php
+++ b/src/Command/GetRaffleWinnerCommand.php
@@ -4,7 +4,9 @@ declare(strict_types=1);
 
 namespace App\Command;
 
-use App\Collection\EventCollection;
+use App\Collection\RsvpCollection;
+use App\UseCase\FindTheWinner;
+use App\ValueObject\Winner;
 use DateInterval;
 use Illuminate\Support\Collection;
 use Symfony\Component\Console\Command\Command;
@@ -17,6 +19,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
 
 final class GetRaffleWinnerCommand extends Command
 {
+
     protected static $defaultName = 'app:get-raffle-winner';
 
     private HttpClientInterface $client;
@@ -58,91 +61,39 @@ final class GetRaffleWinnerCommand extends Command
         OutputInterface $output
     ): int {
         $io = new SymfonyStyle($input, $output);
-        $eventId = (int) $input->getArgument('event_id');
+        $eventId = (int)$input->getArgument('event_id');
 
-        $this->retrieveEventData($eventId);
-        $this->retrieveRsvps($eventId);
-        $this->pickWinner();
+        $result = (new FindTheWinner(
+            $this->client,
+            $this->cache,
+            $eventId
+        ))->__invoke();
 
-        $io->title(sprintf(
-            '%s - %s',
-            $this->eventData['group']['name'],
-            $this->eventData['name']
-        ));
+        $event = $result->getEvent();
+        $io->title($event->getName());
+        $io->text($event->getLink());
 
-        $io->text(rtrim($this->eventData['link'], '/'));
-
-        $io->section(sprintf('%s \'yes\' RSVPs (excluding hosts)', $this->yesRsvps->count()));
-        $io->listing($this->yesRsvps->pluck('member.name')->sort()->toArray());
-        $io->writeln(
-            sprintf('Winner: %s', $this->winner['member']['name'])
+        $io->section(
+            sprintf(
+                '%s \'yes\' RSVPs (excluding hosts)',
+                $result->getRsvps()->count()
+            )
         );
 
-        $this->openWinnerPhoto($io);
+        $io->listing($result->getRsvps()->getNames()->toArray());
+
+        $io->writeln(
+            sprintf('Winner: %s', $result->getWinner()->getName())
+        );
+
+        $this->openWinnerPhoto($result->getWinner(), $io);
 
         return 0;
     }
 
-    private function retrieveEventData(int $eventId): void
+    private function openWinnerPhoto(Winner $winner, SymfonyStyle $io): void
     {
-        $eventData = $this->cache->getItem(sprintf('event.%d', $eventId));
-
-        if (!$eventData->isHit()) {
-            $response = $this->client->request(
-                'GET',
-                sprintf(
-                    'https://api.meetup.com/%s/events/%d',
-                    'php-south-wales',
-                    $eventId
-                )
-            );
-
-            $eventData->expiresAfter(DateInterval::createFromDateString('1 hour'));
-            $this->eventData = $response->toArray();
-            $this->cache->save($eventData->set($this->eventData));
-        } else {
-            $this->eventData = $eventData->get();
-        }
-    }
-
-    private function retrieveRsvps(int $eventId): void
-    {
-        $rsvps = $this->cache->getItem(sprintf('rsvps.%d', $eventId));
-
-        if (!$rsvps->isHit()) {
-            $response = $this->client->request(
-                'GET',
-                vsprintf(
-                    'https://api.meetup.com/%s/events/%d/rsvps',
-                    [
-                      'php-south-wales',
-                      $eventId,
-                    ]
-                )
-            );
-
-            $this->rsvps = EventCollection::make($response->toArray())
-                ->excludeEventHosts();
-
-            $rsvps->expiresAfter(DateInterval::createFromDateString('1 hour'));
-            $this->cache->save($rsvps->set($this->rsvps));
-        } else {
-            $this->rsvps = $rsvps->get();
-        }
-
-        $this->yesRsvps = $this->rsvps->filter(function (array $rsvp): bool {
-            return $rsvp['response'] == 'yes';
-        });
-    }
-
-    private function pickWinner(): void
-    {
-        $this->winner = $this->yesRsvps->random(1)->first();
-    }
-
-    private function openWinnerPhoto(SymfonyStyle $io): void
-    {
-        if ($photo = $this->winner['member']['photo']['photo_link'] ?? NULL) {
+        if ($photo = $winner->getPhoto()) {
             $io->write($photo);
         }
     }
diff --git a/src/UseCase/FindTheWinner.php b/src/UseCase/FindTheWinner.php
new file mode 100644
index 0000000..f7990e8
--- /dev/null
+++ b/src/UseCase/FindTheWinner.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\UseCase;
+
+use App\Collection\RsvpCollection;
+use App\ValueObject\Event;
+use App\ValueObject\Result;
+use App\ValueObject\Winner;
+use DateInterval;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+
+final class FindTheWinner implements UseCaseInterface
+{
+
+    private int $eventId;
+
+    private HttpClientInterface $client;
+
+    private CacheInterface $cache;
+
+    private RsvpCollection $yesRsvps;
+
+    public function __construct(
+        HttpClientInterface $client,
+        CacheInterface $cache,
+        int $eventId
+    ) {
+        $this->eventId = $eventId;
+        $this->client = $client;
+        $this->cache = $cache;
+    }
+
+    public function __invoke(): Result
+    {
+        $eventData = $this->retrieveEventData();
+        $rsvps = $this->retrieveRsvps();
+        $winner = $this->pickWinner($rsvps);
+
+        return new Result(
+            Winner::createFromArray($winner),
+            Event::createFromArray($eventData),
+            $rsvps
+        );
+    }
+
+    private function retrieveEventData(): array
+    {
+        $eventData = $this->cache->getItem(sprintf('event.%d', $this->eventId));
+
+        if (!$eventData->isHit()) {
+            $response = $this->client->request(
+                'GET',
+                sprintf(
+                    'https://api.meetup.com/%s/events/%d',
+                    'php-south-wales',
+                    $this->eventId
+                )
+            );
+
+            $eventData->expiresAfter(
+                DateInterval::createFromDateString('1 hour')
+            );
+            $return = $response->toArray();
+            $this->cache->save($eventData->set($return));
+
+            return $return;
+        } else {
+            return $eventData->get();
+        }
+    }
+
+    private function retrieveRsvps(): RsvpCollection
+    {
+        $rsvps = $this->cache->getItem(sprintf('rsvps.%d', $this->eventId));
+
+        if (!$rsvps->isHit()) {
+            $response = $this->client->request(
+                'GET',
+                sprintf(
+                    'https://api.meetup.com/%s/events/%d/rsvps',
+                    'php-south-wales',
+                    $this->eventId
+                )
+            );
+
+            $filteredRsvps = RsvpCollection::make($response->toArray())
+                ->excludeEventHosts()
+                ->onlyAttending();
+
+            $rsvps->expiresAfter(DateInterval::createFromDateString('1 hour'));
+            $this->cache->save($rsvps->set($filteredRsvps));
+
+            return $filteredRsvps;
+        } else {
+            return $rsvps->get();
+        }
+    }
+
+    private function pickWinner(RsvpCollection $rsvps): array
+    {
+        return $rsvps->random(1)->first()['member'];
+    }
+}
diff --git a/src/UseCase/UseCaseInterface.php b/src/UseCase/UseCaseInterface.php
new file mode 100644
index 0000000..1ceadfe
--- /dev/null
+++ b/src/UseCase/UseCaseInterface.php
@@ -0,0 +1,21 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\UseCase;
+
+use App\ValueObject\Result;
+use Symfony\Contracts\Cache\CacheInterface;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+
+interface UseCaseInterface
+{
+
+    public function __construct(
+        HttpClientInterface $client,
+        CacheInterface $cache,
+        int $eventId
+    );
+
+    public function __invoke(): Result;
+}
diff --git a/src/ValueObject/Event.php b/src/ValueObject/Event.php
new file mode 100644
index 0000000..c5023a2
--- /dev/null
+++ b/src/ValueObject/Event.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace App\ValueObject;
+
+use App\Collection\RsvpCollection;
+use Tightenco\Collect\Support\Collection;
+
+class Event
+{
+    private string $name;
+
+    private string $link;
+
+    public static function createFromArray(array $data)
+    {
+        return new static($data);
+    }
+
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    public function getLink(): string
+    {
+        return rtrim($this->link, '/');
+    }
+
+    protected function __construct(array $data)
+    {
+        [
+            'name' => $name,
+            'link' => $link,
+        ] = $data;
+
+        $this->name = $name;
+        $this->link = $link;
+    }
+
+    public function getRsvps(): Collection
+    {
+        return new Collection();
+    }
+}
diff --git a/src/ValueObject/Result.php b/src/ValueObject/Result.php
new file mode 100644
index 0000000..6d3e267
--- /dev/null
+++ b/src/ValueObject/Result.php
@@ -0,0 +1,42 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\ValueObject;
+
+use App\Collection\RsvpCollection;
+use Tightenco\Collect\Support\Collection;
+
+final class Result
+{
+    private Winner $winner;
+
+    private Event $event;
+
+    private Collection $rsvps;
+
+    public function __construct(
+        Winner $winner,
+        Event $event,
+        RsvpCollection $rsvps
+    ) {
+        $this->winner = $winner;
+        $this->event = $event;
+        $this->rsvps = $rsvps;
+    }
+
+    public function getWinner(): Winner
+    {
+        return $this->winner;
+    }
+
+    public function getEvent(): Event
+    {
+        return $this->event;
+    }
+
+    public function getRsvps(): RsvpCollection
+    {
+        return $this->rsvps;
+    }
+}
diff --git a/src/ValueObject/Winner.php b/src/ValueObject/Winner.php
new file mode 100644
index 0000000..51416e1
--- /dev/null
+++ b/src/ValueObject/Winner.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\ValueObject;
+
+final class Winner
+{
+
+    private string $name;
+
+    private string $photo;
+
+    public static function createFromArray(array $data): self
+    {
+        return new static($data);
+    }
+
+    public function getName(): string
+    {
+        return $this->name;
+    }
+
+    protected function __construct(array $data)
+    {
+        [
+            'name' => $name,
+            'photo' => $photo,
+        ] = $data;
+
+        $this->name = $name;
+        $this->photo = $photo['photo_link'];
+    }
+
+    public function getPhoto(): ?string
+    {
+        return $this->photo ?? null;
+    }
+}