.Net Core 3.1 is in LTS mode (ends support in Dec 2022) where as .Net Core 5 is coming to general availability in November. However, there will never be a LTS version of .Net Core 5. They have a new release life. Every odd release just gets a general availability release, rather than an LTS release.
Pros of .Net Core 5
Unification of runtimes (mono, …)
Language interoperability (swift, java, …)
Not a lot of breaking changes
Cons of .Net Core 5
No LTS release
Fundamental packages like Xunit, Swashbuckler, Serilog, and etc, have not transitioned over yet.
Still a lot of un knowns in terms of bugs, and stability.
No Default Base Image provided my Microsoft yet, everything remains experimental
Recommendation: I think everyone that can should switch to .Net 6 some time after it comes out. Which is in Nov 2021, this would gave you a whole year to migrate to 6, while 3.1 is still being supported.
Person A: Does this sound like a impossible task ?
Person B: No not really
Person A: Does it have limits ?
Person B: Yes it does, but you see dramatic difference in speed regardless.
Person A: This sounds like a scam. Is it a scam ? How much will this cost ?
Person B: No its not a scam, and its free.
Person A: So what is it ?
Person B: You just have to master runtime complexity 😊
Person A: What !? …. 😒
Person B: Yeah I know, I thought that too. But it works 😁
Person A: Yeahhhh well I never really understood that sort of stuff. I just implement businesses logic for living. I don’t know much about computer science. And I am not gonna waste my time on this. If I need speed, I’ll just deploy it on a bigger server 😒
Person A: Come on … Its easy. You don’t have to understand the computer science. You just need to understand graphs, and recognize patterns.
Person B: What … really ?
Person A: Yeah you just got to use the graph below. Or just Google something like “Runtime Complexity Graph” . All you got to know that things in Red are the danger zone, things in Orange are the “meh” zone, and things in the Yellowish Green zone are okay.
Person B: Wait what does this have to do with programming, and what about those function things ?
Person A: Oh yeah right. So those function things represent how your program can run. The “n” represents the input to your function, like an array objects, or numbers. In the danger zone, if you add just one more element, your time to completion more then doubles. Whereas in the Yellowish Green zone adding another element doesn’t do much of anything.
Person B: 😡 This still doesn’t help me.
Person A: Okay okay okay, how about I make cheat sheet for you ? Your little guide to spotting when your in the danger zone ?
Person B: Show me.
No matter how many elements/ inputs you give your function. Its runtime will always stay the same.
When doubling the number of input/elements into your function does not double the runtime. Also this is the runtime of most search algorithms.
When doubling the number of inputs/elements doubles your runtime. This is afor loop spanning from zero to the end of the input.
n + m
Two for loops one after the other, going over two different collections.
A worse version of Log(n). This is the runtime of most sorting algorithms.
Every element in an array is compared with every other element in the input. This is the classic double “for loop” over a single array. For every nested “for loop” you add one more to the exponent. So if you had 5 nested for loops, you would have n5 .
n * m
Two nested for loops, but going over two different collections.
A single extra input doubles runtime. You never want this, ever.
Simply put they allow you to easily write asynchronous programs. Without you ever having to reorganize your code. Which can lead to massive performances increases.
The “async” & “Await” markers are keywords that mark the beginning and end of asynchronous code. Where “async” is put right before a function name, and “await” is put right before calling the function. However if a method is async then it needs to return a Task object.
Now you can use different parts of Task Asynchronous Programming (TAP) model. Such as start a bunch of tasks, and wait for them to finish. Or even call a new task on the completion of another task. All while your main application is running.
How is this possible ? Does it start a bunch of new threads ? Yes and No. If you start a bunch of tasks and wait for them to complete then yes. Where as if you await a heavy task it cuts up everything happening in our program the second it hits an await keyword. And starts executing everything based on the time available on the current thread. So you aren’t able to tell that your programming is waiting around for something.
What is the root object in the base class library ?
For Java and C# that would be “Object”.
What methods does “Object” have ?
Equals – Supports comparisons between two objects
Finalize – Used to perform cleanup operations on un-managed resources being used by the object. Before the object is destroyed.
GetHashCode – Generates a number based on the value of an object. Used to supported hash tables.
ToString – Create a human readable piece of text that describes the object.
Is “String” mutable ?
For C# & Java: Strings are always IMMUTABLE
What is Boxing and Un Boxing ?
Process of converting a value type to the type of object or any interface type implemented by this value type. Like storing int in a object which would be “Boxing” (implicit aka do it with out thinking about it). And then taking that object, and “Un-Boxing” it explicitly. Example of this would be something like “int i = (int)x” where x is type of object. Why would you ever want to do this ? Well that’s cause value types get stored in the stack, whereas reference types get stored in the heap. So if your running into performance problems by having a lot of value types floating around in the stack. You can just dump them into the heap, by boxing them.
This principle is about making sure you never have to rewrite your core logic. Meaning that if your class or piece of code has a dependency on something else. It should never access it directly. Instead it should go through some intermediary that abstracts the functionality away.
For example if your application talked to a database, you would’t want to be writing SQL statements directly into your code. Or if you were using a ORM (Object Relational Mapper) you would want queries every where. Especially if at some point you decide to move to another database type or ORM. To fix this problem you would need to create a wrapper around it, abstracting complex queries into simple common method calls. Like “Update User profile”, or “Set User Password”.
This way if you ever had to make any changes to the logic of how you accessed the database. You could do it with out changing any of your core application logic. Since your core application wouldn’t directly rely on how the method is implemented. This can also be thought of as always coding to a interface, rather then a direct implementation.
This is all about separating your interfaces and making them smaller. Since we don’t want to end up having mega interfaces with a tons of properties, and methods, that may or may not be used by classes that implement them. If you don’t follow this principle you are probably gonna end up with a hair ball of OOP design. That will lead to harder refactors further down the line. For example lets say you have a “Entity” interface, that has properties “attackDamage”, “health”, and also has methods “move”, “attack”, and “takeDamage”. Now lets say classes “Player”, “Enemy” , “Chair”, and “MagicChest” implement it. Does this make sense ? Should the “Chair” class need to implement the “attack” method ? Most likely no it should not, but then it does need the “name” property. So we can factor out the common piece among the classes that implement “Entity”. So instead of just having the “Entity” interface. We can have a “BaseEntity”, “ActorEntity” and “StaticObject” interface. This way we won’t have any unnecessary implementations for any of the classes that implement the interfaces.
This is all about using Object Oriented Programming to its fullest. So what the Wikipedia article says is that: “If S is a sub-type of T then objects of type T maybe replaced with type S”. So what does that mean ?
Well it means that when you create your class hierarchy, and you create your base methods, you have to think about the broader implications. For example if your root parent class was “Bird” it would have methods like “Fly” , “Eat” and “Walk”. And then you would classes like “Hawk” , “Blue Jay”, “Robin”, “Penguin”, and “Ostrich”. Now we should be able to put any of these child classes in place of the parent class, and use them. Can you see the problem ?
The problem is that Penguins and Ostriches can’t fly, which violates the “Liskov Substitution Principle”. You can get around this by instead having the two different children inherit from the “Bird” class: “FlyingBird” and “NonFlyingBird”.
This is all about being “open for extension but closed for modification”. Your code should be extendable. To the point where you don’t need to constantly change anything about it. This can come in many forms; for example instead of overloading a class with a number of different methods. Such as the “Person” class needing a method like “write a book” and also like “fight a fire”, or even “cook a five star meal”. Instead we could separate these into classes that all inherit from the “person” class. Which would allow use to write code to extend existing functionality. Without having us go in and make changes to the core logic of the person class.
Another example of this is when we are using a large “if – else” or “switch” statement. And we do things based on what input we get passed in. Instead of having this large “if -statement” we can refactor the logic back into the input we are are being passed in. If we had gotten a generic account class as an input. And we had to calculate their net-worth based on their account type. We should create classes for each account type, and store the calculation logic in them, rather then in the “if else” clauses.
In this series I am going to be going through each of the principles. Go about explaining them in as simple of a manner as possible.
S = Single Responsibility Principle
Anything inside your code that is parts (class, modules, etc) should only ever have one reason to change. For example if you had a Person class, then everything in that class should only do things related to person. A person class should have methods like “eat”, “sleep”, “play”, and etc. However a person should never need to have a “log” method, cause it has nothing to do with a person.
How does one even know they have duplicates ? or to what extent ? You can use this SQL statement right here:
The key here is that we are using the “group by” clause to aggregate a bunch of data. And after that we are using the “having” filter clause, to add the filter “count(title) > 1” which is just saying “title found more then once”
Now that we have made sure that we actually do have duplicates, lets get down to deleting them.
The key here is that we are using aliases rather than joins or something else. So you can think of “dupes” and “fulltable” as variables. First we set the values of these variables, then we use the where clause to filter the things we are looking for. At this point if we just ran the query, we would just end up deleting our whole table. Therefor we have a final “and” where we specify that we only want to select the id that greater out of the two, rows that were in “dupes” and “fulltable”.