Liz Douglass

Posts Tagged ‘Java

Being a trainer at the JAMS 2012 Workshop

leave a comment »

Image

At the end of March I had the pleasure of being one of 5 trainers at the JAMS 2012 Workshop at the Makerere University in Kampala, Uganda. The workshop was run by ThoughtWorks in partnership with the Grameen Foundation, with further sponsorship from Yo and SMS Media

Most of the 50 workshop participants were second or third year students from the university. For many of them their only prior experience with Java was from a single semester subject. Before we arrived we thought that the ratio of 50 participants to only 5 trainers was going to be quite challenging. We needn’t have worried though because all the participants were very patient and very switched on. 

The curriculum of the workshop was a combination of agile business analysis, project management and, for the majority of it, hands on developer skill training. As part of the course we ran quite a few of the object boot camp exercises. These exercises, put together by ThoughtWorkers several years back, are often used for internal training. They aim to reinforce the principles of object orientation and introduce some design techniques and patterns. The bootcamp was run in Java, as is often the case. 

Despite never having heard of JUnit and not being clear on language essentials like constructors and equals methods, the participants really impressed us with how they applied themselves. The bootcamp exercises intentionally give participants bandwidth to try things out for themselves and discover what works and what doesn’t. Group discussion is used to drive out the learning points and as instructors we look for code smells like YAGNI. Interestingly with the JAMs group we rarely found that we needed raise the same point twice – even where we expected to. Writing unit tests first and implementing value objects are just two examples of concepts that the students picked up immediately and just started using.

In the last 2 days of the workshop we worked on a web application with the group. The app uses the Java Play framework. It’s called MakVibes and it’s intended help Makerere students track what’s happening on campus. The idea for the app came from one of the workshop participants – Alex. It’s already deployed on Heroku and it’ll be extended in the monthly code jams that are currently being planned. The jams will also involve the attendees working on some code kata problems as well as tech talks. There is a lot of fantastic enthusiasm in Kampala for this kind of ongoing learning as well as a desire to increase the use of technology in business. Uganda is an exciting place to be!

Advertisements

Written by lizdouglass

April 22, 2012 at 11:30 am

Posted in Uncategorized

Tagged with ,

Scala Multiple Constructors

with 3 comments

A couple of weeks ago I created a new type of exception for use in our application. If I’d been using Java I would have written something simple like this:

public class MyException extends RuntimeException {

    public MyException(String message) {
        super(message);
    }

    public MyException(String message, Throwable throwable) {
        super(message, throwable);
    }
}

The Scala multiple constructor model is different to the Java one, as described in this article. In Scala, only the primary class constructor can call a superclass constructor, meaning that it’s only possible to invoke only one superclass constructor. The code above makes calls to two constructors on the RuntimeException class. So how can we write a Scala equivalent? Fortunately one of the answers posted to this question explains a pattern for how to do this:

object MyException {
  private def create(message: String): RuntimeException = new RuntimeException(message)

  private def create(message: String, throwable: Throwable): RuntimeException = new RuntimeException(message, throwable)
}

class MyException private (exception: RuntimeException) {
  def this(message: String) = this (MyException.create(message))

  def this(message: String, throwable: Throwable) = this (MyException.create(message, throwable))
}

I think the pattern is really neat but certainly a lot more complicated that the Java equivalent. I guess this is one of the cases where using Java classes in Scala can be tricky.

Written by lizdouglass

December 15, 2010 at 9:24 am

Posted in Uncategorized

Tagged with ,

Part 3: Recursive menu building

leave a comment »

Part 3 of the Freemarker cleanup involved refactoring menu creation. The application has several menus that appear on the left side of the browser window. These menus are either nested inside eachother or stacked on top of one another.

