First 250 days of software dev - Part 6

18 min read

Day 51

I don't feel that I have any difficulty with CSS and HTML anymore. It takes a while to figure out what to use, how to use it and where to use it because there are so many ideas about how to design and so many possibilities of what to do. Of course it's more challenging because we only use coding where Javascript is used. I recently heard an Iranian saying something like "a mystery is simple when its solved". And indeed it was. It may seem easy once solved, but it can be difficult before that. In Javascript or any other language, it requires problem solving skills to get to the desired solution, but once solved, it is easy.

Today HTML and CSS designs are completely finished for the given site design. I used small icon images instead of font awesome, I fixed those parts. I fixed the Product Cards a little and edited the effects on them. I made the sorting part and the picture part right next to the carousels. Here are the missing or problematic parts: I didn't delete and edit unnecessary details in my code in some places. I need to look at them again. The photos in the second carousel are very light after the first loop in the visible part. And when I click somewhere other than the button on the sort button, the content disappears. However, it should disappear when you click the button a second time. I will fix that if I get the chance, but I think the overall desired design structure is complete.

Day 52

Today I researched and tried to learn the concept of SOLID. We have 5 principles for a class-object structure to be solid. I found a nice example and tried to understand this structure. First of all, this was the source I found the most understandable as a reference: Solid Principles- The first five principles of object oriented design

Suppose our goal is to find the area of some shape. Normally it is possible to do this without using any principles, but since our topic is to use the SOLID structure, we will design our code accordingly. Let's imagine that one of our shapes is a square and the other is a circle. The things we need to know to find their areas are the length of the side and the radius of the circle, separately for both. So we can create two classes for these. And we can create a separate class to calculate the areas and produce the output in that class, right? But there is a problem. If we want our output to be in JSON format, we will have to do it in the class we are calculating in because that class provides our output. However, this is against the first of the SOLID principles. Because the first principle says that "a class should serve only one purpose or have only one task in order to do a job". Therefore, if we make another class, different from the class where the calculations are done, where the output is produced either in JSON format or in HTML format, we fulfill the first principle.

As a result, shapes are entered. Then the areas are calculated, summed and output. All operations are performed with different classes. Each class or module has a different task in this way.

Our second principle is the "Open-Closed Principle". This principle states that "a class can be extended, but the class itself cannot be changed". Let's continue with our previous example. Let's say the user enters different shapes, i.e. data that requires different calculations, into the class for area calculations. What we normally do here is to make changes in that class by opening new if/else statements. But the second principle says, don't create every new change in this class. Don't change the content of the class. And do these mathematical operations as methods in the classes where the shapes are located. After doing this, we have the following problem. How can we know the existence of the method that will come from the shape class we will use in the class we are calculating? Here we need to use the concept of interface. We say "this shape class implements this interface" by means of an interface to the method of the field calculation that we will do in the class where the shapes are located. In this way we can check if our shape classes are instances of our interface and if it does not implement it, we can make that interface give an error message.

Our third principle is the "Liskov Substitution Principle". It says that "every subclass or derived class must be substitutable for its parent class". A quick summary and then let's continue:

What have we done so far? We wanted to find the area of shapes. We created a separate class for each shape. In the classes, the shapes had properties and methods. Properties to calculate the area and functions with mathematical equations to calculate the areas. We calculated the areas in a different class with these equations and since we cannot normally query whether there is such a method in the class that the user entered, we used an interface. We said that each shape should implement that interface, that is, implement/use it. And then produce our outputs in a different class. In this way, we have achieved the first two principles.

Let's say we are going to calculate the volume now. And for that, let's say we extend the class that we use for area calculation. After all, we know that area is also required for volume calculation. But after doing this calculation, we may encounter an error like "error: array to string conversion" in our output. Here we can get rid of this error message by making a change in the last class we created and get our output as an integer value instead of an array. This change we made can be given as an example of Liskov's change principle (Obviously they have given it, I'm saying it right now. Because I haven't done any research to confirm this from different sources yet).

The fourth principle is the "Interface Segregation Principle". This principle states that "the client should not be exposed to methods that it will not use or implement interfaces that it has nothing to do with and does not use". The interface we created before only had area calculation for 2D shapes. Let's say we will calculate the volume for 3D objects/shapes. But shapes like squares don't have volume, so we will have to explicitly impose this interface on the classes of 2D shapes. This is where the principle of interface separation comes into play. So let's create a separate interface to calculate the volume of 3D objects. In this way, while trying to calculate both volume and area in a single interface, let's not impose the same interface on shapes that have no area. Because the volume calculation method in that interface is not available for them. There is one more improvement on top of this. The process of combining or managing two separate interfaces in a single interface is applied. So we can think of it as using a single API. For example, if there is a calculate function in this interface, we can manage both the area calculation and the volume calculation through this function.

