Plugins Help Me CRUSH The Rule Of 3 - Here's How!

Plugins Help Me CRUSH The Rule Of 3 - Here's How!

• 18 views
vlogvloggervloggingmercedesmercedes AMGMercedes AMG GTAMG GTbig techsoftware engineeringsoftware engineercar vlogvlogssoftware developmentsoftware developerssoftware engineersmicrosoftprogrammingtips for developerscareer in techfaangwork vlogdevleaderdev leadernick cosentinovlogging lifevlog lifeengineering managermanagerleadershipsoftware engineering managerengineering managementmsftBrandGhostrule of threerule of 3

The rule of three -- Have you heard of it?

In this vlog, I talk about refactoring some BrandGhost code and how I have WAY more than three examples to reflect on.

I had to weigh on a design decision I wasn't big on, but I had over TEN examples that demonstrated it would be very valuable.

📄 Auto-Generated Transcript

Transcript is auto-generated and may contain errors.

all right it is time to head into the office um had a bit of a rough start this morning I woke up I had to do a call for 6:30 a.m. so I woke up at 6:00 and then just felt like like my voice was kind of gone so it kind of felt like a cold was coming on kind of felt like my voice was going um and like while I was taking this call and talking I just remember feeling like I don't know how much I can talk here and uh it wasn't recorded or anything it was just like an informational session so it was fine but uh the issue is that at 7:00 I was supposed to live stream and I was we wrapped up that call a little bit early which is surprising calls always go over but um wrapped it up

a little early and then my phone is playing YouTube because it's a great thing to do for Bluetooth thank you um yeah I wrapped up that call early and then felt like I don't think I can do this live stream and figured okay like maybe it's best I get to bed and just try to rest and now I feel like I'm not losing my voice which is nice um still kind of feel like I might have a bit of a cold coming on I'm not really sure like I feel fine but something feels a little off off um so I'm not sure I am going to the office uh because I'm not totally convinced it's a cold I don't know um but anyway this morning was kind of crap because of that so I didn't really get much of anything done um I had that

call it went back for a bit of a nap voice seemed to kind of recover I guess and uh this morning what I focused on was I was uh and this is what I'm going to be talking about in this video is uh kind of I'm not reworking off in brand ghost I am uh kind of refactoring some of the patterns and I want to be able to talk about this particular pattern and how kind of like building with a plug-in system gives me this opportunity to see the pattern many times to have examples of how to uh massage it if you will and kind of come up with a a good pattern and refine it so before I jump into that uh yesterday Ryan Murphy and I did release our behavioral interview course so we're super excited about that um this morning on YouTube

I saw that Nick chaps has actually uh included the advertisement for it which is awesome it's always fun to watch a video and then kind of see uh and he's a huge YouTuber right he's got like over 300,000 subscribers see your face kind of pop up there here your name so it's cool um that we launched our course we're we're very proud of it um when I was live streaming last night I was talking about uh some of the concepts from that course so uh we think honestly we think it's going to be super helpful for people um it is all about behavioral interviews not um coding or uh system design interviews so uh that is a separate conversation this is really the behavioral part and in particular getting our perspective as managers so um at the end of the day like one of the

the big takeaways uh for that course that I want people to have is like you want to be thinking about when someone asks you a question in an interview like a behavioral interview what is the goal of their question not just like oh they want to hear me talk about projects they want they're looking for something this person just pulled out in front of me and like they were asking for trouble um cuz they were not going fast enough but we survived so anyway that course is out we are meeting tomorrow morning bright and early for me actually it's not we're moving it a little bit but um we're going to be planning our kind of going through the curriculum for our next course and we'll start filming next week uh which is going to be cool uh I'm getting my hair cut completely off

on Thursday so this guy's going to be bald uh by choice and not by not letting the the nature part kind of kick in more than it already is so I wanted to make sure that I could do that between courses and not be filming a course and partway through you're like wow this guy is bald all of a sudden like must have been a must have been uh painful to film it or something okay well that's what's going on so this morning was working on this part of code and brand ghost and uh we have I always build things in plugins so it's not a surprise uh but uh one of the things that we have in our system that lends itself very well to plugins is the ability to post to different social media platforms so each platform that you can post to