Before part 3, the creation of the menus was done by one template called main.ftl. This template included other templates (and so on). This was main.ftl:

 
[#ftl]

[#if user.member]
	[#include "/member-menu.ftl"]
[#else]
	[#include "/cross-role-menu.ftl"]
[/#if]
[#if someCondition?? ]
	[#include "/some-menu.ftl"]
[/#if ]
	[#if foo.id !=  user.id]
		[#include "/foo-menu.ftl"]
[/#if ]

All of the menu templates had some conditional logical statements in them – in fact, there was probably an average of about a dozen per template. The only place that these logic statements were tested was in the Selenium tests – obviously not ideal.

The aim of this refactoring was to get rid of all the conditional logic in the templates. The logic would be replaced with tested Java code. This made it possible to render the menus from one single recursive menu template:

 
[#ftl]
[#import "/spring.ftl" as spring /]

[#if menu??]
    [@buildMenu menu=menu depth=0/]
[/#if]

[#macro buildMenu menu depth]
    [#list menu.menuEntries as menuEntry]
        [#if menuEntry.type == "LINK"]
            <div>
                <a href="[@spring.url menuEntry.link?html /]">${menuEntry.caption?html}</a>
            </div>
        [#else]
            [#if menuEntry.menuEntries?size > 0]
                [#if depth > 0]
                    <h3>${menuEntry.caption}</h3>
                    <div id="${menuEntry.name}" class="menu_sub_block">
                [#else]
                    <div id="${menuEntry.name}" class="menu_block">
                    <h5>${menuEntry.caption}</h5>
                [/#if]
                [@buildMenu menu=menuEntry depth=depth+1/]
                </div>
            [/#if]
        [/#if]
    [/#list]
[/#macro]

The new template builds all the menus from the menu model entry. This is added into the model in the MenuInterceptor. This interceptor has dependencies on four factories that create the required menus. The postHandle method creates a rootMenu that contains the other menus:

 
public class MenuInterceptor extends HandlerInterceptorAdapter {
    private FooMenuFactory fooMenuFactory;
    private CrossRoleMenuFactory crossRoleMenuFactory;
    private MemberMenuFactory memberMenuFactory;
    private SomeMenuFactory someMenuFactory;

    @Autowired
    public void setFooMenuFactory(FooMenuFactory fooMenuFactory) {
        this.fooMenuFactory = fooMenuFactory;
    }

    // omitted setters for the other factories

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
            throws Exception {

        if (mv != null) {
            User user = (User) request.getAttribute(RequestAttributeNames.user.name());

            Menu rootMenu = new Menu("menu");
            Menu memberMenu = memberMenuFactory.createMemberMenu(user);
            Menu crossRoleMenu = crossRoleMenuFactory.createCrossRoleMenu(user);
            Menu someMenu = someMenuFactory.createSomeMenu(user);
            Menu fooMenu = fooMenuFactory.createFooMenu(user);
            rootMenu.addEntries(memberMenu, crossRoleMenu, someMenu, fooMenu);

            mv.addObject("menu", rootMenu);
        }
    }
}

Each of the menu factories creates a Menu object. The Menu class has a list of MenuEntry objects. There are two implementations of the MenuEntry interface: Link and Menu:

The MenuEntry interface:

 
public interface MenuEntry {

    String getCaption();

    MenuEntryType getType();
}

Menu:

 
public class Menu implements MenuEntry {
    private String caption = "";

    private List<MenuEntry> menuEntries;
    private final String name;

    public Menu(String name) {
        this.name = name;
        menuEntries = Lists.create();
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }

    public void addEntry(MenuEntry menuItem) {
        menuEntries.add(menuItem);
    }

    public String getCaption() {
        return caption;
    }

    public List<MenuEntry> getMenuEntries() {
        return menuEntries;
    }

    public void addEntries(MenuEntry... links) {
        menuEntries.addAll(Arrays.asList(links));
    }

    public MenuEntryType getType() {
        return MenuEntryType.MENU;
    }

    public String getName() {
        return name;
    }
}

… and Link:

 
public class Link implements MenuEntry {

    private final String captionText;
    private final SecureLinks.Link link;

    public SecureContextLink(String captionText, SecureContextLinks.Link link) {
        this.captionText = captionText;
        this.link = link;
    }

    public String getCaption() {
        return captionText;
    }

    public String getLink() {
        return link.toString();
    }

    public MenuEntryType getType() {
        return MenuEntryType.LINK;
    }
}

Each of the factories creates a menu using the logic that was previously in the Freemarker templates. Each factory was developed using TDD and looks a bit like this:

 
public class FooMenuFactory {
    private FooRepository fooRepository;
    private final SecureContextLinks links = new SecureContextLinks();

    public FooMenuFactory(FooRepository fooRepository) {
        this.fooRepository = fooRepository;
    }

    public Menu createFooMenu(User user) {
        Menu fooMenu = new Menu("foo_menu");

        fooMenu.setCaption(user.getDisplayName());

        if (context.isMember()) {
           fooMenu.addEntry(new SecureContextLink("Summary", links.getSomeSummary()));
        }

        // add other links

        return fooMenu;
    }
}

Moving to this style of menu creation reduced 7 templates down to one recursive template. All of the logic that was previously in the templates was moved into Java and was unit tested. (Yay!)

Written by lizdouglass

January 11, 2010 at 6:19 am

Posted in Uncategorized

Tagged with ,

Part 2: SecureLinks

leave a comment »

Part two of the Freemarker cleanup came about when we noticed that we were adding the same links many times into various models. This repetition was eliminated by adding the most common links into the model using an interceptor.

The interceptor has a postHandle method that adds an instance of our new SecureLinks class (below) into the model:

 
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
        throws Exception {

    if (mv != null) {
        mv.addObject("links", new SecureLinks());
    }
}

The SecureLinks class provides the most commonly used links in our application:

 
import my.app.LinkBuilder;
import my.app.QueryString;
import my.app.controller.secure.foo.FooController;
import my.app.controller.secure.bar.BarController;

public class SecureLinks {

    private static final LinkBuilder BUILDER = new SecureLinkBuilder();

    public Link getFooSearch() {
        return new PlainLink(FooController.class);
    }

    public Link getBarList() {
        return new LinkWithQueryString(BarController.class, QueryString().add("letter", "A"));
    }
    
    // other methods omitted for brevity

    public static interface Link {
    }

    public static class PlainLink implements Link {
        private final Class<?> controller;
        private final String methodName;

        public PlainLink(Class<?> controller) {
            this(controller, null);
        }

        public PlainLink(Class<?> controller, String methodName) {
            this.controller = controller;
            this.methodName = methodName;
        }

        @Override
        public String toString() {
            if (methodName != null) {
                return BUILDER.linkTo(controller, methodName);
            }
            return BUILDER.linkToGet(controller);
        }
    }

    public static class LinkWithQueryString implements Link {
        private final Class<?> controller;
        private final String methodName;
        private final QueryString query;

        public LinkWithQueryString(Class<?> controller, String methodName, QueryString query) {
            this.controller = controller;
            this.methodName = methodName;
            this.query = query;
        }

        public LinkWithQueryString(Class<?> controller, QueryString query) {
            this(controller, null, query);
        }

        @Override
        public String toString() {
            if (methodName != null) {
                return BUILDER.linkTo(controller, methodName, query);
            }
            return BUILDER.linkToGet(controller, query);
        }
    }
}

Adding the links into the model in the interceptor means that there is something extra in each ModelMap that may not necessarily be used/required, but we thought that it was worth it to remove the repetition.

Written by lizdouglass

January 6, 2010 at 5:29 am

Posted in Uncategorized

Tagged with ,

Java LinkBuilder

with one comment

Shortly before Christmas Tom and I decided to try to remove logic from some project Freemarker templates. Our first step was to move away from building up URIs inside templates, by creating some sort of Java URI builder.

Background:
We had lots of Freemarker template snippets that looked like this:

[#if member.someType.value != 'Foo']
     <div>[@macros.link_to 'Bar reports' 'member/report?id=${id}&amp;type=M&amp;database=${database}' /]</div>
[/#if]

All of them used the link_to Freemarker macro, which was defined as:

[#macro link_to caption path target='_top']
    [#if path?starts_with("/")]
        [#assign newPath=path?substring(1) /]
    [#else]
        [#assign newPath=path /]
    [/#if]
    <a href="[@spring.url '/appSecureServletPath/${newPath}' /]" target="${target}">${caption}</a>
[/#macro]

What we wanted to achieve first up:

Our aim was to replace all the uses of the link_to macro and instead generate all the URIs in Java and then add them to the model. We wanted to move a template usage like this:

<a href="[@spring.url contactDetailsChange?html /]">Change your contact details</a>

Where the link is added in the controller like so:

modelAndView.addObject("contactDetailsChange", linkBuilder.linkTo(ContactDetailsController.class));

Creating the LinkBuilder:

We did an assessment of all the URI endpoints in our project and realised that:
– We have some controller classes with a request mapping, some controllers that have methods with request mappings and some controllers with a combination of both class and method mappings.
– We have some controllers with more than one GET request method mapping and therefore could not assume only one request method mapping per controller.

We test drove a LinkBuilder interface and a DefaultLinkBuilder implementation for all the combinations we found in the controllers. The idea was to link from one handler class/method to another without being concerned about the specific URI mapped paths.

We also included methods that return a ModelAndView for redirecting and forward from a controller. Some of the methods also take a QueryString microtype (see below).

This is the LinkBuilder interface:

import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

public interface LinkBuilder {

    String linkTo(Class<?> controller, String methodName);

    String linkTo(Class<?> controller, RequestMethod method);

    String linkTo(Class<?> controller, String methodName, QueryString query);

    String linkTo(Class<?> controller, RequestMethod method, QueryString query);

    String linkToGet(Class<?> controller);

    String linkToGet(Class<?> controller, QueryString query);

    String forwardTo(Class<?> controller, String methodName);

    ModelAndView redirectTo(Class<?> controller, String method);

    ModelAndView redirectTo(Class<?> controller);

    ModelAndView redirectTo(Class<?> controller, String method, QueryString query);

    ModelAndView redirectTo(Class<?> controller, QueryString query);
}

And the DefaultLinkBuilder:

import org.apache.commons.lang.ArrayUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import java.lang.reflect.Method;

public class DefaultLinkBuilder implements LinkBuilder {

    private final String prefix;

    public DefaultLinkBuilder() {
        this("");
    }

    public DefaultLinkBuilder(String prefix) {
        this.prefix = prefix;
    }

    public String linkTo(Class<?> controller, String methodName) {
        return prefix + getControllerUrl(controller) + getMethodUrl(controller, methodName);
    }

    public String linkTo(Class<?> controller, RequestMethod method) {
        return prefix + getControllerUrl(controller) + getMethodUrl(controller, method);
    }

    public String linkTo(Class<?> controller, String methodName, QueryString query) {
        return linkTo(controller, methodName) + "?" + query;
    }

    public String linkTo(Class<?> controller, RequestMethod method, QueryString query) {
        return linkTo(controller, method) + "?" + query;
    }

    public String linkToGet(Class<?> controller) {
        return linkTo(controller, RequestMethod.GET);
    }

    public String linkToGet(Class<?> controller, QueryString query) {
        return linkTo(controller, RequestMethod.GET, query);
    }

    public String forwardTo(Class<?> controller, String methodName) {
        return "forward:" + linkTo(controller, methodName);
    }

    public ModelAndView redirectTo(Class<?> controller, String method) {
        return new ModelAndView("redirect:" + linkTo(controller, method));
    }

    public ModelAndView redirectTo(Class<?> controller) {
        return new ModelAndView("redirect:" + linkTo(controller, RequestMethod.GET));
    }

    public ModelAndView redirectTo(Class<?> controller, String method, QueryString query) {
        ModelAndView mv = redirectTo(controller, method);
        query.addToModel(mv.getModel());
        return mv;
    }

    public ModelAndView redirectTo(Class<?> controller, Context context) {
        QueryString queryString = context.asQueryString();
        return redirectTo(controller, queryString);
    }

    public ModelAndView redirectTo(Class<?> controller, QueryString query) {
        ModelAndView mv = redirectTo(controller);
        query.addToModel(mv.getModel());
        return mv;
    }

    private String getControllerUrl(Class<?> controller) {
        RequestMapping annotation = AnnotationUtils.findAnnotation(controller, RequestMapping.class);
        if (annotation != null) {
            return getFirstValue(annotation);
        }
        return "";
    }

    private String getMethodUrl(Class<?> controller, String methodName) {
        Method[] methods = controller.getMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
                if (annotation != null) {
                    return getFirstValue(annotation);
                }
            }
        }
        throw new IllegalArgumentException("Cannot find method with name " + methodName
                + " with a RequestMapping annotation on controller " + controller.getName());
    }

    private String getMethodUrl(Class<?> controller, RequestMethod requestMethod) {
        Method[] methods = controller.getMethods();
        for (Method method : methods) {
            RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
            if (annotation != null) {
                if (ArrayUtils.contains(annotation.method(), requestMethod)) {
                    return getFirstValue(annotation);
                }
            }
        }
        throw new IllegalArgumentException("Cannot find method that can handle " + requestMethod
                + " requests on controller " + controller.getName());
    }

    private String getFirstValue(RequestMapping annotation) {
        String[] value = annotation.value();
        if (value.length > 0) {
            return value[0];
        }
        return "";
    }
}

We have two subclasses of the DefaultLinkBuilder the SecureLinkBuilder and the UnsecureLinkBuilder. These classes simply set the appropriate servlet path as the prefix.

The QueryString class knows how to add itself into the model:

import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.util.EncodingUtil;

import java.util.List;
import java.util.Map;

public class QueryString {

    private final List<NameValuePair> pairs = Lists.create();

    public QueryString add(String name, String value) {
        pairs.add(new NameValuePair(name, value));
        return this;
    }

    public boolean isEmpty() {
        return pairs.isEmpty();
    }

    public NameValuePair[] toArray() {
        return pairs.toArray(new NameValuePair[pairs.size()]);
    }

    public void addToModel(Map<String, Object> model) {
        for (NameValuePair pair : pairs) {
            model.put(pair.getName(), pair.getValue());
        }
    }

    @Override
    public String toString() {
        return EncodingUtil.formUrlEncode(toArray(), "UTF-8");
    }
}

The creation of the LinkBuilder and the implementations allowed us to go through all the controllers and add links into the models. We removed a lot of string concatenation in templates doing this.

Written by lizdouglass

January 5, 2010 at 10:13 am

Posted in Uncategorized

Tagged with , ,

Refactoring using an Effect Sketch

with one comment

Today I worked on my own rather than pairing. What made the day even more unusual was that there were no other developers in the room – oddly enough lots of people have taken leave at the same time.

I spent a good part of the day refactoring the one class. This refactoring was the last chunk of work for a story that Silvio and I paired on for a couple of days last week. This morning the code looked a bit like this:

@Component
public class FooStrategyModelFactory {

    private final MemberRepository memberRepository;
    private final BarRepository barRepository;
    private final FooStrategyRepository fooRepository;
    private final BarViewFactory barViewFactory;
    private final JsonConverter jsonConverter;

    @Autowired
    public FooStrategyModelFactory(MemberRepository memberRepository,
                                   BarRepository barRepository,
                                   FooStrategyRepository fooRepository,
                                   BarViewFactory barViewFactory,
                                   JsonConverter jsonConverter) {

        this.memberRepository = memberRepository;
        this.barRepository = barRepository;
        this.fooRepository = fooRepository;
        this.barViewFactory = barViewFactory;
        this.jsonConverter = jsonConverter;
    }

    public ModelMap createViewModel(UserAccount userAccount, Context context, HttpServletRequest request,
                                    List changeData) {

        ModelMap model = new ModelMap();

        Member member = memberRepository.getMember(userAccount, context);

        List availableBars = getAvailableBarsForMember(context, changeData);

        List availableWidgetBars = Lists.select(availableBars, new WidgetBarMatcher());

        List BarViews = barViewFactory.createBarViews(availableWidgetBars, member.getAccountType());

        model.addAttribute("Bars", jsonConverter.toJson(BarViews));

        addBarStrategiesToModel(userAccount, context, request, model, member, availableBars);

        return model;
    }

    private void addBarStrategiesToModel(UserAccount userAccount, Context context,
                                         HttpServletRequest request,
                                         ModelMap model,
                                         Member member,
                                         List availableBars) {

        List strategies = getCurrentStrategiesForMember(userAccount, context, availableBars, request);

        List strategyViews = barViewFactory.createBarStrategyViews(
                strategies, availableBars, member.getAccountType());

        model.addAttribute("cashFlowStrategyItems", jsonConverter.toJson(strategyViews));
    }

    protected List getAvailableBarsForMember(Context context, List changeData) {
        List thing = barRepository.getThingsForMember(context);

        List memberBars = Lists.map(things, new Function() {
            public Bar apply(Thing thing) {
                return thing.getBar();
            }
        });

        List newlyAddedChangeData = Lists.select(changeData, new NewlyAddedChangeDataMatcher());
        for (ChangeData changeDataItem : newlyAddedChangeData) {
            memberBars.add(barRepository.getBarByBarNumber(changeDataItem.getBarNumber()));
        }

        List newChangeData = Lists.select(changeData, new NewChangeDataMatcher());

        return Lists.reject(memberBars, new OtherChangeDataMatcher(newChangeData));
    }

    protected List getCurrentStrategiesForMember(UserAccount userAccount, Context context,
                                                              List Bars, HttpServletRequest request) {

        String json = (String) WebUtils.getSessionAttribute(request, UpdatedBarStrategy.SESSION_KEY);
        if (StringUtils.isNotEmpty(json)) {
            List strategies = jsonConverter.fromJsonArray(json, UpdatedBarStrategy.class);
            return Lists.map(strategies, new BarStrategyFactory(Bars));
        }
        return fooRepository.load(userAccount, context);
    }
}

Hmmm, where to begin?….. I decided to try to tackle this class by drawing an effect sketch in my notebook. This idea is detailed by Michael Feathers in his book Working Effectively With Legacy Code. We’ve been reading this book at book club and have had several group discussions about the approach. On my diagram I drew nodes for each of the class fields as well as the methods, plus the arguments that are passed into createViewModel. I ended up with loads of lines criss-crossing the page connecting them. I won’t even attempt to reproduce what I wound up with here. I did clarify a few things by doing this though:

  • The factory was doing lots of data retrieval and manipulation as well as creating the ModelMap.
  • The getAvailableBarsForMember method was assembling query information from several sources. It had protected scope and there were three unit tests in place that were testing this method.
  • The getCurrentStrategiesForMember method was also querying information from multiple sources. This was the only method that used the fooRepository. It also had a protected scope and a number of dedicated unit tests.
  • The addBarStrategiesToModel method was extracted from the createViewModel method during an earlier refactoring. At one point there was also an addInvestmentsToView method that had since been in-lined. We were left with an inconsistent abstraction level in the createViewModel method.

I refactored this class in a few steps. First up I moved the getAvailableBarsForMember method into its own class called the FooBarRepository. I also kept the method on FooStrategyModelFactory as a wrapper so that all my unit tests would still compile and run. Then I moved the three unit tests for this logic into a test class for my new FooBarRepository.

It took me a little while to come up with a name for this class because I debated over whether this was a service or a repository. I ended up going with a repository name because it does retrieve domain objects.

@Component
public class FooBarRepository {
    private BarRepository barRepository;

    @Autowired
    public FooBarRepository(BarRepository BarRepository) {
        this.barRepository = BarRepository;
    }

    protected List getAvailableBarsForMember(Context context, List changeData) {
        List thing = barRepository.getThingsForMember(context);

        List memberBars = Lists.map(things, new Function() {
            public Bar apply(Thing thing) {
                return thing.getBar();
            }
        });

        List newlyAddedChangeData = Lists.select(changeData, new NewlyAddedChangeDataMatcher());
        for (ChangeData changeDataItem : newlyAddedChangeData) {
            memberBars.add(barRepository.getBarByBarNumber(reweightDataItem.getBarNumber()));
        }

        List newChangeData = Lists.select(changeData, new ChangeDataMatcher());

        return Lists.reject(memberBars, new OtherChangeDataMatcher(newChangeData));
    }

    public List getAvailableWidgetBarsForMember(List availableBarsForMember) {
        return Lists.select(availableBarsForMember, new WidgetBarMatcher());
    }
}

I did something similar with the getCurrentStrategiesForMember method. I moved it into a class called FooBarStrategyRepository and moved the relevant unit tests from the FooStrategyModelFactory test class.

@Component
public class FooBarStrategyRepository {
    private JsonConverter jsonConverter;
    private BarRepository barRepository;
    private FooStrategyRepository fooRepository;

    @Autowired
    public FooBarStrategyRepository(JsonConverter jsonConverter,
                                    BarRepository BarRepository,
                                    FooStrategyRepository fooRepository) {
        this.jsonConverter = jsonConverter;
        this.barRepository = BarRepository;
        this.fooRepository = fooRepository;
    }

    protected List getBarStrategiesForMember(UserAccount userAccount, Context context,
                                                          List candidateBars,
                                                          HttpServletRequest request) {

        String json = (String) WebUtils.getSessionAttribute(request, UpdatedBarStrategy.SESSION_KEY);
        if (StringUtils.isNotEmpty(json)) {
            List strategies = jsonConverter.fromJsonArray(json, UpdatedBarStrategy.class);
            return Lists.map(strategies, new BarStrategyFactory(candidateBars, barRepository));
        }
        return fooRepository.load(userAccount, context);
    }
}

My final step was to assess what was left in the FooStrategyModelFactory. I inlined the addBarStrategiesToModel method and then noticed that I really had two themes:
– Gathering and manipulation of data
– Creating and populating a model using that data

I decided to extract out the model creation and population into a separate method. This is the how FooStrategyModelFactory ended up looking:

@Component
public class FooStrategyModelFactory {

    private final MemberRepository memberRepository;
    private final BarViewFactory barViewFactory;
    private final JsonConverter jsonConverter;
    private FooBarRepository fooBarRepository;
    private FooBarStrategyRepository fooStrategyRepository;

    @Autowired
    public FooStrategyModelFactory(MemberRepository memberRepository,
                                   BarViewFactory barViewFactory,
                                   JsonConverter jsonConverter,
                                   FooBarRepository fooBarRepository,
                                   FooBarStrategyRepository fooStrategyRepository) {

        this.memberRepository = memberRepository;
        this.barViewFactory = barViewFactory;
        this.jsonConverter = jsonConverter;
        this.fooBarRepository = fooBarRepository;
        this.fooStrategyRepository = fooStrategyRepository;
    }

    public ModelMap createViewModel(OnlineUserAccount userAccount, Context context, HttpServletRequest request,
                                    List changeData) {

        Member member = memberRepository.getMember(userAccount, context);

        List availableBars = fooBarRepository.getAvailableBarsForMember(context, changeData);

        List availableWidgetBars = fooBarRepository.getAvailableWidgetBarsForMember(availableBars);

        List strategies = fooStrategyRepository.getBarStrategiesForMember(userAccount, context, availableBars, request);

        return createModel(member.getAccountType(), availableBars, availableWidgetBars, strategies);
    }

    private ModelMap createModel(AccountType membersAccountType, List availableBars,
                                 List availableWidgetBars, List membersFooBarStrategies) {

        ModelMap model = new ModelMap();

        List BarViews = barViewFactory.createBarViews(availableWidgetBars, membersAccountType);

        model.addAttribute("Bars", jsonConverter.toJson(BarViews));

        List strategyViews = barViewFactory.createBarStrategyViews(membersFooBarStrategies,
                availableBars, membersAccountType);

        model.addAttribute("cashFlowStrategyItems", jsonConverter.toJson(strategyViews));

        return model;
    }

}

I think the code is now cleaner than it was at the beginning of the day, although I’m sure there could be more done to it. The effect sketch did help and I think I would use it again, perhaps even when pairing.

(Please note that WordPress removed all the Java generics ‘tags’ from the code in this post)

Written by lizdouglass

December 7, 2009 at 7:23 am

Posted in Uncategorized

Tagged with ,

Log4j SMTPAppender

with one comment

Our current project is due for another release to production very soon. Last week Tom added another appender into our log4j configuration for our UAT enviroment. This appender is an SMTPAppender and it sends emails to a group list for our project team. This new appender is set to the ERROR severity. The configuration for this appender looks like this:

log4j.appender.email=org.apache.log4j.net.SMTPAppender
log4j.appender.email.From=me@email
log4j.appender.email.To=us@email
log4j.appender.email.Subject=[AppName] UAT Exception
log4j.appender.email.SMTPHost=host
log4j.appender.email.SMTPUsername=user
log4j.appender.email.SMTPPassword=pass
log4j.appender.email.layout=org.apache.log4j.PatternLayout
log4j.appender.email.layout.ConversionPattern=%d{ISO8601} %-5p [%t %x] [%c{1}] – %m%n
log4j.appender.email.Threshold=ERROR

As of this morning we had recevied 17 emails from UAT. There were 8 types of errors and  the most occurrences of any one type of error was 6. We always had access to this information in the log files of course, but getting the emails has had several advantages:

  • The emails draw your attention – the visibility of problems in UAT has been increase.
  • We’re more inclined to investigate the cause of the error/exception earlier. Previously the devs would generally only become aware of exceptions in UAT when one of our QAs asked one of us to take a look. Having the email going to all the devs also means that more people look at the exception and we are able to troubleshoot it more easily.
  • It’s easier to group exception types – we can collect data about the exceptions more easily.

The plan is to include an SMTPAppender in the log4j configuration for our production environment. I think this is a very good idea and would recommend doing it.

Written by lizdouglass

October 20, 2009 at 9:02 am

Posted in Java

Tagged with ,