Conceptual design as part of development process

How could conceptual design fit into a complete software development process? Could one start by eliciting requirements, then analyze them, and as part of that analysis process (and iterating with your client), develop and specify a concept model? And to the extent possible, try to nail that down before starting the “physical” design (modules, interfaces, etc.). Of course, you might have to go back and revise the concepts as you learn more in the physical design or implementation activities.

1 Like

Let’s try it with a Todo app.

Customer: “I want a Todo list app, and I think it would be cool to browse all of my archived tasks (completed or not), also I want to categorize tasks, and I’d like to be able to share some Todo lists, either public, secret or to specific people. Can you build this for me?”

1 Like

Welcome, Stephen @siegel and @Tom!

Yes, you could start with a conventional requirements process and then do a concept design. That would essentially be treating concepts as a kind of architectural style.

A better approach, which is what I advocate, is to use concepts to guide the discovery and shaping of requirements. This leads you to more reuse, not only in design but also in requirements too. For the implementation, to the greatest extent possible, I advocate coding concepts as free standing modules, and using whatever modularizations (eg, abstract data types, OO patterns) you like within the concept modules. This is the approach we teach our students at MIT.

So, if I were approaching Tom’s challenge, I’d start like this:

  • A Todo list app? Explore the Todo concept as found in typical apps.
  • Categorizing tasks? A Label concept? Or Folder?
  • Sharing? I’d consider concepts for AccessControl, Capability, maybe SharedDoc…

It’s worth noting that Component-based software engineering (Component-based software engineering - Wikipedia) is a Software architecture pattern (Software architecture - Wikipedia) specific for the web domain, more specially for the React, Vue, Elm (web components) model.

If you plan to implement your UI with a library / language / framework supporting the web component model, then your concepts will be components.

In other words, Component-based software engineering / architecture is compatible with Concept-based design. Both concepts, components are modular and their synchronization, communication, coupling is loose.

You can think concepts as an abstract DSL, and Component-based software engineering as an implementation mechanism.

Thanks, @metamn! Exploring components as a basis for implementing concepts is a good idea to pursue. Two questions to consider:

  • Can you make the concept implementations independent? In component lingo, this means having no “use” relationships between components. The way we teach implementing concept design in our class at MIT is to use synchronizations in controller actions to connect the concept implementations. As an architectural pattern, this is Kevin Sullivan’s mediator.

  • Should concept implementations be full stack? In Deja Vu, concept implementations included a frontend and backend component. This is also the approach that Nectry takes as far as I know. It’s nice because there’s no extra frontend code that’s needed. But this approach can be limiting, and makes it hard to design the kind of typical frontend in which widgets for one concept are embedded within another (eg, an upvote button being placed in the enclosing box of a social media post).

We have had some success with full-stack concept implementations composed in the mediator style as @dnj describes. Mediators go a long way towards keeping component implementations independent while allowing your application to grow and evolve (say, in response to evolving requirements). Their event driven nature also play nice with all sorts of modern tech stacks (e.g., microservices, serverless) allowing you to build serious applications.

Thank you @dnj for the questions.

Let’s take a look at the todo, label concepts from the book together with the todo-label synchronization app and choose React for Component-based software engineering. (I’m more familiar with this library)

With these examples I’ll try to answer multiple questions, affirmations in this thread.

**concept** todo
**purpose**
keep track of tasks
**state**
done, pending: set Task
**actions**
add(t: Task)
when t not in done or pending
add t to pending

delete(T: Task)
when t in done or pending
remove t from done or pending

complete(T: Task)
when t in pending
move t from pending to done

**operational principles**
after add(t) until delete(t) or complete(t), t in pending
after complete(t) until delete(t), t in done
**concept** label [Item]
**purpose**
organize items into overlapping categories
**state**
labels: Item => set Label
**actions**
affix(i: Item, l: Label)
add l to the labels of i

detach(i: Item, l: Label)
remove l from the labels of i

find(l: Label): set Item
return the items labeled with l

clear(i: Item)
remove item i with all it's labels

**operational principles**
after affix(i,l) and no detach(i,l), i in find(l)
if no affix(i,l) or detach(i,l), i not in find(l)
**app** todo-label
**include**
todo
label [todo.Task]
**sync** todo.delete(t)
label.clear(t)

How could conceptual design fit into a complete software development process?

  1. The DSL, the syntax is pretty clear, it’s better than plain English.
  2. The DSL contains more information than an UML diagram (operational principles, state).

To conclude and answer @siegel 's original question, we can say that in the software development process, during the design phase, is good to think in concepts, and the requirements can be delivered with the concept, app DSL syntax.

