SDA SE Wiki

Software Engineering for Smart Data Analytics & Smart Data Analytics for Software Engineering

User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

research:cultivate:refactoringtowardsadsl [2018/05/09 01:59] (current)
Line 1: Line 1:
  
 +=====  Refactoring towards a DSL (not ADSL ;-) =====
 +
 +
 +As I've done these steps quite often now, I think it's time to note them down. As this whole refactoring is quite complex and the steps are not always clear, I think it might be hard to automate it.
 +
 +
 +
 +You're welcome to comment on this.
 +
 +
 +
 +''​dsp:''​ My comments are [[#​ref-refactoringtowardsadsl-1|[here]]].
 +
 +
 +==== original code ====
 +
 +
 +[[swt.v_scroll|swt.wrap);​
 +textfield.setlayoutdata(newgriddata(griddata.fill_both));​
 +
 +labellabelx=newlabel(top,​swt.single);​
 +labelx.settext(getresourcestring("​object.event.fields.finished.name"​));​
 +labelx.setlayoutdata(newgriddata(griddata.beginning));​
 +
 +buttonfinishedfield=newbutton(top,​swt.check);​
 +finishedfield.settext(getresourcestring("​editor.event.fields.finished.description"​));​
 +finishedfield
 +.setlayoutdata(newgriddata(swt.fill,​swt.top,​true,​false));​
 +
 +addproperty(descriptionfield,​event.description);​
 +addproperty(birthdayfield,​event.date,​newdateconverter(
 +getformat()));​
 +addproperty(textfield,​event.note);​
 +addproperty(finishedfield,​event.finished);​
 +}
 +}|{Java2HtmlPlugin
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        Label label = new Label(top, SWT.SINGLE);​
 +        label.setFont(bold(parent,​ label.getFont()));​
 +        label
 +                .setText(getResourceString("​object.event.fields.description.name"​));​
 +        label.setLayoutData(new GridData(GridData.BEGINNING));​
 +
 +        Text descriptionField = new Text(top, SWT.SINGLE);​
 +        descriptionField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP, true,
 +                false));
 +
 +        label = new Label(top, SWT.SINGLE);​
 +        label.setText(getResourceString("​object.event.fields.date.name"​));​
 +        label.setLayoutData(new GridData(GridData.BEGINNING));​
 +
 +        Text birthdayField = new Text(top, SWT.SINGLE);​
 +        birthdayField
 +                .setLayoutData(new GridData(GridData.FILL_HORIZONTAL));​
 +
 +        label = new Label(top, SWT.SINGLE);​
 +        label.setText(getResourceString("​object.event.fields.data.name"​));​
 +        GridData gridData = new GridData(GridData.BEGINNING);​
 +        gridData.verticalAlignment = SWT.BEGINNING;​
 +        label.setLayoutData(gridData);​
 +
 +        Text textField = new Text(top, SWT.MULTI ]]
 +
 +
 +==== move variable usage according to slices ====
 +
 +
 +[[swt.v_scroll|swt.wrap);​
 +textfield.setlayoutdata(newgriddata(griddata.fill_both));​
 +addproperty(textfield,​event.note);​
 +
 +labellabelx=newlabel(top,​swt.single);​
 +labelx.settext(getresourcestring("​object.event.fields.finished.name"​));​
 +labelx.setlayoutdata(newgriddata(griddata.beginning));​
 +
 +buttonfinishedfield=newbutton(top,​swt.check);​
 +finishedfield.settext(getresourcestring("​editor.event.fields.finished.description"​));​
 +finishedfield
 +.setlayoutdata(newgriddata(swt.fill,​swt.top,​true,​false));​
 +addproperty(finishedfield,​event.finished);​
 +}
 +}|{Java2HtmlPlugin
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        Label label = new Label(top, SWT.SINGLE);​
 +        label.setFont(bold(parent,​ label.getFont()));​
 +        label
 +                .setText(getResourceString("​object.event.fields.description.name"​));​
 +        label.setLayoutData(new GridData(GridData.BEGINNING));​
 +
 +        Text descriptionField = new Text(top, SWT.SINGLE);​
 +        descriptionField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP, true,
 +                false));
 +        addProperty(descriptionField,​ Event.DESCRIPTION);​
 +
 +        label = new Label(top, SWT.SINGLE);​
 +        label.setText(getResourceString("​object.event.fields.date.name"​));​
 +        label.setLayoutData(new GridData(GridData.BEGINNING));​
 +
 +        Text birthdayField = new Text(top, SWT.SINGLE);​
 +        birthdayField
 +                .setLayoutData(new GridData(GridData.FILL_HORIZONTAL));​
 +        addProperty(birthdayField,​ Event.DATE, new DateConverter(
 +                getFormat()));​
 +
 +        label = new Label(top, SWT.SINGLE);​
 +        label.setText(getResourceString("​object.event.fields.data.name"​));​
 +        GridData gridData = new GridData(GridData.BEGINNING);​
 +        gridData.verticalAlignment = SWT.BEGINNING;​
 +        label.setLayoutData(gridData);​
 +
 +        Text textField = new Text(top, SWT.MULTI ]]
 +
 +
 +==== split temporary variable, put slices in blocks ====
 +
 +
 +[[swt.v_scroll|swt.wrap);​
 +textfield.setlayoutdata(newgriddata(griddata.fill_both));​
 +addproperty(textfield,​event.note);​
 +}
 +{
 +labellabelx=newlabel(top,​swt.single);​
 +labelx
 +.settext(getresourcestring("​object.event.fields.finished.name"​));​
 +labelx.setlayoutdata(newgriddata(griddata.beginning));​
 +
 +buttonfinishedfield=newbutton(top,​swt.check);​
 +finishedfield
 +.settext(getresourcestring("​editor.event.fields.finished.description"​));​
 +finishedfield.setlayoutdata(newgriddata(swt.fill,​swt.top,​true,​
 +false));
 +addproperty(finishedfield,​event.finished);​
 +}
 +}
 +}|{Java2HtmlPlugin
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label
 +                    .setText(getResourceString("​object.event.fields.description.name"​));​
 +            label.setLayoutData(new GridData(GridData.BEGINNING));​
 +
 +            Text descriptionField = new Text(top, SWT.SINGLE);​
 +            descriptionField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP,
 +                    true, false));
 +            addProperty(descriptionField,​ Event.DESCRIPTION);​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setText(getResourceString("​object.event.fields.date.name"​));​
 +            label.setLayoutData(new GridData(GridData.BEGINNING));​
 +
 +            Text birthdayField = new Text(top, SWT.SINGLE);​
 +            birthdayField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));​
 +            addProperty(birthdayField,​ Event.DATE, new DateConverter(
 +                    getFormat()));​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setText(getResourceString("​object.event.fields.data.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Text textField = new Text(top, SWT.MULTI ]]
 +
 +
 +==== make things common by renaming, copy and paste and so on ====
 +
 +
 +[[swt.v_scroll|swt.wrap);​
 +textfield.setlayoutdata(newgriddata(griddata.fill_both));​
 +addproperty(textfield,​event.note);​
 +}
 +{
 +labellabel=newlabel(top,​swt.single);​
 +label.setfont(bold(parent,​label.getfont()));​
 +label
 +.settext(getresourcestring("​object.event.fields.finished.name"​));​
 +griddatagriddata=newgriddata(griddata.beginning);​
 +griddata.verticalalignment=swt.beginning;​
 +label.setlayoutdata(griddata);​
 +
 +buttonfinishedfield=newbutton(top,​swt.check);​
 +finishedfield
 +.settext(getresourcestring("​editor.event.fields.finished.description"​));​
 +finishedfield.setlayoutdata(newgriddata(swt.fill,​swt.top,​true,​
 +false));
 +addproperty(finishedfield,​event.finished);​
 +}
 +}
 +}|{Java2HtmlPlugin
 +        ​
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        {   
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label
 +                    .setText(getResourceString("​object.event.fields.description.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Text descriptionField = new Text(top, SWT.SINGLE);​
 +            descriptionField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP,
 +                    true, false));
 +            addProperty(descriptionField,​ Event.DESCRIPTION);​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString("​object.event.fields.date.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Text birthdayField = new Text(top, SWT.SINGLE);​
 +            birthdayField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));​
 +            addProperty(birthdayField,​ Event.DATE, new DateConverter(
 +                    getFormat()));​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString("​object.event.fields.data.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Text textField = new Text(top, SWT.MULTI ]]
 +
 +
 +==== hide creation differences behind an interface ====
 +
 +
 +<Code lang-java>​
 +
 +public interface IComponentFactory {
 +
 +    Control create(Composite parent);
 +    ​
 +}
 +
 +</​Code>​
 +
 +
 +
 +[[swt.v_scroll|swt.wrap);​
 +textfield.setlayoutdata(newgriddata(griddata.fill_both));​
 +returntextfield;​
 +}
 +
 +}
 +
 +}|{Java2HtmlPlugin
 +
 +public class MultiLineTextComponentFactory implements IComponentFactory {
 +
 +    public Control create(Composite parent) {
 +        Text textField = new Text(parent,​ SWT.MULTI ]]
 +
 +
 +
 +<Code lang-java>​
 +
 +public class BooleanFieldComponentFactory implements IComponentFactory {
 +    ​
 +    public Control create(Composite parent) {
 +        Button finishedField = new Button(parent,​ SWT.CHECK);
 +        finishedField
 +        .setText(getResourceString("​editor.event.fields.finished.description"​));​
 +        finishedField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP, true,
 +                false));
 +        return finishedField;​
 +    }
 +
 +
 +}
 +
 +</​Code>​
 +
 +
 +
 +<Code lang-java>​
 +
 +public class SingleLineTextComponentFactory implements IComponentFactory {
 +
 +    public Control create(Composite parent) {
 +        Text descriptionField = new Text(parent,​ SWT.SINGLE);​
 +        descriptionField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP,
 +                true, false));
 +        return descriptionField;​
 +    }
 +
 +}
 +
 +</​Code>​
 +
 +
 +
 +<Code lang-java>​
 +        ​
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label
 +                    .setText(getResourceString("​object.event.fields.description.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            IComponentFactory componentFactory = new SingleLineTextComponentFactory();​
 +            Control descriptionField = componentFactory.create(top);​
 +            ​
 +            addProperty(descriptionField,​ Event.DESCRIPTION,​ new NullConverter());​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString("​object.event.fields.date.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            IComponentFactory componentFactory = new SingleLineTextComponentFactory();​
 +            Control birthdayField = componentFactory.create(top);​
 +
 +            addProperty(birthdayField,​ Event.DATE, new DateConverter(
 +                    getFormat()));​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString("​object.event.fields.data.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            IComponentFactory componentFactory = new MultiLineTextComponentFactory();​
 +            Control birthdayField = componentFactory.create(top);​
 +            ​
 +            addProperty(birthdayField,​ Event.NOTE, new NullConverter());​
 +        }
 +        {
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label
 +                    .setText(getResourceString("​object.event.fields.finished.name"​));​
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            IComponentFactory componentFactory = new BooleanFieldComponentFactory();​
 +            Control finishedField = componentFactory.create(top);​
 +
 +            addProperty(finishedField,​ Event.FINISHED,​ null);
 +        }    ​
 +    }
 +</​Code>​
 +
 +
 +==== use extract, rename and move to extract the differences to the beginning of the slice ====
 +
 +
 +<Code lang-java>​
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        {
 +            String labelNameKey = "​object.event.fields.description.name";​
 +            IComponentFactory componentFactory = new SingleLineTextComponentFactory();​
 +            IConverter converter = new NullConverter();​
 +            Property property = Event.DESCRIPTION;​
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString(labelNameKey));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = componentFactory.create(top);​
 +
 +            addProperty(control,​ property, converter);
 +        }
 +        {
 +            String labelNameKey = "​object.event.fields.date.name";​
 +            IComponentFactory componentFactory = new SingleLineTextComponentFactory();​
 +            IConverter converter = new DateConverter(getFormat());​
 +            Property property = Event.DATE;
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString(labelNameKey));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = componentFactory.create(top);​
 +
 +            addProperty(control,​ property, converter);
 +        }
 +        {
 +            String labelNameKey = "​object.event.fields.data.name";​
 +            IComponentFactory componentFactory = new MultiLineTextComponentFactory();​
 +            Property property = Event.NOTE;
 +            IConverter converter = new NullConverter();​
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString(labelNameKey));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = componentFactory.create(top);​
 +
 +            addProperty(control,​ property, converter);
 +        }
 +        {
 +            String labelNameKey = "​object.event.fields.finished.name";​
 +            IComponentFactory componentFactory = new BooleanFieldComponentFactory();​
 +            Property property = Event.FINISHED;​
 +            IConverter converter = null;
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(parent,​ label.getFont()));​
 +            label.setText(getResourceString(labelNameKey));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control finishedField = componentFactory.create(top);​
 +
 +            addProperty(finishedField,​ property, converter);
 +        }
 +    }
 +</​Code>​
 +
 +
 +==== introduce configuration data structure ====
 +
 +
 +<Code lang-java>​
 +
 +public final class PropertyFieldConfiguration {
 +
 +    private final String labelNameKey;​
 +
 +    private final IComponentFactory componentFactory;​
 +
 +    private final IConverter converter;
 +
 +    private final Property property;
 +
 +    public PropertyFieldConfiguration(IComponentFactory factory,
 +            IConverter converter, String labelNameKey,​ Property property) {
 +
 +        this.componentFactory = factory;
 +        this.converter = converter;
 +        this.labelNameKey = labelNameKey;​
 +        this.property = property;
 +    }
 +
 +    public IComponentFactory getComponentFactory() {
 +        return componentFactory;​
 +    }
 +
 +    public IConverter getConverter() {
 +        return converter;
 +    }
 +
 +    public String getLabelNameKey() {
 +        return labelNameKey;​
 +    }
 +
 +    public Property getProperty() {
 +        return property;
 +    }
 +
 +}
 +
 +</​Code>​
 +
 +
 +
 +<Code lang-java>​
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new SingleLineTextComponentFactory(),​ new NullConverter(),​
 +                    "​object.event.fields.description.name",​ Event.DESCRIPTION);​
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(top,​ label.getFont()));​
 +            label.setText(getResourceString(configuration.getLabelNameKey()));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = configuration.getComponentFactory().create(top);​
 +
 +            addProperty(control,​ configuration.getProperty(),​ configuration
 +                    .getConverter());​
 +        }
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new SingleLineTextComponentFactory(),​ new DateConverter(getFormat()),​
 +                    "​object.event.fields.date.name",​ Event.DATE);​
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(top,​ label.getFont()));​
 +            label.setText(getResourceString(configuration.getLabelNameKey()));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = configuration.getComponentFactory().create(top);​
 +
 +            addProperty(control,​ configuration.getProperty(),​ configuration
 +                    .getConverter());​
 +        }
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new MultiLineTextComponentFactory(),​ new NullConverter(),​
 +                    "​object.event.fields.data.name",​ Event.NOTE);​
 +
 +
 +
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(top,​ label.getFont()));​
 +            label.setText(getResourceString(configuration.getLabelNameKey()));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = configuration.getComponentFactory().create(top);​
 +
 +            addProperty(control,​ configuration.getProperty(),​ configuration
 +                    .getConverter());​
 +        }
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new BooleanFieldComponentFactory(),​ null,
 +                    "​object.event.fields.finished.name",​ Event.FINISHED);​
 +
 +            Label label = new Label(top, SWT.SINGLE);​
 +            label.setFont(bold(top,​ label.getFont()));​
 +            label.setText(getResourceString(configuration.getLabelNameKey()));​
 +
 +            GridData gridData = new GridData(GridData.BEGINNING);​
 +            gridData.verticalAlignment = SWT.BEGINNING;​
 +            label.setLayoutData(gridData);​
 +
 +            Control control = configuration.getComponentFactory().create(top);​
 +
 +            addProperty(control,​ configuration.getProperty(),​ configuration
 +                    .getConverter());​
 +        }
 +    }
 +</​Code>​
 +
 +
 +==== extract the configuration method ====
 +
 +
 +<Code lang-java>​
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new SingleLineTextComponentFactory(),​ new NullConverter(),​
 +                    "​object.event.fields.description.name",​ Event.DESCRIPTION);​
 +
 +            initPropertyField(top,​ configuration);​
 +        }
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new SingleLineTextComponentFactory(),​ new DateConverter(getFormat()),​
 +                    "​object.event.fields.date.name",​ Event.DATE);​
 +
 +            initPropertyField(top,​ configuration);​
 +        }
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new MultiLineTextComponentFactory(),​ new NullConverter(),​
 +                    "​object.event.fields.data.name",​ Event.NOTE);​
 +
 +            initPropertyField(top,​ configuration);​
 +        }
 +        {
 +            PropertyFieldConfiguration configuration = new PropertyFieldConfiguration(
 +                    new BooleanFieldComponentFactory(),​ null,
 +                    "​object.event.fields.finished.name",​ Event.FINISHED);​
 +
 +            initPropertyField(top,​ configuration);​
 +        }
 +    }
 +
 +    private void initPropertyField(Composite top, PropertyFieldConfiguration configuration) {
 +        Label label = new Label(top, SWT.SINGLE);​
 +        label.setFont(bold(top,​ label.getFont()));​
 +        label.setText(getResourceString(configuration.getLabelNameKey()));​
 +
 +        GridData gridData = new GridData(GridData.BEGINNING);​
 +        gridData.verticalAlignment = SWT.BEGINNING;​
 +        label.setLayoutData(gridData);​
 +
 +        Control control = configuration.getComponentFactory().create(top);​
 +
 +        addProperty(control,​ configuration.getProperty(),​ configuration
 +                .getConverter());​
 +    }
 +</​Code>​
 +
 +
 +==== use a list for the configurations ====
 +
 +
 +[[{java2htmlplugin
 +
 +publicvoidcreatepartcontrol(compositeparent){
 +compositetop=newcomposite(parent,​swt.none);​
 +
 +gridlayoutlayout=newgridlayout();​
 +layout.marginheight=0;​
 +layout.marginwidth=0;​
 +layout.numcolumns=2;​
 +top.setlayout(layout);​
 +
 +list<​propertyfieldconfiguration>​configurations=newarraylist<​propertyfieldconfiguration>​();​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newsinglelinetextcomponentfactory(),​newnullconverter(),​
 +"​object.event.fields.description.name",​event.description));​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newsinglelinetextcomponentfactory(),​newdateconverter(
 +getformat()),"​object.event.fields.date.name",​
 +event.date));​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newmultilinetextcomponentfactory(),​newnullconverter(),​
 +"​object.event.fields.data.name",​event.note));​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newbooleanfieldcomponentfactory(),​null,​
 +"​object.event.fields.finished.name",​event.finished));​
 +
 +for(propertyfieldconfigurationconfiguration>​configurations){
 +initpropertyfield(top,​configuration);​
 +}
 +
 +..todomovecheckintoupdatemodel()
 +if(this.model!=null){
 +updatemodel();​
 +}
 +}
 +}|{Java2HtmlPlugin
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        List<​PropertyFieldConfiguration>​ configurations = new ArrayList<​PropertyFieldConfiguration>​();​
 +
 +        configurations.add(new PropertyFieldConfiguration(
 +                new SingleLineTextComponentFactory(),​ new NullConverter(),​
 +                "​object.event.fields.description.name",​ Event.DESCRIPTION));​
 +        ​
 +        configurations.add(new PropertyFieldConfiguration(
 +                new SingleLineTextComponentFactory(),​ new DateConverter(
 +                        getFormat()),​ "​object.event.fields.date.name",​
 +                Event.DATE));​
 +        ​
 +        configurations.add(new PropertyFieldConfiguration(
 +                new MultiLineTextComponentFactory(),​ new NullConverter(),​
 +                "​object.event.fields.data.name",​ Event.NOTE));​
 +        ​
 +        configurations.add(new PropertyFieldConfiguration(
 +                new BooleanFieldComponentFactory(),​ null,
 +                "​object.event.fields.finished.name",​ Event.FINISHED));​
 +
 +        for (PropertyFieldConfiguration configuration : configurations) {
 +            initPropertyField(top,​ configuration);​
 +        }
 +
 +        // TODO move check into updateModel()
 +        if (this.model != null) {
 +            updateModel();​
 +        }
 +    }
 +}]]
 +
 +
 +==== extract the list creation into a method ====
 +
 +
 +[[{java2htmlplugin
 +
 +publicvoidcreatepartcontrol(compositeparent){
 +compositetop=newcomposite(parent,​swt.none);​
 +
 +gridlayoutlayout=newgridlayout();​
 +layout.marginheight=0;​
 +layout.marginwidth=0;​
 +layout.numcolumns=2;​
 +top.setlayout(layout);​
 +
 +list<​propertyfieldconfiguration>​configurations=createpropertyfieldconfigurations();​
 +
 +for(propertyfieldconfigurationconfiguration>​configurations){
 +initpropertyfield(top,​configuration);​
 +}
 +}
 +
 +protectedlist<​propertyfieldconfiguration>​createpropertyfieldconfigurations(){
 +list<​propertyfieldconfiguration>​configurations=newarraylist<​propertyfieldconfiguration>​();​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newsinglelinetextcomponentfactory(),​newnullconverter(),​
 +"​object.event.fields.description.name",​event.description));​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newsinglelinetextcomponentfactory(),​newdateconverter(
 +getformat()),"​object.event.fields.date.name",​
 +event.date));​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newmultilinetextcomponentfactory(),​newnullconverter(),​
 +"​object.event.fields.data.name",​event.note));​
 +
 +configurations.add(newpropertyfieldconfiguration(
 +newbooleanfieldcomponentfactory(),​null,​
 +"​object.event.fields.finished.name",​event.finished));​
 +
 +returnconfigurations;​
 +}
 +}|{Java2HtmlPlugin
 +
 +    public void createPartControl(Composite parent) {
 +        Composite top = new Composite(parent,​ SWT.NONE);
 +
 +        GridLayout layout = new GridLayout();​
 +        layout.marginHeight = 0;
 +        layout.marginWidth = 0;
 +        layout.numColumns = 2;
 +        top.setLayout(layout);​
 +
 +        List<​PropertyFieldConfiguration>​ configurations = createPropertyFieldConfigurations();​
 +
 +        for (PropertyFieldConfiguration configuration : configurations) {
 +            initPropertyField(top,​ configuration);​
 +        }
 +    }
 +
 +    protected List<​PropertyFieldConfiguration>​ createPropertyFieldConfigurations() {
 +        List<​PropertyFieldConfiguration>​ configurations = new ArrayList<​PropertyFieldConfiguration>​();​
 +
 +        configurations.add(new PropertyFieldConfiguration(
 +                new SingleLineTextComponentFactory(),​ new NullConverter(),​
 +                "​object.event.fields.description.name",​ Event.DESCRIPTION));​
 +        ​
 +        configurations.add(new PropertyFieldConfiguration(
 +                new SingleLineTextComponentFactory(),​ new DateConverter(
 +                        getFormat()),​ "​object.event.fields.date.name",​
 +                Event.DATE));​
 +        ​
 +        configurations.add(new PropertyFieldConfiguration(
 +                new MultiLineTextComponentFactory(),​ new NullConverter(),​
 +                "​object.event.fields.data.name",​ Event.NOTE));​
 +        ​
 +        configurations.add(new PropertyFieldConfiguration(
 +                new BooleanFieldComponentFactory(),​ null,
 +                "​object.event.fields.finished.name",​ Event.FINISHED));​
 +        ​
 +        return configurations;​
 +    }
 +}]]
 +
 +
 +==== some refactoring in the component factories ====
 +
 +
 +<Code lang-java>​
 +
 +public class BooleanFieldComponentFactory implements IComponentFactory {
 +
 +    private final String fieldResourceKey;​
 +    ​
 +    public BooleanFieldComponentFactory(String key) {
 +        fieldResourceKey = key;
 +    }
 +
 +    public Control create(Composite parent) {
 +        Button finishedField = new Button(parent,​ SWT.CHECK);
 +        finishedField
 +        .setText(getResourceString(fieldResourceKey));​
 +        finishedField.setLayoutData(new GridData(SWT.FILL,​ SWT.TOP, true,
 +                false));
 +        return finishedField;​
 +    }
 +
 +}
 +</​Code>​
 +
 +
 +
 +<Code lang-java>​
 +
 +    protected List<​PropertyFieldConfiguration>​ createPropertyFieldConfigurations() {
 +        List<​PropertyFieldConfiguration>​ configurations = new ArrayList<​PropertyFieldConfiguration>​();​
 +
 +        configurations.add(new PropertyFieldConfiguration(
 +                new SingleLineTextComponentFactory(),​ new NullConverter(),​
 +                "​object.event.fields.description.name",​ Event.DESCRIPTION));​
 +
 +        configurations.add(new PropertyFieldConfiguration(
 +                new SingleLineTextComponentFactory(),​ new DateConverter(
 +                        getFormat()),​ "​object.event.fields.date.name",​
 +                Event.DATE));​
 +
 +        configurations.add(new PropertyFieldConfiguration(
 +                new MultiLineTextComponentFactory(),​ new NullConverter(),​
 +                "​object.event.fields.data.name",​ Event.NOTE));​
 +
 +        configurations.add(new PropertyFieldConfiguration(
 +                new BooleanFieldComponentFactory(
 +                        "​editor.event.fields.finished.description"​),​ null,
 +                "​object.event.fields.finished.name",​ Event.FINISHED));​
 +
 +        return configurations;​
 +    }
 +
 +</​Code>​
 +
 +
 +
 +Now we're pretty close in createPropertyFieldConfigurations() to what Fowler calls an [[http://​martinfowler.com/​articles/​languageWorkbench.html#​InternalDsl|internal DSL]]. Further steps
 +could involve pulling methods up to the superclass (except createPropertyFieldConfigurations(),​
 +which should be a template method), moving the extract classes to a good location, perhaps converting the internal DSL to an external DSL, evolving the DSL as new requirements must be covered, and so on.
 +
 +
 +===  [[[#​1]|[#​1]]] ''​dsp'​s''​ comments: ===
 +
 +  * I like the spirit of this refactoring sequence very much and I agree  that it's close to defining something like a (local) internal DSL.
 +  * The presentation of the refactoring steps is also nice. It would be useful to have a small Java project with each of this intermediate code structures in one package. Dagmar and I did this once for an ExtractMethod example and we found it very useful.
 +  * In my opinion you might be better of with less OO in this example. You could  omit the creation of the Factories and the Configuration if you just introduce one factory method for each type of component. There will still be a similar ​ kind of DSL, I promise.
 +  * Heading for more generality would make things bad. The refactoring was possible ​ because we know that in the context of our application certain parts of the creation process don't vary (or am I wrong here?). Things are easy in a domain because they are not so general.
 +  * ehhhmmmm ... some minutes later ... I did an experiment and started with the version of your code before "​introduce configuration data structure"​. One extract method. Some  inlining. Conversion of the factories to private factory methods and ended up with:
 +
 +<Code lang-java>​
 +
 + public void createPartControl(Composite parent) {
 + Composite top = new Composite(parent,​ SWT.NONE);
 +
 + GridLayout layout = new GridLayout();​
 + layout.marginHeight = 0;
 + layout.marginWidth = 0;
 + layout.numColumns = 2;
 + top.setLayout(layout);​
 +
 + createLabel(top,​ "​object.event.fields.description.name"​);​
 + addProperty(createSingleLineText(top),​ Event.DESCRIPTION,​
 + new NullConverter());​
 +
 + createLabel(top,​ "​object.event.fields.date.name"​);​
 + addProperty(createSingleLineText(top),​ Event.DATE, ​
 + new DateConverter(getFormat()));​
 +
 + createLabel(top,​ "​object.event.fields.data.name"​);​
 + addProperty(createMultiLineText(top),​ Event.NOTE, ​
 + new NullConverter());​
 +
 + createLabel(top,​ "​object.event.fields.finished.name"​);​
 + addProperty(createBooleanField(top),​ Event.FINISHED, ​
 + null);
 + }
 +
 + private void createLabel(Composite top, String labelNameKey) {
 + Label label = new Label(top, SWT.SINGLE);​
 + label.setFont(bold(top.getParent(),​ label.getFont()));​
 + label.setText(getResourceString(labelNameKey));​
 +
 + GridData gridData = new GridData(GridData.BEGINNING);​
 + gridData.verticalAlignment = SWT.BEGINNING;​
 + label.setLayoutData(gridData);​
 + }
 +
 +</​Code>​
 +
 +
 +  * Isn't this code //​slightly//​ more simple? '';​-)''​
 +  * VOTE FOR EXTRACT METHOD!!! '';​-)''​
 +  * Ok, I understand that there might be circumstances where more generality ​ might be useful, but here...
 +  * Expecting your comments! Here they are: [[#​ref-refactoringtowardsadsl-2|[2]]]
 +===  [[[#​2]|[#​2]]] ''​lg'​s''​ comments: ===
 +
 +  * I agree that your solution is easier to read, easier to write, faster to reach and much simpler :-)
 +  * Now, I'm starting to search for arguments for my solution ;-)
 +  * Point 1: In your solution, the developer needs to know that there must be a create label before the add property, this is an implicit constraint. I hope all the constraints in my solution are explicitly communicated by the constructor of PropertyFieldConfiguration.
 +  * Point 2: In your solution, if one wants to add a new field type, a method must be added to the superclass if the creation of that type should be reusable. In my solution, one would write a new factory that is automatically reusable (open-closed principle is used for extension). This is important in this case as I expect to publish the API some day and the others might not be able to change the superclass.
 +  * Point 3: In my opinion, using small objects and interfaces can drastically improve evolution speed and reuse (when you know where they are and what they do, thats the downside). But this may be related to my style of development and does perhaps not apply on others. As a note on the further evolution of this little DSL: it has changed much since the last step I published here, and, although I'm not finished yet and I got very complicated by now (I will make it easier later, I guess), it's possibilities increased a lot. I believer that this change would have been much harder with a less OO variant.
 +  * Point 4: One feature I planed is only possible with the OO version: The user will (some day) be able to move the blocks into an order he likes, and this will be storable.
 +  * The main point: Finally, I remember why I did this that way...: I want editors to be extendible via extension points. This means that different plugins (because they can extend the core entities, too) will be able to deploy lists of PropertyFieldConfigurations for editors, and the content of an editor will configured by a list that is the result of merging configuration lists for this editor from different plugins. I can't currenty see how this would be  possible in a non-oo version. But this is an intention that's not intrinsic to that refactoring and that your didn't know.
 +  * My final comment: In my opinion, your solution is better in most cases, where further evolution is expected to be limited. Indeed, I often did the refactoring that way. In cases where a evolution in the direction of configurability and extendibility can be expected, I tend to use the OO version. I think because of what I've in mind for the further evolution of this code, in my case I've choosen the right solution. ​
research/cultivate/refactoringtowardsadsl.txt · Last modified: 2018/05/09 01:59 (external edit)

SEWiki, © 2019