The fifth principle is the "Dependency Inversion Principle". This principle says that "the 'entities' in our code, such as classes and modules, must be abstracted as opposed to concretized." This means the following: High level modules do not have to depend on low level modules and you should abstract them from each other. Here's why:

Let's have a class called password reminder, and let this class connect to the database through a different class. The class that connects to the database is called low level and the class for remembering passwords is called high level. The reason why they are named like this: The class where execution is done with a tool is called high level, and the tool that exists for execution is called low level. Let's continue. Let's imagine that our database is a MYSQL server and the connection is made to MySQL. If one day we want to change the database engine, we will also have to change the password recall class. This would be against the "open-closed" structure. The idea is that the high level class should be as abstracted as possible, with as little dependency on the low level as possible. In our example, the low level server connecting to mysql or another database engine should not affect the high level class. Again, the interface is used for this. The class that we will create the MySQL connection implements the interface. This way we can use it in the high level class. In this way, high level and low level classes are abstracted from each other.

If there is time, I will try to investigate and understand much better.

Note

In the report I wrote yesterday, I tried to explain about the SOLID structure with a detailed example. Although I think it is sufficient, I will attempt an illustration of my own after a summary. The analogy may fail, but I thought it would be fun to think about it. First, let's summarize SOLID:

Although SOLID structure is used for OOP, it can also be adapted to functional programming. Yes, we will consider this structure for our object-class structures, but like the REST API concept, it is useful to consider it as a set of ideas that we should pay attention to when writing our code, no matter how we call it "belief, philosophy, conceptual design, fictional design models created for optimized results, design pattern, architecture".

The first principle says that each module should have one job and be good at it. Modules should have one job, not different goals or different roles. Like "Make the best thing you can". For example, if Demet Akalın's job is to sing, it would be absurd to ask this object (class or module or entity in general), i.e. Demet Akalın, to represent Turkey in the Tokyo Olympics and compete in the 200 meters breaststroke. So her job should be one. She should do it best.

The second principle says that our modules should not be modified all the time, but they should be extensible. One reason for this is that we don't depend on the author of the class. Or from another point of view, if we have a code and we open it to a 3rd party user, we want the user not to make any changes to our class. We want the user to access only the areas we want, to play with it as much as we allow, to extend things. Here again, we can bring Demet Akalın into play. Now we said that this woman, this object, this being should only sing. The people who should go swimming in the Olympics are the competent athletes. Now we say that Demet Akalın should do other things. But now let's think about how we can connect this with coding. Normally, in the open-closed principle, let's consider other classes other than the Demet Akalın class. For example, we can give our swimmer as an example. They both have different methods and occupations. Let's say I put both of them in a restaurant. Both of them will eat. And in their properties (by default) they also have the ability to eat and drink something. The eating speed, the way these people eat, the way they talk while eating, their attitude to the waiter are all separate methods. And we can create a different class where these methods are collected. So this can be a class with behaviors. So let the name of this class be the book of deeds. Here, in everyone's book of deeds, operations are performed and separate results are obtained, and all of them are collected and saved somewhere. Now each operation should be in different classes according to the first principle so that it fits SOLID. Where we do our mathematical operations in this book of deeds, we only need to return the data and return the outputs numerically or by keeping them in an array. But the calculation methods used for the calculations of people like Demet Akalın, Snopp Dogg, Ricky Martin, Jesus Christ, Buğra, Ömer Hayyam are different. Yes, they are all called calculations, but they are all calculated differently. Therefore, in this class, we only use the methods from the related classes and do our calculation. The divine formulas evaluating Demet Akalın are different, the swimmer's are different. Well, is there a problem? Now we know that unborn babies go directly to heaven, which can be given as an example. So we can say they don't have a method. They have the right of direct passage without processing. But in this calculation class, how do we include unborn babies, martyrs or "good people" in many other religions in the calculation. If they don't have methods and we try to calculate them, we may get a fatal error. That's why we say that there are some same interfaces that every human uses. They all eat, they all sleep, they all are born and die, they all lie or cry (at least once). We can collect all these in one interface. But the methods in this interface must be suitable for all of them. A person who does not use a method in that interface will directly terminate the system with a fatal error. As a result, even if I go on too long, I should come to this point: it is much better for us to use an interface and separate this process instead of trying to define the implementation of each method in the class where the calculations are made differently, changing it many times and causing the system to give errors that can have bad consequences.