You can think concepts as an abstract DSL, and Component-based software engineering as an implementation mechanism.

  1. The concept DSL is – fully, easily (even automatically, via a generator, AI) – translatable into React components
  2. However, on syncing concepts, when implementing the app DSL, aka the mediator pattern, at least in React things get complicated
  3. React lifts state up from children (todo, label) into the common parent, the mediator component (todo-label). Sharing State Between Components – React
  4. This way the concept components become less and they won’t resemble anymore the original DSL. All state, actions, operational principles from concepts will be removed, and lifted up into a single shared state in the parent.

This makes me conclude that, from the software development process point of view, after the design / requirements are ready and delivered using the concept / app DSL, the first iteration in the implementation process can be an 1:1 translation of concepts into React components.

Then on next iterations this 1:1 translation morphs into something else.

In Thinking in React – React the first iteration is steps 1-3, the next iteration is steps 4-5.

Can you make the concept implementations independent?

  1. Initially concept implementations are independent
  2. After syncing them, they become dependent on the parent, the mediator component

Should concept implementations be full stack?

hard to design the kind of typical frontend in which widgets for one concept are embedded within another (eg, an upvote button being placed in the enclosing box of a social media post).

If I get this well, full-stack here refers to components / concepts connected to a backend, and the problem is nested concepts: they imply nested access to the backend.

If this is the problem, the solution is GraphQL, where every concept can declare its own data interface / needs to the backend, and when concepts are nested the GraphQL engine does an auto-merge of these individual needs into a single, optimized call / response round-trip to the backend.

Edit 1

  • Only state will be lifted
  • All state, actions, operational principles from concepts will be removed, and lifted up into a single shared state in the parent. → All state, actions, operational principles from concepts will be removed, and lifted up into a single shared state in the parent.

I think you point out a lot of insightful things here @metamn. I have some thoughts on some of your points.

You can think concepts as an abstract DSL, and Component-based software engineering as an implementation mechanism.

I share a similar view. Component-based engineering can be one of many implementation strategies.

The concept DSL is – fully, easily (even automatically, via a generator, AI) – translatable into React components

I am not sure how easy that is, it might depend on your implementation strategy. For instance, what if you had a microservice architecture to generate? I could imagine a series of concept specification refinements to get you to something that is implementable.

After syncing them, they become dependent on the parent, the mediator component

This dependency worries me. Its probably definitionally at odds with mediators too which maintains the independence of the components and localizes relationships in the mediator itself. Perhaps its the case that mediators are not the right approach to composition in this implementation strategy?

I’m not a React expert, so I don’t really know how hard it would be to translate concepts fully into React, but my student Geoffrey Litt did something like this as part of his Riffle work and can maybe share what he did.

The main snag I see with trying to do the composition all client side is that you can’t use concept sync to establish security properties. That’s why I’ve been assuming that concept syncs need to be at the backend.

@nphair thanks for your observations.

On DSL → React code generation

Since a concept is a DSL you can generate whatever code you want, even a microservice, which is yes, more work than generating a simple React component.

On syncing / mediator

Loose coupling in component based architectures is achieved via the Dependency Inversion Principle. The methods of implementing this principle vary from Dependency Injection, the Mediator Pattern, Unidirectional data flow; or these concepts overlap.

In React I see definitively the mediator pattern applied when two components sync via a new parent component which owns their common state; I also see dependency injection, when the parent injects back the state management (the state, the state updater function) to the children; and this mechanism results in an unidirectional data flow.

In other languages / libs this implementation might be completely different, but I guess the theory should be the same.

For @dnj thanks pointing out Geoffrey. I’m following his work, good to know I can ask React related questions.

On syncing client-side I’m more optimistic with the React / GraphQL / co-location scenario. What I see is that React is capable to describe / declare all it’s external needs. For data it’s GraphQL. For security it might be another mechanism, or perhaps can be embedded into GraphQL.

Overall, I’m glad this topic came up with all these valuable contributions. Now I see concepts as a good base for requirements, and a relatively easy way to implement them with React.

As Daniel mentioned, I’ve done a bit of thinking on how concepts and React applications interact. No firm conclusions, but here are some tentative thoughts.

I don’t think concepts map one-to-one to React components. In MVC terms, React should be responsible for the view, and concepts are a separate part of the system closer to the responsibilities of a model and controller. All the usual arguments for MVC also apply here. The model layer should be testable in isolation, you should be able to have multiple views of the same model, etc.

This is just a general sketch and there are many specific ways you could implement this rough architecture in a React app. In the context of the Riffle architecture, that might mean a concept defines a relational database schema, some queries / views over that data, and some write actions over that data. Daniel and I tried implementing a tutoring bot roughly using this style and it seemed like a promising approach.