Skip to main content
added 5 characters in body
Source Link

Design should evolve in small incremental changessteps. Here's the proper (least painful / time-consuming) sequence of actions leading to performant code:

  • make it work, i.e. the code should pass all testtests (no more, not lessno more no less), without spreading your focus on anything else;
  • make it clean;
  • optimize the performance.

It's akin to the metaphor of hats in TDD (you can wear only one hat at a timeyou can wear only one hat at a time). We need to focus on achieving only one goal at a time, evolving the code in small incremental stepsincrementally.

Eliminating the hack with the static variable and making the method for finding palindromic product a pure function by itself already gives a room for leveraging referential transparency. Since the result of its execution doesn't change, hence it can be computed only once and cached, reducing time complexity to constant. Functional languages like Haskell are leveraging this quite a bit (I'm leaving the research on how to achieve it in Java as homework).

Note, that ideally tests should already be in place during the first phase of writing a solution that "simply works""simply works" and neither clean, no performant

Now we can reimplement isPalindrom(int) using modular arithmeticmodular arithmetic instead of messing with strings:

Method isPalindrome(String candidate) becomes a dead code and goes away, we don't need it anymore.

Design should evolve in small incremental changes. Here's the proper (least painful / time-consuming) sequence of actions leading to performant code:

  • make it work, i.e. the code should pass all test (no more, not less), without spreading your focus on anything else;
  • make it clean;
  • optimize the performance.

It's akin to the metaphor of hats in TDD (you can wear only one hat at a time). We need to focus on achieving only one goal at a time, evolving the code in small incremental steps.

Eliminating the hack with the static variable and making the method for finding palindromic product a pure function by itself already gives a room for leveraging referential transparency. Since the result of its execution doesn't change, hence it can be computed only once and cached reducing time complexity to constant. Functional languages like Haskell are leveraging this quite a bit (I'm leaving the research on how to achieve it in Java as homework).

Note, tests should already be in place during the first phase of writing a solution that "simply works" and neither clean, no performant

Now we can reimplement isPalindrom(int) using modular arithmetic instead of messing with strings:

Method isPalindrome(String candidate) becomes a dead code and goes away, we don't need it anymore.

Design should evolve in small incremental steps. Here's the proper (least painful / time-consuming) sequence of actions leading to performant code:

  • make it work, i.e. the code should pass all tests (no more no less), without spreading your focus on anything else;
  • make it clean;
  • optimize the performance.

It's akin to the metaphor of hats in TDD (you can wear only one hat at a time). We need to focus on achieving only one goal at a time, evolving the code in small incrementally.

Eliminating the hack with the static variable and making the method for finding palindromic product a pure function by itself already gives a room for leveraging referential transparency. Since the result of its execution doesn't change, hence it can be computed only once and cached, reducing time complexity to constant. Functional languages like Haskell are leveraging this quite a bit (I'm leaving the research on how to achieve it in Java as homework).

Note, that ideally tests should already be in place during the first phase of writing a solution that "simply works" and neither clean, no performant

Now we can reimplement isPalindrom(int) using modular arithmetic instead of messing with strings:

Method isPalindrome(String) becomes a dead code and goes away, we don't need it anymore.

added 510 characters in body
Source Link

RE: WhatWhat about Performance?

Dear reader, if you'reinspired by comments

One might be frowning upon the code demonstrated above, saying "it'll not perform well enough""it'll not perform well enough". If that's the case, then, dear reader, please pause for a moment and bear with me, because you completely missed the point of the answer.

"Make the change easy, then make the easy change" - a quote from "Tidy first" by Kent Beck, the father The goal of TDD and Extreme programmingthese changes is to improve the design to enable further changes.

The point is that introducing changes into a code that is far from being clean is costly. Is some cases, it makes sense to improve the design,father of TDD and then make an "easy change".Extreme programming Kent Beck in his book "Tidy first" expressed this idea in the following way:

Make the change easy, then make the easy change

Introducing changes into a code that is far from being clean is costly. Is some cases, it makes sense to improve the design, and then make an "easy change".

