Chuck Conway is a software craftsman with nearly 30 years of experience. His expertise extends to Python, Generative AI, .Net, React JS, and CI/CD practices, emphasizing craftsmanship, architecture, and processes. Passionate about continuous improvement and automation, Chuck's career embodies a commitment to beautiful software and efficiency.
Chuck lives in Folsom, CA, with his wife Erin, daughter, and a cat.
We can only handle so much complexity in our brains.
Ubiquitous language
Use the same language between the coders, QA, BA, Clients
Bounded Context
Separate area’s of the system that don’t make sense to be together.
Core Domain – Focus on the most important part of the system. Think of Core Competency in business
When to unit test
Where Test Coverage meets value. At some point, adding tests doesn’t add value. I.e. principle of diminishing returns
Types of Equality
Identifier equality – do the Id’s between the entities match?
Reference equality – do the two objects point to the same reference in memory
Structural equality – do the two objects have the same values.
Entities vs. Value Objects
Entities
Have inherent Identity
Reference equality
Identifier equality
Single place for equality members
Value Object
Value objects don’t have an identifier field.
Can be treated interchangeably
Immutable
Can’t live on their own, must belong to one or several entities
How to Recognize a Value Object
Value objects are light-weight
Put most of business logic to value objects
Entities act as wrappers
When to create a Repository
Repositories are generally created for each aggregate root.
Bounded Context is a logic separation of the domain in the code. Some examples of this in use is putting all the code related to a Bounded Context under the same folder or using different schemas in the database. Yet, another possibility is different deployments.
A bad code review is a review that makes the person feel bad about the code they just spent hours working on.
We are human beings; instead of saying this is wrong, offer reasoning and suggest another direction.
Code reviews are about learning, collaboration, and conversation to improve the product, the company, and the people.
Book Recommendations
Delusions of Gender: How Our Minds, Society, and Neurosexism Create Difference
Programmed Inequality: How Britain Discarded Women Technologists and Lost Its Edge in Computing
Invisible Women: Data Bias in a World Designed for Men
97 Things Every Java Programmer Should Know
Head First Design
Mark Richards
Software Architecture Styles
Architecture Styles vs. Architecture Patterns
Architecture Styles is a general strategy to an architecture. One or more architecture patterns can be used within an Architecture Style. Architecture Styles may also be hybrids. For example, an event-driven architecture may be made up of small components and with their data sources and deployed independently. This would be a microservice event-driven architecture.
Sonya Natanzon
The Role of the Software Architect
The Three Skills Architects must have
People
The architect must be an influencer. Value proposition, explaining the solution, and selling your ideas.
Conway’s Law. Org structure influences application structure. The lines of communication influence the application structure.
Growing new leadership. A lot of the time, this means training people.
Knowledge sharing.
Delegate to others and support others as they work through the problems. You can’t take on all the work yourself.
Create room for experimentation and have tolerance for mistakes.
Technical
Always learning new technologies and ideas. And then teaching and knowledge sharing. Information hoarding doesn’t work.
Selecting a toolbox. What technologies should our company use to be successful?
4 C’s
Analytical Skills
Thought
Evolve the Big Picture – Understand the path to how we got here and then chart a path forward. Create a roadmap for the next 6 months to a year.
Champion Process – People don’t fail you; the process does. This means having code reviews, retrospectives, following best prates. The process serves the team, not the other way around. Always be looking for ways to eliminate waste, whether this means adding process or removing it.
Set Culture and Values – Build, change, and influence culture and values.
The Four Immeasurables
Near Enemy and Far Enemy
Loving Kindness
near: selfish love
far: ill will
Compassion
near: pity
far: cruelty
Empathic Joy
near: blind euphoria
far: jealousy
Equanimity
near: indifference
far: paranoia
Near Enemies of Software Architect Attributes
People
near: functional management without influence means you become a taskmaster. You don’t have buy-in from your team.
Tactical
near: Individual Contributor rarely leaves time for a broader strategy. You don’t have the time to step back and see the big picture.
Thought
near: Ivory Tower Architect – They make architecture an academic exercise without real and practical value. They get hung up on the "right way" instead of being pragmatic and shipping software.
Solution Process
Problem Definition
problem statement
supporting analysis
as-is documentation
Solution Proposal
Models diagrams and other documentation
Technology selection
POC’s
Ubiquitous language definition
Implementation
API Definition, schemas, data models
production code
changes to everything are done in the previous phases.
Enhancement
Changes
Bugs
Maintenance
Book Recommendations
The Five Dysfunctions of a Team: A Leadership Fable – Patrick Lencioni
Multipliers: How the Best Leaders Make Everyone Smarter – Liz Wiseman and Greg McKeown
Nate Schutta
Thinking Architecturally
We can’t predict the future; we must decide on something concrete now and stick with it. We can’t be chasing the future. We also must plan for the future and move to technologies when it makes sense for the business. That might be because it gives us a competitive advantage or the cost of supporting our existing platform is rising.
In software, we don’t know. It’s about trial and error. Let’s try it and find out.
Every single choice has trade-offs. When someone comes to you and says, "This is the most amazing thing; it’s going to solve every problem we’ve ever had," you should immediately ask, "What are the trade-offs?" This is design, in a nutshell, this is architecture in a nutshell.
There are three answers to every computer science questions
42, this is the geek check to see who is in the know and well-read
Another layer of indirection
it depends
Balancing when to use what tool over the other is the job of the architect. There is no perfect technology.
When presenting new technologies, you should be able to answer the following questions:
What do you like about this technology?
What DON’T you like about this technology? — you should have spent enough time with this technology to understand its shortcomings. If you haven’t, why are you recommending it?
"Quality Requirements" is another way to say the "ilities", for example, Scalability, Reliability, Simplicity.
There are two ways to sell you the idea:
The hammer – I’m going to tell you this is a good idea
The ninja – I’m going to convince you that it’s your idea and it’s a good one.
Sam Newman
Microservices
The Fallacies of Distributed computing apply.
Monolith does not mean a big bad legacy system. It’s just a bigger deployment package with multiple services/domains that share their data.
Fundamentally, Microservices are a type of distributed system.
Any distributed network had the concerns of latency.
You have the concerns of consistent data. Microservices embrace this idea of a single source of truth.
One of the things that set Microservices apart from other services is it does not share its data. It owns all its data. It’s truly an encapsulated service, including its data. There is no big shared database on the backend.
The problem of partitioning is when one service can’t see another service. This happens there is a disruption in the network.
The opinions of Microservices is that each service is independently deployable and that data that mutates is stored within a service boundary.
Microservices is end-to-end functionality modeling around the aspect of the business domain.
Microservices is the first post-DevOps system.
The Monolith is not the enemy. The Monolith is not the enemy; it’s not bad. A monolith is just a different style of architecture.
Microservices is typically not a place to start but a place to end. Start out discovering your business domain by building a modular monolith. When you’ve reached your current architecture limits, and Microservices is a good fit, move to a Microservice architecture.
Not all of your services need to be Microservices.
Microservice size is not about code but about the business domain, functionality, and data. It’s also about how easy is it to create a service? The easier a service is to create, the more and the smaller the services will be.
Start off with one or two services, then add more services as you are successful with the first services. Adding microservices is not an on/off switch but a dial was to increase the volume.
Stick with, you know. Don’t overload yourself with things to learn. If you know, Go, stick with it.
The only prerequisite to Microservices is Log Aggregation.
Data is accessed and mutated via the Microservice, not directly at the data source.
Microservices is a style of modular architecture. It’s data encapsulation at a service level.
Microservices is about functional slicing at the team and architecture level. This includes the UI level also.
Always be measuring – don’t do it because you think it’s the right thing to do. It might not be.
Managed memory is cheap. That’s not true, allocation is cheap and garbage collection is expensive. Garbage collection stops the world while things are cleaned up and optimized. Sometimes memory cleanup can impact the performance of the application.
Performance Low Hanging Fruit
Object reuse
Object pooling. Pass in existing array rather than allocating a new one. Preallocate array length.
String concatenation.
Use StringBuilder, Preallocate length if possible.
In Code: MyParamsMethod("Hello", "World"); MyParamsMethod();
Complier: MyParamsMethod(new {"Hello", "World"}); MyParamsMethod(new [0]); // this creates a new array object in memory
Instead, do this in code: MyParamsMethod(new {"Hello", "World"}); MyParamsMethod(Array.Empty); // reuses an existing empty string array in memory. It's the same idea behind string.Empty
Suggestion: Introduce overloads with common number of arguments.
Boxing
Boxing creates a new object on the heap. Now you have two memory locations with the same value. Changing either value does not impact the other value.
Suggestion: Introduce generic overloads
Closures
The complier converts closures to classes. Captured values are passed in as constructor parameters. This class is then allocated to the heap.
Suggestion: Avoid critical paths. Pass state as argument to lambda. Investigate local functions. Since local functions lifetime is known, it can be allocated on the stack where allocation and cleanup are cheap.
LINQ
Lambda expressions are treated the same as Closures. They are allocated as a class to the heap. Because much of LINQ is based on static methods, additional allocations of Iterators and IEnumerable happen.
Suggestion: Avoid critical paths. Use good old foreach and if statements
Iterators
iterators are rewritten as a state machine, which means more allocations to the heap.
Suggestion: Return a collection. Be aware of the cost.
async/await
Async/await also, generate a state machine. Task and Task also trigger more allocations which then can’t be reused.