In this series I shall dive into topics such as ORM's, automatic data object mapping, dependency injection and other staples of modern software development. I shall examine the pros and cons of each, and consider any alternative approaches that I have been able to find.
I have been working as the lead developer on a medium sized architecture for several months now. Some parts are hard to follow spaghetti code, other parts are much clearer. I worked with the previous project lead to develop a new architecture that was supposed to give us structure and help us develop faster and with fewer bugs, and yet we find it cumbersome and not entirely bug free. We suspect that it may be starting to slow us down.
Maybe I am deluded, maybe I am an incorrigible dreamer, but I can't help wondering whether there isn't a better way...
We store our data in SQL Server. The data structure is defined in C# classes that EntityFramework uses to generate the database schema and migrations.
For faster loading and advanced querying we store composite views of this data in elasticsearch. Basically we use it as a glorified cache, and we have trouble keeping it up-to-date.
The cache updates and a small number of business rules are run via code that intercepts each write operation in EntityFramework.
We use HangFire to queue and run jobs that must run in the background. HangFire gives us a nice interface and automatic retries for free.
The code vaguely follows a layered architecture, but the passage of father time and several interns hasn't done it any favours.
Currently the app runs on a single server, serving a small number of users, but many apps do not have this luxury. This begs the question: What might we need to change in order to run at scale from the cloud?
This is a provisional roadmap and may change.
SQL ORM's and in particular the one we use: EntityFramework.
- Querying and reading data
- The poor performance of reading data from linked tables
- Change tracking and why it could be bad
- Could there be a better way?
- Pros and cons: the bits I like and those I would rather avoid.
- Use as a cache and the difficulty of keeping it up to date
- The challenges of large index generation
- NoSQL vs SQL: could we have both in one storage provider?
- What it can do
- Why is that bad?
- Runtime mappings vs automated code generation
- How we use it
- Why we use it and what we might really need it for
- Double dependency trees
- Alternative approaches
Ideas from the world of functional programming, part 1
- How to combine immutability and EntityFramework
- How to combine immutability and AutoMapper or its alternatives
Ideas from the world of functional programming, part 2
- Fun with .Select, .SelectMany, Linq and the query syntax
- What should we inject and where?
Reacting to changes: events, actors and stuff
- The need to react to certain types of changes
- How we manage it
- Could we use Microsoft Orleans, Akka, or something else instead?
What if we had to run at scale in the cloud?
- What might we have to do differently?
- What might we prefer to do differently?
Tying it all together
- My favourite ingredients
- A recipe for combining them
(some time later) How it all turned out
- The bits we liked and the bits we didn't like
- How we would do it if we started afresh.
Most people want to make things perfect. Sometimes we evaluate the complexity of an upcoming goal or a problem. So, the fear to not complete it perfectly or "wrong" (Yeah, who are judges? 🤔) stops us even from trying.