ARE YOU NOT USING TDD?! – PART 2 (Legacy code)

Last updated Nov 30, 2023 Published May 23, 2015

The content here is under the Attribution 4.0 International (CC BY 4.0) license

In part one, I introduced the life cycle of TDD you can see here and how it works, but often people come to me and ask about the legacy code how can we start using TDD with legacy code? Should we start from zero? Should we use baby steps? I decided to share my experience in how I used TDD in legacy code and how I did to get this task done also I have to say many thanks to my friend Alexandre Cintra who helped me a lot by giving me gold tips.

Edit: Jun 17, 2015

You can find useful information in my slides below. It was created for my talk at Samsung Ocean

Edit: July 28, 2015

Legacy software systems . . . were developed decades ago and have been continually modified to meet changes in business requirements and computing platforms. The proliferation of such systems is causing headaches for large organizations that find them costly to maintain and risky to evolve - Dayani-Fard

Legacy code is the nightmare of everyone

Doesn’t matter if you are in a big company or a small one it is normal to have legacy code and you will need to maintain and even make some improvements as the request of our client comes. How can I identify a legacy that is impossible to test?

  1. Many responsibilities: Usually legacy code has many lines between 1000 and 2000 (I’ve seen many with 3000) and does everything in one file database connection, data persistence, business logic, and IO are a couple of examples.

  2. Without code pattern: A “great” feature of legacy code is the lack of pattern in its code. When you touch the code base you usually see huge files and also blank files, I was just playing around in a company repository and I saw a model without one single line just with its declaration therefore in the controller was everything else the access data, DAO and even the queries were written in the controller!

See here a big piece of legacy code from a real application written in PHP 😲
<?php

class MyLegacyClass {
	
	    // omitted code with 50 lines also construct method and some properties was took off
            public function setXml($xml) {
            	try {
            		$this->xml = $xml;
            		return $this;
            	} catch(Exception $e) {
            		exit($e->getMessage());
            	}
            }

            public function getXml() {
            	return $this->xml;
            }
             
            public function getModalRodoviario() {
            	try {
            		$xml = $this->getXml();
            		return $xml->rodo;
            	} catch(Exception $e) {
            		exit($e->getMessage());
            	}
            }
             
            public function printXML() {
            	$xml = $this->getXml();
            	print($xml->asXML());
            	exit;
            }
             
            public function setIdeValues($config, $Cte) {
            	$xml = $this->getXml();

            	$ide = $xml->infCte->addChild('ide');

            	$confIde = $config;

            	$camposObrigatoriosConfIde = array(
			//omitted code 31 lines
            	);

            	$confToma = $confIde['toma'];

            	if($confToma == '4') {
            		$confToma4 = $confIde['toma4'];
            		unset($confIde['toma4']);
            	}

            	unset($confIde['toma']);

            	$confIde['cUF'] = $this->estadosIBGE[$confIde['cUF']];

            	$this->chaveAcesso = $this->calculaChaveAcesso(
            	$confIde['cUF'],
            	substr(str_replace('-', '', $confIde['dhEmi']),2,4),
            	$Cte['Empresa']['Entidade']['ent_cnpj'],
            	$confIde['mod'],
            	$confIde['serie'],
            	$confIde['nCT'],
            	$confIde['tpEmis'],
            	$confIde['cCT']
            	);

            	$Cte->cte_chave = $this->chaveAcesso;

            	$Cte->save();

            	$confIde['cDV'] = $this->digVer;

            	$xml->infCte->addAttribute('Id', 'CTe' . $this->chaveAcesso);

            	foreach($confIde as $node => $nodeValue) {
            		if($nodeValue != "" && !is_array($nodeValue)) {
            			$ide->addChild($node, $nodeValue);
            		} else {
            			if(array_key_exists($node, $camposObrigatoriosConfIde))
            			throw new Exception($camposObrigatoriosConfIde[$node]);
            		}
            	}

            	//		exit;
            	if(isset($confToma4)) {
            		$toma4 = $ide->addChild('toma4');
            		$toma4->addChild('toma', $confToma);
            		 
            		$camposObrigatoriosTomador = array(
				//omitted code 9 lines
            		);
            		 
            		$confToma4['toma_data_ent_cont'] = date('Y-m-d H:i:s');
            		$confToma4['toma_justificativa_cont'] = "Justificativa teste";
            		 
            		foreach($camposObrigatoriosTomador as $campo => $mensagemErro) {
            			if($confToma4[$campo] == "")
            			throw new Exception($mensagemErro);
            		}
            		 
            		$dePara = array(
				'fone' => 'toma_telefone',
				'xLgr' => 'toma_end_logradouro',
				'nro' => 'toma_end_nro',
				'xCpl' => 'toma_end_cpl',
				'xBairro' => 'toma_end_bairo',
				'cMun' => 'toma_end_cod_mun',
				'xMun' => 'toma_end_mun',
				'UF' => 'toma_end_uf_sigla',
            		//'CEP' => 'toma_end_cep',
				'cPais' => 'toma_cod_end_pais',
				'xPais' => 'toma_end_pais',
				'email' => 'toma_cont_email',
            		//'xJust' => 'toma_justificativa_cont'
            		);
            		 
            		if(strlen($confToma4['toma_cpf_cnpj']) == 11) {
            			$toma4->addChild('CPF', $confToma4['toma_cpf_cnpj']);
            			if($confToma4['toma_nome']!="")
            			$toma4->addChild('xNome', $confToma4['toma_nome']);
            		} else {
            			$toma4->addChild('CNPJ', $confToma4['toma_cpf_cnpj']);
            			if($confToma4['toma_fantasia']!="")
            			$toma4->addChild('xFant', $confToma4['toma_fantasia']);
            			if($confToma4['toma_ie']!="")
            			$toma4->addChild('IE', $confToma4['toma_ie']);
            		}
            		 
            		if(!empty($confToma4['toma_telefone']))
            		$toma4->addChild('fone', $confToma4['toma_telefone']);
            		 
            		$enderToma = $toma4->addChild('enderToma');

            		foreach($dePara as $de => $para) {
            			$confToma4[$para] = $this->cleaner($confToma4[$para]);
            			if($confToma4[$para]!="")
            			$enderToma->addChild($de, $confToma4[$para]);
            		}
            		 
            		/*if(!empty($confToma4['toma_data_ent_cont']))
            		 $enderToma->addChild('dhCont', implode('T', explode(' ', $confToma4['toma_data_ent_cont'])));*/
            	} else {
            		$toma03 = $ide->addChild('toma03');
            		$toma03->addChild('toma', $confToma);
            	}

            	$this->setXml($xml);
            }

