© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2023
V. SarcarSimple and Efficient Programming with C# https://doi.org/10.1007/978-1-4842-8737-8_14

14. More Tips

Vaskaran Sarcar1  
(1)
Kolkata, West Bengal, India
 

This is the last chapter of the book. Earlier I told you that sometimes it’s OK to bend some well-accepted rules for your application if it performs well, but when you keep coding and developing applications, you’ll find that the experts’ suggestions have great value. If you follow their advice, you’ll understand that a simple choice can have a big impact in the long run. This chapter discusses some of these topics in brief.

Learn Design Patterns

Let’s take a tour with a time machine to the early days of software development to understand the following common problem in those days:

There is no standard to instruct developers on how to design an application. We are unique creatures. So, each corporate team follows its own style of coding. A new member joins such a team. Understanding the current architecture is a gigantic task for this member. So, he is continually seeking help from the senior members of the team and requesting that they explain the existing architecture. He keeps asking them: why do you follow this particular design in this code segment? The experienced developer answers his question. This experienced developer also explains why the common alternatives were not considered in a previous team meeting. She also suggests that the new member reuse the existing construct to reduce future development efforts.

What is the problem with this scenario? Actually, there is no problem; this is standard practice, even in today’s world. But think about it from a different perspective. Let’s say the experienced developer tells the new member, “We follow the Facade pattern for this code segment” or “We follow the Singleton pattern in that code segment.” If the new team member already knows about these patterns of coding, how much easier will that make it? Since he knows these styles of coding, following a known pattern, it’s easy for him to contribute to the team quickly. I hope this scenario gives you some idea about the importance of knowing some standard patterns.

Software design patterns address this kind of issue and provide a common platform for all developers. You can think of them as the recorded experience of experts in the field. These patterns were originally intended to be applied in object-oriented designs with the intention of reuse.

Brief History of Design Patterns

The original idea of design patterns came from building architect Christopher Alexander, a professor at Berkeley. He faced many problems that were similar in nature. So, he tackled those issues with similar kinds of solutions.

Each pattern describes a problem, which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.

Christopher Alexander

His original ideas were for a building’s construction within a well-planned town. Later these concepts entered the software engineering community. This community started believing that though these patterns were described for buildings and towns, the same concepts could be applied in object-oriented design. So, they substituted the original concepts of walls and doors with objects and interfaces. The idea was the same: you can apply a known solution to a common problem.

These concepts started gaining popularity through leading-edge software developers like Ward Cunningham and Kent Beck. In 1994, the idea of design patterns entered the mainstream of object-oriented software development through an industry conference called Pattern Languages of Program Design (PLoP) on design patterns. It was hosted by the Hillside Group, and Jim Coplien’s paper “A Development Process Generative Pattern Language” is a famous one in this context.

In addition, in 1994, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides published the book Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). In this book, they introduced 23 design patterns for software development. These authors became known as the Gang of Four. We often refer to them as the GoF. You can easily guess that the patterns they talked about were developed by the common experiences of software developers over a period of time.

It is important to note that the GoF discussed the design patterns in the context of C++. C# 1.0 was released in 2002, and then it went through various changes. It grew rapidly and secured its rank as the world’s top programming languages within a short period, and in today’s market, it is always in high demand. At the time of this writing, C# 11.0 is about to be released. Since the concepts of design patterns are universal, they are always valuable. So, exercising the fundamental design patterns makes you a better programmer and helps you to make a better version of your program.

Here are some important points to remember:
  • A design pattern describes a general reusable solution to software design problems. The basic idea is that while developing software, you can solve similar kinds of problems with similar kinds of solutions. The proposed solutions were tested over a long period.

  • Patterns are actually templates. They suggest to you how to solve a problem. A good understanding of patterns can help you to implement the best possible design much faster.

  • From an OOP perspective, these patterns are descriptions of how to create objects and classes and customize them to solve a general design problem in a particular context.

