Software Engineer

I am a Software Engineer. I have a Bachelor (Honours) of Science in Information Technology from the University of Sunderland - Class of 2003. I have been developing software since 2001 when I was offered a role at CERN as part of their Technical Student Programme.

By 2016 I had grown really tired of the software industry and by the end of 2019 Apple killed whatever excitement I had left. I am not sure what the next 10 years will bring. What I do know is that my apettite to do work that is impactful has only grown bigger and stronger. Great people make me tick more than anything.

I am also tired.

It's about software design - IASD

/* 
     * IASD (It's about software design)
     */
    public class FilterTest 
    {
        @Test
        public void findByName() throws Exception 
        {
            Person john = new Person("John", 20);
            Person markos = new Person("Markos", 30);

            Condition<Person> isNamedJohn = Conditions.hasName("John");
            
            Person actual = Filters.of(john, markos).find( isNamedJohn );
            
            Assert.assertEquals(john, actual);      
        }
        
        @Test
        public void findByAge() throws Exception 
        {
            Person john = new Person("John", 20);
            Person markos = new Person("Markos", 30);       
            
            Condition<Integer> between17and25 = 
                new IntegerConditionChain()
                        .gt(17)
                        .lt(25);
            
            Condition<Person> agedBetween17and25 = 
                Conditions.age( between17and25 );
            
            Person actual = Filters
                .of(john, markos)
                .find( agedBetween17and25 );
            
            Assert.assertEquals(john, actual);      
        }
        
        @Test
        public void findByNameAndAge() throws Exception 
        {
            Person johnAged20 = new Person("John", 20);
            Person johnAged21 = new Person("John", 21);
            Person johnAged29 = new Person("John", 29);
            Person johnAged30 = new Person("John", 30);
            Person markosAged30 = new Person("Markos", 29);
            
            Condition<Integer> between20and30 = 
                new IntegerConditionChain()
                        .gt(20)
                        .lt(30);

            Condition<Person> namedJohnBetween20And30 = 
                new PersonConditionChain()
                        .hasName("John")
                        .age(between20and30);
            
            List<Person> actual = Filters
                .of(johnAged20, 
                    johnAged21, 
                    johnAged29, 
                    johnAged30, 
                    markosAged30)
                .list( namedJohnBetween20And30 );
            
            Assert.assertEquals(2, actual.size());      
            Assert.assertEquals(
                    Lists.newArrayList(johnAged21, johnAged29), 
                    actual);        
        }   
    }

Find it amazing how a single method interface can be the inspiration to a good software design.

Here is the culprit.

	public interface Condition<T>
	{
		public boolean apply(T type);
	}

The idea is that you can apply a condition to any type and see if it adheres to that.

Notice how the usage of generics elevates the design. Using an Object instead would have made the code vulnerable to ClassCastException and fragile to piece together with other classes. An interface instead would force client code to implement it, pose a limit on the conditions you can apply and is rather stiff.

Then came the Filter allowing you to extract the types that satisfy the conditions of yours.

	public interface Filter<T> 
	{
		public T find(Condition<T> condition);
		public List<T> list(Condition<T> condition);
	}

Then the requirement to apply a list of Conditions.

	public interface ConditionChain<T> extends Condition<T>
	{
		public boolean apply(T type);
		public ConditionChain<T> addCondition(Condition<T> condition);	
	}

Without differentiating from the Condition interface thus being able to accomodate for it in the existing API.

With implementations providing public methods to specific conditions that make sense on the type

	public final class IntegerConditionChain implements ConditionChain<Integer>
	{	
		public IntegerConditionChain gt(final int that) 
		{
			this.addCondition(new Condition<Integer>(){
	
				@Override
				public boolean apply(Integer value) {
				return value > that;
				}
			});
			
		return this;
		}
	
		public IntegerConditionChain lt(final int that) 
		{
			this.addCondition(new Condition<Integer>(){
	
				@Override
				public boolean apply(Integer value) {
				return value < that;
				}
			});
			
		return this;
		}
	}

It’s your turn now to DRY the design by introducing a class that encapsulates the implementation of the methods related to the ConditionChain thus increasing cohesion and lowering coupling for creating specific conditions without abusing inheritance.

While doing so you get to win a postcard from Edinburgh.

Source