is like a plug-in um but every platform also needs to have its own type of authentication so um in order for us to do that we have uh what's this is going to be really tricky to explain by the way without like drawing it or showing code so I'm going to try my best but we have a code path that basically will write records for authentication so there's like a it's kind of like recording like a user ID if you will so we have a a user ID and we have a a Social account identifier and it this is writing the association for those things that's the easiest way to put it uh track you know track when it happened kind of thing and we have a table for that now ooth if you haven't worked with ooth it's a pretty crappy thing to work

with uh despite it being a standard everyone seems to do ooth a little bit differently and it makes it ridiculous to work with because it's like if you went into it assuming there was no standard I think it would feel better but given that you know it's supposed to be standard eyes and then you're seeing like how everyone does it slightly different uh it's painful so anyway anytime I have to work with ooth stuff I I hate everything going on and as we've been building this out and adding platforms like you start with one and you don't want to over abstract so like I um I had like this single table in our database that was like okay here's the the platform that's associated with this user and this user sorry and their their social media account and record like the platform type with it

and then I figured okay ooth has to do like everyone does it the same right so you're going to have like an access token this is the thing that you're always authenticating with you're going to have Bearer tokens sorry you're going to have refresh tokens you're going to have expiration dates so like uh we need to be able to refresh to make sure that we can uh continue uh using access tokens on the user's behalf or else the way that this would work is like anytime they want to post they'd have to log in so if you're not following exactly what I'm saying that's the reason why we need to do this is so that we can post on the user's behalf from a server because they're not going to be posting directly from their browser so if we assume that because it's OA you

need an an access token a refresh token an access token expiry date and a refresh token expiry date these are like four pieces of information that make sense that everyone doing AWA should have so I designed the schema for that the reality is no one does that um there's there's some that do but it's not consistent and this is very problematic when you're trying to have like I don't know like shared resources and commonality and stuff so I started to realize as we were adding more I'm like okay like you know for this platform this uh this column's going to be null cuz it's never used for this other platform this other column's going to be null and then I just started to realize there was literally no consistency at all and then I said okay I'm going to go the complete opposite direction and

it's going to create a little bit more work but I'm going to basically Force every plug-in is going to record authentication requirements in their own way so the shared table is still used but it's not used to the same degree now share table is still required because it is at a high level um it's at a high level like sort of agnostic to the social media platforms and then anything that's specific to the social media platforms go was in that platform specific table so so far that pattern is working really well and it means that we can like I can make schema changes and not break like all of the authentication or something like if I have to work and play around with Twitter I don't have to worry that's going to break Facebook or something like that um it's kind of like reducing the

surface area for the other plugins which is cool it's it's been helpful now what's not helpful is that as we start to design these things in code and we think about our design patterns that we're using uh like repository patterns unit of work things like that um the way that I started doing this is that I had authentication with respect to I have a user and I want to know a Social account for them I don't need the details about it I just need to like refer to it like use the identifier with it that could all be done from that shared table that I've been referring to so that's cool and I have an API to work with that and it's sort of in this common spot because it's platform agnostic it's kind of convenient it's nice the problem is that when we want

to go add social media um authentication specific to a platform I have to do it across two tables and it's not like there's a there's a different ways to do this so if you're listening to this and you're familiar with like you know you can conceptualize and you're like oh here's how I would do it like your your way is probably right my way is probably right I don't think there's like a wrong way to do this I'm sure there are wrong ways to do this but what I'm trying to say is that there are probably many right ways and okay ways to do this everything has tradeoffs so my goal with talking through this is not to to have someone comment and be like oh this is clearly wrong here's what you do I don't like there's no absolutes here um I just want

to talk about where there's friction and and ways around that so the issue that I'm facing right now is that I've kind of delegated responsibilities ac across different boundaries of the application so there's a spot that's responsible for writing that um for that like shared table okay so that gets done and then following that if that succeeds which I mean unless the connection of the database is not there it will work and if that succeeds then we'll go write the the platform specific information to a table now that's great all fine and dandy but even with our limited usage there have been situations where you wouldn't think there's a problem doing those two things but we end up writing the first record and then for some reason we're unable to write the second record so what happens now is that someone is in a almost

