The NEA is structured as it is for good reason: to support the process of your development and to mirror real-world development life cycles. Your write-up is expected to tell the story of your process.

Patterns of effective developers

Effective developers often work in a way that mirrors the structure of the NEA.

flowchart TD
    A[Analysis] --> B[Design]
    B --> C[Development]
    C --> D[Evaluation]
    D --> B

Analysis

Effective software developers plan their programming meticulously. First, they analyse the problem to decide what kind of solution is appropriate. Sometimes solutions already exist which can save the developer time (there may be no need to code a solution when a perfect solution already exists). Often, solutions exist but are imperfect. By taking the time to consider existing solutions and the scope of the problem developers want to solve, they achieve two things: they build confidence that the project they are working on has value and more thoroughly explore how their idea might manifest in the real world.

Analysis often includes drafting a list of requirements to explicate the scope of the project, deciding what is essential, nice-to-have, and out-of-scope.

Another key question to consider is who the solution is being made for: what do they need? Of their needs, which are most important? Deciding a list of requirements in advance gives the developer something to work towards and defines ‘success’ in the context of their project.

Design

Once ‘success’ is defined, developers can plan their design. There is one key question at the heart of this process: what is needed to execute the vision? Answering this question:

  • forces refinement of one’s understanding of the problem, leading to a better solution;
  • establishes the elements and data structures required for the solution to be effective;
  • clarifies how the different parts of the solution interact with each other;
  • solidifies what ‘success’ means by deciding how the solution should behave with test data.

Time taken doing careful planning saves time coding and results in better code. If developers can understand at a high-level what they need to do and how the different pieces of their project interact, coding becomes a process of surgical implementation rather than blind exploration.

This is not all to say that developers don’t change their minds: on the contrary, often, a design will be meticulously drafted and then code gets written which reveals a problem. Maybe the design is bad and this doesn’t become apparent until it meets the real world. Maybe the design is perfect but the developer lacks the skills or knowledge to execute it. Maybe the design and implementation are good but the requirements of the project change. Most plans don’t survive 5 minutes in the real world. This is fine. Iteration and refinement are part of the process.

The case for blind exploration

Blind exploration can be a legitimate part of the design process when it is used as a tool to figure out how things work, particularly with unfamiliar tooling and libraries. It can be useful to create a limited prototype to figure out what’s possible and what a good design looks like—often realised through reflecting on bad designs made along the way.

Blind exploration does not mean thoughtless exploration. While a developer might not know exactly what their implementation will look like, they should still have a basic understanding of what they are trying to achieve: for example, what tests will their implementation pass for them to be satisfied that it is progress towards their goal?

Consider a self-taught developer who wants to make a platforming game. They might create a mock-up of a player character and a simple platform to better understand the requirements of their project and inform their design choices. The process of creating this prototype might reveal things they hadn’t considered before:

  • how do they best represent the platform?
    • which data structures, if any, work or don’t work?
  • how do they handle persistent game state so the platform appears game after game?
    • save to file (if so, how?)? hard code? reset on restart?

Blind exploration often raises questions and unforeseen problems, the overcoming of which stretches one’s understanding, providing experience of what doesn’t work and empowering more thoughtful design in the future. The important thing is to go beyond blind exploration: use lessons learned on throwaway prototypes to build something that lasts.

Development

With a good design in hand and clear test cases established, developers can focus on writing as little code as possible to meet the requirements. If the tests are comprehensive, writing the bare minimum code to get the tests to pass should be enough.

Effective developers write some code, test it, reflect, and repeat.

flowchart TD
    A[Code] --> B[Test]
    B --> C[Reflect]
    C --> A

Iterative development

During the process of writing code, it can become apparent that the tests aren’t comprehensive or that they don’t reflect the real world—in which case, they need updating.

The need for a new data structure might emerge that hadn’t been accounted for which means the design needs updating.

Most likely, bugs will be encountered. They need categorising (is it a problem with syntax or logic?) and squashing.

The most important question with all the above is when do these things need to happen?

If test coverage is insufficient, it would probably be sensible to update the tests now and note the change. If the scope of the new tests requires design changes, however, it might be best planned for later.

Likewise, if a new data structure is needed that changes to the original design, this is a substantial piece of work that should be undertaken with due care.

Depending on the impact and suspected source of the bug, its fix might be best planned for later (is it minor? does it likely stem from an unrelated piece of code?). If the bug is small and salient to the current work, it could be wisest to deal with now.

Effective developers think hard about the problems they encounter and are able to justify their approaches to dealing with them.

Evaluation

Evaluation is a critical part of all long-term projects and should happen at key moments during development and at the end of the development process.

Key moments in development could include:

  • the completion of a planned feature;
  • the completion of a module;
  • the completion of a prototype;
  • the need for design changes being identified.

For developers with clear and measurable requirements, evaluation is trivial:

  • Does the solution meet the developer’s requirements?
  • Does the solution meet the stakeholder’s requirements?
  • Do all the tests pass?

When the answer to the above questions is ‘yes’, it might feel like there is little to say. The evaluation, at this point, becomes about the changes and compromises needed to get to this point. Few plans survive 5 minutes in the real world so how did the plan change? Maybe the plan didn’t change—so what barriers were encountered a long the way? What was learned?

When the answer to these questions is ‘no’, evaluation can be its most insightful. Why is the answer ‘no’? Are any changes in the scope of the project or design needed? What needs to happen next?

Effective developers are able to articulate the success (or not) of their solution and explain, with evidence, how it meets their project’s requirements.