In 1977 the Apple II, TRS-80 and the Commodore PET were released. In the same year David Allen Coe wrote a song for Johnny Paycheck called Take This Job and Shove It. (listen on YouTube) The hit single sold over two million copies and inspired a movie by the same title. I have no doubt that it inspired a lot of people to quit their job and find something better.
(from the album image on Amazon)
I was entering junior high school then but having grown up on a farm with the radio tuned to country music, the tune and the words stuck. In my own career I have made the choice to quit or to stay a number of times. Early in my career I burned a bridge that I later regretted. Since then I have not left a job in a way that I have later come to regret, although I have sometimes come to regret leaving the job itself.
What then should you use as criteria for quitting a job or staying in a job where you are thinking about quitting? Obviously the answer to this question will be deeply subjective, so I want you to consider that you ought to make such a choice based on much more than my opinion or an old song. With that caveat in place, let's dive into my personal opinions.
- Unhappy -- This seems obvious. If you're unhappy, you might be in the wrong job. But before you hand in your resignation, ask yourself why you're unhappy. Maybe even consult with a professional. Is it really the job that is making you unhappy? Or is it something about yourself that you could change? If you find yourself in a toxic environment and you cannot alter it, save your sanity and get out.
- Bored -- The job is unchallenging. You find yourself more interested in checking Facebook than you do your work. You complete your tasks without struggle and without learning anything new. You spend more time wondering what you'll have for lunch than you do about how to complete your work.
- Starving -- If you are not getting paid what you need to pay the bills or achieve your financial goals, ask yourself if you could do better. The most likely answer is that you can if you are willing to take some risk. Those may be big IFs for you, so proceed with care. And if you find yourself stuck, perhaps you should think of getting more education or starting a business on the side.
- Unsatisfied -- While it may seem to be the same, this is not the same as being unhappy. You may enjoy your job and the people you work with immensely but you may find that you are still unsatisfied. This may be because you find your work lacking significance or purpose. You may feel as if you're not contributing value to the community you value. A friend told me recently that we ought to, "Do those things that last, not those things that should be last."
- More -- Finally one good reason, in my opinion, to quit your job is that you want more from your career. It may be that you want to work in a different place or industry. You may want to work with a company led by people of a different caliber or with different goals and principles that you more readily identify with. Perhaps you want to explore an entirely different line of work. My father used to tell me, when assigning me a new task on the farm and in response to my complaints of being too tired, "A change is as good as a rest." You may be perfectly satisfied in your job but yearn for a new adventure. Perhaps you are a content hobbit and a band of dwarves come along and entice you to join a new startup far away and over the mountains.
- Finishing -- You may have good reasons to leave but a compelling reason to stay is to finish what you've started. If you hate to leave things incomplete or you want to simply see your current project succeed, you can stuff all the reasons you want to or ought to quit into a box and get them out after you're finished. They'll likely still be there when you're done.
- Stability -- This is where you should do what I say and not what I do. Sometimes I have left a stable job for one of the above reasons and later have thought that I ought to have stayed and made my life less chaotic for myself and my family. Too many job changes in my career has at times been a barrier for potential hiring managers. Take care when you choose to quit. Sometimes staying for another year will open up greater opportunities down the road.
- Learning -- Often the reason we want to quit is exactly the reason we ought to stay. The challenges we face in a job provide an ongoing opportunity to learn and grow. Running away from that because it's hard is often, if not always, a mistake. If you believe that you have more to learn and contribute, it may be to your advantage to stick it out.
- Opportunity -- Many employers promote from within. Some do not. If you have future opportunities coming your way, or even a likelihood of such, it may be worth putting up with whatever is bothering you and kicking things up a notch to get noticed and get promoted. Patience and hard work nearly always pay off. On the other hand, I have watched a few of my peers stay in a job far too long and pass on opportunities for growth in a lateral move, falling behind in growth and financial rewards.
- Anchor -- Your interests in other areas of your life may require you to have an anchor, a job you can count on even if you are not entirely satisfied. You may be serving your community or writing a book or caring for children or another family member. If keeping a job that otherwise you might leave in order to fulfill this other part of your life is necessary, then find a way to be at peace with that decision. It's not wrong to need the anchor or to choose another priority over your career.
Making Up Your Mind
Sometimes it's an easy choice. Sometimes it's much harder. Keep in mind that it's easier to find a job when you have a job. Reach out to those in your life that you care about and that depend on you. Get their support for your decision if you can. Get their input. They may be seeing the next move on the chessboard from the sideline when you cannot.
Weigh the pros and cons. Don't let a recruiter pressure you into making a decision. Don't make a decision because you're angry or otherwise dealing with powerful emotions that could lead you into making a bad decision. Take your time. Make a decision and then move forward. Don't consider an offer from an employer to keep you unless the only reason you are leaving is financial, and even then, take care. Once you take another offer, be sure to stick with it.
Who will win the Serverless Wars? Azure Functions is the latecomer but has much to like. AWS is the original trailblazer but appears to be slacking off in terms of innovation. I’m not sure there needs to be a winner. There will certainly be those who prefer AWS and those who prefer Azure for a variety of reasons. In this post, I’ll attempt to catalog the differences I’ve been able to find.
Incidentally, if you have not been introduced to the topic of Serverless Architectures, I suggest Martin Fowler. I have watched with fascination Martin Fowler’s posts on Serverless architectures. There are many other sources you will find through the magic of Google, but give Martin a read before you resort to the others.
Warning! The comparison below is by no means comprehensive and should not be considered conclusive. These are my initial impressions based on research only.
|Serverless Features ||AWS Lamda ||Azure Functions|
|Supported Languages ||Node.js, Python, Java ||Node.js, Python, PHP, F#, C#|
|Web Dashboard ||adequate ||excellent (VS Online included) |
|Physical Logical Container ||single container deployed from zip (Linux) ||App Service contains multiple functions (Windows)|
|Continuous Deployment ||CLI (some 3rd party tools) ||GitHub, BitBucket, Dropbox, VS Team Services, VS Online editor|
|Source Code ||closed ||open|
|HTTP endpoint per function/lamda ||requires API Gateway configuration (greater flexibility at cost of simplicity) ||automatic (one per)|
|Authentication ||unknown ||Facebook, Google, Twitter, Microsoft|
|Cross-Origin Resource Sharing (CORS) ||unknown ||supported|
|Maximum execution time per request ||5 minutes ||unlimited (potential unlimited cost)|
|Persistence of instance and environment variable ||no ||yes|
If you don’t speak the language, you won’t be much good at communicating, so for me the choice is easy. Azure Functions supports C#, my language of choice. All the rest is just gravy. I’m sure your choice and mileage will vary.
Also check out Google’s Cloud Functions as well. Though I doubt they will succeed like Azure and AWS, anything is possible.
You can find the well written brief on Phillippe Kruchten’s 4+1 architectural view model on Wikipedia along with a link to the original white paper published nearly 20 years ago. Kruchten worked for Rational, as I understand it, and so this is often referred to as the RUP 4+1 model.
Courtesy of Wikipedia
Although I have used this model or some variant of it at times, I had quite forgotten its name and origin until someone reminded me of it the other day. Of course, we often forget that UML also came out of Rational’s famous Grady Booch, Ivar Jacobson and James Rumbaugh..
And yet today I find it difficult to find software developers who know much of anything about the 4+1 model and only a few regularly use UML and even then only for simple class diagrams. So why the disconnect?
Perhaps a Version 2 of these approaches is required. What would you get if you mixed the 4+1 model with more clearly defined non-functional requirement scenarios as I’ve previously discussed and the C4 model presented by Simon Brown along with just a bit more UML that most developers are not currently accustomed to using? I’m thinking this through and will post more thoughts on it soon.
Two days ago I posted Non-Functional Requirements for the Software Architect in which I suggested that quality attributes or non-functional requirements could be categorized into a two by two grid, operational and non-operational by internal and external.
Thinking further along those lines led me to picture the illustration below and hop out of bed to put it to virtual paper.
Most quality attributes will fit into one or two of the big four: security, performance, usability and modifiability. And each of these largely corresponds to its depicted quadrant.
Security is largely an internal concern. Often external stakeholders will profess their concern with this attribute, and hence the Venn-like spill over into the external quadrant. Generally the concern for security and assuring security falls within the domain of internal stakeholders and the implementation team.
External stakeholders are mostly concerned with performance and usability. There are a number of other quality attributes such as availability that fall within or at least are closely related to one or both of those.
Modifiability is almost exclusively a concern of internal stakeholders and implementation teams. Interoperability and testability are largely related to modifiability while interoperability nearly always shares at least some security concerns.
You may mix these differently to match your circumstances and priorities, but the illustration covers the majority of software development efforts but of course does not spell out the details. For guidance on that, I recommend my previous post. If you are concerned with software architecture, perhaps this will help you to visualize how these quality attributes or non-functional requirements compete and compliment one another.
To paraphrase Bass in Software Architecture in Practice, an architecture will either inhibit or enable the achievement of a system’s desired quality attributes. Understanding your desired quality attributes well will drive the critical decisions in your architecture. And your architecture will then provide the requisite containers into which you will place your functionality. To quote, “Functionality is not so much a driver for the architecture as it is a consequence of it.”
While I am not completely certain that is always the case, it is a principle that is well worth considering when creating and refactoring the architectural elements of your system. And it is my hope that by seeing this illustrated, it will get you thinking about how your own desired quality attributes interact with internal and external teams, which are operational and non-operational, and how they may compete with or compliment on another.
I grew up on a small farm in eastern Utah a few miles west of Roosevelt. My dad is still farming but on a smaller scale these days. He and my mom dropped by for a visit the other day. They asked about work and as I described to them what I do, it struck me that there are many similarities between agile software development and farming.
Here are a few that came to mind:
|Agile Architecture and Development Aspects ||Farming ||Agile Software Development |
|Strategy ||The strategic decisions for the next growing season are often made in advance of the current season’s harvest. Will a new well be required to water the south forty? ||Strategies to improve existing systems and even to plow them under and rebuild them are often hatched before the existing system goes live. Will we move this system to cloud for improved availability? |
|Non-Functional Requirements ||Before building a new barn or corral, thought must be given to the usability of the gate, the reliability of the roof, and the performance of the cattle chute. ||Before building that new system or drastically modifying an existing one, much of the same thought process needs to occur. |
|Budget ||While we could plow more acres per day with a new tractor, can we get what we need out of the tractor we have even if we have to work forty more hours? What opportunity will those forty additional hours afford us? ||Should we buy new big iron or enter into that hosting contract for improved performance? Or should we invest in improved engineering practices to improve code performance and storage requirements? |
|Milestones ||On a hay farm, progress through the summer is measured in hay crops. For me that was 3 crops before going back to school. All work revolved around watering the hay, cutting the hay, baling the hay, and hauling the hay. Then repeat. ||Each milestone or set of sprints in agile development often take on a repetitive structure allowing the team to achieve a rhythm or cadence that moves the software toward completion. |
|Sprints ||6 days (Monday through Saturday) – Only after I started my professional career did I realize most people don’t work on Saturday. I’ve never been able to completely accept that pattern in my own life. ||2 weeks (most often) – sometimes a different interval works better. It probably depends on what you’re growing. |
|Sprint Planning ||1 day (Sunday) ||1 day (part of the 10 days in the 2 weeks) |
|Stand Up ||Every day at 6am. Lasts less than 15 minutes is identified and then tasks are begun as work from the previous day was most often discussed at dinner after dark. This includes identifying what equipment broke down the day before and who will fix it and when but rarely includes much discussion of how. The how is known. ||Usually at a more reasonable time. Since we didn’t eat dinner together, we review quickly what happened and discuss what will happen today. We also identify problems that occurred, but this works best if the resolution of such problems are taken offline. |
|Retrospectives ||At the end of the week or when a crop was put up, we took a little time out for a picnic or a day trip to the city. We reflected on how we could work together better—or how my brother and I could stop fighting long enough to get some work done. ||When done properly in the agile / scrum process, the retrospective has the power to improve a team’s ability identify and keep what worked and improve what didn’t. |
|Tactical Action ||When the baler breaks down in the middle of the wee hours of the morning while you’re baling hay that needs to be baled now, you get off the tractor and you fix it right then if at all possible. ||Sometimes, when its broken, you need to get up in the middle of the night and fix it. And then you figure out how to avoid that scenario in the future. Bugs are a part of software life but if you’re killing the same bug over and over again, it may be time to get a new baler. |
|Preventive Maintenance ||If you don’t grease the baler before you start chewing up forty acres of hay that needs to be harvested, you will find yourself fixing the baler at the most inopportune time. Far better to replace that worn out knotter and grease up the plunger before you put it to work. ||Systems deployed and left to their own devices have a tendency to break when you can least afford it. But systems and software that receive regular attention and care will provide longer service and fewer headaches. That extra tube of grease can be invaluable. |
There is one very big difference between software and farming. The former pays better and is easier.
Countless failed software development projects have been kicked off with non-functional requirements delivered to the implementation team with little to no detail. Here are a few of the worst but most common examples:
- Security – The software must be secure.
- Performance – The software must be fast.
- Usability – The software must be easy to use.
Most software professionals have been taught that non-functional requirements are important, but many projects skip over them in order to get to functional use cases and writing code. The result can be profound, leaving the implementation team without sufficient input to make critical design decisions that will be very costly to change when the non-functional requirement is later clarified.
What Every Non-Functional Requirement Needs
For every non-functional requirement, the software architect should assure that the following questions have been adequately answered.
- To whom is this quality important?
- Users and integrators
- Management team
- Implementation team
- Operations team
- Who will assure this quality is met?
- Implementation team
- Operations team
- Management team
- How will this quality be met?
- Cross cutting constraints in software
- System and network constraints
- Log analysis and oversight
- How will we know this quality is met?
- Scenarios with measures
- Monitoring and review
- Acceptable tolerance percentiles
The items below each question are not meant to be an exhaustive list but simply to give you an idea of what may be involved in answering those questions.
Classification of Non-Functional Software Quality Requirements
Clarifying and prioritizing non-functional software quality requirements may be easier when you classify them into one of four groups by answering two questions: operational or non-operation, and internal or external. The following table is anything but exhaustive but it will give you the general idea.
|Quality Classification ||Internal ||External |
|Operational ||Latency |
|Non-Operational ||Maintainability |
Business stakeholders are generally more interested in and will support efforts to meet external qualities. Implementation and IT teams sometimes have to work a little more to garner support for time and effort and expense for internal qualities.
It is often easier to build into an implementation the cross cutting concerns to measure operational qualities. Collecting performance, reliability and security metrics from executing code is always possible with well planned constraints early on in the development effort. If these qualities are defined later, the refactoring process can be challenging.
For non-operational qualities, other systems such as those used to manage support issues and ongoing development efforts are often helpful in measuring the cost of change to the system or whether usability goals are being met. Sometimes time series log analysis can be utilized to extract measures for non-operational qualities, especially those most important to external parties.
Use an Agile Approach to Non-Functional Requirements
However you choose to collect and document non-functional software quality requirements, you should continue to improve and tweak them throughout the development process just as you would with functional requirements, grooming your backlog and prioritizing based on ongoing feedback from stakeholders, users and developers.
I have been enjoying an e-book called Software Architecture for Developers by Simon Brown that was very well worth the price. I also just finished watching the author’s presentation at the 2014 GOTO Conference. A very thought provoking presentation.
Here are a few things that I like very much from the book and presentation.
- “The code is the single point of truth. It is the embodiment of the architecture.”
- TDD does not replace architecture. Do TDD inside a set of boundaries and frameworks provided by the architecture. (see Why Most Unit Tests Are a Waste by James O Coplien.)
- If the diagrams don't reflect the code, the diagrams are basically pointless. We're just deceiving ourselves.
- Component testing is preferable over unit testing but unit tests and mocks for testing against async systems are still useful.
- Layered architecture can lead to a big ball of mud because too much functionality is exposed for public use by other layers.
- Component organization over layered is preferred. Components have limited public interfaces (aka ports) and may have layers within the component that are not improperly publicly accessible.
- If a system has a very large number of unit tests, we may have an out of control layered architecture.
- “If your software system is hard to work with, change it. This is entirely within your hands.”
C4: Context, Containers, Components, Classes
I especially like Brown’s use of what he calls C4. In essence, every software system can be broken down into a simple hierarchy:
- Contexts (systems) made up of
- Containers (web server, app server, database, browser, file system, etc.) which host
- Components which expose one or more interfaces (sometimes referred to by others as ports) and contain
- Classes which implement those interfaces and the layers behind them.
By creating architecture diagrams that follow this hierarchy, it is possible to create code that matches it. It is an architecture that developers can use directly. (Side note: I have often used a Visual Studio solution to lay out a project in similar terms directly in code. I have also gone down the layered road only to regret it later and end up pulling those layers apart and encapsulating them into a component-like approach to ensure that the responsibilities and behaviors exposed to the outside world are used properly and that the system remains well ordered.)
Here is my simplification of what the author already makes rather simple with respect to these constructs. I recommend you buy the book and get full details and example diagrams, but the ideas are what is most important.
- Context Diagram - A context diagram answers what are we building, who is using it and how does it fit into our IT environment and business. It is important to note at a high level how users will interact with the system.
- Container Diagram - In the container diagram, you define the shape of the software, high-level technology decisions, how responsibilities are grouped and separated, how each container communicates with other containers, and where the code lives for each container.
- Component Diagram - The component diagrams answers what course grained building blocks of functionality are required, what are their responsibilities, and how will they interact with other components (interface and communication mechanisms such as sync, async, batched, etc.).
- Class Diagram – Brown does not explicitly discuss this level, as far as I’ve read. I assume this is because it is rather intuitive to most architects and in part because the design at the class level is often better left to the implementation team. However, from my own perspective, the architect should consider defining the public interfaces and primary classes to name and separate key responsibilities into distinct code structures that will be intuitive for the implementation team to complete—naming conventions that separate what may be thought of as traditional layers and that the implementation team will understand is crucial here.
Some of what Brown proposes breaks with what others may consider traditional software architecture. I am excited about Brown’s challenging of the status quo, questioning our assumptions. I believe his ideas will help us narrow the model-code gap (see Just Enough Software Architecture by George Fairbanks—one I’ve just added to my Kindle collection for some fun future reading).
Measurable Non-Functional Quality Scenarios
Brown covers the importance of quality scenarios, but on this topic I prefer the more pedantic but measurable approach of Len Bass in Software Architecture in Practice. I believe his emphasis on defining metrics driven quality scenarios is well worth pursuing, especially to the point of implementing logging and monitoring systems that allow you to constantly measure non-functional quality and improve against those measures. Here’s the structure that Bass recommends:
- Source – where does the input come from?
- Stimulus – what is the input?
- Artifact – what container and component are affected?
- Environment – in what context does this occur?
- Response – how and with what did the software respond?
- Measure – how much time, how many clicks, how many errors, were proper notifications were sent?
Creating quality scenarios that developers understand and can incorporate into the software they are building is critical to long term success of the software. To paraphrase the quality gurus, if you can measure it, you can understand and improve it.
Most important, if your implementation team and your stake holders understand your architecture diagrams and documents, you are more likely to succeed. And if your code does not mirror your diagrams, no amount of code reviewing will tell you whether your architecture has been implemented. And that is Brown’s greatest point in my opinion.
Platform or technology stack specific modifiers on the title of Software Architect are common. Most software architects know that the platform, like a framework, is an interchangeable implementation choice and not really part of the software architecture (see my post entitled Practical Agile Software Architecture).
Why the distinction then? Two reasons:
- Architect as Implementer - Many software architects are involved in guiding and contributing to platform specific implementation which requires specialization that is not specific to the architecture itself. I prefer this combination.
- Platform Specific Language - The platform specific software architect may be most comfortable or even required to produce artifacts that adopt the vernacular of that platform in order to make those artifacts more easily consumed by the implementation team.
The most common platform and implementation specific language elements in architecture artifacts replace the more generic terms of module, component, and software. Here’s an overly simple conversion table that I have found helpful for Java and .NET.
|Architecture Generic ||Java ||.NET |
|Module ||package with public classes defining "port" and sometimes an entire jar ||namespace with public classes defining "port" and sometimes whole assembly |
|Component ||sometimes jar only but usually whole container or daemon ||sometimes an independent assembly but usually a single process/web app |
|Software (physical allocation) ||app servlet engine for container or independent daemon ||IIS web app for one or more components or an independent Windows service |
Connectors are generally common across these stacks, with a few exceptions such as WCF and JAX. More often connectors are literally specified as a SOAP or REST or even a custom TCP based protocol. Message based connectors are very often technology specific, indicating the specific message queue but be careful to avoid limiting your architecture by specifying implementation choices. The implementation choices should be, as much as possible, left to the design and implementation team effort.
The majority of my implementation experience has been in the .NET stack. But software architecture should be the same across implementation stacks. Of course, there may be some things easier said than done in a specific platform and technology stack, and that may have an impact on your software architecture choices, but minimally so.