like what should be an impossible State they have a a record in the shareed table and they don't have the the platform specific information written and that means when they try to go use their account like we can see it but we can't we can't do anything with it and there's no way to really communicate this to the user effectively because it shouldn't happen like it's a state that should not exist in our uh in our data so it seemed like like an impossible Edge case and I wanted to talk about it because it's funny that yeah like because it's possible that's exactly why it's happening so this morning I was working through part of this and I have basically like I was explaining if I have I'm adding a specific like authentication for a specific platform I have to make two calls to write

to the database one for the the Shar table one for this uh platform specific table two calls and if we think about this per uh per plugin every plugin has to go okay write the shared table now write my specific table and that's a pattern that we see across all of our plugins almost it's like almost the exact same code and I was thinking okay like the way that I want to solve this is with a transaction because if something goes wrong at all I roll back the transaction and that means the right to the uh first table will get undone right so this way I can I can have any type of issue I don't want to but any type of issue can happen and then I'm safe and not leaving users in this weird hybrid state where the first table that's shared is

written to and then um something goes wrong and then they're stuck with that like record permanently existing there they like the user would have to know to remove the account from the user interface and then go re it um but they might not they might try to refresh the account cuz they're like hey it's not working Let me refresh it it's permanently broken though if they even if they try to refresh it so I I needed to like think of a way to kind of invert this because I need to write to the first table first because part of that process is that it's going to provide me with an identifier so the act of doing that uh that part of the workflow says this is what we're going to use for an identifier here so that will create one assign one and then we

have it to use which means it has to happen first I can't do the um the platform specific table first because it needs to have that reference like like what is my identifier what's the shared thing that we're using here so I need to do the shared table first that's fine but how do I like and I could put the way the code was structured I could easily make it so that the Shar table had a transaction with it and what I was doing was basically saying like we can use a transaction on the share table but I needed to like s this is going to sound really weird I need to like sandwich the call to insert the records to the other table within that because I need the commit of the transaction to be after both tables are written to so this isn't

that hard to do I just made it so that there's a call back so when we say hey I would like to insert so calling the workflow to insert into the share table that's the first part I say before we finish before we finish that here's a call back and someone can use that call back to basically say hey I'm going to go write my platform specific data and this means that in the order of execution we end up inserting to the share table then we call the call back which can go insert to its own table and then before we leave that entire thing then I can say okay go commit that transaction and if it failed along the way I can use like error handling to say roll back that transaction great now the thing that was really bothering me about this cuz

this this conceptually works the code is easy to structure that way it's very easy to refactor it that it's kind of like pass a call back instead of uh calling it and using the result so pretty simple um again it's really hard to explain it without actually having code or a picture Mustangs trying to race me um so the problem that I didn't like is that the the way that the interfaces looked and like how the code boundaries worked exposing the transaction like the level that we're operating at we shouldn't know that there's a transaction coming from the original spot and I was like battling with this this morning and I'm like man like this is a this feels like I shouldn't be able to know like it doesn't seem right um but I couldn't put my finger on it it's it was like this

seems like it's an implementation detail of of that uh that workflow like I shouldn't need to know that but then I was thinking you know what like I know that if I expose the transaction that I can literally do exactly what I need across all 13 plugins that we have and this was like the the battle that I was having with myself was like it doesn't it seems like it's not right but at the same time I have 13 different use cases because of the plugin uh architecture I'm like 13 different use cases where it fits every single one of them totally fine so I want like it's funny to me because part of me is battling like oh this seems like it's not a good design it's like goes against like maybe common things that I might be thinking of um and then the

reality is like I have 13 pieces of evidence that say completely otherwise so like what should I listen to and for me the answer is obvious it's like do the thing that's going to work that you have 13 pieces of evidence uh because otherwise it's kind of silly you're just like you're almost like being dogmatic about it like hey this isn't right because we read about it on the internet and I'm like you know what like I'm not these aren't plugins for other people to interact with they're internal use so this is the boundary and the API that I need and 13 places say that it works good we're doing it so um that was like what happened this morning basically was that I was finishing up the refactor and then I realized like I really think that I need to expose that transaction so

