Evet bu aralar parserlar ile boğuşuyorum kendi çapımda ufak bir dil yapmaya çalışıyorum. Programlamlama dillerini kullanması kolay ama yapması gerçekten zormuş ilk olarak onu söyleyebilirim. Örnek bir parser bulup nasıl yapıldığı hakkında fikir edinmek için onu inceliyordum.Kodu çok karmaşık ve anlaması çok zor olduğu için önce testlerin sağlamlığından emin olana kadar Unit Test hazırladım. Ardından kodu daha okunabilir,anlaşılabilir olması,ve code smell’lerden kurtulmak için refactoring yaparım.Bunu yaparken aşağıdaki gibi bir kod ile karşılaştım.Aşağıdaki kodu öncelikle biraz inceleyin bir problem görebilecekmisiniz?
private double atom() throws InterpreterException {
double result = 0.0;
if (tokenizer.getTokenType() == TokenTypes.NUMBER){
try{
result = Double.parseDouble(tokenizer.getToken());
}
catch (NumberFormatException exc){
throw new InterpreterException("Syntax Error :" + exc.getMessage());
}
tokenizer.obtainNextToken();
}
else if (tokenizer.getTokenType() == TokenTypes.VARIABLE){
result = getValueOfVariable(tokenizer.getToken());
tokenizer.obtainNextToken();
}
else
throw new InterpreterException("Syntax Error");
return result;
}
Şimdi yukarıdaki koda baktığınızda ilk başta büyük bir problem gözünüze çarpmıyo olabilir benimde çarpmıyordu çünkü. Fakat biraz daha incelediğimde beni rahatsız eden bir kötü kod barındırdığını farkettim. Şimdi if-else yapılarını beraberce inceleyelim. İlk if yapısına baktığımızda Token tipinin numara olup olmadığını kontrol ediyor. Eğer numaraysa Tokeni double çevirip sonucu üretiyor ve bir sonraki tokeni alıyor. İkinci else if yapısına baktığımızda tokenin değişken olup olmadığını kontrol ediyor. Ardından değişken ise değerini alıp sonucu üretiyor ve burada da bir sonraki tokeni alıyor.Son olaral eğer hiçbiri değilse hata fırlatıyor.Yani değişken ya da numara değilse hata fırlatıyor.
Şimdi buradaki problem biraz zor farkedilse de if-else yapıları içerisinde tekrarlayan kod içeriyor.Yukarıda açıklamada farkettiyseniz Eğer token değişken ya da numara ise bir sonraki tokeni alma işlemi ikisinde de yapılıyor.Son else yapısında bu yapılmamış aslında son else ilk başta yapılması gereken bir hata kontrolü.Hani hata kontrolünü başa alırsak bu tekrar daha bariz bir şekilde ortaya çıkacaktır. Kodu aşağıdaki gibi düzenleyip hata kontrolünü başa alalım. Ve tekrar içeren yerleri işaretleyelim.
private double atom(){
double result = 0.0;
if (tokenizer.getTokenType() != TokenTypes.NUMBER && tokenizer.getTokenType() != TokenTypes.VARIABLE)
throw new InterpreterException("Syntax Error");
if (tokenizer.getTokenType() == TokenTypes.NUMBER){
try{
result = Double.parseDouble(tokenizer.getToken());
}
catch (NumberFormatException exc){
throw new InterpreterException("Syntax Error : " + exc.getMessage());
}
tokenizer.obtainNextToken();
}
else if (tokenizer.getTokenType() == TokenTypes.VARIABLE)
{
result = getValueOfVariable(tokenizer.getToken());
tokenizer.obtainNextToken();
}
return result;
}
Şimdi yukarıdaki koda baktığınızda kod tekrarını daha kolay görebilirsiniz. Tekrar olan yerleri kırmızı içinde görüyorsunuz.Şimdi tekrarlardan kurtulup kodu daha iyi hale getirmek için aşağıdaki gibi tekrar refactoring yapıyoruz.
private double atom(){
double result = 0.0;
if (tokenizer.getTokenType() != TokenTypes.NUMBER && tokenizer.getTokenType() != TokenTypes.VARIABLE)
throw new InterpreterException("Syntax Error");
if (tokenizer.getTokenType() == TokenTypes.NUMBER){
try{
result = Double.parseDouble(tokenizer.getToken());
}
catch (NumberFormatException exc){
throw new InterpreterException("Syntax Error : " + exc.getMessage());
}
}
else if (tokenizer.getTokenType() == TokenTypes.VARIABLE){
result = getValueOfVariable(tokenizer.getToken());
}
tokenizer.obtainNextToken();
return result;
}
Yukarıda gördüğünüz gibi if-else yapısının içindeki kod tekrarından kurtulduk.Bu şekilde şartlı yapıların içindeki tekrar eden kodu tek bir yere alıp tekrardan kurtulma işlemine Consolidate Duplicate Conditional Fragments diyoruz. Burada ismi fazla önemli değil aslında yaptığı işlemi anlamanız yeterli.Bu kodu aslında biraz daha düzenleyebiliriz. İlk olarak gözüme çarpan hata kontrolündeki uzun if cümlesi oluyor. Bu uzun ifade daha önce yazdığım Decompose Conditional kullanılarak daha basit ve anlaşılabilir hale getirilir.Onuda size bırakıyorum. Kolay gelsin…




October 19th, 2009
admin
Posted in 