Each of the 23 GoF design patterns focuses on a particular object-oriented design. Each of them can describe the consequences and trade-offs of use. The GoF categorized these 23 patterns based on their purposes, as shown here:
  • Creational Patterns:

  • These patterns abstract the instantiation process. You make the systems independent of how the objects are composed, created, and represented. Here you ask: “Where should I place the new keyword in my application?” This decision can help you determine the degree of coupling of your classes. The following five patterns belong to this category:
    • Singleton pattern

    • Prototype pattern

    • Factory Method pattern

    • Builder pattern

    • Abstract Factory pattern

  • Structural Patterns:

  • Using these patterns, you combine the classes and objects to form a relatively large structure. Normally you use inheritance or composition to group different interfaces or implementations. In Chapter 7, you saw that preferring object composition over inheritance (and vice versa) can affect the flexibility of your software. The following seven patterns fall into this category:
    • Proxy pattern

    • Flyweight pattern

    • Composite pattern

    • Bridge pattern

    • Facade pattern

    • Decorator pattern

    • Adapter pattern

  • Behavioral Patterns:

  • These patterns focus on algorithms and the assignment of responsibilities among objects. Here you concentrate on the object’s communication and its interconnection. The following 11 patterns fall into this category:
    • Observer pattern

    • Strategy pattern

    • Template Method pattern

    • Command pattern

    • Iterator pattern

    • Memento pattern

    • State pattern

    • Mediator pattern

    • Chain of Responsibility pattern

    • Visitor pattern

    • Interpreter pattern

The Good News

I have some good news for you. You have already implemented some of these patterns! Not only that, you actually learned at least one pattern from each category. Part III of this book helps you understand them.
  • In Chapter 6, you learned about the Factory Method pattern. In fact, you also learned the simple Factory pattern, which is the foundation of this pattern.

  • In Chapter 7, you learned about the Decorator pattern.

  • In Chapter 8, you learned about the Template Method pattern.

  • In Chapter 9, you learned about the Facade pattern.

In addition
  • Chapter 2 in Part I created a foundation for the Strategy pattern.

  • Chapter 11 in Part IV discussed the non-GoF patterns called the Null Object pattern and the Special Case pattern.

These patterns are common in C# applications. Congratulations! You are on the right path.

Q&A Session

14.1 Can I combine two or more patterns in an application?

Answer:

Yes, in real-world scenarios, this type of activity is common.

14.2 Do these patterns depend on a particular programming language?

Answer:

Programming languages can play an important role. But the basic ideas are the same. Patterns are just like templates, and they give you some idea in advance about how to solve a problem. Instead of any object-oriented programming language, suppose you have chosen some other language like C. In that case, if you follow object-oriented programming, you need to implement the core object-oriented principles such as inheritance, polymorphism, encapsulation, abstraction, and so on. So, the choice of a particular language is important, because it may have some specialized features that can make your programming life easier.

14.3 Should I consider the common data structures like arrays and linked lists also as different design patterns?

Answer:

The GoF clearly excludes those saying that they are not complex, domain-specific designs for an entire application or subsystem. They can be encoded in classes and reused as is. So, they are not design patterns in this context.

14.4 If no particular pattern is 100 percent suitable for my problem, how should I proceed?

Answer:

An infinite number of problems cannot be solved with a finite number of patterns for sure. But if you know these common patterns and their trade-offs, you can pick a close match. Lastly, no one prevents you from using a pattern for your own problem. But you have to tackle the risk, and you need to think about your return on investment.

Remember that the world is always changing, and new patterns keep evolving. To understand the necessity of a new pattern, you may also need to understand why an old (or existing) pattern is not enough to fulfill the requirement. These patterns attempt to make a solid foundation for you. These concepts can help you move smoothly in your professional life.

Avoid Anti-patterns

The design patterns can help you make better applications. They have been developed and tested over time. So, in general, using them is considered a good practice. But often people misuse them and cause more trouble. The anti-patterns point to those bad practices and warn you. Here is a common example: a developer implements a quick fix without analyzing the potential pitfalls or skips the test cases to meet a delivery schedule. Now think about the company’s reputation if a customer finds a big bug due to that quick fix.

Anti-patterns alert you in similar situations and help you to take precautionary measures. They remind you of the proverb “Prevention is better than the cure.”

POINTS TO REMEMBER

Anti-patterns not only warn about common mistakes but also suggest better solutions. Some of these solutions may not be attractive at the beginning, but in the long run, they save your time, effort, and reputation.

Brief History of Anti-patterns

Undoubtedly, the ideas of design patterns helped (and are still helping) millions of programmers. Gradually people started noticing the negative impacts due to the tendency to overuse these patterns. For example, say many developers wanted to show their expertise without the true evaluation or consequences of these patterns in their specific domains. As an obvious side effect, patterns were implanted in the wrong context, produced low-quality software, and ultimately caused big penalties to them or their organizations.

