Christmas tree antipattern

Anti-patterns, or simply examples of ineffective code, can be very insidious contributors, even in the source code of seasoned developers. Sometimes this is a consequence of setting a task or very tight deadlines, sometimes inattention fails.





In this article I will tell you about the Christmas tree design antipattern. The essence of this anti-pattern lies in the fact that in some cases, the imperative approach affects the source text much more difficult to understand and maintain. One complication provokes the next, and so on, until we realize that it's easier to rewrite everything from scratch.





I find this anti-pattern interesting because you can get it not with a single change, but with a whole chain of improvements related to the development of the code. And yes, you understood correctly, we convince ourselves and the customer that the code is getting better, but in the end we get a Christmas tree. To understand this better, consider a cascade of tasks, from simple to complex, and try to trace the course of judgments that lead to ineffective code.





The birth of a problem

Let's imagine that there is a simple component that displays a certain number - "Counter"





const Counter = ({ value }) => {
	return <div>{ value }</div>;
};
      
      



“Counter” should not be taken literally. It is simply a simplified model to contrast the essence of the problem.





We received a task to make it more functional, say, after the number, to put units of measurement - digits



. The component now looks like this:





const Counter = ({ value, digits }) => {
	return <div>{ `${value} ${digits}` }</div>
};
      
      



, , : 10 ()



. , :





const Counter = ({ value, digits, type }) => {
	const temp = type ? `(${digits})` : digits;
	return <div>{ `${value} ${temp}` }</div>
};
      
      



, . , «Counter» , . . , — a



, b



c



, y



- f(a, b, c)



, .





, « ». , , . , . , , a * b



. , a + b.







«Counter» , (digits



type



) , . . a * b



, . , , :





y = a * b + c

, digits



, value



, , a



, . , , . . type



.





y = b + 1

... . , , , , .





, , digits



, , , «Counter» . , ...





?

, «Counter» . , , , . digits



type



, b' = f(b)



. :





const getCoveredDigits = (digits) => `(${digits})`;

<Counter
  value={value}
  digits={getCoveredDigits(digits)}
/>
      
      



, :





y = a + b ', b' = f (b)

, f(b)



, . , «Counter».





Of course, when implementing "Counter" we deliberately made several mistakes that often go unnoticed in real production. Although there is no ideal component model, but with a more profitable decomposition, it is possible to reduce the amount of source text and, as a result, increase the overall reliability and scalability of their applications.








All Articles