I think planning is also very important. I find myself doing a much cleaner code when I spend some time drawing some flowchart and wrtting down sort of a plan on a piece of paper before jumping on my keyboard. I would also add to that, separation of concerns and decouplized code is the key to maintain a large piece of code.
@@geraldjoe-smith-mcnea6829 I'm 31 and I can't remember any of my passwords. There are too many to remember. You should switch your phone password to a swipe to unlock or something easier.
One thing for the new programmers to know (at least from my perspective as I consider my self a mid/advanced programmer) is that not always you get the code as the last file for the first time writing a function. I think the 90% of the time we will write the "noob" code and then start depurating code readability and errors caused by un-programmed test cases. So, if there's a new programmer around here, don't worry if your code doesn't look as the "pro" code at first, but make sure it ends looking and working as so. And remember it's a never ending journey of learning, there's no programmer in the world that has nothing to learn or improve.
As a professional developer, I greatly dislike one liner if statements. In my view it makes it harder to see the logic if it does something even slightly long. Adding some spacing, and curly braces is always good.
I wonder what you feel about one liner if statements WITH braces. In my view, if you don't get over the 80 character limit, then putting everything in one line is fine.
There are some cases when I am a fan of single-line if-statements. The thing I use it most for is guard checks that simply return. For example the if (input == null) return; is really concise to me. I'm not a fan of putting much more there though, and I also dislike using it for more complex logic checks...
I agree, I am actually in favor of creating wrapping functions with dedicated guard functions if your logic it's too complex, that's better than creating one liners a hundred characters long with your code still being compact and easy to read, this video is lacking some good functional programming principles and also some good test driven development principles
Ironically I think a common mark of novice programmers is mistaking concision for efficiency. Clean code is readable first and foremost, there's really no advantage to minimizing line count for it's own sake. If the length of your code is suspicious, dropping braces and using ternary statements probably shouldn't be your first reaction.
Seing your "pro" or "senior" code I would recommend creating one more level above it, since still few things can be fixed, so the whole is more maintanable. First of all, if you have function `numberToString` you should throw if you get anything other than number. You actually made code *worse* by returning undefined, since you are silently failing that way, and it will throw in completely another place, will take longer time to debug, and the error will be less meaningul. It's even better to not handle it at all, and let it fall naturally, since then you get an error in precise place, which caused it. The same applies to handling "null" in second function. Further more: if you insist on handling such things, don't cherry pick. What's the point of validating if argument is null or not, if you expect array? You are still not validating the content of the array, but you get the impression, that you have validated the code. You quickly come to a place when you are either still cherry-picking or validating absolutely everything, and the code becomes unreadable. You need to trust your own application, you need to add validation mostly only on I/O layer (reading unexpected input like files or API), and you need to *let it fail*. Failing is good, because it shows during simple input testing, if everything works. Each one used `if` or some kind of condition, or nesting is literally making code worse. The less the better. I would even imply, that most of the things do not require handling anything more than happy-path (and any states, that are actually valid and possible), because if something fails, then it means you have the bug in your code: either your validation on input is not right, or you have typo or something. By not handling it, you are going to find it ten times quicker, usually during manual testing
I agree about cherry picking, but not so sure about "not validating and trusting your application" part. in this scenario, it does work, but if there is a class that is just storing things, and you are not the only developer working on the project, should you not validate what other data sources are sending to the class? or is there a better way to handle it? I am in the habit of writing validations in all parts of the program :)
@@szwimzs it depends on separation of concerns. You should trust the code you have influence over. If there is another team developing another modules, you may treat them as external input. It really comes down to architecture. If architecture mirrors team structure it may be nice to add validation on the borderline. If you are talking about domain objects, then it is good behavior to ensure they are built correctly, as it is not function performing operation, but the data itself.
@@soanvig Why have another layer when the advanced level in itself is difficult for most. Let us not forget that most of the crowd out here would be very happy just getting to the advanced level. If you go on adding layers you will agree that there will always be a guy out there much smarter than you are and who can write code better than you.
I don't agree with you that you shouldn't validate your functions or methods. I believe it's crucial to validate functions or methods, especially when they're intended for use by other teams or programs. Let's consider an example: imagine we have a function named calculateInterest(amount). We might trust that it's implemented correctly and will return the expected interest amount so no validation checks are written, just the logic that calculates the interest. However, in practice, mistakes happen, and in our haste, we might accidentally pass in incorrect values, potentially breaking the code. The real problem arises when the function fails silently, without raising an error. In such cases, the code continues execution, unaware that something went wrong but returning the wrong results. This silent failure can lead to significant issues, especially when even small discrepancies in calculations, like one percent versus eighty percent, can result in substantial differences for users - either paying more or less than they should. To mitigate this risks, validation checks must incorporated into our methods or functions. We can even separate the validation logic to keep our code organized. The validation checks should also address edge cases and ensuring inputs are valid. A function or method without checks is a function or method doomed to fail.
About the first pro function "numberToAccountingString": While "==" (double equal signs) does indeed cover both "undefined" and "null", I'd argue that using "===" (triple equal signs) in general is more readable. And as others already mentioned, "typeof number === 'number'" would be the most readable and logically correct way to check for the type. And when entering undefined/null, it would just return undefined. Wouldn't I expect a string? Let it throw, preferrably with a custom message "throw new Error('Invalid parameter type')". If the function expects a number parameter and receives something else, it should stop so the stacktrace to debug will be as short as possible.
I am not even close to a pro, but is it even necessary to check the type here? Even if we are expecting string numbers, we can just rely on the less_than condition to account for nullish values since javascript type coercion will automatically recognize a number string as a number in our condition -- like so: const numberToAccountingString = number => number < 0 ? `(${Math.abs(number)})` : number?.toString();
Absolutely! Don’t blame programming language faults on programmers. They would use anything that the language offers. This is the problem of a fully dynamic language... why think about naming the variable so that you can guess that it takes a number, but not adding a type description???
What differentiates a junior and a senior dev is the fact that seniors can solve problems way faster due to their experience. Seniors are not always the 'better' ones. Good video!
Back in the old days of having to insert cards into a machine, efficiency of code was the most important aspect. You didn't have any capacity to fuck around. Technology moved forward in such a way that optimization became an after thought. Back in the day you had no choice but to make your code as best as possible.
I didn't know they were called "guard clauses" but I used them all the time. It just seemed smarter to me. But I got criticized by senior programmers saying that the code in functions should flow from top to bottom and returning early was bad. So now I use noob programming styles to keep the senior programmers happy.
I used to go back and forth all the time about this myself. I finally settled on making it as visible and as obvious as possible. If I can put all my guard clauses at the top I do so, and if not I like to create a small “island” and comment it so it stands out. Also, I notice they looking through either my old code or other examples, a lot of early returns could be circumvented by doing validation elsewhere or just making type safe objects. Granted, you can go overboard with that quite easily. I’d say for simple programs and small functions guard clauses are totally fine. For bigger beasts, some rewriting to include the above might be a good tool to use. Had to learn all this the hard way when someone looked over my work and told me I was “primitive obsessed” and I though, “I have no idea what that means, but it doesn’t sound good!” 😂
@@Blast-Forward A bad joke, since most of the time he was 💯 percent right. The worst thing about programmers is that they are like normal people - they want a solution that always work, a paradigm that is always the best. There is no universal formula. But people are people.
true xDDDD I think a lot of this 'pro' programming comes from people in their late 20s and early 30s who have already gathered quite some experience in coding but not lost their passion that much, like myself(just talking 'bout my age here xD). But in practice it is usually more important to get things done than getting it done with nicely formatted code
I pulled my hair apart looking at "pro" code in production I pulled my hair apart looking at my own code I wrote a few weeks ago I retired from coding and changed industry
if we're so concerned about the number parameter being a number; We can just use the typeof operator. (typeof number == 'number'). This is how I would approach this problem set when it comes to validating the argument(s).
I disagree on the pro code. the function silence the error, it's not a good practice. if the function isn't design to get an undefined or a null, just make it crash and catch the error elsewhere. . if you don't you gonna have hard times finding bugs when you'll get an undefined... because the function just silence the error....
Just a few from me: - Document (state the allowed argument type and return type, for other languages you can data type) at the beginning of the function/method and comment less in the block. - Indentation is key, space out and line out. - Middleware: Quick exit or safe guard blocks at the beginning when needed. - Less depth of code blocks (one to two way deep is okay). - One line - No braces for blocks: if the code block is less than 50 chars or less than your ruler, use one line. - Ternary operator. - I use concise variable,function/method names. - Less return keywords. - Less code size: The less block of code, the better.
I am only a hobby programmer and first time i heard about Guard Clauses. I really love it! Looking at others code specially with tons of if else statements can be a nightmare. This is so much cleaner! Looking at guard clauses i see immediatly what its doing.
Really surprised you didn’t use an example where helper functions would be beneficial. Learning to decompose a problem into smaller steps that are solved by well-named functions is a key aspect of writing “pro” code. Still, there were some good tips in there when it comes to writing a single function or block of logic.
Agree. In the second example, the function should use helper functions for readability and clean code practices. Otherwise, a good video but could be a bit shorter tho.
@@siddharthverma4017 news flash: people rarely give a fuck about a few extra extra function calls in real codebases. And even if they did, good engineers know that you should almost always be willing to sacrifice microseconds of performance for code readability.
I was writing code just like the advanced version 4-5 months back. Recently, I learnt about writing clean code and now I think I write like a pro.😁 I was requesting you in comment section of your other videos to create videos on refactoring/clean code since long time. 😄 I like your explanation. Keep bringing more videos like this. Thanks. 👍🏼
Juan2003gtr Yeah. I know most of the experienced guys don’t know about clean code because either they are not interested in learning or they don’t even know that the code they write can be made better. Many of us(young coders) are very good at DSA due to the growing competitive programming culture. It will take some time to develop the culture of clean code.
Yo, I have been learning from your channel all morning. I just wanted to say, thanks for putting these up, thanks for showing your passion and making code fun. Also thank you for keeping almost all of your videos around 30-60 minutes. It really helps me focus and take it like a small class, take a break and then come to the next one. Keep up the great work my guy. Rock on
@@sodiboo what? minified code is just code that is run through a minifier/compressor... having minified code does not really suggest/imply that the quality of code being written is "pro" lol.
Terrain Yes. But the thumbnail is minified code on the top under “noob” and formatted code under “pro code” which - as you stated - is inaccurate. I was pointing out the, understandable (how does one portray noob code in a thumbnail?) but inaccurate nature of the thumbnail. It just struck me as odd, is all.
We work with minified javascript packages daily in production - but (at least I do) prefer to use the regular versions during development. Certain IDE’s don’t really like indexing minified code very well and will miss imported functions quite often...Particularly Jetbrains IDE. Despite this, they are still my favorite development environments to work with.
"And that is the important thing about programming - It's not about writing something that works, Its about writing something that easy to read and easy to maintain"
AsgaiaMetal that’s not true at all. What happens if you’re linking to an external library and that library changes? What if there are features added, removed, or changed? What if new devices use hardware that’s incompatible with your code and induces bugs or outright breaks your code; for example, a domino effect from some change in the way an op code works cascades down and disrupts out of date libraries and APIs? Of course you need maintenance.
It is, but there is this one little trick : good code, doesn't need to be improved, and thus doesn't need to be maintained. There's no perfect code, but I know when I'm looking at code that has very little bugs. It's very hard to achieve, but it is possible.
A little code review of the 'pro' version at 6:14 - 1. A 'pro' would simplify function name to accountingFormat() or just format() if the module name has the word 'accounting' in it (which it should). No need to say 'number' because you already have an argument named number. There is also very little value in suffixing function names with return types so that can be omitted as well. 2. A 'pro' should use semicolons at the end of each statement. Consistency and clearly communicating intent is more important than omitting a single character. 3. A 'pro' should avoid returning null or undefined if at all possible. Returning null or undefined usually forces the calling code to do an immediate null/undefined check on the returned value. 4. A 'pro' would either use null object pattern with a meaningful string value or throw an exception.
@@foxyl0l A 'pro' knows that consistent usage of semicolons in JS is considered best practice. Not only that, but a 'pro' actually understands the importance of semicolons in JS. Even though one can get away with not using them, they provides significant benefits: - Avoiding rare but very hard to detect bugs (with potentially significant consequences). - Avoiding issues with minification. - Making code more readable by clearly differentiating statements from expressions and other code elements. - Better communicating developer's intent. - Making code easier to understand for less experienced colleagues (the ones that don't have intimate knowledge of how JS ASI behaves). - In consistent usage, a missing semicolon can indicate a potential error. All of the above in exchange for just a single extra character per statement.
@@milosmrdovic7233 Agreed to all you said. In addition, I think a real pro knows when to weight the benefits of code performance, maintainability, readability and conciseness depending on what it's used for and project time limitations. For example not all code has to be super-performing when there's really no real need for it, in which case it's better to sacrifice some performance for something that's easier to maintain, read and more concise. On another note, I also see a heavy lack of code comments in his example. It's a misconception no code requires comments as long as it's well written, even if it's super simple a comment is always nice. For instance, if the code he wrote threw an error when the number is null or undefined, then that would be nice to know by the consumer of the function without even needing to looking at the code. Adding jsdoc to this function would be ideal here overall, but especially @throws
Noob: Writes code that is functional and never refactored. Never doubts the efficiency of selfwritten code, writes it once and be done with it. 'Professional': Writes clean code, easy to read and maintain. Code is a result of many refactors to have each component be a of single purpose and therefore here to stay. Code does not use references and parts that can have its functionality change by outside sources. A pleasant person to work with. Professional: Writes code that is perfectly maintainable by the professional himself. Obscures many processes without sacrificing performance. Makes use of personal roundabout functions that would make rewriting/refactoring difficult for his potential successor. The professional became irreplacable for the employed company.
Once I realized guard clauses were a thing (didn't have a word for them until now), I've always done my best to use them. It makes so much sense, and is cleaner.
@@sinamirhejazi268 I disagree. I find them very readable. Admittedly you have to know what they are to read them but when you do it's very easy to construct readable operations. user.isAuthenticated? : null vs if (user.isAuthenticated) { return } else { return null }
That was very interesting, but as a pro, you need to do a better kind of type checking and throw an error if you pass wrong data. You can test your script using other data types (like an object or a string) to see what happens. This can be avoided by using a better comparison operator (always prefer === over ==). For example, you don't want to return something other than a string (your function name has to...String 🤷♂️). So, you should consider using some kind of type validation and throw an error. There are many options for doing that. You can use typeof number === 'number', trying to convert to number with Number(), parseInt() or parseFloat(), but my favorite is using isNaN: if (isNaN(number)) throw new Error('Not a number'). That way you can use string representations of numbers like "-0.75", but keep in mind that you need to use Number(number) after validation to turn the strings into numbers for good results.
Loved it, this how we roll. Everytime I visit our code, I stare it for a while and see if I can apply something I learnt recently. JavaScript has evolved like anything, specially since last few years. From FOR loops to MAP, REDUCE and FILTER, makes Dev's life interesting.
for `logic/pro` I would also recommend using a ternary operator to better explain the if then else behavior, and it also keeps it in one lines (unless you wanna break each statement for better readability) and it also makes you not repeat the return statement more than the number of times you need to ;)
In the first example, I expected to see ```-number``` instead of ```Math.abs(number)``` in the number < 0 case. After all, you know the number variable is a negative number by then, so you can save yourself the hassle of calling a function that checks for it again. Also, I checked and updated my Python miniproject while watching this to make it cleaner. The concepts work the same. Also, for other pythonistas out there watching this: Have docstrings. The feature is in the spec for a reason.
Congratulations on this great video, a pleasure to watch! But with all the respect, let me disagree with you regarding 5:09. You mentioned a very good point regarding edge cases. However, returning `undefined` is also not ideal. I’d suggest either throwing an Error with a descriptive message here or using a Maybe type (like in FP) and chain any further computation. Returning `undefined` will simply defer the problem as the caller needs to check what kind of value the function returned. For example, the following snippet might fail due to the same reason: numberToAccountingString().charAt(1). What do you think?
yeah, the good old 10mio dollar mistake.. I also tend to agree. When something unforseen happens then functions should rather crash (verbosely in the best case) than trying to defer the crash - what if some later part of the program writes the accounting records one by one to a file and crashes then - with a half written file. Being processed by a booking system, detecting the change and... ok, I stop here ;-) So yeah, better assert than return, agreed.
@@kybkap8686 In my opinion the use of "?" only disguises the "if-else". The problem is that there's no "else"-branch when "?" is used. But, often there must be one. Imagine, you click a button, the "if" part evaluates to false and the button does nothing. This is the worst for the user - a "sometimes-do-something" button.
Great video, but as a tech lead I have some complaints about your pro code :p First of all you should always fail early. Instead of returning undefined in your function you should definitely throw! Also the name numberToAccountingString implies: - should always return a string - should only accept numbers So if you decide to check inputs you need to make sure that its a number. You need to ensure that only strings are returned. If your turning a number into a string you should use toLocaleString(). If you want to disrespect locale to is explicitly by giving it as param to toLocaleString().
Coming in from another language than javascript you will know why people do advanced programming rather than "pro" programming. A lot of the time I want to be consistent not only in one language but in multiple languages. So switching from one to another I keep the same good habits of making the code look readable to devs that write other than JS as well as myself.
Reading this comment as a newbie, this makes sense. When I'm learning, the instructor will use semantically descriptive variable names, but will do the opposite when it comes to naming arguements and parameters. Good comment bro
Alifka Aditya Putra one reason is because a different variable type, specially object, could be the value and it would make the code break. If you check for number type, it prevents more possible errors, and is not any more complex
Alifka Aditya Putra just to elaborate, we are expecting a number , so it makes sense to only proceed if it is a number being passed in, this will cover all non number scenarios in one test.. 🤘
@@PB72UK Why? You mean ugly or unreadable? It checks type for you... And specifically returns result in parenthesis like he wanted for negative numbers. Sure you can use just a standard if else if you don't like this "? :" syntax. I just wanted emphasize that there is something like NaN.
This freaking function thing i ran away for long.bbut now i start understanding pro functional programming and its benefits, thanks to tutorials like this. Thanks sir.
I cannot remember the last time I did manual type checking; if the project utilizes TS, great, we can catch a lot of runtime bugs that way but if not we still don't go around manually checking each argument value for everything it is not allowed to be. That just creates bloatware.
I am not understanding why type checking is even necessary here. We should be able to rely on the less_than condition to perform the type coercion if the user passes in a string number, and it will return false if the user passes in a nullish value.
Even if you don't use typescript, you can still use doc comments for typechecking (using the typescript compiler on any IDE, but it doesn't require your code to actually be typescript code).
Ahhh... there is no guarantee that the values that trickle through the code at runtime are what the TS type annotations say they are. You can easily end up with lots of bugs if you don't do any type checking. Calculation can go bad and result in numbers being NaN or Infinite; DOM input values, when parsed/validated, can end up as the wrong type (null, undefined, invalid Date objects, etc.); data from APIs and databases can change without your knowledge or may contain invalid data, causing values to be some completely different type; and so on. It doesn't mean that types are useless, not at all. You just need to know when explicit type checking is necessary and to be very strict about outside data, that you have little or no control over, always being properly validated, parsed and typed (e.g. using a helper function, like "const dateOfBirth = getDateFromString(unknownValue);").
I don't like the inconsistency of single line if statements. It makes it more difficult for other programmers to add any updates. "Clean" is nice, but consistent is a lot better!
Math.abs(n) returns the positive value of n for positive numbers and the negative value of n for negative numbers. When you've already checked and know that n is negative, you don't need an additional conditional negator. Just negate manually using `(${-n})`.
Not always a fan on multiple exit points, especially in more complex functions, but I'll quote Martin Fowler in "Refactoring: Improving the Design of Existing Code": ". . . one exit point is really not a useful rule. Clarity is the key principle: If the method is clearer with one exit point, use one exit point; otherwise don't"
Great video explaining the difference in readability. Just one nitpick, I'd expect the pro version of the last sample of code dealing with cost to be accurate to the required decimals. If we're going to go all the way with professional grade code, floating point numbers need to be handled carefully when it comes to money. We actually had a discrepency crop up at an insurance firm that was not rounding the values before adding the total resulting in decimals that couldn't be reconciled, which is a super important detail when dealing with money.
From my 16 years of IT experience; I can say even senior or super senior also end up writing spaghetti code most of the times. For me writing code is like preparing omlette or lemon tea, everyone is proud of their own recipe and sometimes ego clash. What's your take on this ? In case of arguments how to come to conclusion if it's good , bad or ugly code ?
@@A_Lesser_Man That's a very stupid (sorry) answer. The worst programmers are those who doesn't want their code to be better and cleaner. They just smash something, yes, fast, it's working. But you can't do anything else with it later. Poor guy who will need to make any changes in the future :)
@@enjay86 although I agree code should be readable, no matter how much better it is it can never be perfect. Get it working. Clean it up. Refine over time
In the first example, you can avoid the function call to absolute since you already know the value is negative. Just negate the value. This would keep the program from making a function call that just replicates your negative check.
there used to be a site, codefights, that was great for this. They posted problems and you could code a solution in any language they listed. Once you submitted your solution and it passed the test suite, here's the great part: you could look at other solutions that passed. It was great for seeing how other people successfully solved the issue and compare efficiency, and number of lines used, big O complexity, etc.
Everyone who is programming professionally: "use proper names for functions and variables" Meanwhile what university courses use: function, func, x, y, z, a, b, c for pretty much everything
One down side to that reduce function is not everyone can follow that function. But i've learnt more from your decomposition of code in the last 4 videos i've watched than years of grind vs uni. More! im hooked!
Then there is the grand master level, that is basically the same as noob but with good names and all the checking needed. With this the poor junior fella that wins the terrific opportunity to maintain it will not call you every 5 minutes to ask you how that line works, for every line of course...
Yeah. I usually prefer to write "dumb" code because anyone can read it. No ternary operators for example. While they're great it's also confusing if you are not used to them. I kind of feel the same way about the whole stack. By all means, refactor everything into the coolest new frameworks if you need your resume to stay hot. But if not, just go for stable reliable stuff that anyone understands. A regular LAMP setup works great for a whole truckload of use cases :)
As a high-level, low-level, and assembly programmer, I disagree with a lot of what this video tries to make you think is "better code". There are different nuances, implementations, and optimizations between all languages, whether interpreted or compiled. Above all else, code should be bug free. Next in priority would be scalability and speed, then readable/ maintainable, then compact. The video should be titled, Junior vs Senior Code - How to Write Senior Code; which isn't always BETTER. Here's one example, the "if(n < 0)" and the "else", I would keep the else "if(n>=0)" because it's a little more readable and scalable, in the case where you want to add other conditionals, and in the end, a compiler will likely optimize the assembly into 1 conditional and 1 jump instruction, and a fall through, in either situation.
Congratulations, you just explained the benefits of working with higher level languages. I bet you don't maintain ten million lines of assembler in a team of dozens, either.
I disagree on priorities. they are dependend on the goal of the project. in some project AND some situations you can get away with that working > speed > readable stuff. but mostly it is more like readable > working > speed. reason for readable first, is simple: if you cant read the code, you will have difficulties to make it working in the first place. and if you dont have binding between work packages for code and a developer, or you are working with a tester/integrator together, you will get kicked in the ass, as soon as someone else has to handle an issue, or just do his work, with the code, you wrote... speed is an OPTIONAL thing, because, in most cases, biggest part of the code is not even the bottle neck. there are some possibilities to make the code so broken, that it slows everything down, but thats not the case of "not fast enough", thats the case of "wtf did you here? your code is blocking the whole cpu, while waiting for some peripherie all the time!" where you need speed is decided at the architecture lvl or during tests. you dont need to invest time into speed, if it wasnt a requirement from above, as long as tests didnt show that it is required, to get correct(NEEDED) results. therefore again READABLE > working >> speed. and the most important "lifehack" is not to tweak on the programm code in the first place, but intead to improve the data structure. because the structure of the data has a lot more relevance for all 3 points: readability, komplexity (as the cost for getting it to work) and the speed.
If you want to make your code even more concise, you can use the inline short hand for if. This doesn't help with understandability, on the contrary it makes your code a bit more harder to understand, but it really shortens long nested if blocks const bracketifyNumbers= (number) => { return number != null ? (number < 0 ? `(${number})` : number.toString()) : undefined; }; great video btw, helped me realize my mistakes.
If you have a "sum" function, and the parameters are x and y. It's kinda obvious what the arguments will be. But using strongly typed languages like Typescript and Elm helps a lot. When you're working with really abstract things, It's not much of a problem if you're using a language strongly typed or has specs like Elixir or Clojure.
My friend who is a PHP developer said that no curly brackets for single expression(guard clause) syntax is very unreadable for him. Can someone confirm it is the best practice?
It's fairly subjective isn't it? A lot of people avoid doing it, because it could be a bit more work to change if you need more lines, but I've also seen a lot of people do it. It's more readable if you're used to it, and in my opinion isn't that bad to modify anyway
@@bakk. I can see that a code without any indents might be unreadable because someone might be expecting only one scope when in fact there are many. I think there is involved aspect of getting used to it
It's mostly a preference thing, I know some people prefer the single line syntax for short functions, but I'd say as long as there is consistency across the project then it's fine regardless of what code style is used.
I think that there are two schools of logic here: 1: Removing the braces encourages short functions and diving your logic into multiple functions. 2: Keeping the braces makes the code easier to change. For instance if an additional option had to be added it is easier to add to that specific if statement rather than in functions called, since there might be multiple callers. Just agree on one style in your team and that is the best one. Source: Been a programmer for 7 years now.
4:50 Would also check for isNaN(number) here to handle non-numeric input. 18:07 For better readability, I would also change return total + item.price * item.quantity to return total + (item.price * item.quantity) For me, noob code is more like prototyping code that no one else will read. Single character variable names save a lot of typing. Production code is a mix of advanced & pro. Good video. Already subbed :D Edit: Typo
To make the function _numberToAccountingString_ more flexible, I'd do a two-step process: If it's a string that has been passed, convert it to a number, and if anything goes awry there, throw something like "illegal value". Next, check whether or not we are dealing with a number (if we had a string earlier, we now do), and if anything invalid has been passed, again throw an exception. That being said, the "pro" code still is buggy, because merely *null* is trapped and no further type checks are performed. In more complex scenarios I'd also log a meaningful error message to the browser's console besides throwing as it can greatly simplify tracking down hard-to-find bugs. If necessary, I'd even add a console.trace()
Always tell people programming is really about controlling complexity (otherwise your code is hard to follow, maintain and scale). There's so many cool techniques out there that can make you better. Great book on this topic is Code Complete (Microsoft Press).
So basically the 70% of the video is about "JS can do very funky stuff with types", which can be solved by using a type checker and writing docs, or *ahem* don't *ahem* use *ahem* JS *ahem* on server side *ahem*. And his "pro" code sometimes is less readable and has unnecessary complexity. > What if we pass an undefined? If you are worried about passing undefined, then why do you check for `(n !== null)`, instead of `(n)`? Okay, now you can properly handle an `undefined` argument, but should you *EVER* pass `undefined`? Because IMO if anyone will ever pass `undefined` to a function, that works with currency, that must be a bug. And the earlier you will detect this bug, the faster you will notice and fix it. Because by returning `undefined` you just made your app harder to debug by moving an invalid value down the line and introducing an *undefined behavior.* And your app might work for months without anyone noticing, that "John has undefined USD in his bank account". _But sure nothing bad will happen, right?_ Also V8 will optimize its own type check down to a single if-not-eq-jump ASM command, which will be faster, then dereferencing your variable to check if the type is `null` or `undefined`. So you have hurt the performance and introduced the *undefined behavior* with this type guard. Also inlining `if (n < 0) { .. } else { .. }` made code less clear, because you lose indentation, that subconsciously helps you read the code. It's a tiny thing, but overtime tiny things add up. Then you use `items.forEach(item => {..})`, I'm not a pro JS dev but even I know, that every modern browser supports `for(let item of items)`, and it's more readable. So you fixed some of the readability problems but later you threw half of those improvements away, and introduced an *UE*. I'm not sure this is a video I would recommend to newbies.
"If you are worried about passing undefined, then why do you check for `(n !== null)`, instead of `(n)`?" Falsy values are something to be considered especially when handling numbers. All of this shit can be solved with TS.
Totally awesome man! \m/ . Would love to see more of these advanced videos as well and real scenarios and good practices. Would you also consider doing projects where you can cover different JS frameworks? I would be interested in Svelte a lot.
Some tips. Use the correct decision structures. Use descriptive variable names. Correct casing. Dont be afraid of comments. Optimise your darn images. Use the correct semantic tags (Dont use div and span elements for everything) Indent your code. Use the correct meta tags and ffs sake isolate your functionality.
My key takeaway: - Avoid using numbers inside your code block. Rather, set up your numbers as variables, and name them in a way to indicate what the number means/does. - Using this variable name will make your code easier to read and interpret.
The "pro" version you introduced at 6:15 - Would a "pro" actually put the return statements on the same line as the if() clauses? I don't think so. I think what you have there is actually a stage between noob and pro where the developer thinks they're good enough to do away with formatting rules because they can read it just fine. Later they realize that those formatting rules are really for the folks that come after them.
I don't know why, I start code with the "pro" one for the first time. But now, I think my code just like "amature" programer. Just because you are overuse if() clause. And don't know when is the right time to use the "else" statement. If posible, I just write code into one single line.
@@Rhidayah It is almost never necessary to use an else clause. It must be years since I've written one, because they are just so unnecessary, most of the time. And yes, the function here should've been one single line. This is not pro code; it just tries to pass itself as such.
@@lucas.campora Personally my issue is with #1 the double equals operator. This is simply a no-no; If you're not using the triple equals operator, you're doing it wrong. Guaranteed this would be flagged in a peer review. #2 Why are you type checking anyway? If the type concerns you, use TypeScript. Otherwise, passing the wrong type is a user error. If you absolutely have to type check, throw an error. Returning nothing is not helpful and causes side-effects. #3 Removing brackets from your conditional doesn't make it "better." The brackets are there to partition the code, to provide readability. Here are examples of how I would've done it --> www.paste.org/105678
usually those types of statements are at the top of a function, and are the "guard clauses" he spoke of. i write my functions to have a "let rv = false" at the top, and modify rv, then return rv at the end of the function. one return statement, essentially. rarely do i use guard clauses, even. i tend to use the nested if statements. if you use a decent editor, you can collapse code blocks, making it far easier to read code, and debug. i find advanced code, although pretty, difficult to read - at least it takes me longer to decypher it. shrugs.
my issue is that i always just try to get things work first and only after im done with the whole thing then i go back and clean up everything . but sometimes i get lazy and even end up with unused code lines lol a total mess .
And then we have these guys: var accounting = new Accounting(); accounting.add(0); accounting.print(); accounting.clear(); accounting.add(10); accounting.print(); accounting.clear(); accounting.add(-5); accounting.print() accounting.destroy();
Thank you for sharing your ideas, I'd love to see more such videos :) I prefer such notation: return number < 0 ? `(${Math.abs(number)})` : number.toString()
It was nice to mention good code isnt written like that in one go but is the result of several revisions, trial and error, meaning discipline is key to better outputs
I think the difference is that as a beginner many times as he says, we focus on the perfect scenario only and we unconsciously we’d to see lleve logic as clear as possible, when you are a pro, you have a lot of experience and knows how to take advantage of the language itself to do things clear and clean.
I'm not completely agree. Return "void", and string still beign a middle/advanced practice. A pro always manage to avoid moving typing, memory lack, and throws.
I would argue, that not understanding a concept and not understanding someones thinking are two completely different things. What I mean by that, is that if you are having trouble reading a fundamental aspect of the language, then that may be your own fault. If you are having trouble understanding they way somebody used it however, that's probably on them.
I personally prefer reduce() because it encourages early declaration of intentions. Something like this: const weighedAvg = arr.reduce((acc, cv) => acc + cv.val * cv.weight, 0) / arr.length; You know instantly what the code is trying to achieve without necessarily needing to read the implementation. I guess the problem is when people try to fit too many things into one reduce(), then it can surely cause readability issues. Therefore I always (try to) keep my reduce() statements short and sweet, and make sure that it does one thing only.
@@scheimong Why are you all using "reduce" function to actually increase the values. That's oxymoron. This is the main reason why one should never use such things. Especially if there will be another noob who will have to take over the project and will try to read. He will spend countless hours reading up on all these functions just to find out, that this all could have been done in a much easier, cleaner and clearer way.
@@alet3348 reduce, also known as fold in other languages, is a *VERY* common operation on array/list/vector. Any self-respecting person who calls themselves a developer should know this by heart. If not, they should not be taking over any project. What, just because noobs can't understand something means I have to code stupidly? Get real here.
If you want to write a better code, learn some old less complex cpu(like 6502 or 8086) with its assembler language (get a book in a library and work it through in like 2 weeks), then get a book for math and learn logic and the set theorie, then get books for theoretical knowledge (not language specific) of programming paradigms, data structures, and dependency of programming techniques on data structures, open wikipedia and read about iso osi 7 layer model. then get the assembler book again and learn java and c, while you think how you could implement the stuff, you write in java and c, in asm. take a pick on sql and some sdl(see bonus part below). make connections between stuff you learned in all previous steps and your programming experience. what you get: you will get a lot smarter for everyday life; (ability to make yourself clear and to understand others, solving problems, by that get more attractive, asf) you will understand, that data structure (and other aspects of the architecture) is/are more important than the programm code, and that the programm code evolves around the data structure you choose and is limited by it in every regard; you will understand that the readability is the highest priority in any description, if humans have to work with it, and learn all techniques to achieve a better readability; you will be able to use all existing techniques/paradigms/algos/whatever fitting to the problem you have to solve, mostly regardless of language you have to work with, because you will mostly invent or extend the langauge, to hide the complexity and make the programm easier readable, and by that less buggy (because you and others will be more able to see the errors in the code); as a bonus, get book about vhdl, get yourself a book about digital technology, get a evaluation board for about 20$ and implement some exercises and own ideas. what you get: understanding of parallel execution, its problems and standard solutions; good starting point to multithreading/multiprocessing; p.s.: did you realy think, that you can get good, without changing yourself from the ground up?🙄 you cant create structures better than you have inside your brain, you need to feed your brain up first. p.p.s: java script is hard to learn, if you dont understand what you do and why (not in regard to language, but in regard to desicions concerning the sw-architecture and the code/data structures you choose), because java script can a lot in many ways and you have to know what is more fitting to what and when. it can even be hard for professionals, who already know the theory and couple other languages.
A function should have one way in and one way out. A great program would know the probability and put the most positive hits at the top. You don't handle the null or undefined value you return an any empty string. If you know that you get more positive numbers than negative ones that check should be done first.
Template literals: Everyone using it everywhere. It is not readable and not more clear in the first example. It is readable when you have a longer template string with more than a few variables. But when you have only one or two variable and want to add a string to either end, it is just way more clear to write that way. In the original code it can be seen instantly why even that thing is there: to add some prefix/suffix, and what is the main logic: Math.abs() In the template literal version everything is just a pile of symbols. When you don't have syntax highlight, it is definitely harder to read. Input argument type checks: JS is a dynamically typed language. Live with it. If you feel the need to check the type as an assertion, you are using the wrong programming language. Assume your code calling that func is correct. Debugging and QA is a different story. Lets make a development version and a production version, and only include the type assertions and meaningful console.logs in the devel version. In the prod. version those checks are always false, just eating up resources and in the rare case when it is triggered, your app. will break anyway and none of the end users will read the console. Just my opinion...
Yes, exactly. When the coder thinks he or she is so clever because they made the error not appear where it should because the input was not allowed, that's a problem. Now the error is likely to be thrown in some third party library instead of by the function that is not supposed to process anything but numbers.
This is actually an ongoing debate, to use semicolon or not. It's pretty much an even split however, so just choose one and go with it. Just make sure you are consistent. I personally prefer to use semicolon just to avoid a few edge cases where ASI does weird things. But again, personal opinion.
@@scheimong Ah I didn't know we could leave out the semicolon, I have been doing it like that for a few years because I came from java where it was a must. I'll still stick with the semicolons though.
@@KevinWho it's actually better with sticking with semicolons, because what really happens when you don't put your semicolons is the syntax parser will look through your code and check the lines to see if they end with a semicolon; if your code doesn't have semicolons at the end of the lines, syntax parser will add semicolons to your code by itself before sending it to compiler. So if you put your semicolons, syntax parser won't have to put them by itself and will send your code to the compiler a bit faster. It's not a huge difference thanks to modern processing speed and modern JS engines but still good to know. Another thing, maybe more important, leaving the semicolons to syntax parser might cause some unexpected bugs. For example you might wanna do something like this: const myFunction = (a, b) => { return // I can put comments here to describe what this function // will return. a, // I will also return b here for some reason b; } if you don't put your semicolon at the end of the whole return statement, syntax parser will look at this code and say "OK, here is a return keyword and the line just ends here so I will put a semicolon here" and will insert a semicolon right after the return keyword and your function will just return there without returning any value. I'm coming from Java as well, started learning JS a couple months ago. And as a former Java developer your hands should put a semicolon after each statement/expression automatically anyways. So it's actually better sticking with what you've been doing all the time in this case.
I've been bitten several times by bugs caused by missing semicolons that took ages to track down. E.g. When adding code after a long comment block that is a valid continuation of the code before the comments. Not worth the risk to me.
About the variables names... it's the tutorials we watch that teaches us. I would like to see more real life examples in tutorials, to better understand the concepts behind programing and the way to apply them. Like this one, which It is crystal clear about products, shipping, etc. I mean.. look at the w3schools javascript variables page (var x = 5;). Sometimes the noobie practices shows holes in the teaching process. Thank you for another great video.
I really dislike having multiple exit points from a function. It leads to return type discrepancies and it’s often easy to miss that an early return statement has been triggered when debugging.
Yes, and he doesn't need to write "number" in the function name when the parameter is called "number". I have fixed this... const accountingStyle = num => { if (!isNaN(num)) { return num < 0 ? `(${Math.abs(num)})` : num.toString() } }
Imagine having to if statements, where the second looks like it will always be true when the first is false, but it, in fact, just prevents null or undefined as parameter. Like, breaking the code and THEN showing, that it didn't account for undefined/null... What is this? A joke?
7:07 What about NaN and an alpha string being passed? I would do a two part check: First: I would Check for a falsy value (false, 0, -0, 0n, "", null, undefined, and NaN) by multiply the variable by 1 If it is a number, it just returns the number and will return NaN for most everything else. - Note1: Using a bam ( ! ) in front of a falsy value turns it to true - Note2: A number as a string when multiplied by 1 will return the number value. - Note3: `null * 1 === 0` which is a falsy value, but we'll eliminate that in the next step Second: Check that the variable is not equal to 0 (since 0 is a falsy value). If both conditions are met, then it will just return the guard clause. Lastly: If we made it this far, then it is a number. I would then use a ternary operator to format the number to a string. ``` function numberToAccountingString(number) { if ( !(number * 1) && number !== 0 ) return; return number < 0 ? `(${Math.abs(number)})` : number.toString(); } console.log(numberToAccountingString(undefined)); console.log(numberToAccountingString(null)); console.log(numberToAccountingString(NaN)); console.log(numberToAccountingString('A')); console.log(numberToAccountingString('-9')); console.log(numberToAccountingString(0)); console.log(numberToAccountingString(10)); console.log(numberToAccountingString(-5)); ```
possible alternative to first one... function numberToAccountingString(number) { if (number == null) return; return number < 0 ? `(${Math.abs(number)})` : number.toString(); } It's still fairly easy to read with the ternary approach, though it could be a little confusing to the noob level so there's an argument for avoiding it. On the other hand, it's good to learn since they'll almost certainly come across it at some point and it's a very useful and concise way to return a value or assign one to a variable in cases where you're only choosing between two options (after that it gets confusing very quickly)
I think planning is also very important. I find myself doing a much cleaner code when I spend some time drawing some flowchart and wrtting down sort of a plan on a piece of paper before jumping on my keyboard. I would also add to that, separation of concerns and decouplized code is the key to maintain a large piece of code.
weird you didnt get more likes:p finally someone mentions flowcharts:p so old-schoold, me like it;>
@@geraldjoe-smith-mcnea6829 I'm 31 and I can't remember any of my passwords. There are too many to remember. You should switch your phone password to a swipe to unlock or something easier.
Wait... people don't plan ahead before writing code? /s
One thing for the new programmers to know (at least from my perspective as I consider my self a mid/advanced programmer) is that not always you get the code as the last file for the first time writing a function. I think the 90% of the time we will write the "noob" code and then start depurating code readability and errors caused by un-programmed test cases. So, if there's a new programmer around here, don't worry if your code doesn't look as the "pro" code at first, but make sure it ends looking and working as so. And remember it's a never ending journey of learning, there's no programmer in the world that has nothing to learn or improve.
Thanks
As a professional developer, I greatly dislike one liner if statements. In my view it makes it harder to see the logic if it does something even slightly long. Adding some spacing, and curly braces is always good.
Agreed. This video is not that great. Yea there is objectively good code but at a certain point it is subjective.
I wonder what you feel about one liner if statements WITH braces. In my view, if you don't get over the 80 character limit, then putting everything in one line is fine.
There are some cases when I am a fan of single-line if-statements. The thing I use it most for is guard checks that simply return. For example the if (input == null) return; is really concise to me. I'm not a fan of putting much more there though, and I also dislike using it for more complex logic checks...
I agree, I am actually in favor of creating wrapping functions with dedicated guard functions if your logic it's too complex, that's better than creating one liners a hundred characters long with your code still being compact and easy to read, this video is lacking some good functional programming principles and also some good test driven development principles
Ironically I think a common mark of novice programmers is mistaking concision for efficiency. Clean code is readable first and foremost, there's really no advantage to minimizing line count for it's own sake. If the length of your code is suspicious, dropping braces and using ternary statements probably shouldn't be your first reaction.
Seing your "pro" or "senior" code I would recommend creating one more level above it, since still few things can be fixed, so the whole is more maintanable.
First of all, if you have function `numberToString` you should throw if you get anything other than number.
You actually made code *worse* by returning undefined, since you are silently failing that way, and it will throw in completely another place, will take longer time to debug, and the error will be less meaningul. It's even better to not handle it at all, and let it fall naturally, since then you get an error in precise place, which caused it.
The same applies to handling "null" in second function.
Further more: if you insist on handling such things, don't cherry pick. What's the point of validating if argument is null or not, if you expect array? You are still not validating the content of the array, but you get the impression, that you have validated the code. You quickly come to a place when you are either still cherry-picking or validating absolutely everything, and the code becomes unreadable.
You need to trust your own application, you need to add validation mostly only on I/O layer (reading unexpected input like files or API), and you need to *let it fail*. Failing is good, because it shows during simple input testing, if everything works.
Each one used `if` or some kind of condition, or nesting is literally making code worse. The less the better.
I would even imply, that most of the things do not require handling anything more than happy-path (and any states, that are actually valid and possible), because if something fails, then it means you have the bug in your code: either your validation on input is not right, or you have typo or something. By not handling it, you are going to find it ten times quicker, usually during manual testing
I agree about cherry picking, but not so sure about "not validating and trusting your application" part. in this scenario, it does work, but if there is a class that is just storing things, and you are not the only developer working on the project, should you not validate what other data sources are sending to the class? or is there a better way to handle it? I am in the habit of writing validations in all parts of the program :)
@@szwimzs it depends on separation of concerns. You should trust the code you have influence over. If there is another team developing another modules, you may treat them as external input. It really comes down to architecture. If architecture mirrors team structure it may be nice to add validation on the borderline.
If you are talking about domain objects, then it is good behavior to ensure they are built correctly, as it is not function performing operation, but the data itself.
With that being said what are your versions?
@@soanvig Why have another layer when the advanced level in itself is difficult for most. Let us not forget that most of the crowd out here would be very happy just getting to the advanced level. If you go on adding layers you will agree that there will always be a guy out there much smarter than you are and who can write code better than you.
I don't agree with you that you shouldn't validate your functions or methods. I believe it's crucial to validate functions or methods, especially when they're intended for use by other teams or programs. Let's consider an example: imagine we have a function named calculateInterest(amount). We might trust that it's implemented correctly and will return the expected interest amount so no validation checks are written, just the logic that calculates the interest. However, in practice, mistakes happen, and in our haste, we might accidentally pass in incorrect values, potentially breaking the code.
The real problem arises when the function fails silently, without raising an error. In such cases, the code continues execution, unaware that something went wrong but returning the wrong results. This silent failure can lead to significant issues, especially when even small discrepancies in calculations, like one percent versus eighty percent, can result in substantial differences for users - either paying more or less than they should.
To mitigate this risks, validation checks must incorporated into our methods or functions. We can even separate the validation logic to keep our code organized. The validation checks should also address edge cases and ensuring inputs are valid. A function or method without checks is a function or method doomed to fail.
About the first pro function "numberToAccountingString":
While "==" (double equal signs) does indeed cover both "undefined" and "null", I'd argue that using "===" (triple equal signs) in general is more readable. And as others already mentioned, "typeof number === 'number'" would be the most readable and logically correct way to check for the type.
And when entering undefined/null, it would just return undefined. Wouldn't I expect a string? Let it throw, preferrably with a custom message "throw new Error('Invalid parameter type')". If the function expects a number parameter and receives something else, it should stop so the stacktrace to debug will be as short as possible.
This!
Throwing an error is the way to go. Fail fast and spectacularly - less bugs in production that way.
How About if(number) //.....
@@piyushupadhyay4571 0 is a number, but is considered falsy and would not go into that if block.
I am not even close to a pro, but is it even necessary to check the type here? Even if we are expecting string numbers, we can just rely on the less_than condition to account for nullish values since javascript type coercion will automatically recognize a number string as a number in our condition -- like so:
const numberToAccountingString = number => number < 0 ? `(${Math.abs(number)})` : number?.toString();
Today i realized i am a mix of noob, advanced and pro programmer.
Awekening Bro noob, advanced, and 'pro'-grammer
So you are awkward programmer🤣
i am a (prog)r(am)m(er)
We call that LEGENDS
-1 + 0 + 1 = 0 so your just average
When you watch this, you realize how many errors typescript prevents
Absolutely! Don’t blame programming language faults on programmers. They would use anything that the language offers. This is the problem of a fully dynamic language... why think about naming the variable so that you can guess that it takes a number, but not adding a type description???
John Yepthomi
?
@@user-vs1mn8ig8w go read what a type script is
@@johnyepthomi892 ?
@@hashnoodle2499 noob
What differentiates a junior and a senior dev is the fact that seniors can solve problems way faster due to their experience. Seniors are not always the 'better' ones. Good video!
I think this covers my sentiments too, but I would also say that a good senior also knows to listen to juniors as well.
Back in the old days of having to insert cards into a machine, efficiency of code was the most important aspect. You didn't have any capacity to fuck around. Technology moved forward in such a way that optimization became an after thought. Back in the day you had no choice but to make your code as best as possible.
I didn't know they were called "guard clauses" but I used them all the time. It just seemed smarter to me. But I got criticized by senior programmers saying that the code in functions should flow from top to bottom and returning early was bad. So now I use noob programming styles to keep the senior programmers happy.
I don't know what kind of 'seniors' you're working with but returning early is not a bad thing whatsoever.
@@_yakumo420 Dijkstra's grandsons probably.
I used to go back and forth all the time about this myself. I finally settled on making it as visible and as obvious as possible. If I can put all my guard clauses at the top I do so, and if not I like to create a small “island” and comment it so it stands out. Also, I notice they looking through either my old code or other examples, a lot of early returns could be circumvented by doing validation elsewhere or just making type safe objects. Granted, you can go overboard with that quite easily. I’d say for simple programs and small functions guard clauses are totally fine. For bigger beasts, some rewriting to include the above might be a good tool to use. Had to learn all this the hard way when someone looked over my work and told me I was “primitive obsessed” and I though, “I have no idea what that means, but it doesn’t sound good!” 😂
@@Blast-Forward A bad joke, since most of the time he was 💯 percent right. The worst thing about programmers is that they are like normal people - they want a solution that always work, a paradigm that is always the best. There is no universal formula. But people are people.
I've seen "pro" code in production that looks worse than the "noob" code.
HAHAHAHAHAHAHA true that
Sorry about that.
I see these jr. vs. sr. code quite often as if these seniors don't write ugly codes as well.. why not just call it "write better code"...
true xDDDD
I think a lot of this 'pro' programming comes from people in their late 20s and early 30s who have already gathered quite some experience in coding but not lost their passion that much, like myself(just talking 'bout my age here xD). But in practice it is usually more important to get things done than getting it done with nicely formatted code
I pulled my hair apart looking at "pro" code in production
I pulled my hair apart looking at my own code I wrote a few weeks ago
I retired from coding and changed industry
if we're so concerned about the number parameter being a number; We can just use the typeof operator. (typeof number == 'number'). This is how I would approach this problem set when it comes to validating the argument(s).
you're right, with the exception that it should be === instead of ==, in javascript. (not that yours wouldn't work, it's just best practice)
Yes, but you forgot that typeof NaN == 'number' too in JS. And so it would be better to use (typeof number === 'number' && isFinite(number))
I disagree on the pro code.
the function silence the error, it's not a good practice.
if the function isn't design to get an undefined or a null, just make it crash and catch the error elsewhere.
.
if you don't you gonna have hard times finding bugs when you'll get an undefined...
because the function just silence the error....
um...seems if you need to make the function ensure it got the right data you have a bigger flaw this function shouldn't be addressing!
Very true... it's makes debugging easy. and that way you can manage all the errors from diff functions in one places
Sir, you have my vote. I literally wrote the same comment, longer tough, and then scrolled through what's already written.
How can you prevent thread exception errors without a try catch?
@@M1KE9815 make sure you pass right datum?
I like that you take the time to work us through the beginner, advanced and pro versions. Very nice touch.
Just a few from me:
- Document (state the allowed argument type and return type, for other languages you can data type) at the beginning of the function/method and comment less in the block.
- Indentation is key, space out and line out.
- Middleware: Quick exit or safe guard blocks at the beginning when needed.
- Less depth of code blocks (one to two way deep is okay).
- One line - No braces for blocks: if the code block is less than 50 chars or less than your ruler, use one line.
- Ternary operator.
- I use concise variable,function/method names.
- Less return keywords.
- Less code size: The less block of code, the better.
I am only a hobby programmer and first time i heard about Guard Clauses. I really love it! Looking at others code specially with tons of if else statements can be a nightmare. This is so much cleaner! Looking at guard clauses i see immediatly what its doing.
Really surprised you didn’t use an example where helper functions would be beneficial. Learning to decompose a problem into smaller steps that are solved by well-named functions is a key aspect of writing “pro” code. Still, there were some good tips in there when it comes to writing a single function or block of logic.
Agree. In the second example, the function should use helper functions for readability and clean code practices. Otherwise, a good video but could be a bit shorter tho.
Thank you, was looking for this comment. That code is not 'pro' yet
but multiple function calls increase time complexity
@@siddharthverma4017 news flash: people rarely give a fuck about a few extra extra function calls in real codebases. And even if they did, good engineers know that you should almost always be willing to sacrifice microseconds of performance for code readability.
@@siddharthverma4017 in some old or dynamic languages, but most languages inline those kinds of small functions
I was writing code just like the advanced version 4-5 months back. Recently, I learnt about writing clean code and now I think I write like a pro.😁 I was requesting you in comment section of your other videos to create videos on refactoring/clean code since long time. 😄 I like your explanation. Keep bringing more videos like this. Thanks. 👍🏼
How and where did you learn to write clean code please?
Mikael Borhzka geektrust.in
Juan2003gtr Yeah. I know most of the experienced guys don’t know about clean code because either they are not interested in learning or they don’t even know that the code they write can be made better. Many of us(young coders) are very good at DSA due to the growing competitive programming culture. It will take some time to develop the culture of clean code.
@@mikaelborhzka7627 Robert C. Martin - "Clean Code: A Handbook of Agile Software Craftsmanship" is a nice read :-)
Started watching your videos today and instantly became a fan! This here is code gold!
Yo, I have been learning from your channel all morning. I just wanted to say, thanks for putting these up, thanks for showing your passion and making code fun. Also thank you for keeping almost all of your videos around 30-60 minutes. It really helps me focus and take it like a small class, take a break and then come to the next one. Keep up the great work my guy. Rock on
Thumbnail be like:
Minified code vs formatted code
minified code is certainly not noob code, it's more just pro code that's been made to look impossible to read
@@sodiboo what? minified code is just code that is run through a minifier/compressor... having minified code does not really suggest/imply that the quality of code being written is "pro" lol.
Terrain
Yes.
But the thumbnail is minified code on the top under “noob” and formatted code under “pro code” which - as you stated - is inaccurate. I was pointing out the, understandable (how does one portray noob code in a thumbnail?) but inaccurate nature of the thumbnail.
It just struck me as odd, is all.
We work with minified javascript packages daily in production - but (at least I do) prefer to use the regular versions during development. Certain IDE’s don’t really like indexing minified code very well and will miss imported functions quite often...Particularly Jetbrains IDE.
Despite this, they are still my favorite development environments to work with.
The pro code is also not very good. If you need comments to explain what you are doing then you need to introduce more functions.
"And that is the important thing about programming - It's not about writing something that works, Its about writing something that easy to read and easy to maintain"
"[...] something that easy to read and easy to maintain **and works**"
@@HenriqueErzinger Code that works needs no maintenance .... ;-)
At least 60% of professional (paid for ...) programmers dont know this.
AsgaiaMetal that’s not true at all. What happens if you’re linking to an external library and that library changes? What if there are features added, removed, or changed? What if new devices use hardware that’s incompatible with your code and induces bugs or outright breaks your code; for example, a domino effect from some change in the way an op code works cascades down and disrupts out of date libraries and APIs? Of course you need maintenance.
It is, but there is this one little trick : good code, doesn't need to be improved, and thus doesn't need to be maintained. There's no perfect code, but I know when I'm looking at code that has very little bugs. It's very hard to achieve, but it is possible.
A little code review of the 'pro' version at 6:14 -
1. A 'pro' would simplify function name to accountingFormat() or just format() if the module name has the word 'accounting' in it (which it should). No need to say 'number' because you already have an argument named number. There is also very little value in suffixing function names with return types so that can be omitted as well.
2. A 'pro' should use semicolons at the end of each statement. Consistency and clearly communicating intent is more important than omitting a single character.
3. A 'pro' should avoid returning null or undefined if at all possible. Returning null or undefined usually forces the calling code to do an immediate null/undefined check on the returned value.
4. A 'pro' would either use null object pattern with a meaningful string value or throw an exception.
2. A 'pro' should use semicolons at the end of each statement. :surprisedPikachu:
@@foxyl0l A 'pro' knows that consistent usage of semicolons in JS is considered best practice. Not only that, but a 'pro' actually understands the importance of semicolons in JS. Even though one can get away with not using them, they provides significant benefits:
- Avoiding rare but very hard to detect bugs (with potentially significant consequences).
- Avoiding issues with minification.
- Making code more readable by clearly differentiating statements from expressions and other code elements.
- Better communicating developer's intent.
- Making code easier to understand for less experienced colleagues (the ones that don't have intimate knowledge of how JS ASI behaves).
- In consistent usage, a missing semicolon can indicate a potential error.
All of the above in exchange for just a single extra character per statement.
A 'pro' would encourage their team to stop bikeshedding about semi-colons and just pick a standard linter, e.g. StandardJS or Prettier.
@@milosmrdovic7233 Agreed to all you said.
In addition, I think a real pro knows when to weight the benefits of code performance, maintainability, readability and conciseness depending on what it's used for and project time limitations.
For example not all code has to be super-performing when there's really no real need for it, in which case it's better to sacrifice some performance for something that's easier to maintain, read and more concise.
On another note, I also see a heavy lack of code comments in his example. It's a misconception no code requires comments as long as it's well written, even if it's super simple a comment is always nice.
For instance, if the code he wrote threw an error when the number is null or undefined, then that would be nice to know by the consumer of the function without even needing to looking at the code. Adding jsdoc to this function would be ideal here overall, but especially @throws
Noob: Writes code that is functional and never refactored. Never doubts the efficiency of selfwritten code, writes it once and be done with it.
'Professional': Writes clean code, easy to read and maintain. Code is a result of many refactors to have each component be a of single purpose and therefore here to stay. Code does not use references and parts that can have its functionality change by outside sources. A pleasant person to work with.
Professional: Writes code that is perfectly maintainable by the professional himself. Obscures many processes without sacrificing performance. Makes use of personal roundabout functions that would make rewriting/refactoring difficult for his potential successor. The professional became irreplacable for the employed company.
Once I realized guard clauses were a thing (didn't have a word for them until now), I've always done my best to use them. It makes so much sense, and is cleaner.
What about ternary operators , simple and elegant.
That's too pro :+)
Yup, I was looking for the one-liner.
Ternary is for only who is become Advance Pro in programming. 😂😀
Ternary operators are hard to read. It's better to use if-else instead of ternary operators
@@sinamirhejazi268 I disagree. I find them very readable. Admittedly you have to know what they are to read them but when you do it's very easy to construct readable operations. user.isAuthenticated? : null
vs
if (user.isAuthenticated) {
return
} else {
return null
}
Thanks for the emphasis on using 'constant' patterns. Something I 'kind of'' do but without really realising its worth
That was very interesting, but as a pro, you need to do a better kind of type checking and throw an error if you pass wrong data. You can test your script using other data types (like an object or a string) to see what happens. This can be avoided by using a better comparison operator (always prefer === over ==). For example, you don't want to return something other than a string (your function name has to...String 🤷♂️). So, you should consider using some kind of type validation and throw an error. There are many options for doing that. You can use typeof number === 'number', trying to convert to number with Number(), parseInt() or parseFloat(), but my favorite is using isNaN: if (isNaN(number)) throw new Error('Not a number'). That way you can use string representations of numbers like "-0.75", but keep in mind that you need to use Number(number) after validation to turn the strings into numbers for good results.
Loved it, this how we roll. Everytime I visit our code, I stare it for a while and see if I can apply something I learnt recently. JavaScript has evolved like anything, specially since last few years. From FOR loops to MAP, REDUCE and FILTER, makes Dev's life interesting.
for `logic/pro` I would also recommend using a ternary operator to better explain the if then else behavior, and it also keeps it in one lines (unless you wanna break each statement for better readability) and it also makes you not repeat the return statement more than the number of times you need to ;)
I thought the same thing!
In the first example, I expected to see ```-number``` instead of ```Math.abs(number)``` in the number < 0 case. After all, you know the number variable is a negative number by then, so you can save yourself the hassle of calling a function that checks for it again.
Also, I checked and updated my Python miniproject while watching this to make it cleaner. The concepts work the same.
Also, for other pythonistas out there watching this: Have docstrings. The feature is in the spec for a reason.
Came here to comment this about ```-number``` instead of expensive library function Math.abs(). Good eye @Alchemist!!
+num works either way
Congratulations on this great video, a pleasure to watch! But with all the respect, let me disagree with you regarding 5:09. You mentioned a very good point regarding edge cases. However, returning `undefined` is also not ideal. I’d suggest either throwing an Error with a descriptive message here or using a Maybe type (like in FP) and chain any further computation. Returning `undefined` will simply defer the problem as the caller needs to check what kind of value the function returned. For example, the following snippet might fail due to the same reason: numberToAccountingString().charAt(1). What do you think?
I had a guy downvote me on a SO answer over this exact point… I really dislike returning undefined. It always reminds me of returning NULL in Java.
yeah, the good old 10mio dollar mistake..
I also tend to agree. When something unforseen happens then functions should rather crash (verbosely in the best case) than trying to defer the crash - what if some later part of the program writes the accounting records one by one to a file and crashes then - with a half written file. Being processed by a booking system, detecting the change and... ok, I stop here ;-)
So yeah, better assert than return, agreed.
if i ran something with console on and got undefined returned, i'd just think there is an error with the code.
A hundred percent i agree
Do function()?.methode(1)
What do you think
@@kybkap8686 In my opinion the use of "?" only disguises the "if-else". The problem is that there's no "else"-branch when "?" is used. But, often there must be one. Imagine, you click a button, the "if" part evaluates to false and the button does nothing. This is the worst for the user - a "sometimes-do-something" button.
Great video, but as a tech lead I have some complaints about your pro code :p
First of all you should always fail early. Instead of returning undefined in your function you should definitely throw!
Also the name numberToAccountingString implies:
- should always return a string
- should only accept numbers
So if you decide to check inputs you need to make sure that its a number.
You need to ensure that only strings are returned.
If your turning a number into a string you should use toLocaleString(). If you want to disrespect locale to is explicitly by giving it as param to toLocaleString().
Coming in from another language than javascript you will know why people do advanced programming rather than "pro" programming.
A lot of the time I want to be consistent not only in one language but in multiple languages. So switching from one to another I keep the same good habits of making the code look readable to devs that write other than JS as well as myself.
Reading this comment as a newbie, this makes sense. When I'm learning, the instructor will use semantically descriptive variable names, but will do the opposite when it comes to naming arguements and parameters.
Good comment bro
11:20 Would definitely trip me up since my primary language is Ruby. In Ruby (0 || 5 ) would evaluate to 0, because 0 is not "Falsey", it's "Truthy".
Kyle: "noob programmer-"
Me: what is it?
The first example you should really test number is of type number , rather than test for null imo
Alifka Aditya Putra one reason is because a different variable type, specially object, could be the value and it would make the code break. If you check for number type, it prevents more possible errors, and is not any more complex
Alifka Aditya Putra just to elaborate, we are expecting a number , so it makes sense to only proceed if it is a number being passed in, this will cover all non number scenarios in one test.. 🤘
I would use this: if (!NaN(number)) return number > 0 ? number.toString : '('+number.toString+')' in the first example. Simple and clean solution.
Lazy you may use it, but I wouldn't .. it looks like a spider ran across your code while the ink was still wet😬
@@PB72UK Why? You mean ugly or unreadable? It checks type for you... And specifically returns result in parenthesis like he wanted for negative numbers. Sure you can use just a standard if else if you don't like this "? :" syntax. I just wanted emphasize that there is something like NaN.
man hear this from a noob: I wouldn't use any function, i'd just write the whole code every time i need it... duh
then you are ultra pro max bro
This freaking function thing i ran away for long.bbut now i start understanding pro functional programming and its benefits, thanks to tutorials like this. Thanks sir.
Some developer follow the theory - "If it was not easy to write, it shouldn't be easy to read".
A philosophy or a saying, not a theory.
This video makes noob to think he can write advanced and advanced a pro.....Amazing video Kyle as always.....🤚🏻👌🏻
This video makes noob think he just became a pro and tomorrow will go ask for wage rise :))
@@Borlays 😂😂
Seniors also use TypeScript these days. You don't need to do all the monotonous manual type checking
I cannot remember the last time I did manual type checking; if the project utilizes TS, great, we can catch a lot of runtime bugs that way but if not we still don't go around manually checking each argument value for everything it is not allowed to be. That just creates bloatware.
I am not understanding why type checking is even necessary here. We should be able to rely on the less_than condition to perform the type coercion if the user passes in a string number, and it will return false if the user passes in a nullish value.
Even if you don't use typescript, you can still use doc comments for typechecking (using the typescript compiler on any IDE, but it doesn't require your code to actually be typescript code).
TypeScript compiles really shitty non performance code, really do not like it
Ahhh... there is no guarantee that the values that trickle through the code at runtime are what the TS type annotations say they are. You can easily end up with lots of bugs if you don't do any type checking.
Calculation can go bad and result in numbers being NaN or Infinite; DOM input values, when parsed/validated, can end up as the wrong type (null, undefined, invalid Date objects, etc.); data from APIs and databases can change without your knowledge or may contain invalid data, causing values to be some completely different type; and so on.
It doesn't mean that types are useless, not at all. You just need to know when explicit type checking is necessary and to be very strict about outside data, that you have little or no control over, always being properly validated, parsed and typed (e.g. using a helper function, like "const dateOfBirth = getDateFromString(unknownValue);").
I don't like the inconsistency of single line if statements. It makes it more difficult for other programmers to add any updates. "Clean" is nice, but consistent is a lot better!
I agree, sir!
agree
I prefer single-line to non-block two-liners.
I basically always use blocks, except for one scenario, in Guard Clauses - "if (True) return;".
Math.abs(n) returns the positive value of n for positive numbers and the negative value of n for negative numbers. When you've already checked and know that n is negative, you don't need an additional conditional negator. Just negate manually using `(${-n})`.
Not always a fan on multiple exit points, especially in more complex functions, but I'll quote Martin Fowler in "Refactoring: Improving the Design of Existing Code":
". . . one exit point is really not a useful rule. Clarity is the key principle: If the method is clearer with one exit point, use one exit point; otherwise don't"
Great video explaining the difference in readability. Just one nitpick, I'd expect the pro version of the last sample of code dealing with cost to be accurate to the required decimals. If we're going to go all the way with professional grade code, floating point numbers need to be handled carefully when it comes to money. We actually had a discrepency crop up at an insurance firm that was not rounding the values before adding the total resulting in decimals that couldn't be reconciled, which is a super important detail when dealing with money.
From my 16 years of IT experience; I can say even senior or super senior also end up writing spaghetti code most of the times.
For me writing code is like preparing omlette or lemon tea, everyone is proud of their own recipe and sometimes ego clash.
What's your take on this ? In case of arguments how to come to conclusion if it's good , bad or ugly code ?
answer: don't try to assess the code that way. does the code work, yes or no.
@@A_Lesser_Man Does your code work? Yes!
One year later: Can you change a few things? Sure! _looks at code_ Oh f***.
I have been there.
@@the8flo1 lol i have too, its hell.
@@A_Lesser_Man
That's a very stupid (sorry) answer.
The worst programmers are those who doesn't want their code to be better and cleaner. They just smash something, yes, fast, it's working. But you can't do anything else with it later. Poor guy who will need to make any changes in the future :)
@@enjay86 although I agree code should be readable, no matter how much better it is it can never be perfect. Get it working. Clean it up. Refine over time
In the first example, you can avoid the function call to absolute since you already know the value is negative. Just negate the value. This would keep the program from making a function call that just replicates your negative check.
there used to be a site, codefights, that was great for this. They posted problems and you could code a solution in any language they listed. Once you submitted your solution and it passed the test suite, here's the great part: you could look at other solutions that passed. It was great for seeing how other people successfully solved the issue and compare efficiency, and number of lines used, big O complexity, etc.
Pro code is also more easily maintainable and extensible. Your last example shows these aspects very well.
This really gave me some simple actionable advice to improve my code. Thank you!
Our developers make sure the code they write is readable and straightforward to edit.
Everyone who is programming professionally: "use proper names for functions and variables"
Meanwhile what university courses use: function, func, x, y, z, a, b, c for pretty much everything
Ilja Knis God the pain of trying to understand professors random variables.
I love how every question i began to ask as i was watching was answered by the end of the video. Thank you!
One down side to that reduce function is not everyone can follow that function. But i've learnt more from your decomposition of code in the last 4 videos i've watched than years of grind vs uni. More! im hooked!
Then there is the grand master level, that is basically the same as noob but with good names and all the checking needed. With this the poor junior fella that wins the terrific opportunity to maintain it will not call you every 5 minutes to ask you how that line works, for every line of course...
Yeah. I usually prefer to write "dumb" code because anyone can read it. No ternary operators for example. While they're great it's also confusing if you are not used to them.
I kind of feel the same way about the whole stack. By all means, refactor everything into the coolest new frameworks if you need your resume to stay hot. But if not, just go for stable reliable stuff that anyone understands. A regular LAMP setup works great for a whole truckload of use cases :)
As a high-level, low-level, and assembly programmer, I disagree with a lot of what this video tries to make you think is "better code". There are different nuances, implementations, and optimizations between all languages, whether interpreted or compiled. Above all else, code should be bug free. Next in priority would be scalability and speed, then readable/ maintainable, then compact. The video should be titled, Junior vs Senior Code - How to Write Senior Code; which isn't always BETTER.
Here's one example, the "if(n < 0)" and the "else", I would keep the else "if(n>=0)" because it's a little more readable and scalable, in the case where you want to add other conditionals, and in the end, a compiler will likely optimize the assembly into 1 conditional and 1 jump instruction, and a fall through, in either situation.
interesting, the priorities would then be: Working, Fast, then Readable
@@eldwinc9884 Working -> Fast -> Readable
I'll remember that. thanks
I was about to say something like this but without the example. Great example.
Congratulations, you just explained the benefits of working with higher level languages. I bet you don't maintain ten million lines of assembler in a team of dozens, either.
I disagree on priorities. they are dependend on the goal of the project.
in some project AND some situations you can get away with that working > speed > readable stuff.
but mostly it is more like readable > working > speed.
reason for readable first, is simple: if you cant read the code, you will have difficulties to make it working in the first place. and if you dont have binding between work packages for code and a developer, or you are working with a tester/integrator together, you will get kicked in the ass, as soon as someone else has to handle an issue, or just do his work, with the code, you wrote...
speed is an OPTIONAL thing, because, in most cases, biggest part of the code is not even the bottle neck.
there are some possibilities to make the code so broken, that it slows everything down, but thats not the case of "not fast enough", thats the case of "wtf did you here? your code is blocking the whole cpu, while waiting for some peripherie all the time!"
where you need speed is decided at the architecture lvl or during tests. you dont need to invest time into speed, if it wasnt a requirement from above, as long as tests didnt show that it is required, to get correct(NEEDED) results.
therefore again
READABLE > working >> speed.
and the most important "lifehack" is not to tweak on the programm code in the first place, but intead to improve the data structure.
because the structure of the data has a lot more relevance for all 3 points: readability, komplexity (as the cost for getting it to work) and the speed.
The thumbnail for the "Noob" code is just a min.js file :D I don't think a noob could write a minimized js :D
If you want to make your code even more concise, you can use the inline short hand for if. This doesn't help with understandability, on the contrary it makes your code a bit more harder to understand, but it really shortens long nested if blocks
const bracketifyNumbers= (number) => {
return number != null ? (number < 0 ? `(${number})` : number.toString()) : undefined;
};
great video btw, helped me realize my mistakes.
Good point and it is called the ternary operator btw. Though personally, I don't think I would ever nest it :)
Hell at that point just get rid of the return and the brackets and go with the implicit return. Ladies and gentlemen, we now have a one liner 😅
If you have a "sum" function, and the parameters are x and y. It's kinda obvious what the arguments will be. But using strongly typed languages like Typescript and Elm helps a lot.
When you're working with really abstract things, It's not much of a problem if you're using a language strongly typed or has specs like Elixir or Clojure.
In the first example you could've made it even simpler with a ternary operator:
return number < 0 ? `(${Math.abs(number)})` : number.toString()
even further:
return number != null && number < 0 ? `(${Math.abs(number)})` : `${number}`;
My friend who is a PHP developer said that no curly brackets for single expression(guard clause) syntax is very unreadable for him. Can someone confirm it is the best practice?
It's fairly subjective isn't it? A lot of people avoid doing it, because it could be a bit more work to change if you need more lines, but I've also seen a lot of people do it. It's more readable if you're used to it, and in my opinion isn't that bad to modify anyway
@@bakk. I can see that a code without any indents might be unreadable because someone might be expecting only one scope when in fact there are many. I think there is involved aspect of getting used to it
It's mostly a preference thing, I know some people prefer the single line syntax for short functions, but I'd say as long as there is consistency across the project then it's fine regardless of what code style is used.
I think that there are two schools of logic here:
1: Removing the braces encourages short functions and diving your logic into multiple functions.
2: Keeping the braces makes the code easier to change.
For instance if an additional option had to be added it is easier to add to that specific if statement rather than in functions called, since there might be multiple callers.
Just agree on one style in your team and that is the best one.
Source: Been a programmer for 7 years now.
@@Shadow10011 Yes!
4:50 Would also check for isNaN(number) here to handle non-numeric input.
18:07 For better readability, I would also change
return total + item.price * item.quantity
to
return total + (item.price * item.quantity)
For me, noob code is more like prototyping code that no one else will read. Single character variable names save a lot of typing. Production code is a mix of advanced & pro.
Good video. Already subbed :D
Edit: Typo
To make the function _numberToAccountingString_ more flexible, I'd do a two-step process: If it's a string that has been passed, convert it to a number, and if anything goes awry there, throw something like "illegal value". Next, check whether or not we are dealing with a number (if we had a string earlier, we now do), and if anything invalid has been passed, again throw an exception.
That being said, the "pro" code still is buggy, because merely *null* is trapped and no further type checks are performed.
In more complex scenarios I'd also log a meaningful error message to the browser's console besides throwing as it can greatly simplify tracking down hard-to-find bugs. If necessary, I'd even add a console.trace()
Always tell people programming is really about controlling complexity (otherwise your code is hard to follow, maintain and scale). There's so many cool techniques out there that can make you better. Great book on this topic is Code Complete (Microsoft Press).
So basically the 70% of the video is about "JS can do very funky stuff with types", which can be solved by using a type checker and writing docs, or *ahem* don't *ahem* use *ahem* JS *ahem* on server side *ahem*.
And his "pro" code sometimes is less readable and has unnecessary complexity.
> What if we pass an undefined?
If you are worried about passing undefined, then why do you check for `(n !== null)`, instead of `(n)`?
Okay, now you can properly handle an `undefined` argument, but should you *EVER* pass `undefined`?
Because IMO if anyone will ever pass `undefined` to a function, that works with currency, that must be a bug.
And the earlier you will detect this bug, the faster you will notice and fix it.
Because by returning `undefined` you just made your app harder to debug by moving an invalid value down the line and introducing an *undefined behavior.*
And your app might work for months without anyone noticing, that "John has undefined USD in his bank account". _But sure nothing bad will happen, right?_
Also V8 will optimize its own type check down to a single if-not-eq-jump ASM command, which will be faster, then dereferencing your variable to check if the type is `null` or `undefined`.
So you have hurt the performance and introduced the *undefined behavior* with this type guard.
Also inlining `if (n < 0) { .. } else { .. }` made code less clear, because you lose indentation, that subconsciously helps you read the code. It's a tiny thing, but overtime tiny things add up.
Then you use `items.forEach(item => {..})`, I'm not a pro JS dev but even I know, that every modern browser supports `for(let item of items)`, and it's more readable.
So you fixed some of the readability problems but later you threw half of those improvements away, and introduced an *UE*.
I'm not sure this is a video I would recommend to newbies.
Single 'param != null' works for null and undefined
"If you are worried about passing undefined, then why do you check for `(n !== null)`, instead of `(n)`?"
Falsy values are something to be considered especially when handling numbers. All of this shit can be solved with TS.
This was a very well made video, super useful!
Thank you. It was really fun to make.
Totally awesome man! \m/ . Would love to see more of these advanced videos as well and real scenarios and good practices.
Would you also consider doing projects where you can cover different JS frameworks? I would be interested in Svelte a lot.
Some tips. Use the correct decision structures. Use descriptive variable names. Correct casing. Dont be afraid of comments. Optimise your darn images. Use the correct semantic tags (Dont use div and span elements for everything) Indent your code. Use the correct meta tags and ffs sake isolate your functionality.
My key takeaway:
- Avoid using numbers inside your code block. Rather, set up your numbers as variables, and name them in a way to indicate what the number means/does.
- Using this variable name will make your code easier to read and interpret.
and easier to MODIFY! then you won't have to find every instrance of that number right? you just change the variable and boom, done.
The "pro" version you introduced at 6:15 - Would a "pro" actually put the return statements on the same line as the if() clauses? I don't think so. I think what you have there is actually a stage between noob and pro where the developer thinks they're good enough to do away with formatting rules because they can read it just fine. Later they realize that those formatting rules are really for the folks that come after them.
I don't know why, I start code with the "pro" one for the first time. But now, I think my code just like "amature" programer. Just because you are overuse if() clause. And don't know when is the right time to use the "else" statement. If posible, I just write code into one single line.
@@Rhidayah It is almost never necessary to use an else clause. It must be years since I've written one, because they are just so unnecessary, most of the time. And yes, the function here should've been one single line. This is not pro code; it just tries to pass itself as such.
And how could be more cleaner ? 🧐
@@lucas.campora Personally my issue is with #1 the double equals operator. This is simply a no-no; If you're not using the triple equals operator, you're doing it wrong. Guaranteed this would be flagged in a peer review.
#2 Why are you type checking anyway? If the type concerns you, use TypeScript. Otherwise, passing the wrong type is a user error. If you absolutely have to type check, throw an error. Returning nothing is not helpful and causes side-effects.
#3 Removing brackets from your conditional doesn't make it "better." The brackets are there to partition the code, to provide readability.
Here are examples of how I would've done it --> www.paste.org/105678
usually those types of statements are at the top of a function, and are the "guard clauses" he spoke of.
i write my functions to have a "let rv = false" at the top, and modify rv, then return rv at the end of the function. one return statement, essentially. rarely do i use guard clauses, even. i tend to use the nested if statements. if you use a decent editor, you can collapse code blocks, making it far easier to read code, and debug. i find advanced code, although pretty, difficult to read - at least it takes me longer to decypher it. shrugs.
my issue is that i always just try to get things work first and only after im done with the whole thing then i go back and clean up everything . but sometimes i get lazy and even end up with unused code lines lol a total mess .
That’s me except for the fact that I clean up the code after
And then we have these guys:
var accounting = new Accounting();
accounting.add(0);
accounting.print();
accounting.clear();
accounting.add(10);
accounting.print();
accounting.clear();
accounting.add(-5);
accounting.print()
accounting.destroy();
Levi Johansen AHHHHHHHHHHHHHHH that var is scaring me
**Replaces with const**
@@Luka-he5mr *creates post on stackoverflow why he can't override const*
Over-engineered OO code is the hot garbage
He'll I fired one of these this week.
@@cyclonic5206 *OO code is hot garbage
having started programming with c# and typescript and learning from professionals i cant really believe someone does this :D
I am a fan of one-liners, BUT, being a PRO means following best practices. It will make the person taking over your code so much happier.
Thank you for sharing your ideas, I'd love to see more such videos :) I prefer such notation:
return number < 0
? `(${Math.abs(number)})`
: number.toString()
Serious question regarding the guard clause:
Wouldnt it be cleaner to just use e.g. if (!items || .....)
This option will catch null and undefined
legendary mode: ternary with coalescing
lmao
It was nice to mention good code isnt written like that in one go but is the result of several revisions, trial and error, meaning discipline is key to better outputs
I think the difference is that as a beginner many times as he says, we focus on the perfect scenario only and we unconsciously we’d to see lleve logic as clear as possible, when you are a pro, you have a lot of experience and knows how to take advantage of the language itself to do things clear and clean.
using a statically typed language makes everyone an advanced programmer according to your definition
I'm not completely agree.
Return "void", and string still beign a middle/advanced practice. A pro always manage to avoid moving typing, memory lack, and throws.
16:14 Some would argue, including some Google employees, that .reduce() not only is able to reduce your code, but often also its readability
Yes, those discussions are part of the pro mode 😄
I would argue, that not understanding a concept and not understanding someones thinking are two completely different things. What I mean by that, is that if you are having trouble reading a fundamental aspect of the language, then that may be your own fault. If you are having trouble understanding they way somebody used it however, that's probably on them.
I personally prefer reduce() because it encourages early declaration of intentions. Something like this:
const weighedAvg = arr.reduce((acc, cv) => acc + cv.val * cv.weight, 0) / arr.length;
You know instantly what the code is trying to achieve without necessarily needing to read the implementation.
I guess the problem is when people try to fit too many things into one reduce(), then it can surely cause readability issues. Therefore I always (try to) keep my reduce() statements short and sweet, and make sure that it does one thing only.
@@scheimong Why are you all using "reduce" function to actually increase the values. That's oxymoron. This is the main reason why one should never use such things. Especially if there will be another noob who will have to take over the project and will try to read. He will spend countless hours reading up on all these functions just to find out, that this all could have been done in a much easier, cleaner and clearer way.
@@alet3348 reduce, also known as fold in other languages, is a *VERY* common operation on array/list/vector. Any self-respecting person who calls themselves a developer should know this by heart. If not, they should not be taking over any project.
What, just because noobs can't understand something means I have to code stupidly? Get real here.
Great video. The community needs more persons who evangelize clean code
A lot of this is language-specific stuff instead of actual thoughts of a mature mind at programming. You do have a clear point, though. Great video 😃
I'm self taught, so I'm surprised I code like a pro in logic. In variable manipulation, I'm between advanced and pro.
That's amazing bro! You should be proud of yourself!
Sure dude also NOBODY FUCKING CARES
CheeseChef are you mad that this guy is better than you or something?
@@stillbai no one asked and that's why
Mateusz do you get some sort of kick out of being a douchebag?
I've seen people with years of experiences writing code like the "noob programmer" that's a bit scary
so they're noob experienced programmers
Because some experienced people don't bother learning from mistakes
There's ?? operator, you can use it instead || - it's not "triggered" by zero or empty string only null or undefined
Well, an empty string and zero technically means "FALSE" in almost every case.
@@well.8395 In this particular case shown in the video ?? is reasonable replacement for ||
Mikołaj Bogucki Yeah agree, I was talking about in general use case :-)
For number 1, you can do:
if num < 0: return stuff
if num >= 0: return other stuff
no need for null clause...
If you want to write a better code,
learn some old less complex cpu(like 6502 or 8086) with its assembler language (get a book in a library and work it through in like 2 weeks),
then get a book for math and learn logic and the set theorie,
then get books for theoretical knowledge (not language specific) of programming paradigms, data structures, and dependency of programming techniques on data structures,
open wikipedia and read about iso osi 7 layer model.
then get the assembler book again and learn java and c, while you think how you could implement the stuff, you write in java and c, in asm.
take a pick on sql and some sdl(see bonus part below).
make connections between stuff you learned in all previous steps and your programming experience.
what you get:
you will get a lot smarter for everyday life; (ability to make yourself clear and to understand others, solving problems, by that get more attractive, asf)
you will understand, that data structure (and other aspects of the architecture) is/are more important than the programm code, and that the programm code evolves around the data structure you choose and is limited by it in every regard;
you will understand that the readability is the highest priority in any description, if humans have to work with it, and learn all techniques to achieve a better readability;
you will be able to use all existing techniques/paradigms/algos/whatever fitting to the problem you have to solve, mostly regardless of language you have to work with, because you will mostly invent or extend the langauge, to hide the complexity and make the programm easier readable, and by that less buggy (because you and others will be more able to see the errors in the code);
as a bonus, get book about vhdl, get yourself a book about digital technology, get a evaluation board for about 20$ and implement some exercises and own ideas.
what you get:
understanding of parallel execution, its problems and standard solutions;
good starting point to multithreading/multiprocessing;
p.s.: did you realy think, that you can get good, without changing yourself from the ground up?🙄 you cant create structures better than you have inside your brain, you need to feed your brain up first.
p.p.s: java script is hard to learn, if you dont understand what you do and why (not in regard to language, but in regard to desicions concerning the sw-architecture and the code/data structures you choose), because java script can a lot in many ways and you have to know what is more fitting to what and when.
it can even be hard for professionals, who already know the theory and couple other languages.
A function should have one way in and one way out. A great program would know the probability and put the most positive hits at the top. You don't handle the null or undefined value you return an any empty string. If you know that you get more positive numbers than negative ones that check should be done first.
Template literals:
Everyone using it everywhere. It is not readable and not more clear in the first example.
It is readable when you have a longer template string with more than a few variables.
But when you have only one or two variable and want to add a string to either end, it is just way more clear to write that way. In the original code it can be seen instantly why even that thing is there: to add some prefix/suffix, and what is the main logic: Math.abs()
In the template literal version everything is just a pile of symbols. When you don't have syntax highlight, it is definitely harder to read.
Input argument type checks:
JS is a dynamically typed language. Live with it. If you feel the need to check the type as an assertion, you are using the wrong programming language. Assume your code calling that func is correct.
Debugging and QA is a different story. Lets make a development version and a production version, and only include the type assertions and meaningful console.logs in the devel version. In the prod. version those checks are always false, just eating up resources and in the rare case when it is triggered, your app. will break anyway and none of the end users will read the console.
Just my opinion...
Yes, exactly. When the coder thinks he or she is so clever because they made the error not appear where it should because the input was not allowed, that's a problem. Now the error is likely to be thrown in some third party library instead of by the function that is not supposed to process anything but numbers.
Jó napot :D
@@anakinskywalker2314 🌞
I know I'm a noob. Throughout this video all I kept thinking is, "what about ending lines with semi-colon?"
lol. welcome to the new world of javascript.
This is actually an ongoing debate, to use semicolon or not. It's pretty much an even split however, so just choose one and go with it. Just make sure you are consistent.
I personally prefer to use semicolon just to avoid a few edge cases where ASI does weird things. But again, personal opinion.
@@scheimong Ah I didn't know we could leave out the semicolon, I have been doing it like that for a few years because I came from java where it was a must. I'll still stick with the semicolons though.
@@KevinWho it's actually better with sticking with semicolons, because what really happens when you don't put your semicolons is the syntax parser will look through your code and check the lines to see if they end with a semicolon; if your code doesn't have semicolons at the end of the lines, syntax parser will add semicolons to your code by itself before sending it to compiler. So if you put your semicolons, syntax parser won't have to put them by itself and will send your code to the compiler a bit faster. It's not a huge difference thanks to modern processing speed and modern JS engines but still good to know.
Another thing, maybe more important, leaving the semicolons to syntax parser might cause some unexpected bugs. For example you might wanna do something like this:
const myFunction = (a, b) => {
return
// I can put comments here to describe what this function
// will return.
a,
// I will also return b here for some reason
b;
}
if you don't put your semicolon at the end of the whole return statement, syntax parser will look at this code and say "OK, here is a return keyword and the line just ends here so I will put a semicolon here" and will insert a semicolon right after the return keyword and your function will just return there without returning any value.
I'm coming from Java as well, started learning JS a couple months ago. And as a former Java developer your hands should put a semicolon after each statement/expression automatically anyways. So it's actually better sticking with what you've been doing all the time in this case.
I've been bitten several times by bugs caused by missing semicolons that took ages to track down. E.g. When adding code after a long comment block that is a valid continuation of the code before the comments. Not worth the risk to me.
About the variables names... it's the tutorials we watch that teaches us. I would like to see more real life examples in tutorials, to better understand the concepts behind programing and the way to apply them. Like this one, which It is crystal clear about products, shipping, etc. I mean.. look at the w3schools javascript variables page (var x = 5;). Sometimes the noobie practices shows holes in the teaching process. Thank you for another great video.
I have been working in JavaScript for 13 years but seems first time seeing pro version thanks bro
I really dislike having multiple exit points from a function. It leads to return type discrepancies and it’s often easy to miss that an early return statement has been triggered when debugging.
Yes, and he doesn't need to write "number" in the function name when the parameter is called "number". I have fixed this...
const accountingStyle = num => {
if (!isNaN(num)) {
return num < 0 ? `(${Math.abs(num)})` : num.toString()
}
}
Imagine having to if statements, where the second looks like it will always be true when the first is false, but it, in fact, just prevents null or undefined as parameter.
Like, breaking the code and THEN showing, that it didn't account for undefined/null... What is this? A joke?
People should be careful with this video
That proves you must use TypeScript to avoid a lot of errors
If you are a js noob and come from java, then yeah
otherwise it can add a useless layer of complexity
@@guillemgarcia3630 I have to admit I mostly use strongly typed languages but why should type safety be useless?
Guillem Garcia sounds like you dont know how to utilise the type system because it saves a ton of time and adds a ton of reusability
7:07 What about NaN and an alpha string being passed? I would do a two part check:
First: I would Check for a falsy value (false, 0, -0, 0n, "", null, undefined, and NaN) by multiply the variable by 1 If it is a number, it just returns the number and will return NaN for most everything else.
- Note1: Using a bam ( ! ) in front of a falsy value turns it to true
- Note2: A number as a string when multiplied by 1 will return the number value.
- Note3: `null * 1 === 0` which is a falsy value, but we'll eliminate that in the next step
Second: Check that the variable is not equal to 0 (since 0 is a falsy value). If both conditions are met, then it will just return the guard clause.
Lastly: If we made it this far, then it is a number. I would then use a ternary operator to format the number to a string.
```
function numberToAccountingString(number) {
if ( !(number * 1) && number !== 0 ) return;
return number < 0 ? `(${Math.abs(number)})` : number.toString();
}
console.log(numberToAccountingString(undefined));
console.log(numberToAccountingString(null));
console.log(numberToAccountingString(NaN));
console.log(numberToAccountingString('A'));
console.log(numberToAccountingString('-9'));
console.log(numberToAccountingString(0));
console.log(numberToAccountingString(10));
console.log(numberToAccountingString(-5));
```
possible alternative to first one...
function numberToAccountingString(number) {
if (number == null) return;
return number < 0 ? `(${Math.abs(number)})` : number.toString();
}
It's still fairly easy to read with the ternary approach, though it could be a little confusing to the noob level so there's an argument for avoiding it. On the other hand, it's good to learn since they'll almost certainly come across it at some point and it's a very useful and concise way to return a value or assign one to a variable in cases where you're only choosing between two options (after that it gets confusing very quickly)