Flow was designed from the ground up to be modular, adaptive and agile to
enable developers of all skill levels to build maintainable, extensible and
robust software through the implementation of several proven design paradigms.
Building software based on these principles will allow for faster, better
performing applications that can be extended to meet changing requirements while
avoiding inherent problems introduced by traditional legacy code maintenance.
Flow aims to make what you “should” do what you “want” to do by providing the
framework and community around best practices in the respective essential design
patterns.

Aspect-Oriented Programming (AOP) is a programming paradigm which complements
Object-Oriented Programming (OOP) by separating concerns of a software
application to improve modularization. The separation of concerns (SoC) aims for
making a software easier to maintain by grouping features and behavior into
manageable parts which all have a specific purpose and business to take care of.

OOP already allows for modularizing concerns into distinct methods, classes and
packages. However, some concerns are difficult to place as they cross the
boundaries of classes and even packages. One example for such a cross-cutting
concern is security: Although the main purpose of a Forum package is to display
and manage posts of a forum, it has to implement some kind of security to assert
that only moderators can approve or delete posts. And many more packages need a
similar functionality for protect the creation, deletion and update of records.
AOP enables you to move the security (or any other) aspect into its own package
and leave the other objects with clear responsibilities, probably not
implementing any security themselves.

Tip

Planning out the purpose and use cases of a package before you create it will
allow for backwards compatibility by creating an unchanging interface for
independent classes to consume.

In AOP there is focus on building reusable components that can be wired together
to create a cohesive architecture. This goal becomes increasingly difficult
because as the size and complexity of an application expands, so does its
dependencies. One technique to aliviate dependency management is through
Dependency Injection (DI).

Dependency Injection (DI) is a technique by which a package can request and gain
access to another package simply by asking the injector. An injector is the
service provided within a framework to instantiate and provide access to
package interfaces upon request.

DI enables a package to control what dependencies it requires while allowing the
framework or another third party system to handle the fullfillment of each
dependency. This is know as Inversion of Control (IoC). IoC delegates the
responsibility of dependency resolution to the framework while each package
specifies which dependencies it needs.

AOP provides a means for interaction between packages through various interfaces
and aspect. Without Dependency Injection AOP would suffer from creating
untestable code by requiring you to manage dependencies in the constructor
and thus breaking the Law of Demeter by allowing a package to “look” for
its dependencies with a system instead of “asking” for them through the
autonomous injector.

Test Driven Development (TDD) is a means in which a developer can explore,
implement and verify various independent pieces of an application in order to
deliver stable and maintainable code. TDD has become popular in mainstream
development because the first step required is to think about what the purpose
of a class or method is in the scope of your package’s feature requirements
incrementally, revising and refining small pieces of code while maintaining
overall integrity of the system as whole.

Think: Before you write anything, consider what is required of the code
you are about to create.

Frame: Write the simplest test possible, less than five lines of code or
so that describe what you expect the method to do.

Fulfill: Again, write a small amount of code to meet the expectations of
your test so that is passes. (It’s acceptable to hard code variables and
returns as you explore and think about the method, cleaning it up as you go.)

Re-factor: Now that you have a simple passing test, you know that your
code as it stands works and can work on making it better while keeping an
eye on if it breaks of not. Think about ways to improve your code by removing
duplication and other “ugly” code until you feel it looks correct. Re-run the
tests and make sure it still passes, if not, fix it.

Repeat: Do it again. Look at your test to make sure you are testing what
it should do, not what it is doing. Add to your test if you find something
missing and continue looping through the process until you’re happy that the
code can’t be made any clearer with its current set of requirements. The more
times you repeat, the better the resulting code will be.

Domain-driven Design (DDD) is a practice where an implementation is deeply
coupled with the evolving business model within its respective domain.
Typically when working with DDD, technical experts are paired with a domain
experts to ensure that each iteration of a system is getting closer to the core
problem.

DDD relies on the following foundational elements:

Domain: An ontology of concepts related to a specific area of
knowledge and information.

Model: An abstract system that describes the various aspects of a
domain.

Ubiquitous Language: A glossary of language structured around a
domain model to connect all aspects of a model with uniformed definitions.

Context: The relative position in which an expression of words are
located that determine it’s overall meaning.

In DDD the Domain Model that is formed is a guide or measure of the overall
implementation of an applications relationship to the core requirements of the
problem it is trying to solve. DDD is not a specific technique or way of
developing software, it is a system to ensure that the desired result and end
result of a development iteration or aligned. For this reason, DDD is often
coupled with TDD and AOP.