Legacy Projects
How to win the race
Legacy Projects
How to win the race
TechnicalLead@ InfopulseUA
Victor Polischuk
Many years of legacy systems reviving
and refactoring experience
Loves it
E-mail:
victor2@ukr.net
Skype:
victor-cr
Legacy Projects History
2004
Others Java
2014
Others Java
What is…
…legacy projects?
Comparison Sheet
Legacy
Earned a fortune
Important
Predictable
Crappy
Designed by morons
Boring
Unmaintainable
No documentation
Legacy
Crappy
What is the main difference?
Happy owner
Better quality
No difference
Project cost
What is the main difference?
Happy owner
Better quality
No difference
Project cost
Why Does…
…a legacy project born?
Time passed
Time
Because of time
Timepassed
Time
Because of time
Is it the ONLY reason?
Would you choose...
Shiny
Dull
Mainstream
Terrible
Project
Clean
Project
In future Now
Legacy
No escape
ReWRite…
…or not?
Failed somewhere?
Refactoring
…cookbook
Boy-scout rule
Libraries
upgrade
Build migration
Code
transformation
Code generation
Miscellaneous
Keep Stack Updated
Build Health
Bulk Code Changes
Know Your Tools
Regexp:
(?ms)publics+statics+([^{]+).*?(?=s+publics+|}s+z)
XSLT:
<xsl:stylesheet…>
<xsl:template match="/">
<beans>
<xsl:apply-templates
select="struts-config/action-mappings/*"/>
</beans>
</xsl:template>
<xsl:template match="action">
<bean id="{@path}" class="{@type}"/>
</xsl:template>
</xsl:stylesheet>
Prototyping
Scripting
Visio
Rational
Rose
Power
Designer
Maintain Clean Code
ResultSet aResultSet = null;
ArrayList theAttribute1List = new ArrayList();
ArrayList theAttribute2List = new ArrayList();
…
ArrayList theAttribute30List = new ArrayList();
…
StringBuffer aQuery = new StringBuffer("select ")
.append("ATTRIBUTE1,")
.append("ATTRIBUTE2,")
…
while (aResultSet.next()) {
if (aResultSet.getString("ATTRIBUTE1") != null)
theAttribute1List.add(aResultSet.getString("ATTRIBUTE1"));
…
htAttributeList.put("ATTRIBUTE1", distinct(theAttribute1List));
htAttributeList.put("ATTRIBUTE2", distinct(theAttribute2List));
010
What have you done to prevent me seeing it?
Universal soldier...
public class UniversalComparator implements Comparator {
…
if (value1 instanceof GregorianCalendar) {
GregorianCalendar lcal_obj1 = (GregorianCalendar) value1;
GregorianCalendar lcal_obj2 = (GregorianCalendar) value2;
boolean lb_value = lcal_obj1.before(lcal_obj2);
if (ii_comparatorDirection == COMP_ASC) {
if (lb_value == true) {
return 1;
} else {
return -1;
}
} else {
if (lb_value == true) {
return -1;
} else {
return 1;
}
}
} 07
if (value1 instanceof Boolean) {
Boolean lv_obj1 = (Boolean) value1;
Boolean lv_obj2 = (Boolean) value2;
String ls_value1 = lv_obj1.toString();
String ls_value2 = lv_obj2.toString();
logService.debug("compare: lb_value1, lb_value2: "
+ ls_value1 + ", " + ls_value2);
int lv_value1 = (ls_value1 == "true") ? 1 : 0;
int lv_value2 = (ls_value2 == "true") ? 1 : 0;
if (ii_comparatorDirection == COMP_ASC) {
int val = (lv_value1 < lv_value2) ? -1 : 1;
// log("val: " + val);
return (lv_value1 < lv_value2) ? -1 : 1;
} else
return (lv_value1 < lv_value2) ? 1 : -1;
}
06
JavaDoc... No, have never heard
private void moveFile(String from, String to) throws Exception {
//move files from 'from' to 'to'
String[] cmd;
if (File.separator.compareTo("") == 0) { //windows
cmd = new String[] {"cmd", "/c", "move",
from.trim().replace("/", File.separator),
to.trim().replace("/", File.separator)
};
} else {//linux like, simple mv command does not work, using script
cmd = new String[] {parameters.get("movePath") + ".sh",
from.trim().replace("/", File.separator),
to.trim().replace("/", File.separator)
};
}
System.gc(); //reduces current process size before fork
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
p.destroy(); //free up memory
} 05
Code review?... WTF?
private static final List<Option> DEFAULT_OPTIONS =
new ArrayList<Option>(4);
{
DEFAULT_OPTIONS.add(new Option(1, "Unavailable"));
DEFAULT_OPTIONS.add(new Option(2, "Unidirectional"));
DEFAULT_OPTIONS.add(new Option(3, "Bidirectional"));
DEFAULT_OPTIONS.add(new Option(4, "Not applicable"));
}
04
Fail of fail-over protection
public static void lockPartyWithLog(Party p, UnitOfWork uow) {
// Local variables
Party partyClone = null;
// Lock the object
// LOCK_NOWAIT : an exception occurs if the object is being locked
try {
partyClone = (Party) uow.refreshAndLockObject(p,
ObjectLevelReadQuery.LOCK_NOWAIT);
} catch (DatabaseException dbe) {
logService.info("The party ID = " + p.getId()
+ " is locked by an other process");
try {
Thread.currentThread().sleep(1000);
} catch (Exception e) {
logService.error("Thread Exception ", e);
}
lockPartyWithLog(p, uow);
}
}
03
Master class of API design
public interface Parser {
void setReport(InputStream inputstream);
void setReport(String s);
String getReport();
void save();
void delete(String Query) throws HibernateException;
void setParams(Map<String, String> map);
Map<String, String> getParams();
void saveReport(String reportPath);
Boolean isDuplicated(String fileName);
}
23: public class PMScanReport extends AbstractParser
23: implements Parser {
..........
1556: }
02
Fatality!
public int compare(TradeConfirmation tc1, TradeConfirmation tc2) {
int value;
Offer o1 = (Offer) tc1.getOffer();
Offer o2 = (Offer) tc2.getOffer();
if (o1.getTradingInterval() < o2.getTradingInterval()) {
value = -1;
} else {
if (o1.getTradingInterval() == o2.getTradingInterval()) {
if (o1.getType() < o2.getType()) {
value = -1;
} else {
if (o1.getType() == o2.getType()) {
PartyDef p1 = o1.getParty().getEffectiveNow();
PartyDef p2 = o2.getParty().getEffectiveNow();
if (p1.getName().compareTo(p2.getName()) < 0) {
value = -1;
} else {
if (p1.getName().compareTo(p2.getName()) == 0) {
if (o1.getTradingZone().getEffectiveNow().getIdentification().compareTo(…) < 0) {
value = -1;
} else {
if (o1.getTradingZone().getEffectiveNow().getIdentification().compareTo(…)) == 0) {
value = 0;
} else {
value = 1;
}
}
} else {
value = 1;
}
}
} else {
value = 1;
}
}
} else {
value = 1;
}
}
return value;
}
01
What Else?
Transaction Management
Dependency Injection
Mass Relocation
Various Migrations
Mindset
Prepare yourself
Legacy Law
Successful
Legacy Non-legacy
Legacy
Crappy Non-crappy
I cannot understand
It is a crap
Assumptions
I cannot understand
It may be a crap
Assumptions
Pet Clinic Comparison
Poor Successful
…
Carenot, killing
…
…
Care, not killing
…
Who would you trust with
your most precious pet?
Conclusions
Finally
Legacy is everywhere
• You cannot hide or pretend it has nothing to do with you
Legacy means success
• Truly crappy things do not live long
Knowledge is a weapon
• People feel calm when encounter known problems
Change your mindset
• It is up to you: run crying or deal with it like a boss
Trust is important
• It also influences your freedom in decision making
Questions
Thank you for attention

Legacy projects: how to win the race

  • 1.
  • 2.
  • 3.
    TechnicalLead@ InfopulseUA Victor Polischuk Manyyears of legacy systems reviving and refactoring experience Loves it E-mail: victor2@ukr.net Skype: victor-cr
  • 4.
  • 5.
  • 6.
    Comparison Sheet Legacy Earned afortune Important Predictable Crappy Designed by morons Boring Unmaintainable No documentation
  • 7.
  • 8.
    What is themain difference? Happy owner Better quality No difference Project cost
  • 9.
    What is themain difference? Happy owner Better quality No difference Project cost
  • 10.
  • 11.
    Time passed Time Because oftime Timepassed Time Because of time Is it the ONLY reason?
  • 14.
  • 15.
  • 16.
  • 18.
  • 19.
  • 20.
  • 22.
  • 23.
  • 24.
  • 25.
  • 27.
  • 29.
  • 30.
    Know Your Tools Regexp: (?ms)publics+statics+([^{]+).*?(?=s+publics+|}s+z) XSLT: <xsl:stylesheet…> <xsl:templatematch="/"> <beans> <xsl:apply-templates select="struts-config/action-mappings/*"/> </beans> </xsl:template> <xsl:template match="action"> <bean id="{@path}" class="{@type}"/> </xsl:template> </xsl:stylesheet>
  • 31.
  • 32.
  • 34.
  • 35.
    ResultSet aResultSet =null; ArrayList theAttribute1List = new ArrayList(); ArrayList theAttribute2List = new ArrayList(); … ArrayList theAttribute30List = new ArrayList(); … StringBuffer aQuery = new StringBuffer("select ") .append("ATTRIBUTE1,") .append("ATTRIBUTE2,") … while (aResultSet.next()) { if (aResultSet.getString("ATTRIBUTE1") != null) theAttribute1List.add(aResultSet.getString("ATTRIBUTE1")); … htAttributeList.put("ATTRIBUTE1", distinct(theAttribute1List)); htAttributeList.put("ATTRIBUTE2", distinct(theAttribute2List)); 010
  • 36.
    What have youdone to prevent me seeing it?
  • 37.
  • 38.
    public class UniversalComparatorimplements Comparator { … if (value1 instanceof GregorianCalendar) { GregorianCalendar lcal_obj1 = (GregorianCalendar) value1; GregorianCalendar lcal_obj2 = (GregorianCalendar) value2; boolean lb_value = lcal_obj1.before(lcal_obj2); if (ii_comparatorDirection == COMP_ASC) { if (lb_value == true) { return 1; } else { return -1; } } else { if (lb_value == true) { return -1; } else { return 1; } } } 07
  • 39.
    if (value1 instanceofBoolean) { Boolean lv_obj1 = (Boolean) value1; Boolean lv_obj2 = (Boolean) value2; String ls_value1 = lv_obj1.toString(); String ls_value2 = lv_obj2.toString(); logService.debug("compare: lb_value1, lb_value2: " + ls_value1 + ", " + ls_value2); int lv_value1 = (ls_value1 == "true") ? 1 : 0; int lv_value2 = (ls_value2 == "true") ? 1 : 0; if (ii_comparatorDirection == COMP_ASC) { int val = (lv_value1 < lv_value2) ? -1 : 1; // log("val: " + val); return (lv_value1 < lv_value2) ? -1 : 1; } else return (lv_value1 < lv_value2) ? 1 : -1; } 06
  • 40.
  • 41.
    private void moveFile(Stringfrom, String to) throws Exception { //move files from 'from' to 'to' String[] cmd; if (File.separator.compareTo("") == 0) { //windows cmd = new String[] {"cmd", "/c", "move", from.trim().replace("/", File.separator), to.trim().replace("/", File.separator) }; } else {//linux like, simple mv command does not work, using script cmd = new String[] {parameters.get("movePath") + ".sh", from.trim().replace("/", File.separator), to.trim().replace("/", File.separator) }; } System.gc(); //reduces current process size before fork Process p = Runtime.getRuntime().exec(cmd); p.waitFor(); p.destroy(); //free up memory } 05
  • 42.
    Code review?... WTF? privatestatic final List<Option> DEFAULT_OPTIONS = new ArrayList<Option>(4); { DEFAULT_OPTIONS.add(new Option(1, "Unavailable")); DEFAULT_OPTIONS.add(new Option(2, "Unidirectional")); DEFAULT_OPTIONS.add(new Option(3, "Bidirectional")); DEFAULT_OPTIONS.add(new Option(4, "Not applicable")); } 04
  • 43.
  • 44.
    public static voidlockPartyWithLog(Party p, UnitOfWork uow) { // Local variables Party partyClone = null; // Lock the object // LOCK_NOWAIT : an exception occurs if the object is being locked try { partyClone = (Party) uow.refreshAndLockObject(p, ObjectLevelReadQuery.LOCK_NOWAIT); } catch (DatabaseException dbe) { logService.info("The party ID = " + p.getId() + " is locked by an other process"); try { Thread.currentThread().sleep(1000); } catch (Exception e) { logService.error("Thread Exception ", e); } lockPartyWithLog(p, uow); } } 03
  • 45.
    Master class ofAPI design
  • 46.
    public interface Parser{ void setReport(InputStream inputstream); void setReport(String s); String getReport(); void save(); void delete(String Query) throws HibernateException; void setParams(Map<String, String> map); Map<String, String> getParams(); void saveReport(String reportPath); Boolean isDuplicated(String fileName); } 23: public class PMScanReport extends AbstractParser 23: implements Parser { .......... 1556: } 02
  • 47.
  • 48.
    public int compare(TradeConfirmationtc1, TradeConfirmation tc2) { int value; Offer o1 = (Offer) tc1.getOffer(); Offer o2 = (Offer) tc2.getOffer(); if (o1.getTradingInterval() < o2.getTradingInterval()) { value = -1; } else { if (o1.getTradingInterval() == o2.getTradingInterval()) { if (o1.getType() < o2.getType()) { value = -1; } else { if (o1.getType() == o2.getType()) { PartyDef p1 = o1.getParty().getEffectiveNow(); PartyDef p2 = o2.getParty().getEffectiveNow(); if (p1.getName().compareTo(p2.getName()) < 0) { value = -1; } else { if (p1.getName().compareTo(p2.getName()) == 0) { if (o1.getTradingZone().getEffectiveNow().getIdentification().compareTo(…) < 0) { value = -1; } else { if (o1.getTradingZone().getEffectiveNow().getIdentification().compareTo(…)) == 0) { value = 0; } else { value = 1; } } } else { value = 1; } } } else { value = 1; } } } else { value = 1; } } return value; } 01
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
    I cannot understand Itis a crap Assumptions
  • 54.
    I cannot understand Itmay be a crap Assumptions
  • 56.
    Pet Clinic Comparison PoorSuccessful … Carenot, killing … … Care, not killing …
  • 57.
    Who would youtrust with your most precious pet?
  • 58.
  • 59.
    Legacy is everywhere •You cannot hide or pretend it has nothing to do with you Legacy means success • Truly crappy things do not live long Knowledge is a weapon • People feel calm when encounter known problems Change your mindset • It is up to you: run crying or deal with it like a boss Trust is important • It also influences your freedom in decision making
  • 60.

Editor's Notes

  • #2 Боль
  • #3 Больная тема. Хотел бы дать живые примеры, но...
  • #4 10 лет
  • #7 Легаси код против грязного кода, можете перевести дословно, я не могу, меня наругают
  • #8 Ортогональные вещи Как на самом деле?
  • #9 Чем выделяется легаси на фоне грязи... Довольный владелец, качеством, ничем, стоимостью... И-и-и-и-и-и....
  • #10 Довольным, но хотящим большего.
  • #11 Есть идеи как они появляются на свет? Не обращая внимания на картинку... Ну был проект как проект, а тут бац и легаси... Многие из вас наверное скажут...
  • #12 Так ли это? Определяющая ли это причина...
  • #16 Ульта-модные «мотивирующие» библиотеки и фреймворки
  • #17 Грустный и унылый мейнстрим...
  • #18 Бросить вызов неизведанному или испытывать свое терпение? Кто за левую часть?
  • #22 То как я определяю для себя и своей команды...