I'm a code folder
I know it looks strange the first time you see it, but hear me out for a minute: I am a code folder.
class TwitterSyncCommand extends Command { protected $signature = 'twitter:sync {--clean}'; /** @var \Illuminate\Database\Eloquent\Collection<Mute> */ private Collection $mutes; public function handle(Twitter $twitter) { /* … */ } public function syncFromList(Twitter $twitter): void { /* … */ } public function syncFromSearch(Twitter $twitter): void { /* … */ } private function storeTweets(array $tweets, TweetFeedType $feedType): void { /* … */ } private function shouldBeRejected(Tweet $tweet): ?RejectionReason { /* … */ } }
I hide most of my code, most of the time. I have keyboard shortcuts to easily show and hide blocks of code; and when I open a file, all method and function bodies are collapsed by default.
The reason? I’m not a superhuman speed reader that understands dozens of lines of code at one glance. And… I also don’t have a two-metre-high screen.
I just can’t read and understand all of this — you know?
class TwitterSyncCommand extends Command { protected $signature = 'twitter:sync {--clean}'; /** @var \Illuminate\Database\Eloquent\Collection<Mute> */ private Collection $mutes; public function handle(Twitter $twitter) { $this->mutes = Mute::query()->select('text')->get(); if ($this->option('clean')) { $this->error('Truncating tweets!'); Tweet::truncate(); } $this->syncFromSearch($twitter); $this->syncFromList($twitter); $this->info('Done'); } public function syncFromList(Twitter $twitter): void { do { $lastTweet = Tweet::query() ->where('feed_type', TweetFeedType::LIST) ->orderByDesc('tweet_id') ->first(); $tweets = $twitter->request('lists/statuses.json', 'GET', [ 'list_id' => config('services.twitter.list_id'), 'since_id' => $lastTweet?->tweet_id, 'count' => 200, 'tweet_mode' => 'extended', ]); $count = count($tweets); if ($count === 0) { $this->comment('No more new tweets'); } else { $this->comment("Syncing {$count} tweets from list"); $this->storeTweets($tweets, TweetFeedType::LIST); } } while ($tweets !== []); } public function syncFromSearch(Twitter $twitter): void { do { $lastTweet = Tweet::query() ->where('feed_type', TweetFeedType::SEARCH) ->orderByDesc('tweet_id') ->first(); $tweets = $twitter->request('/search/tweets.json', 'GET', [ 'q' => 'phpstorm', 'since_id' => $lastTweet?->tweet_id, 'count' => 200, 'tweet_mode' => 'extended', ])->statuses; $count = count($tweets); if ($count === 0) { $this->comment('No more new tweets'); } else { $this->comment("Syncing {$count} tweets from search"); $this->storeTweets($tweets, TweetFeedType::SEARCH); } } while ($tweets !== []); } private function storeTweets(array $tweets, TweetFeedType $feedType): void { foreach ($tweets as $tweet) { $subject = $tweet->retweeted_status ?? $tweet; $tweet = Tweet::updateOrCreate([ 'tweet_id' => $tweet->id, ], [ 'state' => TweetState::PENDING, 'feed_type' => $feedType, 'text' => $subject->full_text , 'user_name' => $subject->user->screen_name, 'retweeted_by_user_name' => isset($tweet->retweeted_status) /** @phpstan-ignore-next-line */ ? $tweet->user->screen_name : null, 'created_at' => Carbon::make($subject->created_at), 'payload' => json_encode($tweet), ]); if ($reason = $this->shouldBeRejected($tweet)) { $tweet->update([ 'state' => TweetState::REJECTED, 'rejection_reason' => $reason->message, ]); } (new ParseTweetText)($tweet); } } private function shouldBeRejected(Tweet $tweet): ?RejectionReason { if ($tweet->isRetweet() && $tweet->feed_type === TweetFeedType::SEARCH) { return RejectionReason::retweetedFromSearch(); } // Reject tweets containing a specific word foreach ($this->mutes as $mute) { if ($tweet->containsPhrase($mute->text)) { return RejectionReason::mute($mute->text); } } // Reject replies if ($tweet->getPayload()->in_reply_to_status_id) { return RejectionReason::isReply(); } // Reject mentions if (str_starts_with($tweet->text, '@')) { return RejectionReason::isMention(); } // Reject non-english tweets $language = $tweet->getPayload()->lang; if ($language !== 'en') { return RejectionReason::otherLanguage($language); } return null; } }
I feel overwhelmed looking at all that code, especially when I’m searching for one specific method.
Now, when I create a new file, it’s all fine, it’s a blank slate, and I’ve got control. But code grows rapidly, and real life projects more often than not include work in existing files instead of blank slates. So I really need a way to reduce cognitive load, I can’t “take it all in at once”. And that’s why I’ve grown to like code folding so much.
Give yourself a week to get used to it. Configure your IDE to automatically fold method bodies and functions, and assign proper key bindings to show and hide blocks. I promise you, you’ll like it.