Design should evolve in small incremental changes. Trying to create from scratch an implementation which works correctly, which is clean, which is performant is counterproductive. TheHere's the proper (least painful / time-consuming) sequence would beof actions leading to performant code:

  • make it work (i, i.e. the code should pass all test (no more, not less), without spreading your focus on anything else;
  • make it clean;
  • improveoptimize the performance.

It's akin to the metaphor of hats in TDD (you can wear only one hat at a time). YouWe need to be focusedfocus on achieving only one goal at a time, evolving the code in small incremental steps.

SoThe same holds true, when it comes to refactoring existing code the first change that enables a massivesame principle applies as well. Tiding the code should happen separately from making performance improvementoptimizations. It's called a preparatory refactoring. Otherwise, an attempt to optimize a ball of mud is already donelikely to produce a code which is still a mess and has a suboptimal performance -(in the worst case you end up with the broken code and rolling back the changes losing time for no avail).

So, what performance tweaks we can introduce with the current design changes?

Eliminating the hack with the static variable and making the method for finding palindromic product is a pure function. Which means it's by itself already gives a room for leveraging referentialy transparentreferential transparency,. Since the result of its execution doesn't change, hence it can be computed only once and cached reducing time complexity to constant. Functional languages like Haskell are leveraging this quite a bit (I'm leaving the research on how to achieve it in Java as homework).

Another performance improvement, we can make is to not mess withquit employing strings at allwhile checking if a number is palindrome.

But first we need tests (note they already have to be in place during the phase of creating a solution that "just works" and not tidy and performant):.

Note, tests should already be in place during the first phase of writing a solution that "simply works" and neither clean, no performant

Now we can just plug another implementation ofreimplement isPalindrom(int) which doesn't mess with string, but instead is based onusing modular arithmetic instead of messing with strings:

Method isPalindrome(String candidate) becomes a dead codedead code and goes away, we don't need it anymore.

So, the main point is:

Before improving the performance of the palindrome check, it makes sense to define this functionality properly in the first place. It's called a preparatory refactoring. Otherwise, you'll end up with a mess (and potentially even with the broken code).

DESIGN MATTERS period

The algorithm of going through combinations can be improved as well, it's a simple brute force, but I'm not going to poke into this topic, there are already too many things to unpack here.

RE: What about Performance?

Dear reader, if you're frowning upon the code demonstrated above saying "it'll not perform well enough", then you completely missed the point of the answer.

"Make the change easy, then make the easy change" - a quote from "Tidy first" by Kent Beck, the father of TDD and Extreme programming.

The point is that introducing changes into a code that is far from being clean is costly. Is some cases, it makes sense to improve the design, and then make an "easy change".

Design should evolve in small incremental changes. Trying to create from scratch an implementation which works correctly, which is clean, which is performant is counterproductive. The proper sequence would be:

  • make it work (i.e. the code should pass all test), without spreading your focus on anything else;
  • make it clean;
  • improve the performance.

It's akin to the metaphor of hats in TDD (you can wear only one hat at a time). You need to be focused on achieving only one goal at a time, evolving the code in small incremental steps.

So the first change that enables a massive performance improvement is already done - the method for finding palindromic product is a pure function. Which means it's referentialy transparent, result of its execution doesn't change, hence it can be computed only once and cached. Functional languages like Haskell are leveraging this quite a bit (I'm leaving the research on how to achieve it in Java as homework).

Another performance improvement, is to not mess with strings at all.

But first tests (note they already have to be in place during the phase of creating a solution that "just works" and not tidy and performant):

Now we can just plug another implementation of isPalindrom() which doesn't mess with string, but instead is based on modular arithmetic:

Method isPalindrome(String candidate) becomes a dead code and goes away.

So, the main point is:

Before improving the performance of the palindrome check, it makes sense to define this functionality properly in the first place. It's called a preparatory refactoring. Otherwise, you'll end up with a mess (and potentially even with the broken code).

DESIGN MATTERS period

The algorithm can be improved as well, it's a simple brute force, but I'm not going to poke into this topic, there are already too many things to unpack here.

What about Performance?

inspired by comments

One might be frowning upon the code demonstrated above, saying "it'll not perform well enough". If that's the case, then, dear reader, please pause for a moment and bear with me, because you completely missed the point of the answer.

The goal of these changes is to improve the design to enable further changes.

The father of TDD and Extreme programming Kent Beck in his book "Tidy first" expressed this idea in the following way:

Make the change easy, then make the easy change

Introducing changes into a code that is far from being clean is costly. Is some cases, it makes sense to improve the design, and then make an "easy change".

Design should evolve in small incremental changes. Here's the proper (least painful / time-consuming) sequence of actions leading to performant code:

  • make it work, i.e. the code should pass all test (no more, not less), without spreading your focus on anything else;
  • make it clean;
  • optimize the performance.

It's akin to the metaphor of hats in TDD (you can wear only one hat at a time). We need to focus on achieving only one goal at a time, evolving the code in small incremental steps.

The same holds true, when it comes to refactoring existing code the same principle applies as well. Tiding the code should happen separately from making performance optimizations. It's called a preparatory refactoring. Otherwise, an attempt to optimize a ball of mud is likely to produce a code which is still a mess and has a suboptimal performance (in the worst case you end up with the broken code and rolling back the changes losing time for no avail).

So, what performance tweaks we can introduce with the current design changes?

Eliminating the hack with the static variable and making the method for finding palindromic product a pure function by itself already gives a room for leveraging referential transparency. Since the result of its execution doesn't change, hence it can be computed only once and cached reducing time complexity to constant. Functional languages like Haskell are leveraging this quite a bit (I'm leaving the research on how to achieve it in Java as homework).

Another performance improvement we can make is to quit employing strings while checking if a number is palindrome.

But first we need tests.

Note, tests should already be in place during the first phase of writing a solution that "simply works" and neither clean, no performant

Now we can reimplement isPalindrom(int) using modular arithmetic instead of messing with strings:

Method isPalindrome(String candidate) becomes a dead code and goes away, we don't need it anymore.

The algorithm of going through combinations can be improved as well, but I'm not going to poke into this topic, there are already too many things to unpack here.

added 2 characters in body
Source Link

Dear reader, if you're frowning upon the code demonstrated above saying "it'll not perform well enough", then you completely missed the pointmissed the point of the answer.

Dear reader, if you're frowning upon the code demonstrated above saying "it'll perform well enough", then you completely missed the point of the answer.

Dear reader, if you're frowning upon the code demonstrated above saying "it'll not perform well enough", then you completely missed the point of the answer.

added 108 characters in body
Source Link
Loading
added 108 characters in body
Source Link
Loading
added 70 characters in body
Source Link
Loading
added 70 characters in body
Source Link
Loading
added 35 characters in body
Source Link
Loading
added 85 characters in body
Source Link
Loading
added 3307 characters in body
Source Link
Loading
added 3307 characters in body
Source Link
Loading
deleted 118 characters in body
Source Link
Loading
added 105 characters in body
Source Link
Loading
added 1314 characters in body
Source Link
Loading
added 155 characters in body
Source Link
Loading
added 155 characters in body
Source Link
Loading
Source Link
Loading