            public function setCompl($config) {
            	//		if($this->validaInputacao($config)) {
            	$xml = $this->getXml();

            	$compl = $xml->infCte->addChild('compl');

            	$confComplPrimeiroBloco = array(
					'xCaracAd', 
					'xCaracSer', 
					'xEmi'
					);

					foreach($confComplPrimeiroBloco as $node) {
						$config[$node] = $this->cleaner($config[$node]);
						if($config[$node]!="")
						$compl->addChild($node, $config[$node]);
					}

					if($config['fluxo']['xOrig'] != "" || $config['fluxo']['pass'] != "") {
						$fluxo = $compl->addChild('fluxo');
					}

					if(!empty($config['fluxo']['xOrig'])) {
						$fluxo->addChild('xOrig', $config['fluxo']['xOrig']);
					}

					if($config['fluxo']['pass'] != "" && count($config['fluxo']['pass']) > 0) {
						foreach($config['fluxo']['pass'] as $pass) {
							$xpass = $fluxo->addChild('pass');

							$nodesPass = array(
						'xPass' => 'cdp_sigla_aeroporto_passagem',
						'xDest' => 'cdp_sigla_aeroporto_destino',
						'xRota' => 'cdp_codigo_rota_entrega'
						);
							
						foreach($nodesPass as $nodePass => $nodePassIndex) {
							$pass[$nodePassIndex] = $this->cleaner($pass[$nodePassIndex]);
							if($pass[$nodePassIndex]!="")
							$xpass->addChild($nodePass, $pass[$nodePassIndex]);
						}
						}
					}

					if(count($config['Entrega'])) {
						$Entrega = $compl->addChild('Entrega');

						$config['Entrega']['tpPer'] = $this->cleaner($config['Entrega']['tpPer']);

						if($config['Entrega']['tpPer']=="")

						switch($config['Entrega']['tpPer']) {
							case '0' :
								$semData = $Entrega->addChild('semData');
								$semData->addChild('tpPer', $config['Entrega']['tpPer']);
								break;
							case '1' :
							case '2' :
							case '3' :
								$comData = $Entrega->addChild('comData');
								$comData->addChild('tpPer', $config['Entrega']['tpPer']);
								$config['Entrega']['dProg'] = $this->cleaner($config['Entrega']['dProg']);

								if($config['Entrega']['dProg']!="")
								$comData->addChild('tpPer', $config['Entrega']['dProg']);
								
								break;
							case '4' :
								$noPeriodo = $Entrega->addChild('noPeriodo');
								$noPeriodo->addChild('tpPer', $config['Entrega']['tpPer']);
								$config['Entrega']['dtIni'] = $this->cleaner($config['Entrega']['dtIni']);
								if($config['Entrega']['dtIni']!="")
								$noPeriodo->addChild('dtIni', $config['Entrega']['dtIni']);
								
								$config['Entrega']['dtFim'] = $this->cleaner($config['Entrega']['dtFim']);
								if($config['Entrega']['dtFim']!="")
								$noPeriodo->addChild('dtFim', $config['Entrega']['dtFim']);
								
								break;
						}

						$config['Entrega']['tpHor'] = $this->cleaner($config['Entrega']['tpHor']);

						switch($config['Entrega']['tpHor']) {
							case '0' :
								$semHora = $Entrega->addChild('semHora');
								$semHora->addChild('tpHor', $config['Entrega']['tpHor']);
								break;
							case '1' :
							case '2' :
							case '3' :
								$comHora = $Entrega->addChild('comHora');
								$comHora->addChild('tpHor', $config['Entrega']['tpHor']);
								$config['Entrega']['hProg'] = $this->cleaner($config['Entrega']['hProg']);
								if($config['Entrega']['hProg']!="")
								$comHora->addChild('tpHor', $config['Entrega']['hProg']);
								break;
							case '4' :
								$noInter = $Entrega->addChild('noInter');
								$noInter->addChild('tpHor', $config['Entrega']['tpHor']);
								$config['Entrega']['hIni'] = $this->cleaner($config['Entrega']['hIni']);
								if($config['Entrega']['hIni']!="")
								$noInter->addChild('hIni', $config['Entrega']['hIni']);
								$config['Entrega']['hFim'] = $this->cleaner($config['Entrega']['hFim']);
								if($config['Entrega']['hFim']!="")
								$noInter->addChild('hFim', $config['Entrega']['hFim']);
								break;
						}
					}

					if ( !empty($config['xObs']) ){
						$compl->addChild('xObs', $config['xObs']);
					}

					if(isset($config['ObsCont']) && count($config['ObsCont']) > 0) {
						foreach($config['ObsCont'] as $ObsCont) {
							$xObsCont = $compl->addChild('ObsCont');

							$ObsCont['coic_identificador'] = $this->cleaner($ObsCont['coic_identificador']);
							if($ObsCont['coic_identificador']!="")
							$xObsCont->addChild('xCampo', $ObsCont['coic_identificador']);
							$ObsCont['coic_obs'] = $this->cleaner($ObsCont['coic_obs']);
							if($ObsCont['coic_obs']!="")
							$xObsCont->addChild('xTexto', $ObsCont['coic_obs']);
						}
					}

					if(isset($config['ObsFisco']) && count($config['ObsFisco']) > 0) {
						foreach($config['ObsFisco'] as $ObsFisco) {
							$xObsFisco = $compl->addChild('ObsFisco');

							$ObsFisco['coif_identificador'] = $this->cleaner($ObsFisco['coif_identificador']);
							if($ObsFisco['coif_identificador']!="")
							$xObsFisco->addChild('xCampo', $ObsFisco['coif_identificador']);
							$ObsFisco['coif_obs'] = $this->cleaner($ObsFisco['coif_obs']);
							if($ObsFisco['coif_obs']!="")
							$xObsFisco->addChild('xTexto', $ObsFisco['coif_obs']);
						}
					}

					$this->setXml($xml);
					//		}
            }

            public function setEmitValues($config) {
            	$xml = $this->getXml();

            	$emitDePara = array(
			'CNPJ' => 'CNPJ',
			'IE' => 'IE',
			'xNome' => 'nome_razao',
			'xFant' => 'fantasia'
			);

			$camposObrigatorios = array(
			//omitted code 3 lines
			);

			$emit = $xml->infCte->addChild('emit');

			foreach($emitDePara as $node => $nodeValue) {
				$config[$nodeValue] = $this->cleaner($config[$nodeValue]);
					
				if($config[$nodeValue]!="") {
					$emit->addChild($node, $config[$nodeValue]);
				} else {
					if(array_key_exists($node, $camposObrigatorios)) {
						throw new Exception($camposObrigatorios[$node]);
					}
				}
			}

			$emitEnderDePara = array(
				'xLgr' => 'logradouro',
				'nro' => 'numero',
				'xCpl' => 'complemento',
				'xBairro' => 'bairro',
				'cMun' => 'cod_municipio',
				'xMun' => 'municipio',
				'UF' => 'UF',
				'fone' => 'fone'
				);
					
				$camposObrigatoriosEnder = array(
				//omitted code 7 lines
				);
					
				$enderEmit = $emit->addChild('enderEmit');
					
				foreach($emitEnderDePara as $node => $nodeValue) {
					$config[$nodeValue] = $this->cleaner($config[$nodeValue]);

					if($config[$nodeValue]!="") {
						$enderEmit->addChild($node, $config[$nodeValue]);
					} else {
						if(array_key_exists($node, $camposObrigatoriosEnder)) {
							throw new Exception($camposObrigatoriosEnder[$node]);
						}
					}
				}
					
				$this->setXml($xml);
            }