uh I spent some time doing that in particular but um I hope that was kind of like a helpful conversation I realized it might be weird to uh to visualize it and how it all works but the whole idea was that um like different design patterns that you might have like having examples of how they're used can be really helpful because if you if you only have one or two and you try to refactor to make common things like it might not be enough right there's a thing called the rule of three I think that's what it's called and you know before you start refactoring things to extract common code you probably want to see at least three examples of it um and for me I've been evolving this over time like I've had over three examples for a long time and this isn't the

first iteration of what this pattern has look like it's actually probably closer to iteration five or six by now and now I have 13 examples not three so it's really like I don't know like using the evidence that's in front of you and I think what could be interesting is like in the fure F if I'm refactoring other code like we're not it's not microservice based maybe that becomes an issue if we ever want to go micros Service uh for for that part of the application but like I just don't foresee that being the case and if it is I think that's an awesome problem to have because it it means our application survived long enough that we needed microservices and we have the scale where we need microservices we don't we don't have the scale we don't have the requirement for it so I'm

just trying to reduce coupling as much as possible and in this case the coupling that I decided to introduce was like was knowledge that we are working with a database connection so we are coupled to the same database connection uh and I shouldn't even say that we're we are we're not forcibly coupled to it you're optionally coupled to it uh that's what my API introduces and for me I was like I think that's a totally fine uh trade-off to make here but it took me a lot of reasoning this morning to try and say like am I okay with that okay this is the fun part of the highway we do every morning it's backed up significantly earlier so I need to go from the left lanes that are the Fast Lanes over three lanes oh it's picking up again that's good I don't know

if you saw that silver Mustang that just went past me but he's been driving really weird trying to like get my attention people are funny I'm not going to race your silly Mustang in traffic no thank you okay we should be able to do this pretty easily cool that's one lane now there's a bunch of trucks and stuff two lanes oh man oh man this guy's going to crash what a dummy it's a personal favorite when people put on their signal and they they use the signal to say look out I'm coming not like although I would like to be let in I joke with my wife about this because she's very much a I use the signal to say look out the car is on the way uh and not please let me in so I try to let her know like that's not

the point of this signal you want to let people know your what your intention is not it's too bad I'm my car is already going to be there but that's what just happened in front of me so I still got to move over one lane but we should be fine so yeah right now I got that code in brand ghost I'm kind of at the point now where I got to like I need to test it and I need to I need to like try it like this is a weird thing to say like local prod I guess like uh I don't have a a test instance of our database and schema and everything set up probably should get around to that but um I've been fortunate enough that I can like I for however long I've been building this now I've been able to

kind of test uh test locally running a server and then pointing at the production database um that's been fine so what I'll probably do is use one of my social media accounts that I don't uh like Tumblr for example we support Tumblr and tumblr's not a huge platform for us obviously it's like a little bit I don't know it's not like Facebook it's not like Instagram it's not like LinkedIn and I think if I use that then I'll feel pretty safe that way if it messes up then it's easy enough for me to reconstruct if I lost like my Linkin integration or something and that was busted for a day that I would feel like pretty crappy about that but Tumblr is fine so I'll do that um the other thing and I just remembered this now but I before I left for work I

was like okay I'm going to start integrating uh Reddit and I was like May I'll just build on top of that branch and kind of like make Reddit work and use that as The Proving Ground because nothing nothing that I have right now through brand ghost is posting to Reddit cuz the integration doesn't exist so I was trying to switch lanes the same time someone in front of me was deciding they were going to move over much slower so two lanes it is so I'm going to finish Reddit integration I think um which will be exciting I have different thoughts about Reddit integration um I think the safe thing to do it might not be what people want and we have to kind of survey for this I think but the safe thing to do is Reddit integration should post to your your personal like

profile which is its own subreddit and I think that's the safe thing to do cuz you can kind of post whatever you want there what I don't want to have happen is like if people are going to go for example for for software developer is like oh well there's uh the subreddit for programming there's a subreddit for software engineering there's a whatever subreddits for everything and then they go cool I'm going to hook up all of my social media posting to basically be blasting subreddits um I don't want that even though someone someone might say well that's the best way that I'm going to get my content seen like that's nice but I I really want to limit that so if we are going to post to other subreddits I want to be very careful that like I don't I don't know how it's going