So, the software industry needed to focus on the negative consequences of similar kinds of mistakes, and eventually, the idea of anti-patterns evolved. Many experts started contributing to this field, but the first well-formed model came through Michael Akroyd’s presentation entitled “AntiPatterns: Vaccinations against Object Misuse.” It was the antithesis of the GoF’s design patterns. Wikipedia says the term was coined in 1995 by computer programmer Andrew Koenig. Martin Fowler, a well-known author and speaker in the software industry, also believes this. The term anti-pattern became popular with the book Anti Patterns: Refactoring Software, Architectures, and Projects in Crisis (Robert Ipsen/Wiley). This book says the following:

“Because AntiPatterns have had so many contributors, it would be unfair to assign the original idea for AntiPatterns to a single source. Rather, AntiPatterns are a natural step in complementing the work of the design pattern movement and extending the design pattern model.”

Examples of Anti-patterns

These are some examples of the anti-patterns and the concepts/mindsets behind them:
  • Overuse of Patterns: Developers may try to use patterns at any cost, regardless of whether they are appropriate.

  • God Class: A big object controls almost everything with many unrelated methods.

  • Not Invented Here: I am a big company, and I want to build everything from scratch. Though there is a library that was developed by a small company, I will not use it. I will make everything of my own, and once it is developed, I’ll use my brand value to announce: “Hey, we are here to provide you the ultimate library to fulfill your every need.”

  • Zero Means Null: A programmer may use some special numbers, such as -1 or 999 (or anything similar) to represent an inappropriate integer value. A similar example can be seen when a programmer treats something like “09/09/9999” as a null date in an application. In these cases, if the user needs to have these values, they will not get them.

  • Golden Hammer: Mr. X believes that technology T is the best. So, if he needs to develop a new system (that demands new learning), he will still prefer T even if it is inappropriate. He thinks, “I am old enough and quite busy. I do not need to learn any more technology if I can somehow manage it with T.”

  • Shoot the Messenger: You believe that the tester “Josie” always finds hard defects for you because she does not like you. You think you’re already under pressure, and the program deadline is approaching. So, you do not want her to be involved in this crucial stage to avoid more defects.

  • Swiss Army Knife: A company targets a product that can serve every need of a customer. Imagine that a company tries to make a drug that can cure all illnesses. Or, someone wants to design software that can serve a wide range of customers with varying needs. It does not matter to the concerned person how complex the interface is.

  • Copy-and-Paste Programming: This is when you need to solve a problem, but you already have a piece of code to deal with a similar situation. So, you can take a copy of the old code that is currently working and start modifying it if required. But when you start from an existing copy, you essentially inherit all the potential bugs associated with it. Also, if the original code needs to be modified in the future, you need to implement the modification in multiple places. This approach violates the don’t repeat yourself (DRY) principle.

  • Architects Don’t Code: Say you are an architect. Your time is valuable, so you only show paths or give great lectures on coding. There are enough implementers who should implement your ideas. Architects Play Golf is also a sister of this anti-pattern.

  • Disguised Links and Ads: This comes from a mindset that is fooling users and earning revenue when they click a link or an advertisement. Often the customer does not get what they really want. We call them dark patterns.

  • Management by Numbers: Someone may believe that a larger number of commits, a larger number of lines of code, or a larger number of defects fixed, etc., is a sign of a great developer.

I’ll finish this discussion with an interesting quote that suits perfectly in this discussion.

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