            public function setRemValues($config) {
            	$config = $this->limpaEspacos($config);
            	$xml = $this->getXml();

            	$rem = $xml->infCte->addChild('rem');
            	if(strlen($config['cpfcnpj']) == 14) {
            		$rem->addChild('CNPJ', str_pad($config['cpfcnpj'], 14, '0', STR_PAD_LEFT));
            	} else {
            		$rem->addChild('CPF', str_pad($config['cpfcnpj'], 11, '0', STR_PAD_LEFT));
            	}

            	if ( !is_numeric($config['IE']) ) {
            		$rem->addChild('IE', '000000000');
            	} else {
            		$rem->addChild('IE', str_pad($config['IE'], 9, STR_PAD_LEFT));
            	}

            	if ( TIPO_AMBIENTE_CTE == 2 ) {
            		$config['nome'] = 'CT-E EMITIDO EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL';
            		$config['xFant'] = 'CT-E EMITIDO EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL';
            	}

            	$rem->addChild('xNome',$config['nome']);
            	$rem->addChild('xFant', $config['nome']);

            	if (!empty($config['fone'])){
            		$rem->addChild('fone', $config['fone']);
            	}
            	$enderReme = $rem->addChild('enderReme');

            	$enderReme->addChild('xLgr', $config['logradouro']);
            	$enderReme->addChild('nro', $config['numero']);
            	$enderReme->addChild('xCpl', $config['bairro']);
            	$enderReme->addChild('xBairro', $config['bairro']);
            	$enderReme->addChild('cMun', $config['cod_municipio']);
            	$enderReme->addChild('xMun', $config['municipio']);

            	if ( !empty($config['CEP']) ) {
            		$enderReme->addChild('CEP', str_pad($config['CEP'], 8, STR_PAD_LEFT));
            	}

            	$enderReme->addChild('UF', $config['UF']);
            	$enderReme->addChild('cPais', $config['cod_pais']);
            	$enderReme->addChild('xPais', $config['pais']);

            	if ( !empty($config['email']) ) {
            		$rem->addChild('email', $config['email']);
            	}

            	
            	$this->setXml($xml);

            }
             
            public function setDestValues($config) {
            	$xml = $this->getXml();

            	$dest = $xml->infCte->addChild('dest');

            	if(strlen($config['cpfcnpj']) == 14) {
            		$dest->addChild('CNPJ', $config['cpfcnpj']);
            	} else {
            		$dest->addChild('CPF', $config['cpfcnpj']);
            	}

            	if ( !is_numeric($config['IE']) ) {
            		$dest->addChild('IE', '000000000');
            	} else {
            		$dest->addChild('IE', str_pad($config['IE'], 9, STR_PAD_LEFT));
            	}

            	if ( TIPO_AMBIENTE_CTE == 2 ) {
            		$config['nome'] = 'CT-E EMITIDO EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL';
            	}

            	$dest->addChild('xNome', $config['nome']);

            	if( !empty($config['fone']) ) {
            		$dest->addChild('fone', $config['fone']);
            	}

            	$enderDest = $dest->addChild('enderDest');
            	$enderDest->addChild('xLgr', $config['logradouro']);
            	$enderDest->addChild('nro', str_pad($config['numero'], 3, STR_PAD_LEFT));

            	if( !empty($config['complemento']) ) {
            		$enderDest->addChild('xCpl', $config['complemento']);
            	}
            	$enderDest->addChild('xBairro', $config['bairro']);
            	$enderDest->addChild('cMun', $config['cod_municipio']);
            	$enderDest->addChild('xMun', $config['municipio']);

            	if( !empty($config['CEP']) ) {
            		$enderDest->addChild('CEP', str_pad($this->cleaner($config['CEP']), 8, '0', STR_PAD_LEFT));
            	}

            	$enderDest->addChild('UF', $config['UF']);

            	if( !empty($config['cod_pais']) ) {
            		$enderDest->addChild('cPais', $config['cod_pais']);
            	}
            	if( !empty($config['pais']) ) {
            		$enderDest->addChild('xPais', $config['pais']);
            	}

            	if( !empty($config['email']) ) {
            		$dest->addChild('email', $config['email']);
            	}

            

            	$this->setXml($xml);
            }
             
            public function setRecValues($config) {
            	$xml = $this->getXml();

            	$rec = $xml->infCte->addChild('receb');

            	if(strlen($config['cpfcnpj']) == 14) {
            		$rec->addChild('CNPJ', $config['cpfcnpj']);
            	} else {
            		$rec->addChild('CPF', $config['cpfcnpj']);
            	}

            	if ( !is_numeric($config['IE']) ) {
            		$rec->addChild('IE', '000000000');
            	} else {
            		$rec->addChild('IE', str_pad($config['IE'], 9, STR_PAD_LEFT));
            	}

            	if ( TIPO_AMBIENTE_CTE == 2 ) {
            		$config['nome'] = 'CT-E EMITIDO EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL';
            	}
            	$rec->addChild('xNome', $config['nome']);

            	if( !empty($config['fone']) ) {
            		$rec->addChild('fone', $config['fone']);
            	}
            	$enderRec = $rec->addChild('enderReceb');
            	$enderRec->addChild('xLgr', $config['logradouro']);
            	$enderRec->addChild('nro', str_pad($config['numero'], 3, STR_PAD_LEFT));

            	if( !empty($config['complemento']) ) {
            		$enderRec->addChild('xCpl', $config['complemento']);
            	}
            	$enderRec->addChild('xBairro', $config['bairro']);
            	$enderRec->addChild('cMun', $config['cod_municipio']);
            	$enderRec->addChild('xMun', $config['municipio']);

            	if( !empty($config['CEP']) ) {
            		$enderRec->addChild('CEP', $config['CEP']);
            	}

            	$enderRec->addChild('UF', $config['UF']);

            	if( !empty($config['cod_pais']) ){
            		$enderRec->addChild('cPais', $config['cod_pais']);
            	}

            	if( empty($config['pais']) ) {
            		$enderRec->addChild('xPais', $config['pais']);
            	}

            	if( !empty($config['email']) ) {
            		$rec->addChild('email', $config['email']);
            	}
            	$this->setXml($xml);
            }