Liskov summarizes in his third principle: If something behaves in the same way as something else, you should be able to change it. In object class structure, more so in inheritance logic, we look at it like this: A child takes a property of the parent. And it can change it on its own. For example, Demet Akalın's father may be a very bad alcoholic, but Demet Akalın may only drink a glass of whiskey every night. She doesn't have to maintain the whole genetic or learned/behavioral heritage. But she always has to carry its traces. Even if Demet Akalın wants to go and live in foreign countries one day and thinks that she would be very happy, she should know that she cannot escape from herself. From her past, from what she was taught. But of course she can make small changes.

The fourth principle boils down to, give the client what it wants. So don't give it an interface it won't use or force it to do unnecessary things. Let's go back to Demet Akalın. If Demet Akalın is singing at a concert, she should not talk about the problems she told her psychologist about at the concert. If she is very emotional or troubled, she can write a song about it and convey her feelings to the client, that is, to her fans, but she should not give them what they do not want.

The fifth principle is that you should use abstraction to link high level and low level entities. The high level entity (module, class, object, whatever you call it) uses the low level entities to do its operations. And we need to abstract the low level entity a bit from the high level. In this way, we don't need to make a change in our high level entity in case of a change in the low level. Of course, interface can also be used for this structure. At least in the examples I saw, it was used in that way to abstract it. Let's say Demet Akalın has a boyfriend. And she is very dependent on him, she is fond of him, she can't live without him and she is still secretly listening to "Join me in death". This is very wrong. So you are Demet Akalın. If he breaks up with you, you will be very sad and you will have to change yourself to get him back. But our principle says, "Demet, if you want to be valued in a relationship, don't give too much value." Think of him as no different from other men. Think like one comes and one goes and be immoral (according to who and according to what). In this way, you won't wear out no matter who you date. You'll get used to it quickly and accept it.".

Choosing Demet Akalın as an entity was never in my mind and probably a very bad idea, but I still wanted to try it. Normally, I wanted to take galaxies as an object/class and think of our code as the universe, but I don't know where Demet Akalın came from.

The sample was tried to be formed more in connection with what I learned from the website I looked at yesterday.

Day 53

Today I tried to get a good grasp of SOLID and OOP principles. I tried to illustrate the SOLID architecture myself. Since I tried to explain what I understood about SOLID both yesterday and during the day and through examples, this report is a bit more about the different things that stayed in my mind. Why do we use all this in a nutshell? We are actually breaking down our code. We create a different object structure for each task. When we want to make changes to a certain part of our code in the later stages, we use the SOLID structure to prevent it from damaging or affecting the entire system and to make the correction process in a much better way. This of course applies to all articles of SOLID. Concepts such as clean code and agile work together with this architectural philosophy. When we use the SOLID structure, we inevitably have a much cleaner code structure.

The subsequent modifications to this code can be thought of as "maintenance and extending". If we make a change in the database engine, a high level module that will be affected by this change using the interface can easily adapt to our new system using abstraction, for example.

Well, we tried to understand the SOLID architecture and I think we understood as much as we could understand by reading without practicing. When I was working on SOLID today, I researched some OOP concepts because I needed to understand why we should realize a design on OOP. It was actually simple. The best result that OOP provides is related to the Encapsulation principle in its structure. When an error occurs somewhere in our code, it would be much more difficult to find where the error is if we were not using OOP, but if there is a problem with a particular object, we can say that it must be a problem with the class it is in. If my car object is broken, I can say that there is a problem with my car class and I can resolve the source of the problem. In terms of code reusability, we can add many different vehicles and their properties as child classes in our Car class. We can create a change in all of them with a change in the base class, or we can create separate methods for each car object and make them special. Moreover, with a single "drive" function, we can specify a method for all car objects (that is, as instances that will be created from child classes). Or we can create it as an interface and say that every class implements this interface. We can say that the best benefit of the object/class structure is that it gives us the ability to solve problems much more efficiently (compared to architectures like top-down language-C, functional style language-Haskell or ML). If we summarize its benefits in one sentence, we can say that it uses modular structure to solve problems in an easy way (like a jigsaw puzzle, each piece has its own place in this modular structure), provides code reusability with inheritance, provides flexibility with polymorphism, and of course provides the ability to solve problems efficiently.

Day 54

