Showing posts with label code speaks 2u. Show all posts
Showing posts with label code speaks 2u. Show all posts

Friday, February 7, 2014

Nice Move With ValueSetter

I've been working on software architecture refactoring for last couple weeks. During a workshop one of architects showed me an interesting approach.

We were applying MVP-like style and then faced with the question: How a Presenter should tell a View to change its state?

Brute force approach looks like following:
public class Presenter {

 private View view;

 public void doSomething() {

//Here, services are processing something really important

 view.setTitle( "Updated" );
 view.setName( "New name" );
 }
}

public class Form extends JFrame implements View {

 private JTextfield nameTf;

 @Override
 public void setTitle( String title ) {
  setTitle( title );
 }

 @Override
 public void setName( String name ) {
  nameTf.setText( name );
 }
}
Well, this is actually ok, but the more components you have on the form, more verbose View interface becomes.

The move I am talking above is encapsulating a setter into separate object. Look here:
public abstract class ValueSetter {

private static Map<Class<?>, ValueSetter> SETTERS;
 
 static {
  SETTERS = new HashMap<Class<?>, ValueSetter>();
  SETTERS.put(JTextField.class, new JTextFieldSetter());
 }
 
 public static ValueSetter get( Class<?> type ) {
  if( SETTERS.containsKey(type) ) {
   return SETTERS.get(type);
  }
  
  throw new IllegalArgumentException( "Missing ValueSetter for " + type );
 }
 
 public abstract void set( Object target, Object value );

 private static class JTextFieldSetter extends ValueSetter {

  @Override
  public void set(Object target, Object value) {
   ((JTextField)target).setText( (String) value );
  }
 }

 private static class JFrameSetter extends ValueSetter {

  @Override
  public void set(Object target, Object value) {
   ((JFrame)target).setTitle( (String) value );
  }
 }
}
Now it is possible to write more elegant code:
public class Form extends JForm implements View {

 private Map<String, JComponent> components;

 @Override
 public void updateComponent(String id, Object value) {
  JComponent component = components.get(id);
  ValueSetter.get(component.getClass()).set(component, value);  
 }
}
So thanks Marcin for this nice tip and fresh idea for me ;)

Thursday, June 27, 2013

[en] Code Speaks To You

A colleague asked me to translate this post for some non-Polish fellows. I've been thinking about blogging in English for couple months. Some guys from Polish blogosphere have already done so. Who knows, maybe this is sign of times. Let's this one be my first small step.


So, I had an idea for a code readability criteria: code should speaks to you. I took this sentence very seriously.

Take code piece you want to challenge and:
  1. Replace all operators by words.
  2. Replace a "{" following "if" statement by "then".
  3. Split camel case names into words.
  4. Take only right "=" operator argument. Ignore the left one.
  5. Treat each line of code as a sentence ended with a dot.
  6. And now paste the given text into Text-to-Speach engine .
  7. So if you understand (without looking at the code) what you hear, the code is readable.

Let's we try with the following code.
public class List {

 private final static int DEFAULT_SIZE = 10;
 private Object[] elements;
 private boolean readOnly;
 private int size;

 public List() {
   elements = new Object[DEFAULT_SIZE];
   size = DEFAULT_SIZE;
 }
 
 public void add(Object element) {
   if (!readOnly) {
     int newSize = size + 1;
     if (newSize > elements.length) {
       Object[] newElements = new Object[elements.length+10];
       for (int i = 0; i < size; i++) {
         newElements[i] = elements[i];
       }
       elements = newElements;
     }
     elements[size++] = element;
   }
 }
}

Challenging the add method we would have a text similar to this:
If not read only.
Size plus one.
If new size greater than elements length then.
New objects size of elements length plus one.
For each elements: i of elements.
New elements.
Element.


Now paste the text above to the Text-to-Speach engine and listen :) Does it make sense?

After small refactoring of the add method it looks little bit differently.
public void add(Object anElement) {
  if (readOnly) {
    return;
  }
  
  if (atCapacity()) {
    grow();
  }
  
  put(anElement, into(elements));
}
 


private Object[] into(Object[] elements) {
  return elements;
}

private void put(Object anElement, Object elements[]) {
  elements[size++] = anElement;
}
 
private boolean atCapacity() {
  return size + 1> elements.length;
}

private void grow() {
  Object[] newElements = new Object[elements.length + 10];
  for (int i = 0; i < size; i++) {
    newElements[i] = elements[i];
  }

  elements = newElements;
}

This time the text would look a little bit different:
If read only then return.
If at capacity then grow.
Put an element into elements.


Again, paste the text above to the Text-to-Speach engine and listen what your code speaks to you. Better? :)

Monday, June 24, 2013

Code Speaks 2U, czyli Test Ivony

Przyszło mi ostatnio do głowy następujące kryterium czytelności kodu: kod musi do Ciebie przemówić. I potraktowałem to bardzo dosłownie.

Zatem weź fragment kodu, który chcesz sprawdzić i:
  1. Operatory zamień na słowa
  2. Klamerkę "{" po ifie zamień na "then"
  3. Rozbij nazwy camel case na pojedyncze wyrazy
  4. Z wyrażeń przypisania bierz pod uwagę tylko prawą stronę, lewą ignoruj
  5. Każdy wiersz kodu traktuj jako osobne zdanie zakończone kropką.
  6. Tak powstały tekst wklej do syntezatora mowy ivona.com
  7. Jeśli to, co słyszysz (bez patrzenia na kod), jest w pełni zrozumiałe, to kod jest czytelny :)

Weźmy taki przykład na przykład:
public class List {

 private final static int DEFAULT_SIZE = 10;
 private Object[] elements;
 private boolean readOnly;
 private int size;

 public List() {
   elements = new Object[DEFAULT_SIZE];
   size = DEFAULT_SIZE;
 }
 
 public void add(Object element) {
   if (!readOnly) {
     int newSize = size + 1;
     if (newSize > elements.length) {
       Object[] newElements = new Object[elements.length+10];
       for (int i = 0; i < size; i++) {
         newElements[i] = elements[i];
       }
       elements = newElements;
     }
              elements[size++] = element;
   }
 }
}

Dla metody add tekst będzie następujący:
If not read only.
Size plus one.
If new size greater than elements length then.
New objects size of elements length plus one.
For each elements: i of elements.
New elements.
Element.

No, a teraz wklej do ivona.com i słuchaj :) Ma sens?

A teraz niewielki refaktoring metody add związany przede wszystkim nazywaniem i pierwszymi dwoma krokami Naturalnego Porządku Refaktoryzacji.

Metoda przybiera następującą postać:


public void add(Object anElement) {
  if (readOnly) {
    return;
  }
  
  if (atCapacity()) {
    grow();
  }
  
  put(anElement, into(elements));
}
 


private Object[] into(Object[] elements) {
  return elements;
}

private void put(Object anElement, Object elements[]) {
  elements[size++] = anElement;
}
 
private boolean atCapacity() {
  return size + 1> elements.length;
}

private void grow() {
  Object[] newElements = new Object[elements.length + 10];
  for (int i = 0; i < size; i++) {
    newElements[i] = elements[i];
  }

  elements = newElements;
}

Tym razem tekst dla Ivony jest następujący:
If read only then return.
If at capacity then grow.
Put an element into elements.

Ponownie odsłuchaj, co Twój kod ma Ci do powiedzenia. Lepiej? :)