"Please Tear My Code Apart" // Code Review
To try everything Brilliant has to offer-free-for a full 30 days, visit brilliant.org/TheCherno. The first 200 of you will get 20% off Brilliant’s annual premium subscription!
Patreon ► / thecherno
Instagram ► / thecherno
Twitter ► / thecherno
Discord ► / discord
Peter’s channel ► @peter1745dev
Code ► github.com/cameronotten/think
CHAPTERS
0:00 - Intro
3:20 - Running the project
4:21 - The build system 😠
5:21 - The main function
8:41 - Doing things for the first time
11:29 - Recognizing patterns in code
15:36 - Complex vs lots of code
18:09 - Data-Oriented Programming
21:04 - What the Debug config should be
28:20 - Writing better "debug" code
35:04 - Custom memory allocation and management
Hazel ► hazelengine.com
🕹️ Play our latest game FREE (made in Hazel!) ► studiocherno.itch.io/dichotomy
🌏 Need web hosting? ► hostinger.com/cherno
💰 Links to stuff I use:
⌨ Keyboard ► geni.us/T2J7
🐭 Mouse ► geni.us/BuY7
💻 Monitors ► geni.us/wZFSwSK
This video is sponsored by Brilliant.
Пікірлер: 139
Thanks for watching! Hope you all enjoyed this code review with Peter! To try everything Brilliant has to offer-free-for a full 30 days, visit brilliant.org/TheCherno. The first 200 of you will get 20% off Brilliant’s annual premium subscription!
@herbnord5351
9 ай бұрын
Hey, Yan! What color theme are you using?
@cameronetto
9 ай бұрын
Thanks! learned a lot
God my chair squeaks a lot 😅Anyway it was a pleasure to have you and Anya over! Had a lot of fun 🙂
@RolandKontson
9 ай бұрын
Just add oil/lubricant - stuff needs maintenance. WD40 doesn't stay on well and is thin - good to get other stuff off your hands and then wash it off with soap (pro tip). I've used industrial chain lubricant, simply because I have it at hand for mowers, bearing etc.
@zweitekonto9654
9 ай бұрын
@@RolandKontson gosh, he wasn't expecting an answer to this
@anyachernikov
9 ай бұрын
…what about Liza? 🥺 🤭
@RolandKontson
9 ай бұрын
@@zweitekonto9654 Still got one :)
@Rosen2221
9 ай бұрын
About that Hazel code you showed - more than 2 bools in a struct calls for defining flags. I would recommend that you implement a wrapper type around an enum (using the enums underlying type for data storage) and defining some utility functions to it for full/partial matching of single flags and flag combinations. Then you basically have a very low-cost abstraction (maybe instead of the four bits you store eight, big woop), make the wrapper constexpr of course, and start enjoying type safety with flags (since you can use typedefs on enums to define flags classes)
@TheCherno wow thanks for reviewing my code! Learned a lot and I agree with your improvements, I'll have to go back to this at some point and take some elbow grease to it. As for the memory allocator, I just made 💩 up haha, I loved the reaction to it. Yes it is weird and not very flexible, so that's on the list for sure, thanks again
Imho what the main() and actually the entire code base is lacking is a consistent layer of abstraction. The main() does not have to know anything about all these details such as file paths for shaders, etc. Compare your code base to Google Maps: * If you are zoomed out fully, you only see a blue ball. This is the equivalent to your main() who only needs to know that there is an Application and how to start it. And maybe how to read some parameters from the command line. * If you zoom in a bit more, you will be able to see in can see individual continents such as America, Europe, Asia. You won't see countries or cities or streets. Now this is what your application class sees which knows about the main components such as the renderer, the scene, etc. But does not know any of its internals. * If you zoom in more, you will see individual countries of one of the main components. These can be modules or subcomponents. * On the next zoom level you see more details. * Only on maximum zoom you see all the internals, such as calls to your graphics API, etc.
Summary of the video: Cherno: Blah Blah Blah Peter: Yeaaah :D
I think debug tools are still useful in production builds. You'll want some way of troubleshooting issues "on the field" so to say. In source engine almost all console commands are available to players and they're so useful for developers and players alike
@lysy-zn2gg
9 ай бұрын
I always liked that you could in older games type cheat commands into console or see the "guts" of the game there
I feel like every time you search for the question of "struct vs class", the general consensus seems to lean towards structs when it's POD and classes when it has to *do* things.
@MsDuketown
8 ай бұрын
Probably for C and Python, but what about let's say Rust or Julia?
@Liam_The_Great
7 ай бұрын
@@MsDuketown did you respond to the wrong comment
@MsDuketown
7 ай бұрын
@@Liam_The_Great nah, just pushing discussion towards compilers.
"Make it work, make it better" is the mantra I try to follow. A lot of the time in large codebases, hooking things up can get messy especially if you don't know the existing patterns in that codebase.
@mattshu
9 ай бұрын
yeah same here. Hack it together until it works then smooth out the bumps after!
a lot of nintendo's first-party switch games use a file called the resource size table or something that tells them how much memory they need, and they presumably generate that after they've made all the content so they don't need to know at compile time and it can be changed but it's also determined beforehand.
Around 34:48 about the #ifdef DEBUG issue. There is a simpler alternative to get rid of it, but not always better in all ways. This is the case where a pointer would be more flexible than a ref param. It could be called, say, _visualizeBounds_ and replace both the _Debug_ and the _showCollisionBounds_ parameters. One could just call the function with nullptr normally, and with a pointer to the Debug object (or even directly to the LineBuffer to be shorter and more convenient to use) when the feature needs to be activated. Then it's just a simple _if (visualizeBounds)_ instead of all the #ifdef/if/#endif stuff.
I too prefer C-style code, not because I don’t understand OOP, but because I just don’t like it.
@human-ft3wk
9 ай бұрын
what don't u like about it?
Large main functions are a common thing for me, it just means I am not dead set on a concerete architecture. A couple section comments go a long way(I usually use a section comment + a code block just to make it super explicit how things are separated). As long as you keep your code local in the sense that you don't share too much state between the sections, it's perfectly fine and even desirable, because there is that one less level of abstraction that comes with for example refactoring the game into subsystems.
@ltstaffel5323
9 ай бұрын
If you can easily define major sections in main with those comments, why not just break them out into separate functions? Seems like by the time you know where to put those comments you should know that those sections belong in their own functions
@nexovec
9 ай бұрын
@@ltstaffel5323 Why would I do that if I'm not reusing the code? Ocam's razor. It adds another layer of indirection, bloats the code, and causes you to have to physically jump in the code text, and makes it tempting to abstract further for no reason. To play the devil's advocate of abstraction, besides the obvious stuff like code reuse, grouping up code and polymorphism, it can have the added benefit of explicitly stating what the shared state is and enforce it with the type system (like what captures do in jai), but that's not worth it for most code. I urge you to read 'John Carmack on Inlined Code' for some practical showcase of what this approach can do for you.
@xinaesthetic
9 ай бұрын
@@ltstaffel5323I guess because if you introduce the wrong abstractions at an early stage it might be more difficult to refactor. Generally not, of course. Actually the memory allocation stuff here might be an example of a higher-level system that was introduced and gets used across the codebase, that then could do with being redesigned requiring a fair bit of friction to do the refactor.
About that Hazel code you showed - more than 2 bools in a struct calls for defining flags. I would recommend that you implement a wrapper type around an enum (using the enums underlying type for data storage) and defining some utility functions to it for full/partial matching of single flags and flag combinations. Then you basically have a very low-cost abstraction (maybe instead of the four bits you store eight, big woop), make the wrapper constexpr of course, and start enjoying type safety with flags (since you can use typedefs on enums to define flags classes)
@Rosen2221
9 ай бұрын
As Bonus, here is some sample code: enum MyOptions { OptionA = 0x1, OptionB = 0x2, Both = OptionA | OptionB }; using MyOptionFlags = MyFlags; MyOptionFlags options{ OptionA | OptionB }; options.hasFlag(OptionA) == true; options.hasFlag(Both) == true; options.setFlag(OptionA, false); options.hasFlag(OptionB) == true; options.hasFlag(OptionA) == false; options.hasAnyFlag(Both) == true;
@Rosen2221
9 ай бұрын
As a sidenote, if you decide to go down this route and find a good way to autodefine "constexpr MyFlags operator|(MyOptions l_flag, MyOptions r_flag)" without a macro, please inform me. Since this is meant to be type-safe, we forbid the init from the underlying type directly, so one needs to implement the above operator, to be able to init via copy/move when initializing flag with unnamed flag combos
thank you for your advise, awesome!!
Let's go!!!!! Watching someone else is the best way to learn
Quick question about the TextureSpecification struct in Hazel. Does it have a reason that there is a DebugName in it without some kind of #if to not have that in a release version? Probably not that big of a deal after all was rather curious.
@fuj1n
9 ай бұрын
If debug name was conditional, everywhere that assigns it would have to also do so conditionally.
@Revin2402
9 ай бұрын
@@fuj1n true I'm aware of that, but could be done with guarding it with setter and getter easily to not have that issue. I was rather curious what the variable is for, maybe it's like in the video explained not for debug only but rather for debugging release as well but in that case I would probably omit it in dist nonetheless.
Cherno Daddy : "Please Tear My Code Apart"
I would also so No - a debug-build SHOULD ENABLE Optimisations: There are many bugs that are not just hard but impossible to find and fix in a build without optimisations. If your code has any undefined behaviour (accessing an uninitialised variable) then the compiler might very well just remove your sanity-check preconditions, or for integral types initialise them to 0 anyways. In that case having optimisations disabled actually removes the bug.
To me, having a polluted main function is bad because of "stack pollution." No clue if that's what it's called, but if you store variables in the main function, unless the compiler somehow optimizes it (not sure when or if this happens) they never go out of scope, therefore increasing the chance of a stack overflow. Obviously, the stack isn't tiny on most computers anymore, but it's simply a matter of OCD for me.
@ltstaffel5323
9 ай бұрын
The compiler can usually perform "liveness analysis" that mitigates this but you can also manually use plain curly braces around code to create object lifetime scopes
@IndellableHatesHandles
9 ай бұрын
@@ltstaffel5323 I thought that would be something the compiler would do. You can't count on most beginner devs using curly braces, though. I don't think I even knew that was a thing for a few years after I started programming, and I still prefer to use functions or lambdas as a matter of style.
@d7samurai
7 ай бұрын
if using up stack space is a concern, just create scopes around segments that don't need their variables to persist.
I have a question, what are your thoughts on the Rust Programming Language?
Whats up guys, my name is China.... youtube auto generated subtitles doing their own thing.
Welcome to Sweden!
Makes me wonder how I got from nothing, like a beginner, to where I am. I realise, in my first job, the quality of code from the senior developer was excellent. That was so lucky. I think I took on all their great habits. ☺️ 🤔 Others not so lucky.
Dont forget you can always override new/delete so you can still have your app in continuous memory.
When your front facing code ends up being as opaque and convoluted as raw graphics API code... it's time to have a serious think about how to refactor things, even when you are the only user of your code.
Where is the Q&A with peter??
idea: i see a lot of examples of bad codes , but can you make a video of someone who send u a good code project that was actually professional and impressive?
We are still waiting for the next episode of Programming 3D Game in java :(
Wait why do you guys not like jetbrains' color style lol
Is your playlist for c++ back in 6 years still valid in 2023? I wanted to learn C++
@user-yg5jj8fl4b
9 ай бұрын
of course man,just do it!
"Casey Muratori" style of code
@user-ic5nv8lj9d
8 ай бұрын
curious which "style" is similar to casey's
So I have so much to say about c++ and all the 100M budget games use this, but you probably won't be able. So only option is here to repeat web developer story how you fixed a website and made tweeks and communicated with your team mainly about informing your organization and the public about anything is happening here and C# and Unity or Unreal in a level of Fortnite seems to be something you were looking for. That Python is just like this and you like it objective, but we don't do it here. Trust me I'm a lecturer and that means something as a recommendation.
CMake > premake Change my mind
Would be great to hear why at all would people write in c style code in a cpp env.
@animarain
9 ай бұрын
Either because they're from an older background and that's what they know, or they just like that style. There isn't really any grand idea behind it.
@linuxameteur
9 ай бұрын
I'm just used to it bro, not that deep
9 ай бұрын
Maybe you just like C style more but want some pre-built containers.
Peter is a cute
היי
I guess the biggest problem is that you are not using patterns, clean code principles etc. Its okey, if it is your hobbistic project, but if you want go to next level, you need to do research of that, and try to refactore whole project. Just implementing the right rules will allow you to port your code to other projects, easily extend it, and simply understand it better.
ironically most industry code is c-style script + function style or just pure assembler
@Jkauppa
9 ай бұрын
meh, dont automate before you can walk
@Jkauppa
9 ай бұрын
managing nonsense and getting bogged by it is not worth it, killing life is not fine
@Jkauppa
9 ай бұрын
and have some oil bro
@Jkauppa
9 ай бұрын
being bound by forces with all the stuff is not fine
@Jkauppa
9 ай бұрын
doing the stuff instead of actually doing something, is nonsense
cmake is better
@zweitekonto9654
9 ай бұрын
Whats he using?
@mtgarcez
9 ай бұрын
vcpkg + cmake = W
@Stroopwafe1
9 ай бұрын
@@zweitekonto9654 TheCherno uses Premake
@captainfordo1
9 ай бұрын
I just use a simple Makefile
@jonforhan9196
9 ай бұрын
@@captainfordo1good luck keeping that cross platform