            public function setExpValues($config) {
            	$xml = $this->getXml();
            	$exp = $xml->infCte->addChild('exped');

            	if(strlen($config['cpfcnpj']) == 14) {
            		$exp->addChild('CNPJ', $config['cpfcnpj']);
            	} else {
            		$exp->addChild('CPF', $config['cpfcnpj']);
            	}

            	if ( !is_numeric($config['IE']) ) {
            		$exp->addChild('IE', '000000000');
            	} else {
            		$exp->addChild('IE', str_pad($config['IE'], 9, STR_PAD_LEFT));
            	}

            	if ( TIPO_AMBIENTE_CTE == 2 ) {
            		$config['nome'] = 'CT-E EMITIDO EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL';
            	}
            	$exp->addChild('xNome', $config['nome']);

            	$config['fone'] = $this->cleaner($config['fone']);

            	if( !empty($config['fone']) ) {
            		$exp->addChild('fone', $config['fone']);
            	}

            	$enderExp = $exp->addChild('enderExped');
            	$enderExp->addChild('xLgr', $config['logradouro']);
            	$enderExp->addChild('nro', str_pad($config['numero'], 3, STR_PAD_LEFT));

            	if($this->cleaner($config['complemento']))
            	$enderExp->addChild('xCpl', $config['complemento']);

            	$enderExp->addChild('xBairro', $config['bairro']);
            	$enderExp->addChild('cMun', $config['cod_municipio']);
            	$enderExp->addChild('xMun', $config['municipio']);

            	if($this->cleaner($config['CEP']))
            	$enderExp->addChild('CEP', $config['CEP']);

            	$enderExp->addChild('UF', $config['UF']);

            	if($this->cleaner($config['cod_pais'])!="")
            	$enderExp->addChild('cPais', $config['cod_pais']);

            	if($this->cleaner($config['pais'])!="")
            	$enderExp->addChild('xPais', $config['pais']);

            	if( !empty($config['email']) ) {
            		$exp->addChild('email', $config['email']);
            	}

            	$this->setXml($xml);
            }

            
            public function setInfCteComp($config) {
            	$xml = $this->getXml();

            	if($config['chave']!="") {
            		$infCteComp = $xml->infCte->addChild('infCteComp');
            		$infCteComp->addChild('chave', $config['chave']);
            	}

            	$this->setXml($xml);
            }

            public function setInfCteAnu($config) {
            	$xml = $this->getXml();

            	if($config['chCte']!="" && $config['dEmi']!="") {
            		$infCteAnu = $xml->infCte->addChild('infCteAnu');
            		$infCteAnu->addChild('chCte', $config['chCte']);
            		$infCteAnu->addChild('dEmi', $config['dEmi']);
            	}

            	$this->setXml($xml);
            }

            public function setAutXML($config) {
            	$xml = $this->getXml();

            	foreach($config as $cda) {
            		$autXML = $xml->infCte->addChild('autXML');
            		 
            		if(strlen($cda['cda_cpf_cnpj_autori']) == 14)
            		$autXML->addChild('CNPJ', $cda['cda_cpf_cnpj_autori']);
            		else
            		$autXML->addChild('CPF', $cda['cda_cpf_cnpj_autori']);
            	}

            	$this->setXml($xml);
            }

            public function setModalRodoviario($config) {
            	$xml = $this->getXml();
            	$rodo = $xml->infCte->infCTeNorm->infModal->addChild('rodo');
            	$modal = $config['rodo'];

            	$rodo->addChild('RNTRC', $modal['RNTRC']);
            	$rodo->addChild('dPrev', $modal['dPrev']);
            	$rodo->addChild('lota', $modal['lota']);

            	if( !empty($modal['CIOT']) ) {
            		$rodo->addChild('CIOT', str_pad($this->cleaner($modal['CIOT']), 12, STR_PAD_LEFT));
            	}

            	if(isset($modal['occ']) && count($modal['occ']) > 0) {
            		foreach($modal['occ'] as $occ) {
            			$xocc = $rodo->addChild('occ');

            			$xocc->addChild('serie', $occ['occ_serie']);
            			$xocc->addChild('nOcc', $occ['occ_numero']);
            			$xocc->addChild('dEmi', $occ['occ_demi']);

            			$emiOcc = $xocc->addChild('emiOcc');

            			$emiOcc->addChild('CNPJ', $occ['occ_cnpj']);

            			if($this->cleaner($occ['occ_cint'])!="")
            			$emiOcc->addChild('cInt', $occ['occ_cint']);

            			$emiOcc->addChild('IE', $occ['occ_ie']);
            			$emiOcc->addChild('UF', $occ['Uf']['uf_sigla']);

            			if($this->cleaner($occ['occ_fone'])!="")
            			$emiOcc->addChild('fone', $occ['occ_fone']);
            		}
            	}

            	if(isset($modal['valePed']) && count($modal['valePed']) > 0) {
            		foreach($modal['valePed'] as $valePed) {
            			$xValePed = $rodo->addChild('valePed');

            			$xValePed->addChild('CNPJForn', $valePed['vpd_cnpj_forn']);
            			$xValePed->addChild('nCompra', $valePed['vpd_ncompra']);

            			if($this->cleaner($valePed['vpd_cnpj_pg'])!="")
            			$xValePed->addChild('CNPJPg', $valePed['vpd_cnpj_pg']);

            			$xValePed->addChild('vValePed', $valePed['vpd_valor_vale_pedagio']);
            		}
            	}

            	if(isset($modal['veic']) && count($modal['veic']) > 0) {
            		foreach($modal['veic'] as $confVeic){
            			$veic = $rodo->addChild('veic');

            			if($this->cleaner($confVeic['CteVeiculo']['cve_cod_interno'])!="")
            			$veic->addChild('cInt', $confVeic['CteVeiculo']['cve_cod_interno']);

            			$veic->addChild('RENAVAM', $confVeic['CteVeiculo']['cve_renavam']);
            			$veic->addChild('placa', str_replace(' ', '', $confVeic['CteVeiculo']['cve_placa'])); // remove qualquer espa\E7o branco
            			$veic->addChild('tara', $confVeic['CteVeiculo']['cve_tara']);
            			$veic->addChild('capKG', $confVeic['CteVeiculo']['cve_capacidade_kg']);
            			$veic->addChild('capM3', $confVeic['CteVeiculo']['cve_capacidade_mc']);
            			$veic->addChild('tpProp', $confVeic['CteVeiculo']['cve_proprietario']);
            			$veic->addChild('tpVeic', $confVeic['CteVeiculo']['CteVeiculoTipo']['cvt_codigo']);
            			$veic->addChild('tpRod', $confVeic['CteVeiculo']['CteVeiculoRodado']['cvr_codigo']);
            			$veic->addChild('tpCar', $confVeic['CteVeiculo']['CteVeiculoCarroceria']['cvc_codigo']);
            			$veic->addChild('UF', $confVeic['CteVeiculo']['Uf']['uf_sigla']);

            			if($confVeic['CteVeiculo']['cve_proprietario'] != 'P') {
            				$prop = $rodo->addChild('prop');
            				$infoVeicProp = CteVeiculo::consultaVeiculo($confVeic['CteVeiculo']['cve_id']);
            				 
            				$veicProp = reset($infoVeicProp['CteEmpresaVeiculoProprietarioAtrb']);
            				$veicPropTipo = $veicProp['CteEmpresaVeiculoProprietarioTipo'];
            				 
            				if($veicProp['evpa_tipo_pessoa'] == 'FIS'){
            					$prop->addChild('CPF', $veicProp['evpa_cpf_cnpj']);
            				} else {
            					$prop->addChild('CNPJ', $veicProp['evpa_cpf_cnpj']);
            				}
            				$prop->addChild('RNTRC', $veicProp['evpa_rntrc']);
            				$prop->addChild('xNome', $veicProp['evpa_nome_razao']);
            				$prop->addChild('IE', $veicProp['evpa_rg_ie']);
            				$prop->addChild('UF', $veicProp['Uf']['uf_sigla']);
            				$prop->addChild('tpProp', $veicPropTipo['evpt_codigo']);
            			}
            		}
            	}

            	if(isset($modal['lacre']) && count($modal['lacre']) > 0) {
            		foreach($modal['lacre'] as $infLacre) {
            			$lacRodo = $rodo->addChild('lacRodo');

            			$lacRodo->addChild('nLacre', $infLacre['cmrl_num_lacre']);
            		}
            	}

            	if(isset($modal['moto']) && count($modal['moto']) > 0) {
            		foreach($modal['moto'] as $infMoto) {
            			$moto = $rodo->addChild('moto');

            			$moto->addChild('xNome', $infMoto['CteMotorista']['mot_nome']);
            			$moto->addChild('CPF', $infMoto['CteMotorista']['mot_cpf']);
            		}
            	}

            	$this->setXml($xml);
            }