Bill Gates (https://www.goodreads.com/quotes/536587-measuring-programming-progress-by-lines-of-code-is-like-measuring)

POINTS TO NOTE

Q&A Session

14.5 How are anti-patterns related to design patterns?

Answers:

When you use design patterns, you reuse the experiences of others who came before you. When you start blindly using those concepts for the sake of use only, you fall into the trap of reusing recurring solutions. This can lead you to a bad situation in the future, and then you identify that your return on investment (ROI) keeps decreasing, but maintenance cost keeps increasing. In simple words, if you are not careful enough, then an apparently easy and attractive solution (or, pattern) may cause more problems for you in the future.

14.6 A design pattern may turn into an anti-pattern. Is the understanding correct?

Answers:

Yes, if you apply a design pattern in the wrong context, it can cause more trouble than the problem it solves, and eventually it will turn into an anti-pattern. So, before you start, understanding the nature and context of the problem is very important. For example, inappropriate use of the Mediator pattern may end up with a God Class anti-pattern.

14.7 Anti-patterns are related to software developers only. Is the understanding correct?

Answers:

No. You have already seen various types of anti-patterns. So, the usefulness of an anti-pattern is not limited to developers; it may apply to others also. For example, they can be useful to managers and technical architects too.

14.8 Even if you do not get much benefit from anti-patterns now, these can help you to adapt new features easily with fewer maintenance costs in the future. Is the understanding correct?

Answers:

Yes.

14.9 What are the probable causes of anti-patterns?

Answers:

Anti-patterns can come from various sources or mindsets. A few common examples of what someone might say (or, think) are listed here:
  • “We need to deliver the product as soon as possible.”

  • “We have a very good relationship with the customer. So, at present, we do not need to analyze much about the future impact.”

  • “I am an expert on reuse. I know design patterns very well.”

  • “We will use the latest technologies and features to impress our customers. We do not need to care about legacy systems.”

  • “More complicated code will reflect my expertise in the subject.”

14.10 Can you mention some symptoms of anti-patterns?

Answers:

In object-oriented programming (OOP), the most common symptom is that your system cannot adopt a new feature easily. Also, maintenance cost is continuously increasing. You may also notice that you have lost the power of key object-oriented features like inheritance, polymorphism, etc.

In addition, you may notice some or all of the following symptoms:
  • Use of global variables

  • Code duplication

  • Limited/no reuse of code

  • One big class (God class)

  • Presence of a big number of parameters-less methods

14.11 What is the remedy if you detect an anti-pattern?

Answers:

You may need to refactor your code and find a better solution. For example, here are some solutions to avoid the following anti-patterns:
  • Golden Hammer: You may try to educate Mr. X through some proper training.

  • Zero Means Null: You can use an additional Boolean variable that is more sensible to you to indicate the null value properly.

  • Management by Numbers: Numbers are good if you can use them wisely. But you cannot judge the ability of a programmer only by the number of defects fixed per week. Quality is also important. A typical example is that fixing a simple UI layout is much easier compared to fixing a critical memory leak in the system. Consider another example. “More tests are passing” does not indicate that your system is more stable unless these tests exercise different code paths/branches.

  • Shoot the Messenger: Welcome tester “Josie” and involve her immediately. Don’t consider her as a rival of you. You can properly analyze all of her findings and fix the real defects early to avoid last-moment surprises.

  • Copy-and-Paste Programming: Instead of searching for a quick solution, you can refactor your code. You can also make it commonplace to maintain the frequently used methods to avoid duplicates and easier maintenance.

  • Architects Don’t Code: Involve architects in some parts of the implementation phase. It can help both the organization and themselves. This activity can give them a clearer picture of the true functionalities of the product. And truly, they should value your effort.

14.12 What do you mean by refactoring?

Answers:

In the coding world, the term refactoring means improving the design of existing code without changing the external behavior of the system/application. This process helps you to get more readable code. At the same time, this code should be more adaptable to new requirements (or, change requests), and they should be more maintainable.

Final Suggestions

Before I end this chapter, let me share some of my thoughts with you.

Decide Between a Static Method and an Instance Method

A static method is easy to use. A novice programmer may think that it does not matter much whether they use a static method or an instance method in their program. They know that they can call a method without instantiating an object. They love this and are further impressed when they see some static utility methods that are extremely helpful. But an experienced programmer often finds it interesting and decides whether they should use a static method or not. In each possible design, the programmer may ask, which of them is better? The short answer is that there is no universal rule. I believe that it purely depends on the application you use. Let us verify the fact.

Remember the simple factory (demonstration 1) in Chapter 6? See Figure 14-1.
Figure 14-1

The AnimalFactory class from demonstration 1 in Chapter 6

If you investigate the arrow tip, you see the message in Figure 14-2.
Figure 14-2

A message that says you can use a static method instead of an instance method

This is a partial snapshot; I am expanding the full message for you:

CA1822 Member 'CreateAnimal' does not access instance data and can be marked as static.

It also says the following:
  • Active Members that do not access instance data or call instance methods can be marked as static. After you mark the methods as static, the compiler will emit nonvirtual call sites to these members. This can give you a measurable performance gain for performance-sensitive code.

Note

I can see this suggestion when I set the target framework to .NET 7, .NET 6, or .NET 5. But it is not visible when I use .NET 3.1 as my target framework.

I did not take this suggestion in Chapter 6. The reason is obvious.
  • You cannot mark a static method with virtual or abstract keywords.

  • As a result, you cannot override a static method. So, you cannot use the override keyword either.

  • When you cannot redefine a method using the override keyword, you do not get polymorphic behavior.

  • In Chapter 6, I enhanced the initial implementation and deferred some responsibilities to subclasses. This was because I wanted to implement the polymorphic behavior. When you predict that you may need to do the same for your application, it’s better to make the method nonstatic.

Let me summarize the key points for you:
  • If you use a method that can get all the information from its parameters and does not operate on any instance of a class, you can make the method static. For example, look at the following Utility class with the static method ShowGreater:

class Utility
{
    public static double ShowGreater(
        double first,
        double second)
    {
       return first >= second ? first : second;
    }
}
It makes sense to me to use it as Utility.ShowGreater(24.7, 75.2) to print the greater number between 24.7 and 75.2. It is unnecessary to create an instance of Utility before you print the maximum between 24.7 and 75.2. You can refer to the built-in Math class to get an idea about good static methods. For example, using Math.Max(2,3), you can get 3, or using Math.Abs(-2.52), you can get 2.52.
  • If you do not want to see polymorphic behavior or you care only about the performance of your application, you can consider making your method static.

  • Sometimes you see partial code, and then you feel that a static method makes more sense to you. But you have seen that you may need to enhance your program in the future, so you apply the concept of polymorphism to make your code flexible. Whenever you are in doubt, prefer a nonstatic method over its counterpart (i.e., a static method).

Know the Common Terminology

You learn continuously. You can read articles, develop new code, discuss problems, and learn from others. To do so, you need to understand common terminology. In this section, I’ll remind you of some of them.

Starting with a good design is important, but maintaining it is equally important. If we focus on quick fixes without maintaining the original design goals or architecture, we’ll create more troubles for us. This is the reason that an inappropriate design can make an application rigid. Even if you start with a good design, the continuous quick fixes to this application can make it inefficient. A simple change may demand lots of effort. In the worst case, you see the fragility issue. What does this mean? In simple words, one small change in one location causes changes in multiple locations, and in the worst case, you discover that some of these areas are in no way related to the original change request.

You can develop applications quickly if you reuse some built-in parts that you or someone else developed earlier. When an entry-level programmer hears about reuse, they think that inheritance is the best possible option in every possible scenario, but that is not true. You have seen that in many situations object composition offers a better solution than inheritance. But the use of inheritance, or composition, becomes secondary if you use a code segment that is dependent on many other things, or already has potential errors. The inability to reuse software is often termed immobility.

Viscosity is another important thing to consider in OOP. Wikipedia describes it as the ease at which a developer can add design-preserving code to a system. If you can add new code to your program easily, your program has a low viscosity. The opposite is obvious: in a high-viscosity design, adding hacks is easy, instead of preserving the original design. You can surely predict that by providing these hacks you make your system more rigid. This is one form of viscosity, which is also referred to as the viscosity of design.

Note

Adding new code while preserving the core design requires expertise. The word hack in the previous context is used to mark an inelegant or bad solution. This solution with a hack can inefficiently serve the purpose. Here I am not talking about the hackers who can find loopholes and security breaches in a system. Once they find those loopholes, they can use their talents either for good purposes or for bad purposes. But undoubtedly, those are programmers with exceptional skills.

There is a different form, called viscosity of environment. Consider a case when developers use a pillar build before they push a change in the main codebase. What do I mean by a pillar build? Suppose your company has developed a large application that has many components or modules. I refer to them as pillars. Since these components are big, to maintain separate components, the company may employ separate teams. Each team has a facility: they can compile a specific pillar using a special command to ensure that a new change in the pillar does not break other parts of the same pillar/component. This is a pillar build. So, you can think of it as a single module build or a single component build. It is attractive when the full build (i.e., the complete compilation of all pillars) is a time-consuming activity, but you need to verify a fix as soon as possible. I do not need to tell you that purely relying on this kind of pillar build is risky if you work on interconnected modules.

Cohesion and coupling are two more important concepts that were invented by Larry Constantine in the late 1960s. What do we mean by cohesion? The dictionary’s meaning of cohesion is interconnection or unity. In OOP, when you design a class, it measures the strength of the relationship between a class’s method and data. It will be easy for you if you can remember the single responsibility principle (SRP) in Chapter 4. These concepts go hand in hand, though cohesion is a more general concept.

The opposite is coupling. Wikipedia says that coupling is the degree of interdependence between software modules. In OOP, it is a measure of interdependence between two classes. Say there are two separate classes: A and B. Now consider the case when A uses a B object in one of its methods, or you create a B class object inside the A class constructor and work on that. In these cases, A and B are tightly coupled. Even if B is a subclass of A and uses A’s method, you can say that they are tightly coupled. Remember that you should aim for high cohesion and low coupling. I finish this section with Robert C. Martin’s words from “The Clean Code Blog” (https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html):

If you think about this (SRP) you’ll realize that this is just another way to define cohesion and coupling. We want to increase the cohesion between things that change for the same reasons, and we want to decrease the coupling between those things that change for different reasons.

Accept Failures!

As software developers, we are continuously developing new functionalities or features. When the test team validates them, you will see that lots of tests have failed. For example, if a test suite contains 100 test cases, the result may show pass, pass, fail, pass, fail, fail, fail, pass, fail, fail, and so on. This is quite natural. But I have seen that often people like to see only “passes,” not the failures. Ask any expert about this. These mean that you have done good so far; now you’ll need to fix the failing scenarios one by one. Just like introducing bad code in one part of the software can create many bugs, the opposite is also true! A fix in one place can fix many problems in other places. In fact, if I do not see any test failures with my initial development, I doubt the strength of the test suite. You should not forget the hard truth: your job is to produce good-quality software, not to produce code that passes every test in a test suite.

Q&A Session

14.13 You have used top-level statements throughout the second edition of this book. Is there any specific reason?

Answer:

The honest answer is that I can type less, the code size is small, and I can get the desired output without a problem. Consider the following code:
using System;
namespace UsingTopLevelStatements
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
In earlier versions of C# and .NET, the namespace and the args parameter were optional. Starting with .NET 5, you can have a further simplified version, shown here:
using System;
Console.WriteLine("Hello World!");

Author’s Note Remember that to compile this you have to use C# 9.0 (target framework .NET 5.0); otherwise, you will see the following: Error CS8400 Feature 'top-level statements' is not available in C# 8.0.

When I started writing code for this second edition of the book and targeting .NET 7, I could see that I did not need to mention the namespace. How is that possible? Starting with .NET 6 SDK, we have a set of implicit global using directives for certain projects. These implicit directives include the most common namespaces for the project type. You can see that everything is done behind the scenes!

For example, now I can write a one-liner and compile the following code:
Console.WriteLine("Hello, World!");
Note that in .NET 5, you’ll the following error for this one-liner code (without the namespace):
Error CS8773 Feature 'global using directive' is not available in C# 9.0. Please use language version 10.0 or greater.

So, it’s a big simplification. This feature is useful for scripting scenarios too. I agree that today if a beginner starts with this shortcut, it can be hard to imagine the background stuff and the legacy code. (But it is possible that after a few years, all beginners will prefer to start from here.)

14.14 I have read your other books. It appears to me that you always focus on design, not on the latest features. Is there any specific reason for this?

Answer:

We all know that change is the only “constant” in the software industry. Whatever is new today will be outdated tomorrow. Most of the time, you work with a legacy version to support existing customers. Unless the company decides you should work on an update, you keep fixing the bugs in the legacy versions too. So, I always try to keep a balance. In my other books, I also use the fundamental features of a programming language and focus on the program design so that you can learn about the design changes easily. This is the main reason I prefer to write code that is supported in a wide range of versions.

14.15 Do you suggest any general advice for me?

Answer:

I like to follow in the footsteps of senior programmers and teachers who are experts in this field. Here are some general suggestions from them:
  • Program to a supertype (abstract class/Interface), not an implementation.

  • Except for a few cases, prefer composition over inheritance wherever you can.

  • Try to make a loosely coupled system.

  • Segregate the code that is likely to vary from the rest of your code.

  • Encapsulate what varies.

Summary

Following in the expert’s footprints and learning from experience is a good strategy. Therefore, understanding design patterns is important. At the same time, it is recommended that you use them wisely; otherwise, you will notice the impact of anti-patterns. As an obvious effect, you need to invest your time to refactor the code or implement a new design starting from scratch. At any cost, you should prefer an unattractive, better fix over an attractive quick fix.

I also described some common terminologies and shared some of my thoughts with you at the end of this chapter. I believe that you’ll find them helpful in the future.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.143.65