to work if they if basically if posts are going up and people are downloading them and stuff because because the creators using our platform are like spamming Reddit I don't want our app's reputation to drop like I'm very nervous about that and then like we'd lose like Reddit integration or something like I I don't want a couple of bad apples to ruin it for everyone I guess so we trying to look at things to help with that so I think initially I will I'll code it so that you can post to any subreddit and then the way that we'll actually enable the feature is that it will be restricted and then what I might do is I haven't hooked this stuff up yet but uh we need to have like it's kind of a weird thing to explain almost like a listener concept like you

can listen to an R RSS feed I wanted to say RRS but RSS feed and um if there's new entries there then we can go automatically create content for you that kind of thing I think I'd like to try doing that with my newsletter so build that kind of functionality to listen to substack say oh new newsletter is posted let me go create a Content entry for it and then the new content entry will be in your topic stream and then that topic stream we can post to Reddit and I might experiment with my own that like by default if there's certain um like hashtags or categories and stuff included that it will then go post to a subred if it's not um it's not just my personal profile so I might trial that and see what it looks like but I'm going to start

with just doing the user profiles uh in terms of what other users can access cuz I think that's just the safest thing to do so those are a couple things um what else on the development side we were using I don't know like we were using this tool called Bubble for our website and it's a website builder uh seem to be super easy and I'm not the one doing the the actual like frontend website and I'm not talking about the front end app I just mean the website for like the landing page and stuff and it looked I thought it looked pretty good um did everything we needed but we had these weird quirks and I had other people telling me this were like your website's down I'm like well what do you mean then I go to visit and I'm like it's absolutely there

but I realized that it must be some type of CDN situation where and if you bubble and you're watching this like please let me know cuz we did a little bit of research and saw other people running into this sometimes it would take minutes literal minutes to load the website and then the next time you refresh it's instant like it's lightning fast but the first time it was like literal minutes to the like to the extreme situation where people just thought the website was down they're like doesn't exist like what's going on and I observed it m multiple times so um I'm assuming it's some type of caching or CDN thing where like you make updates to the site they have to push to all these different regions um I'm guessing right I'm speculating that's what it seems like and that's why once you get

it and you refresh it's instant because cash Andor CDN so we're uh we were trying to get our was it was Facebook yeah we're trying get Facebook approved so that we can do comments and they rejected us and they were like you're they're so so dumb I can't stand meta's app approval process it's completely insane um it it needs to be redesigned it's horrific so out of nowhere they're like oh we're just going to go check your your privacy policy and they're like your privacy policy doesn't work and we're like obviously it does we haven't touched our privacy policy but it's this bubble issue so they won't approve our app because the website's not loading our privacy policy likely because of some CDN crap so where's a good spot okay um so we're moving I think we're just going to go over to to web

flow uh sucks because it's just like extra work but I think it's going to be way better we've had success with web flow in the past I think the websites always look cool in web flow like they're the they're the kind of website that catch my eye I'm not the uh the best person to ask about this stuff I should adjust this parking job but um we're going to move over to that so we're hopefully by the end of today the uh the guy that's working on that will have it done and then uh we're going to be blasting out to a big newsletter and we'll see if uh we get some some traction with that so we are pretty excited but I'm at the office I hope that was eventful and I will uh we do this on the way home so take care

Frequently Asked Questions

These Q&A summaries are AI-generated from the video transcript and may not reflect my exact wording. Watch the video for the full context.

How do you handle authentication for multiple social media platforms in your plugin system?
I handle authentication by using a shared table for high-level, platform-agnostic data and separate platform-specific tables for each social media platform's unique authentication details. Each plugin records authentication requirements in its own way, which reduces the risk of breaking other platforms when making schema changes. This approach allows me to manage different OAuth implementations without forcing a one-size-fits-all schema.
What strategy do you use to avoid inconsistent database states when writing authentication records?
I use database transactions to ensure consistency when writing to both the shared authentication table and the platform-specific tables. I insert the shared record first to get an identifier, then use a callback to insert platform-specific data within the same transaction. If any part fails, the transaction rolls back, preventing users from being stuck in an incomplete state with partial data.
How do you decide when to refactor common code patterns in your plugin architecture?
I follow the rule of three, which means I wait until I have at least three examples of a pattern before refactoring to extract common code. Since I have 13 plugin examples now, I feel confident refining the pattern based on real evidence rather than assumptions. This approach helps me avoid premature abstraction and ensures the refactor is practical and effective.