            public function setVPrestValues($config) {
            	$xml = $this->getXml();

            	$vPrest = $xml->infCte->addChild('vPrest');

            	$vPrest->addChild('vTPrest', empty($config['vTPrest'])? '0.00' : $config['vTPrest']);
            	$vPrest->addChild('vRec', empty($config['vRec'])? '0.00' : $config['vRec']);

            	if(isset($config['Comp']) && count($config['Comp']) > 0) {
            		// \E8 obrigat\F3rio ter um elemento filho do Comp para emitir a nota
            		foreach($config['Comp'] as $Comp) {
            			// \E8 necess\E1rio fazer a verifica\E7\E3o para n\E3o ocorrer erros no xml
            			if ( !empty($Comp['cic_nome_componente']) && !empty($Comp['cic_valor_componente']) ){
            				$xComp = $vPrest->addChild('Comp');
            				// verificar se esse campo \E9 vazio caso contr\E1rio ocorrer\E1 um erro no xml
            				$xComp->addChild('xNome', (empty($Comp['cic_nome_componente']))? 'ND' : $Comp['cic_nome_componente']);
            				$xComp->addChild('vComp', (empty($Comp['cic_valor_componente']))? '00.00' : $Comp['cic_valor_componente']); //13,2 ER25 15 posi\E7\F5es, sendo 13 inteiras e 2 decimais.
            			}
            		}
            	}

            	$this->setXml($xml);
            }

            public function setImpValues($config) {
            	$xml = $this->getXml();

            	$imp = $xml->infCte->addChild('imp');

            	$ICMS = $imp->addChild('ICMS');

            	switch($config['CST']) {
            		case '00' :
            			$ICMS00 = $ICMS->addChild('ICMS00');

            			$ICMS00->addChild('CST', $config['CST']);
            			$ICMS00->addChild('vBC', $config['vBC']);
            			$ICMS00->addChild('pICMS', $config['pICMS']);
            			$ICMS00->addChild('vICMS', $config['vICMS']);
            			break;
            		case '20' :
            			$ICMS20 = $ICMS->addChild('ICMS20');
            			$ICMS20->addChild('CST', $config['CST']);
            			$ICMS20->addChild('pRedBC', $config['pRedBC']);
            			$ICMS20->addChild('vBC', $config['vBC']);
            			$ICMS20->addChild('pICMS', $config['pICMS']);
            			$ICMS20->addChild('vICMS', $config['vICMS']);
            			break;

            		case '40' :
            		case '41' :
            		case '51' :
            			$ICMS45 = $ICMS->addChild('ICMS45');
            			$ICMS45->addChild('CST', $config['CST']);
            			break;

            		case '60' :
            			$ICMS60 = $ICMS->addChild('ICMS60');

            			$ICMS60->addChild('CST', $config['CST']);
            			$ICMS60->addChild('vBCSTRet', $config['vBCSTRet']);
            			$ICMS60->addChild('vICMSSTRet', $config['vICMSSTRet']);
            			$ICMS60->addChild('pICMSSTRet', $config['pICMSSTRet']);
            			$ICMS60->addChild('vCred', $config['vCred']);
            			break;

            		case '90' :
            			$ICMS90 = $ICMS->addChild('ICMS90');
            			$ICMS90->addChild('CST', $config['CST']);
            			$ICMS90->addChild('pRedBC', $config['pRedBC']);
            			$ICMS90->addChild('vBC', $config['vBC']);
            			$ICMS90->addChild('pICMS', $config['pICMS']);
            			$ICMS90->addChild('vICMS', $config['Vicms']);
            			$ICMS90->addChild('vCred', $config['vCred']);
            			break;

            		case 'SN' :
            			$ICMSSN = $ICMS->addChild('ICMSSN');
            			$ICMSSN->addChild('indSN', 1);
            			break;

            		default: // Default ser\E1 outra UF
            			$ICMSOutraUF = $ICMS->addChild('ICMSOutraUF');

            			$ICMSOutraUF->addChild('CST', '90');
            			$ICMSOutraUF->addChild('pRedBCOutraUF', $config['pRedBCOutraUF']);
            			$ICMSOutraUF->addChild('vBCOutraUF', $config['vBCOutraUF']);
            			$ICMSOutraUF->addChild('pICMSOutraUF', $config['pICMSOutraUF']);
            			$ICMSOutraUF->addChild('vICMSOutraUF', $config['vICMSOutraUF']);
            	}

            	if ( !empty($config['vTotTrib']) ) {
            		$imp->addChild('vTotTrib', $config['vTotTrib']);
            	}

            	if ( !empty($config['infAdFisco']) ) {
            		$imp->addChild('infAdFisco', $config['infAdFisco']);
            	}

            	$this->setXml($xml);
            }