First of all, I fell asleep when I got home tonight, I was supposed to work afterwards. Let's talk about what I did yesterday. It was good while reading SOLID, I thought I understood it for the most part, but when it came to practice, I couldn't do it the way I wanted. At least I say I tried. Of course, it seemed easy when a mystery was solved again. In fact, if I created the inheritance structure, my code would almost be there, but it never occurred to me to think of creating ineritance in that way. Because if there is a function in the parent and the child doesn't change it and use it, I thought what is the need for this relation, but I realized that it can both change it and use it as it is in the parent.

Day 55

Today I learned the concept of Depenedency Injection clearly. It is a design pattern, a technique. As far as I understand, there is no clear rule in design patterns. They can be created differently for each situation. For example, to use Dependency Injection, we take our dependent class as a parameter in the contructor or seeter methods while getting an object from a different class. I don't seem to have a problem with this for now.

I've always had problems in similar places with XML-related operations, but I still feel inadequate in solving problems. I mean, I don't understand why I couldn't do something that seemed simple in such a short time when I had so many more problems before. I'm probably getting the same errors and repeating the same operations. So I'm repeating myself. Towards the end of the day, I completed my mistakes a little bit, and at the end of the day I found exactly where the error was coming from. But that's for tomorrow. asXML() returns a string to us, yes, but it returns it in XML format. However, we don't need to write the start tags again. However, I was writing it too. Tomorrow morning I will see how I can convert the object to string without using asXML() (I will also see if there is another option in XML related functions).

Although I am happy that it contributes to my development because I am curious about the cause-effect relationship in some subjects and I am curious about many things in some subjects, the fact that I still need a long time to fix the error I get in the code even though it has been 2 months, or the possibility of needing a long time (where I feel it is simple) makes me sad. But on the other hand, it makes me even more curious and ambitious. Everything is very complicated in this world of our thoughts. Anyway, let's not go into these issues. Keeping my faith that I will be the way I want to be.

Day 56

The topics I learned and saw in practice today were generally related to OOP. I learned new things such as the use of Trait, the need to keep the classes in different namespaces if they have the same name or they will affect each other. In the morning I completed the task we did yesterday. In the afternoon I didn't fully understand the task and tried to do it as I understood it. I generally used functions everywhere because there were no strict rules. Today was generally full of research. I reviewed examples of SOLID principles from different sources. It was like a repetition.

Day 57

I forgot the report yesterday, so I'm sending it today. Yesterday I just studied a nice document about clean code. I tried to learn every detail. While reading and studying, I could understand the reason for almost everything, I could understand the difference between a really well written code and a badly written code. This job (software) is like learning to read and write, as they say. Not every literate person is a good writer. They may not be able to construct sentences well or may not even follow the rules of spelling. Yes, I think I have learned to read and write a little bit with both PHP and JavaScript. But I really want to write sentences, long articles, stories, novels. I definitely believe that I can do this too. I will just need to practice a lot. I didn't have many problems on Saturday. That's why I can't specify anything like that. I discovered something called competitive programming, and I found some great resources in that respect. In my free time, I will look at those topics to bring my coding skills, my thinking, to the level where I can best get along with the machine. Since that part is not very relevant to the tasks assigned to us at work, I will look at it outside of working hours.

Day 58

Today, the task was completely passed. The design was almost identical. W3Schools He helped me with the JavaScript part. It's not finished yet, because even though it seemed very easy at the beginning, the details were a bit tricky. In general, the desired structure is formed, but towards the end of the day, there were some undesirable results because I could not fully create some parts of the JavaScript Instead of making the same mistake over and over again (and since I haven't come up with a different solution yet), I thought it would be more useful to look again tomorrow morning. And I wanted to rest. That's all for today.

Day 59

Today I may have relived the discovery of manual labor. I really learned what not to do today. I could do what I wanted to do much more easily without mixing javascript into html. I could. Actually, we had looked at those topics before, but I used the onclick structure (the structure called inline event handler) thinking that it would work for me. It will be a topic I will avoid from now on. Other than that, I think the design is there. As I said, the day was spent with a little too much detail. But it was still fun, just seeing the result was enough to be satisfied.

Day 60

I really enjoyed the work I did today. I don't know how much I did right, how much better I could have done, but I created most of what I needed to do using foreachs. In the morning, I completed the deficiencies in the javasctip code. I realized that we wrote long code in 2-3 days (thanks to HTML and CSS, of course). When I first saw such long codes on your computer, I was amazed, I wondered how you could write such long codes and still read them. Now, at least with HTML and CSS, almost all of it can be written and readable (at least the ones we made).