Happy Sunday! I really enjoy refactoring because IMO it's the best way to keep your programming skills sharp! I hope you do too! 👍
@ВалентинТерентьев-п4рАй бұрын
I don't love refactoring because I can't reliably feel the line between refactoring and overengineering What I love, tho, is to receive notification about new git-amend video upload ❤
@bogoidАй бұрын
Regarding what you mentioned about technical debt at the beginning, many years ago, during my first project as a lead, I had the opportunity to work with a very experienced architect, guy in his sixties I guess he must be retired by now. Well, one day, we were discussing a feature we needed to implement, but the timeline was pretty tight. I suggested we could do a basic, quick-and-dirty implementation and then "properly implement it later, after the release." He replied, "There's never a 'later'..." It took me some time and a few challenging projects under my belt to truly understand why he was so strict about technical debt... But Craig, if you're reading this, you were absolutely right!
@git-amendАй бұрын
Hahaha, those are VERY wise words! Thanks for the comment!
@enbawatchesАй бұрын
Dude your tutorials are the highest quality, free and paid, of unity tutorials I‘ve come across. Always happy when you post a new one!
@git-amendАй бұрын
Thanks for the Super and the kind words!
@oldshamenАй бұрын
This type of video is awesome .. not only will it encourage programmers not to start over "because I know better now" but also shows how to use all the important programming patterns you have already taught in previous videos. Great work :)
@git-amendАй бұрын
Thank you!
@nickolasbrown2260Ай бұрын
This is the type of youtube channel where u see ur first video and hit subscribe within 10 min
@git-amendАй бұрын
Haha nice!
@gonzaloasencio4503Ай бұрын
like that you bring advanced things and videos like these. Excellent work as always 😃
@git-amendАй бұрын
Thank you!
@lemetamaxАй бұрын
This is really good! Nicely done. I actually learned the factory pattern from one of your previous videos. Now I use it everywhere possible. It ties cleanly with an object pooling system and jobs and burst. Please make more refactor videos like this one. And Happy Sunday!
@git-amendАй бұрын
Great to hear! Thanks for the comment!
@LuciphearАй бұрын
It's interesting to watch even though I knew the majority of concepts here, but there were some things that were new to me! It's a nice feeling to realize how much I've learned since I started. I really appreciate that you're giving good advice and habits right away despite being a bit more complex unlike many tutorials, that even I had to follow, which taught me some really awful habits that I had to spend a lot of time unlearning. It'll take time either way so better to take that time to learn than have to take the time later on unlearning and feeling unproductive because now you're kind of back to what feels like square one.
@git-amendАй бұрын
I agree 💯 - thanks for the great comment!
@bromanguyАй бұрын
I can never get enough of strategy pattern. Thank you so much for another great video, these refactors are really helpful!
@git-amendАй бұрын
Glad you like them!
@nickdevprod3667Ай бұрын
Super cool type of vieeos. Just let viewers send messy code and refractor it. Best way to learn something
@git-amendАй бұрын
Thanks! More to come I'm sure!
@ewwitsantonioАй бұрын
Absolutely love this refactoring video approach! It's so helpful to see the before and after, because I know so many of us work ourselves into corners and it can be quite hard to see a path out when you are too close to the project and have been looking at it from one perspective for too long. Thanks a lot for sharing these videos with us!
@git-amendАй бұрын
You are so welcome!
@Mikso46Ай бұрын
Hey there. I wanted to thank you from the bottom of my heart for all the amazing content you create. I'm a self-taught programmer and game dev, and after coding for 2 years, I hit a learning plateau. That is, until I discovered your channel. At first, I didn't fully grasp your videos, but I kept rewatching them over and over again, slowly refactoring my game's code. Nowadays, I feel like my code is on steroids, and it's all thanks to you
@git-amendАй бұрын
Thanks for the kind words, very motivating!
@silchasruin4487Ай бұрын
This is fantastic, I can always admit I've made a few mistakes that I wish I knew some of these programming principles and patterns long before I had made the mistake. I always recommend your channel to those devs who struggle with redundancy and scalability. Congratulations on the 20K milestone! But it looks like you've already passed that, at this pace you should hit another milestone before the end of the year!
@git-amendАй бұрын
Thanks! Yup, a million views is just around the corner. Thanks for the comment!
@DeiveExАй бұрын
This was very insightful! I love your videos and learning new concepts, and seeing a actual refactoring being done is really helpful. I gotta use the strategy pattern more...
@git-amendАй бұрын
Glad you found it helpful!
@grzegorzpedrycz2630Ай бұрын
Love that series :) My game code is so much better thanks to you !
@git-amendАй бұрын
Glad to hear it!
@marlonruvalcaba386Ай бұрын
Another great video, You can also use an animator override, that way the unit will have different animations depending of the weapon that it is holding.
@git-amendАй бұрын
Thanks! Good reminder about the override, that can be useful.
@abdou2247Ай бұрын
So, I understood about 80% of everything you did here. The issue arises when i try to do those things when i’m working on project. All hell breaks loose and I end up with a whole bunch of classes, interfaces and bunch of code that I don’t know what to do with. Any help, suggestions is appreciated. As always, you videos are very well detailed, very high quality. This the level i aspire to reach one day. Thank you for the all the work you do. Looking forward to more amazing content!
@git-amendАй бұрын
Thank you, there will be more videos like this in the future!
@BriezarАй бұрын
I don't know your coding progress and what the code looks like so I can't really give a targetted advice, but for the most part, aside from applying 0 programming pattern, hell breaking loose comes with premature abstraction and generally excessive application of programming patterns. In the case of abstraction, if you're only ever gonna have one single implementation detail, abstration's gonna bloat the hell outta your codebase (that's what the name implies, it hides the actual flow of the code). It's a good habit to ask yourself before the abstraction process if it's gonna bring any meaningful results, namely: - Reduce future alterations to the base class and promote extensions (if you know for sure it's gonna branch out, like the weapon system in the video). - Reduce repeated code. - Increase code readability and reduce spaghetti by leaking only necessary properties and methods outside. If the answer is nay then don't force yourself to do it just because it looks professional lol. Remember, EVERY programming pattern comes with costs and benefits, even for non-pattern. Code architecture is simply picking the pattern (or not) with the least cost according to your needs. Example of a good abstraction choice: - Managing native calls across different operating systems (Editor, iOS, Android, etc.). You can use #define but it comes at a cost of non-continuous cognitive processing when reading the code and also bloats the class, whereas abstraction will neatly arrange each implementation it its own world and expose common functionalities through an interface. Example of an arguably bad abstraction choice (depending on your game's scope): - A singleton manager class where you can simply instantiate and it works by itself. There are multiple ways to group common functionalities without inheritance hell. You can extract the commonly used implementation details into groups of classes, then instantiate the desired behavior class and inject the interface into whatever class that requires. This is the so-called "Prefer composition over inheritance", which the Strategy pattern in the video demonstrates. Personal example, I wrote a save system that must save/load using either JsonUtility or NewtonsoftJson, but instead of JsonUtilitySaveSystem : SaveSystem and NewtonsoftJsonSaveSystem : SaveSystem, I only have 1 SaveSystem class that accepts a SerializationStrategy parameter in the constructor which can be JsonUtilityStrategy or NewtonsoftJsonStrategy. Now you might think it's literally the same, which is true within this scope, but I also allow different EncryptionStrategy, SavePathObfuscationStrategy and even BackupStrategy which can simply be injected through the constructor; also if you decide to add a new behavior and a bug occurs, you can be 99% certain it's only in that new class. The inheritance pattern cannot support these many branches of the base class. It's a little hard to wrap your head around this at first, but once you know how to do it, it will greatly benefit your codebase. Another simpler way to group common functionalities is to simply extract them into a static Utils or Extensions class and reroute all similar calls to that class. The class should preferably be state-less and only transforms the input into a predetermined output. E.g. transform a TimeSpan into a common string format, calculate damage, etc. All of this comes with experience and practice. In my case it took me 2 years before I start to get the jist of patterns and another year to actually implement it correctly. I highly recommend Zoran Horvat's channel which only has C# content but really nails how to implement different patterns.
@abdou2247Ай бұрын
@@Briezar I can’t even think of a proper way to thank you for this. I really appreciate you taking time to write this. I’ll take a look at that youtube channel. Huge thanks!
@AnotherGameDev2411Ай бұрын
This was brilliant!
@git-amendАй бұрын
Thank you!
@RayznGamesАй бұрын
A lovely bit of refactoring never hurts anybody!! .Even if I know some things its a great video! Subbin!
@git-amendАй бұрын
Thanks for the sub!
@ilkangamedev4477Ай бұрын
Teşekkürler.
@git-amendАй бұрын
Teşekkürler! Çok sağ ol, Süper için!
@kyoseoulАй бұрын
One of my favorite types of videos! I love seeing so many coding patterns in action. Some are still a bit tricky for me, but I was surprised to realize I’ve already used a few. Do you code like this in your own projects, or do you use more "niche" tools like R3 or other libraries/assets? I'd be curious to see some of your older code!
@git-amendАй бұрын
Thanks for the comment! I actually don't use too many niche libraries - mostly it's just regular C# when I'm coding. Of course I do use my own systems, like the Service Locator, Event Bus, Improved Timers and the Unity Utility library that we keep adding to as well.
@TyptickАй бұрын
Beautifully explained
@git-amendАй бұрын
Thank you!
@JustLetMePickAFuckingUsernameАй бұрын
Grest video as always. Cheers
@git-amendАй бұрын
Thank you!
@Haze_E1Ай бұрын
amazing content as usual 10/10
@git-amendАй бұрын
Much appreciated
@simeonvasilev4074Ай бұрын
really nice video, pretty educational.
@git-amendАй бұрын
Thanks!
@검은모래Ай бұрын
Thank you for the great video! I'll enjoy listening to it
@git-amendАй бұрын
You're welcome! Thank you!
@KojiKazamaАй бұрын
Never listen to that person who says "We'll refactor later" because it never happens.
@git-amendАй бұрын
Very true.
@VensJemАй бұрын
In Unity I noticed that "SetParent" or "transform.parent =" noticeably affects performance. But if you just Instantiate an object with a parent object specified it seems okay.
@StrangertoyourlifeАй бұрын
Great video, learnt a lot! Especially the power of Scriptable Objects in this type of situation! Random question: How do you get the timescale slider at the top of the unity editor? That looks like a really useful feature
@git-amendАй бұрын
That's a free asset from the store, check the description for a link.
@StrangertoyourlifeАй бұрын
@@git-amend Thanks!
@GTZ-98Ай бұрын
Hey Adam, love those type of videos. :D Your example should be easily applicable to just a pure FPS game right? I've had a weapon wheel in mind for that UI weapon swap and a simpler one with just moving the mouse wheel up or down. A factory seems perfect for achieving this.
@git-amendАй бұрын
Absolutely, though one thing I would consider for fast swapping is instead of instantiating weapons as you need them, you could start with all options instantiated and just enable/disable them so you just have the current weapon enabled. Instead of destroying a model, just turn it off. Then instead of referencing a prefab to instantiate, have a model lookup that will enable the weapon model on the player.
@GTZ-98Ай бұрын
@ Thank you for the input. I‘ll keep that in mind! :)
@techdave99Ай бұрын
Awesome. will watch again. could apply this to a toy i am working on.
@git-amendАй бұрын
Nice! Glad you liked this one.
@kpm25Ай бұрын
Hi Adam, as always I really appreciate your teaching and share your videos. What is a way that anyone could ever have the chance to get their code reviewed by you? Cheers 🍻
@git-amendАй бұрын
Next time I make one of these videos, I'll ask in Discord for some submissions.
@MarushiaDark316Ай бұрын
8:55 How did you make it so that your SO's appear lower down in the Create menu? Mine always seem to default to the top. Is this something new with Unity 6?
@git-amendАй бұрын
Just the default I guess, but I think it's been that way for a few versions now.
@bodardrАй бұрын
Had a lot of refactoring to do this week as well. I ended up moving the factory pattern to the scriptable object directly, so it doesn't use a factory instance, plus I can override it in the child classes. I wonder what's your opinion on that. As always, keep up the good work, your code is top notch!
@git-amendАй бұрын
Having a static factory method is a viable option, especially if you don't need to mock the factory for testing purposes. I do it fairly often actually. Thanks for the comment!
@bodardrАй бұрын
Yeah when I can I love going static. But I actually meant moving the object creation to the WeaponConfig as a public function. That way you can make it virtual and override it for child Config classes. You could for instance load the projectile prefab for BowConfig or StaffConfig, or any kind of additional stuff. But in your scenario it was perfect because it was simple enough to not be required at all, since there's only WeaponConfig class for now.
@skylarmuffin8145Ай бұрын
I have a project that failed due to it getting to complicated and spaghetti if you want to try refactoring that next, I would love to see how you would apprch some of the problems I currently don't have the skills to solve. ^-^
@git-amendАй бұрын
I _may_ put out a request on Discord before the next one...
@skylarmuffin8145Ай бұрын
@@git-amend Awsome I'll keep an eye out for it ^-^
@youtubechannel548Ай бұрын
Love your videos! This is a bit out of topic of this video, but was curious, I recently saw your data persistance video, which was very helpful, however, I wonder, how do I identify scene objects? I have a scene that has many objects that I can alter during runtime. As an example, there are multiple buildings that have doors. You can open/close a door which means each door holds a state. However, when I want to save all scene objects, which includes all doors how do I then when I load the data back identify which state belongs to which door? I know that some create an object id component that each object has, however, when I tried implementing something like that I couldn't figure out how to avoid each scene prefab instance object id from being overwritten when I apply changes. It seems kind of tricky and would love to know how would you tackle such problem? 🙂
@git-amendАй бұрын
The challenge you're describing-persisting and reloading object states while maintaining a consistent way to identify objects-is a common one. Here’s how I’d approach it: Use a Persistent ID System: Assign a unique, immutable ID to each scene object using a scriptable component. This ID should be generated at design time (e.g., with a GUID) and stored with the prefab, ensuring it doesn’t reset when applying prefab changes. Handle Prefab Overrides Carefully: To prevent IDs from being overwritten when applying changes to prefab instances: - Use a custom editor script to ensure the IDs are only regenerated for new objects or manually when needed. Serialize the ID field explicitly to retain its value even when applying changes to prefabs. - Link State with IDs: When saving, associate each object’s state with its persistent ID in your save data. On loading, iterate through the saved states and match them to scene objects by comparing their IDs. For runtime-instantiated objects (like new buildings), assign IDs dynamically when they’re created and track them separately in your save system. This ensures every object has a consistent ID regardless of prefab overrides and enables reliable mapping of saved states to objects in the scene.
@GameDragon2kАй бұрын
@git-amend Sensei! Great video! Great way to showcase refactoring workflow. I have two questions regarding your setup. 1. How are you getting those Hierarchy Folders? 2. When you're doing null checks in Rider, I noticed there's a little icon there. What is that for?
@git-amendАй бұрын
The folders are an Asset created by Sisus that is extremely useful, I'll add a link in the description of this video. Actually, I recommend (and own/use) all Assets made by that creator, especially InitArgs and Debug Extensions. The icon in Rider indicates an implicit check on Unity object lifetime, which is different from regular objects.
@jukka-pekkalyytinen6558Ай бұрын
Thanks for the video! I'm following along until the Preconditions are mentioned. Can't seem to find where this class was introduced?
@git-amendАй бұрын
Can search the repository, or it is also in a gist here: gist.github.com/adammyhre/82d495ab99e2c59a19362119b2d43194
@TheKr0ckeRАй бұрын
Nice video content mate! Where would we need enum in that case? Can we solve that differently, every time we add new item type, we also need to add enum, thats what i dont like about enums.
@git-amendАй бұрын
Further refactoring would probably lead to a Generic Weapon instead of enums. Maybe in a future video...
@DapperNurdАй бұрын
Could you elaborate what the point of the interface for the Weapon is, when you just load it into the abstract class anyways? You could remove the interface from your code and have the exact same functionality.
@git-amendАй бұрын
The interface ensures a clear contract for any weapon implementation. This approach comes from the "start from interfaces" principle, rooted in the Interface Segregation and Dependency Inversion principles of SOLID. While it may seem redundant with an abstract class, I almost always start refactoring classes that have things in common by first defining the interface they must all adhere to.
@BriezarАй бұрын
it doesn't have to be an abstract BaseWeapon that implements IWeapon, a new WackassWeapon : IWeapon can be injected into any parameter that accepts IWeapon. The abstract BaseWeapon class' purpose is to provide a preset of common implementation details of a standard weapon.
@guillem99Ай бұрын
8:29 Would it be acceptable to make WeaponFactory and its methods static?
@git-amendАй бұрын
As it stands right now, you certainly could. However, one of the nice things about a Factory or Abstract Factory is it's use in testing - if you added an interface, it would be very easy to add a test version of the factory and just produce exactly the kinds of output that you need to executing test logic. We don't necessarily need it in this simple example, but injecting a factory is an extremely common practice. Another option you could go with, instead of a static factory, is have a static factory method on the WeaponConfig object so that it can create itself.
@joll98Ай бұрын
10:48 is this a custom window you made or from asset store ?
@git-amendАй бұрын
This is a store Asset. I talk about it and a link in this video: kzbin.info/www/bejne/ZpC9g3uKZ8uUh9k
@joll98Ай бұрын
@ thank you
@akifemrebozdemirАй бұрын
How do you draw the line between refactoring and over engineering?
@git-amendАй бұрын
Well, keep in mind that over engineering means adding features that were NOT requested. Refactoring is improving code so that you can facilitate changes that were requested. It's important to keep this in mind so you don't build things that are unnecessary, while still building the things that you do need in the best way you can for your skill level.
@unitydev457Ай бұрын
what is this favorites window? is that new to unity 6.x? or an editor extension utility you use?
@git-amendАй бұрын
It's a store Asset, I talk about it here (and link here too) kzbin.info/www/bejne/ZpC9g3uKZ8uUh9k
@unitydev457Ай бұрын
@@git-amend ah awesome! definitely grabbing that. super handy for workflow. thanks!
@mmertdumanАй бұрын
I have no problem refactoring the code to the state you've shown in the video, but then things get more complicated and the patterns start to feel insufficient. For example, what if the bow needs additional config variables that the sword doesn't need? What if the staff needs the same? What if I make variations to the staff that all take different elemental attributes and their configs? Soon enough, each weapon would need its own "WeaponConfig". Its not the end of the world, but different weapons would need to cast the given WeaponConfig to their own config type, e.g. StaffConfig, BowConfig. Maybe there is a better way to handle this? The biggest pitfall I encounter is that the inheritance hierarchy that made sense the first time I'm writing it starts to make less and less sense as the project gets more complicated, and refactoring an inheritance tree is a mess. I really liked the IWeaponState refactoring that allowed each weapon type to implement its own Down/Up/Update functionality and still be driven by the WeaponController. Because the bow would probably need to aim before shooting, etc. And if a weapon needs additional variables to function correctly (instead of the simple target we get from Use(Transform target)), they can collect it during these 3 states. As I was watching, I was wondering how you'd handle that, and the solution makes a lot of sense to me! I would love to see more videos like this as the project gets more complicated. Even though your example has great coverage, the game is not really 'playable' from the POV of a consumer. At the later stages, I feel like patterns become a hassle to maintain as well. Nonetheless, they are much better than the initial code you showed at the beginning.
@git-amendАй бұрын
Thanks for the comment. I'm sure we'll look at some more challenging scenarios in the future, maybe some works in progress from Discord.
@bodardrАй бұрын
There's always generics. For instance I'm working on an inventory system, and I decided to make the item config as a generic parameter in my item class. So something like *Item where TConfig : ItemConfig*. That way the definition is always of the type you want it to be. So you'd have Bow : Weapon, Sword : Weapon. And they all inherit from the contract, either IWeaponConfig or WeaponConfigBase. But generics aren't perfect because sometimes you want to use a Weapon as a parameter, but you can't because it requires that generic argument now. You can't make an equip function that takes in Weapon, or Weapon, it won't compile (which is understandable). Solution? Weapon should inherit an interface or a base class that has no generic argument. Now you're good to go. I know this is a mouthful but the takeaway is : if you're going generics, it's great, but make sure you have no generics at the top.
@git-amendАй бұрын
@@bodardr Great advice. Maybe a good topic for a future video as well.
@mmertdumanАй бұрын
@@bodardr Yes, but as you said, functions still need to take the non-generic definition. How would your example work with the WeaponFactory shown in the video? The factory also needs to be generic then. Even so, i feel like there needs to be casting somewhere down the line. Same with the UI buttons which take in a List. How would that work? In my mind, if I need to cast the non-generic definition to one of the generic and concrete types, its not much different than casting at the weapon level. Maybe it does help, but Id need to sit down and try to code it to see. Nonetheless, I agree generics are great, especially for EventNotifier, Messaging etc patterns where by nature of the design you need to be able to work with any type of event, message, or payload.
@BriezarАй бұрын
you can put the CreateWeapon method from the factory into the ScriptableObject itself, this way the WeaponConfig becomes the factory and there's no need for a seperate factory class. Have another CreateWeaponUI/Button method for UI purposes. Make the methods virtual and override if you ever need to implement a different behaviour. BowConfig : WeaponConfig will have Bow related configs and still output a GameObject, but a Sword with default weapon behaviour can still use the default WeaponConfig. The video demonstrates the use of the factory pattern, doesn't mean there's no better patterns.
@Fitz0furyАй бұрын
This feels like someone wanted help transitioning from stephen Hubbards arpg course to something more scalable....
@git-amendАй бұрын
Could be, I don't think I'm familiar with that one.
@RonaldMcDonald-o5zАй бұрын
for the algo!
@git-amendАй бұрын
Nice thank you!
@damonfedorickАй бұрын
Nice! Only 50k more views.
@git-amendАй бұрын
So close!
@PerroConChalecoАй бұрын
How would you like taking a look into a project that already became a mountain of tech debt?
@git-amendАй бұрын
How would I like it? Haha, well I have to do that a lot in my current work, and I can't say I like it too much. Nobody likes it, which is why it should be avoided in the first place. Of course, in the real world it does pay very well. But if you are asking me to consider looking at a specific project for a video, maybe before the next refactoring video I'll ask on Discord for some submissions.
@raymkАй бұрын
Ah... much clean! I think most programmers are capable to clean up their codes, but laziness and ignorance take the best of them.
@git-amendАй бұрын
Hahah true!
@ilkangamedev4477Ай бұрын
Thanks a lot can you upload 2K or 4k please :), High quality videos deserve higher resolution.
@git-amendАй бұрын
I'll see what I can do!
@neinxxl1440Ай бұрын
帅
@git-amendАй бұрын
谢谢支持!😊
@lee1davis1Ай бұрын
Interface question??? I see in most of your videos you write an interface then never edit it. This vid. You edited the interface three times then had to update all the scripts that implement it. My questioni is...Isn't it bad practice to ever edit an interface?
@git-amendАй бұрын
Editing interfaces isn’t inherently bad practice, but it can lead to maintenance overhead as all implementing classes must be updated. If it’s your own code, it just requires some extra work. However, in published or shared code, changing an interface can break dependent systems, so be careful if you are doing that.