            public function setInfCTeNormValues($config) {
            	$xml = $this->getXml();

            	$infCTeNorm = $xml->infCte->addChild('infCTeNorm');
            	$dInfCarga = $config['infCarga'];

            	$infCarga = $infCTeNorm->addChild('infCarga');

            	if( $this->cleaner( $dInfCarga['vCarga']) != '' ){
            		$infCarga->addChild('vCarga', $dInfCarga['vCarga']);
            	}

            	if ( empty($dInfCarga['proPred']) ){
            		$dInfCarga['proPred'] = 'N/D';
            	}
            	$infCarga->addChild('proPred', $dInfCarga['proPred']);

            	if( $this->cleaner($dInfCarga['xOutCat']) != '') {
            		$infCarga->addChild('xOutCat', $dInfCarga['xOutCat']);
            	}

            	if(count($config['infQ']) > 0) {
            		foreach($config['infQ'] as $dInfQ) {
            			$infQ = $infCarga->addChild('infQ');

            			$infQ->addChild('cUnid', str_pad($dInfQ['cnc_codigo_unidade_medida'], 2, '0', STR_PAD_LEFT)/*'01'*/);
            			$infQ->addChild('tpMed', $dInfQ['cnc_tipo_medida']/*'PESO BRUTO'*/);
            			$infQ->addChild('qCarga', $dInfQ['cnc_valor_componente']/*'12345678911.1154'*/);
            		}
            	}

  
            	$documentos = $config['infDoc'];
            	if ( isset($documentos) && count($documentos) > 0){

            		$infDoc = $infCTeNorm->addChild('infDoc');
            		foreach($documentos as $dInfDoc) {
            			
            			switch($dInfDoc['cnf_tipo']) {
            				case 1 :
            					$infNF = $infDoc->addChild('infNF');
            					$infNF->addChild('nRoma', str_pad($dInfDoc['cnf_numero_romaneio'], 20, STR_PAD_LEFT)/*'12315646156189189111'*/);
            					$infNF->addChild('nPed', str_pad($dInfDoc['cnf_numero_pedido'], 20, STR_PAD_LEFT)/*'12315646156189189111'*/);
            					$infNF->addChild('mod', '01'/*$dInfDoc['cnf_modelo_nota']'04'*/);	//Preencher com:01 - NF Modelo 01/1A e Avulsa;04 - NF de Produtor
            					$infNF->addChild('serie', str_pad($dInfDoc['cnf_serie'], 3, STR_PAD_LEFT)/*'1'*/);

            					$infNF->addChild('nDoc', str_pad($dInfDoc['cnf_numero'], 20, STR_PAD_LEFT)/*'1'*/);

            					$infNF->addChild('dEmi', ($dInfDoc['cnf_data_emissao'] == '---')? $dInfDoc['cnf_data_emissao'] : date('Y-m-d')); /
            					$infNF->addChild('vBC', ($dInfDoc['cnf_valor_base_icms'])? $dInfDoc['cnf_valor_base_icms'] : '0.00'/*'8047.11'*/);
            					$infNF->addChild('vICMS', ($dInfDoc['cnf_total_icms'])? $dInfDoc['cnf_total_icms'] : '0.00'/*'965.65'*/);
            					$infNF->addChild('vBCST', ($dInfDoc['cnf_valor_base_icms_st'])? $dInfDoc['cnf_valor_base_icms_st'] : '0.00'/*'123.00'*/);
            					$infNF->addChild('vST', ($dInfDoc['cnf_valor_icms_st'])? $dInfDoc['cnf_valor_icms_st'] : '0.00'/*'123.00'*/);
            					$infNF->addChild('vProd', ($dInfDoc['cnf_valor_total_produtos'])? $dInfDoc['cnf_valor_total_produtos'] : '0.00'/*'123.00'*/);
            					$infNF->addChild('vNF', ($dInfDoc['cnf_valor_total_nf'])? $dInfDoc['cnf_valor_total_nf'] : '0.00'/*'123.00'*/);
            					$infNF->addChild('nCFOP', ($dInfDoc['cnf_cfop_prodominante'])? $dInfDoc['cnf_cfop_prodominante'] : '5353'/*'5353'*/);

            					if ( !empty($dInfDoc['cnf_peso_total']) ){
            						$infNF->addChild('nPeso', $dInfDoc['cnf_peso_total']);
            					}

            					if ( !empty($dInfDoc['cnf_suframa']) ) {
            						$infNF->addChild('PIN', str_pad($dInfDoc['cnf_suframa'], 9, STR_PAD_LEFT/*'123'*/));
            					}

            					if ( !empty($dInfDoc['cnf_data_prevista_entrega']) && $dInfDoc['cnf_data_prevista_entrega'] != '---' ) { 
            						$infNF->addChild('dPrev', $dInfDoc['cnf_data_prevista_entrega']);
            					}
            					break;
            				case 2 :
            					$infNFe = $infDoc->addChild('infNFe');
            					$infNFe->addChild('chave', $dInfDoc['cnf_eletronica_chave_acesso']);

            					if ( !empty($dInfDoc['cnf_eletronica_suframa']) ){
            						$infNFe->addChild('PIN', str_pad($dInfDoc['cnf_eletronica_suframa'], 9, STR_PAD_LEFT));
            					}

            					if ( !empty($dInfDoc['cnf_eletronica_data_prevista']) && $dInfDoc['cnf_eletronica_data_prevista'] != '---' ){ 
            						$infNFe->addChild('dPrev', $dInfDoc['cnf_eletronica_data_prevista']);
            					}

            					$unidadeTransporteNFe = $dInfDoc['CteInfNotaFiscalUnidadeTransporte'];
            					if(count($unidadeTransporteNFe) > 0) {
            						foreach($unidadeTransporteNFe as $dInfUnidTranspNFe) {
            							$infUnidTranspNFe = $infNFe->addChild('infUnidTransp');

            							$infUnidTranspNFe->addChild('tpUnidTransp', $dInfUnidTranspNFe['cut_tipo_unidade_transportadora']);
            							$infUnidTranspNFe->addChild('idUnidTransp', $dInfUnidTranspNFe['cut_identificacao_unidade_transportadora']);

            							$lacresUnidTranspNFe = $dInfUnidTranspNFe['CteInfNotaFiscalUnidadeTransporteLacre'];

            							if(count($lacresUnidTranspNFe) > 0) {
            								foreach($lacresUnidTranspNFe as $dLacUnidTranspNFe) {
            									$lacUnidTranspNFe = $infUnidTranspNFe->addChild('lacUnidTransp');

            									$lacUnidTranspNFe->addChild('nLacre', $dLacUnidTranspNFe['ctl_numero_lacre']);
            								}
            							}

            							$unidadesDeCargaTransNFe = $dInfUnidTranspNFe['CteInfNotaFiscalUnidadeCarga'];

            							if(count($unidadesDeCargaTransNFe) > 0) {
            								foreach($unidadesDeCargaTransNFe as $dInfUnidCargaTranspNFe) {
            									$infUnidCargaTranspNFe = $infUnidTranspNFe->addChild('infUnidCarga');

            									$infUnidCargaTranspNFe->addChild('tpUnidCarga', $dInfUnidCargaTranspNFe['cuc_tipo_unidade_carga']);
            									$infUnidCargaTranspNFe->addChild('idUnidCarga', $dInfUnidCargaTranspNFe['cuc_identificacao_unidade_carga']);

            									$lacresUnidCargaTranspNFe = $dInfUnidCargaTranspNFe['CteInfNotaFiscalUnidadeCargaLacre'];

            									if(count($lacresUnidCargaTranspNFe) > 0) {
            										foreach($lacresUnidCargaTranspNFe as $dLacUnidCargaTranspNFe) {
            											$lacUnidCargaTranspNFe = $infUnidCargaTranspNFe->addChild('lacUnidCarga');

            											$lacUnidCargaTranspNFe->addChild('nLacre', $dLacUnidCargaTranspNFe['ccl_numero_lacre']);
            										}
            									}

            									$infUnidCargaTranspNFe->addChild('qtdRat', $dInfUnidCargaTranspNFe['cuc_qtd_rateado']);
            								}
            							}
            						}
            					}
            					break;
            			}
            	
            	foreach($config['seg'] as $dSeg) {
            		$seg = $infCTeNorm->addChild('seg');
            		 
            		$seg->addChild('respSeg', $dSeg['cns_responsavel_seguro']/*'4'*/);
            		 
            		if($this->cleaner($dSeg['cns_nome_seguradora'])!="") {
            			$seg->addChild('xSeg', $dSeg['cns_nome_seguradora']/*'Zurich'*/);
            		}

            		if($this->cleaner($dSeg['cns_numero_apolice'])!="") {
            			$seg->addChild('nApol', $dSeg['cns_numero_apolice']);
            		}
            		 
            		if($this->cleaner($dSeg['cns_numero_averbacao'])!="") {
            			$seg->addChild('nAver', str_pad($dSeg['cns_numero_averbacao'], 20, STR_PAD_LEFT));
            		}
            		// Padr\E3o da carga \E9 13,2
            		if($this->cleaner($dSeg['cns_valor_carga_efeito_averbacao'])!="" && $dSeg['cns_valor_carga_efeito_averbacao'] != '000') {
            			$seg->addChild('vCarga', $dSeg['cns_valor_carga_efeito_averbacao']/*'47000.00'*/);
            		}
            	}


            	$infModal = $infCTeNorm->addChild('xs:infModal', $config['infModal']['xs:any']->asXML());
            	$infModal->addAttribute('versaoModal', $config['infModal']['versaoModal']);

            	foreach($config['peri'] as $dPeri) {
            		$peri = $infCTeNorm->addChild('peri');

            		$peri->addChild('nONU', $dPeri['cno_numero_onu']);
            		$peri->addChild('xNomeAE', $dPeri['cno_nome_apropriado_embarque_produto']);
            		$peri->addChild('xClaRisco', $dPeri['cno_classe_subclasse']);
            		$peri->addChild('grEmb', $dPeri['cno_grupo_embarque']);
            		$peri->addChild('qTotProd', $dPeri['cno_quantidade_total_produto']);
            		$peri->addChild('qVolTipo', $dPeri['cno_quantidade_tipo_volume']);
            		$peri->addChild('pontoFulgor', $dPeri['cno_ponto_fulgor']);
            	}

            	// Se existir carros novos \E9 obrigat\F3rio informar os campos abaixo
            	if ( count($config['veicNovos']) > 0 ) {
            		foreach($config['veicNovos'] as $dVeicNovos) {
            			$veicNovos = $infCTeNorm->addChild('veicNovos');

            			$veicNovos->addChild('chassi', $dVeicNovos['cvt_chassi_veiculo']);
            			$veicNovos->addChild('cCor', $dVeicNovos['cvt_cor_veiculo']);
            			$veicNovos->addChild('xCor', $dVeicNovos['cvt_descricao_cor']);
            			$veicNovos->addChild('cMod', $dVeicNovos['cvt_codigo_marca_modelo']);
            			$veicNovos->addChild('vUnit', $dVeicNovos['cvt_valor_unitario_veiculo']);
            			$veicNovos->addChild('vFrete', $dVeicNovos['cvt_frete_unitario']);
            		}
            	}

            	$this->setXml($xml);
            }

            public function save($cte_id) {
            	try {
            		$xml = $this->getXml();

            		$cteXml = CteXmlTable::getInstance()->findOneByCteId($cte_id);
            		 
            		if(!$cteXml instanceof CteXml)
            		$cteXml = new CteXml();
            		 
            		$cteXml->ctx_xml = $xml;
            		$cteXml->cte_id = $cte_id;
            		$cteXml->ctx_qem = 1;
            		 
            		$cteXml->save();

            		return $this;
            	} catch(Exception $e) {
            		exit($e->getMessage());
            	}
            }
          

            private function limpaEspacos($arranjo) {
            	foreach($arranjo as $indice => $valor) {
            		if(!is_array($valor)) {
            			$arranjo[$indice] = trim($valor);
            		}
            	}
            	return $arranjo;
            }

            private function cleaner($str) {
            	$str = trim($str);
            	return $str;
            }

            public function calculaDv($cCT) {
            	// omitted code with 11 lines
            }
             
            public function calculaChaveAcesso($cUF, $AAMM, $CNPJ, $mod, $serie, $nCT, $tpEmis, $cCT) {
		// omitted code with 20 lines
            }
}

Crying, Thinking and Planning

As you can see now we have a class with 1054 lines and our challenge is to transform it into testable code. As a first step, I’d recommend you to cry and as a second step, we can start to think about what the code does and how can we break it down in pieces.

In our code we have a couple of methods that can be separated into classes instead of methods because they have their behavior for example the method setCompl($config) will add to our XML a bunch of nodes depending on some conditions in this case is used a switch statement either a couple of if’s.

See here an example of code from a legacy application 😲
class Compl {
public function setCompl($config) {
            	$xml = $this->getXml();

            	$compl = $xml->infCte->addChild('compl');

            	$confComplPrimeiroBloco = array(
					'xCaracAd', 
					'xCaracSer', 
					'xEmi'
					);

					foreach($confComplPrimeiroBloco as $node) {
						$config[$node] = $this->cleaner($config[$node]);
						if($config[$node]!="")
						$compl->addChild($node, $config[$node]);
					}

					if($config['fluxo']['xOrig'] != "" || $config['fluxo']['pass'] != "") {
						$fluxo = $compl->addChild('fluxo');
					}

					if(!empty($config['fluxo']['xOrig'])) {
						$fluxo->addChild('xOrig', $config['fluxo']['xOrig']);
					}

					if($config['fluxo']['pass'] != "" && count($config['fluxo']['pass']) > 0) {
						foreach($config['fluxo']['pass'] as $pass) {
							$xpass = $fluxo->addChild('pass');

							$nodesPass = array(
						'xPass' => 'cdp_sigla_aeroporto_passagem',
						'xDest' => 'cdp_sigla_aeroporto_destino',
						'xRota' => 'cdp_codigo_rota_entrega'
						);
							
						foreach($nodesPass as $nodePass => $nodePassIndex) {
							$pass[$nodePassIndex] = $this->cleaner($pass[$nodePassIndex]);
							if($pass[$nodePassIndex]!="")
							$xpass->addChild($nodePass, $pass[$nodePassIndex]);
						}
						}
					}

					if(count($config['Entrega'])) {
						$Entrega = $compl->addChild('Entrega');

						$config['Entrega']['tpPer'] = $this->cleaner($config['Entrega']['tpPer']);

						if($config['Entrega']['tpPer']=="")

						switch($config['Entrega']['tpPer']) {
							case '0' :
								$semData = $Entrega->addChild('semData');
								$semData->addChild('tpPer', $config['Entrega']['tpPer']);
								break;
							case '1' :
							case '2' :
							case '3' :
								$comData = $Entrega->addChild('comData');
								$comData->addChild('tpPer', $config['Entrega']['tpPer']);
								$config['Entrega']['dProg'] = $this->cleaner($config['Entrega']['dProg']);

								if($config['Entrega']['dProg']!="")
								$comData->addChild('tpPer', $config['Entrega']['dProg']);
								
								break;
							case '4' :
								$noPeriodo = $Entrega->addChild('noPeriodo');
								$noPeriodo->addChild('tpPer', $config['Entrega']['tpPer']);
								$config['Entrega']['dtIni'] = $this->cleaner($config['Entrega']['dtIni']);
								if($config['Entrega']['dtIni']!="")
								$noPeriodo->addChild('dtIni', $config['Entrega']['dtIni']);
								
								$config['Entrega']['dtFim'] = $this->cleaner($config['Entrega']['dtFim']);
								if($config['Entrega']['dtFim']!="")
								$noPeriodo->addChild('dtFim', $config['Entrega']['dtFim']);
								
								break;
						}

						$config['Entrega']['tpHor'] = $this->cleaner($config['Entrega']['tpHor']);

						switch($config['Entrega']['tpHor']) {
							case '0' :
								$semHora = $Entrega->addChild('semHora');
								$semHora->addChild('tpHor', $config['Entrega']['tpHor']);
								break;
							case '1' :
							case '2' :
							case '3' :
								$comHora = $Entrega->addChild('comHora');
								$comHora->addChild('tpHor', $config['Entrega']['tpHor']);
								$config['Entrega']['hProg'] = $this->cleaner($config['Entrega']['hProg']);
								if($config['Entrega']['hProg']!="")
								$comHora->addChild('tpHor', $config['Entrega']['hProg']);
								break;
							case '4' :
								$noInter = $Entrega->addChild('noInter');
								$noInter->addChild('tpHor', $config['Entrega']['tpHor']);
								$config['Entrega']['hIni'] = $this->cleaner($config['Entrega']['hIni']);
								if($config['Entrega']['hIni']!="")
								$noInter->addChild('hIni', $config['Entrega']['hIni']);
								$config['Entrega']['hFim'] = $this->cleaner($config['Entrega']['hFim']);
								if($config['Entrega']['hFim']!="")
								$noInter->addChild('hFim', $config['Entrega']['hFim']);
								break;
						}
					}

					if ( !empty($config['xObs']) ){
						$compl->addChild('xObs', $config['xObs']);
					}

					if(isset($config['ObsCont']) && count($config['ObsCont']) > 0) {
						foreach($config['ObsCont'] as $ObsCont) {
							$xObsCont = $compl->addChild('ObsCont');

							$ObsCont['coic_identificador'] = $this->cleaner($ObsCont['coic_identificador']);
							if($ObsCont['coic_identificador']!="")
							$xObsCont->addChild('xCampo', $ObsCont['coic_identificador']);
							$ObsCont['coic_obs'] = $this->cleaner($ObsCont['coic_obs']);
							if($ObsCont['coic_obs']!="")
							$xObsCont->addChild('xTexto', $ObsCont['coic_obs']);
						}
					}

					if(isset($config['ObsFisco']) && count($config['ObsFisco']) > 0) {
						foreach($config['ObsFisco'] as $ObsFisco) {
							$xObsFisco = $compl->addChild('ObsFisco');

							$ObsFisco['coif_identificador'] = $this->cleaner($ObsFisco['coif_identificador']);
							if($ObsFisco['coif_identificador']!="")
							$xObsFisco->addChild('xCampo', $ObsFisco['coif_identificador']);
							$ObsFisco['coif_obs'] = $this->cleaner($ObsFisco['coif_obs']);
							if($ObsFisco['coif_obs']!="")
							$xObsFisco->addChild('xTexto', $ObsFisco['coif_obs']);
						}
					}

					$this->setXml($xml);
					//		}
            }
}

It is much better now, isn’t it? We’ve got one class with one responsibility and very tiny just 146 lines although this class we have just created could be improved as well it is a subject to other posts. So we got what we need to do and we have a plan already:

  1. Analyze the methods
  2. Extract and create new classes

Our last step before going to the unit test is to substitute the source code to use or new class instead of the current code let’s find where is the setComple($config) and switch our code.

public function setIdeValues($config, $Cte) {
//omitted code
}

public function setCompl($config) {
            	$newCode = new Compl();
		$newCode->setCompl($config);
}

public function setEmitValues($config) {
//omitted code
}

3. Substitute legacy code to your new code

Now we should test our code to see if** it’s still working**, once we have this confirmation we can now create our unit tests and repeat the cycle. As you start refactoring all the legacy using those steps you’ll start to have your source code with better quality, maintainability and of course testability.

It is hard

It is not easy to restructure all the legacy with new code but the result is amazing. You can follow the ideology of baby steps in this refactor as well so as you change the legacy to the new code you test to see if everything is the same. The trick here is to be patient and change piece by piece. I tried to show one single way of doing it but on the internet, you can find thousands.

  1. Analyze the methods
  2. Extract and create new classes 3. Substitute legacy code with your new code
  3. Make sure everything is working 5. Create your unit tests

References

  1. [1]P. M. Jones, Modernizing Legacy Applications in PHP. Packt Publishing Ltd, 2016.

Resources

Changelog

  • Nov 30, 2023 - Added “How to use TDD in Legacy Projects - Tech excellence” as a resource