Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Monday, July 10, 2017

The Role of the Software Architect


What's in a Name?

Collaboration improves when the roles of individual team members are clearly defined and well understood.
— Tammy Erickson April 05, 2012
I recently switched roles, from distributed systems engineer to distributed systems architect. I've been doing professional software development for about ten years. I remember telling my boss five years ago that my five year plan was to be a software architect. Guess that worked out! (Now what!?)

Looking back, it's obvious that I'm much better equipped for the position than I was five years ago. But the role itself also seems to have changed over time, as the tech world has evolved to integrate agile tendencies. So as I approached the new position, I found myself needing to repeatedly answer the same questions. Here are some of my notes.

What is a "Software Architect"?

An architect is an engineer who empowers other engineers as a force multiplier.

An architect focuses on the big picture of the system as a holistic product, rather than owning individual components.

An architect drives consensus between tech leads and product managers, rather than making or dictating critical decisions.

An architect promotes flexibility by identifying potential interface points and presenting engineers with options to reduce the cost of change, balancing short-term tactics and long-term strategy.

An architect is a specialist with strengths in diagramming, documenting, communicating, information architecture, and system design.

What is a "Distributed Systems Architect"?

The title itself doesn't seem to have a commonly accepted definition. So let's build one from similar titles.

A systems architect defines the architecture of computerized systems to fulfill specified requirements. Such definitions include the design and specification of components, component interactions, interfaces, technologies, resources, and dependencies.
Wikipedia - Systems architect
A distributed system is a model in which components located on networked computers communicate and coordinate their actions by passing messages to achieve a common goal. Significant characteristics of distributed systems include: concurrency of components, lack of a global clock, and independent failure of components.
Wikipedia - Distributed computing

Therefore, a distributed systems architect is a systems architect who defines the architecture of distributed systems, with special focus on communication and coordination between components.

Increasing Complexity

Whether you call yourself a software architect, a systems architect, or a distributed systems architect, the computing landscape continues to evolve with or without you. A few things specifically have changed in the last decade or two that make these roles harder than they used to be.

1) The demand for high availability and intolerance of down time has caused components that used to be simple to be replaced by distributed systems. Likewise, previously distributed systems became systems of systems. With multi-layer systems it's no longer appropriate to rely on legacy architectural design patterns, like a single API layer or a single communication bus.

2) The demand for agility and larger development teams has mutated service-oriented architecture into microservice architecture. This mode of development pushes even more glue code out of the individual components and into the platform or infrastructure layers, increasing their complexity. Deploying and managing a sufficiently large system of microservices increasingly requires a container or application platform above and beyond the scope of modern infrastructure platforms.

3) The demand for hyperscale (the ability to quickly scale up and down without re-architecting) often calls for the architect to design a dynamic system that considers dramatic change over time normal to system operation. The ability to survive a flash crowd of users (aka the slashdot effect) caused by social media is increasingly required by even the most mundane of business domains. Preparation for this and similar phenomenon happens largely at the system level.

4) The demand for open source software creates proprietary systems that aren't completely controlled by their developers. Unlike proprietary components, where one company is in charge of development, open source components can be both easier to change (with a fork or local modification) and harder to persist change (merging changes upstream often requires politics, persuasion, and modification). Partial control of the architecture of a system is nothing new, but partial control over individual components (specifically their APIs and communication patterns) increases demand for intermediary translation, proxy, and caching services. These ancillary components are often tightly coupled with one component to allow loose coupling with another, but tight coupling in a microservice environment often requires new deployment and management patterns, like sidecars and pods.

Musings

Not all software engineers will or should aspire to be software architects. Architecture is a specialization of the engineering track for people who enjoy abstract thinking, are good at and enjoy documentation and diagramming, have the ability to be political and drive consensus, and have demonstrated a solid grasp on prior art and the competitive landscape.

An architect may or may not also be an engineering manager or tech lead, depending on how much focus on architecture is required or desired. Since being hands off of code tends to erode peer confidence and personal skill set, it is desirable that an architect continue to be partly involved in programming efforts, either through tool, component, or ecosystem development.

The bigger an architecture team gets, the more they tend to lose touch with the every day life of the engineers they're supposed to be supporting. However, the more engineers an architect has to support, the less time they will have to stay hands on with code. So a balance must be struck such that architects retain respect and skill yet also spend enough time on architecture to actually provide the benefit of a higher level perspective. It's a fine balance.

Ontological Evolution

The idea of a distinct architect role has in recent past become somewhat contentious among software engineering agile practitioners. The more senior a thought worker, the less they want to be told what to do. But at the same time, modern development patterns are pushing complexity out of individual components with well defined teams into the between space. Plus each component may have a life of its own: independent release cycles, independent versioning, multiple interface/protocol paradigms, independent motivations, and external contributors. Someone has to align these components and the teams that develop them, to unify them into a single cohesive system. So just as engineering practice has evolved, so must architecture practice evolve from controlling and managing technical vision to leading the direction of its evolution. And since collaboration is easier with clearly defined roles, hopefully this new definition can help point the way.


(Revised on 2017-07-13 to expound on the increasing complexity of systems and the increasing demand for architectural design.)

Saturday, May 10, 2014

TDD Is a Tool, Not a Religion

Catching Up

The internet is abuzz since DHH's blog post: TDD is Dead.
There have been many responses, including many by Bob Martin.

Breaking News

The latest new entry to the saga is a video conversation on YouTube where DHH, Martin Fowler and Kent Beck discuss the virtues and pains of test driven development. Definitely worth watching.

Subjective Summary

  1. TDD scratches an itch. It's one way to make you feel good about your work, confident that it works as intended, every step of the way. 
  2. TDD does not work well for all problems, like when the output is unknown or unquantifiable.
  3. Self-testing code (programmatic & repeatable) is highly desirable, but TDD is not the only way to get there.
  4. Heavy use of reflective mocking can tightly couple tests to implementations, counteracting one of the primary reasons to have tests: to enable refactoring. (Bob Martin has some thoughts on when and how to mock.)
  5. Programming has many trade offs (testability, maintainability, usability, speed, etc.), and it is important to keep them all in perspective, re-prioritizing as needed, without becoming myopic.

Corollary

Just because writing unit tests and making them pass is easier and provides faster feedback than end-to-end tests doesn't mean unit testing is more important. It's critical that good unit design doesn't come at the cost of good system design.

I'll leave you with my favorite list of Object Oriented Design Principles. As with most sets of goals, it's impossible to satisfy them all all the time, but it's important to keep them all in mind, and know when to apply them.

Saturday, September 21, 2013

SteamLevel

SteamLevel.com Forwards Here.

SteamLevel was a site for comparing gamer profiles on Valve's Steam digital distribution platform.

The primary reason I wrote SteamLevel was to be able to decide what game to play at LAN parties with my friends. We could add all the people there to the search list and it would generate a big table of all our games, making it easy to see which ones we all had.

But hosting a web application is expensive. There was no ad revenue and not many users. I tried Amazon sponsered links to games, but that just felt like a slap in the face to my users, who were there because of Steam, not Amazon's digital distribution platform.

But the real problem was that I had heavily cached everything. So it took gobs of memory. And web hosts really hate to give you memory. Memory turns out to be the hardest thing to increase. It's easier to get a dozen CPU cores than it is to get more than 4GB of memory, and my host had capped me at 2GB. I was hosed. The application needed a rewrite to even continue using that web host and anything with more memory was 10x as expensive. I just really didn't want to pay that much for hosting. it would have been cheaper to buy my own box and upgrade my ISP to business class.

So SteamLevel is down, indefinitely.

It may get resurrected at some point. I still own the domain. But not today. Sorry.

Sunday, August 25, 2013

Updating Nexus 7 (2013) from JWR66N to JSS15Q on Windows

So the Nexus 7 had 2 issues at launch: GPS & Multitouch

The launch android build that comes with the Nexus 7 is JWR66N. The fixes are in JSS15Q.
Find your build number: Settings > About Tablet > Build Number

There was a patch soon after launch, JSS15J, but it doesn't fix either of the above issues. If you don't already have JSS15J google probably wont give it to you over the air (OTA) any more, because it doesn't fix the issues and might make them worse. If you already have JSS15J don't worry, you can still upgrade.

Now if you're squeamish about developer mode you shouldn't be here, just wait for Google to give you JSS15Q over the air. But if you want to get your hands dirty you can resolve those pesky issues now!

1) You'll need developer mode enabled on your tablet.
http://www.androidcentral.com/how-enable-developer-settings-android-42

2) You'll need to change the USB mode on your tablet to "Camera(PTP)".
http://zacktutorials.blogspot.ca/2012/08/nexus7-android-development.html

3) You'll want "stay awake" and "usb debugging" enabled in your developer options on your tablet.
http://zacktutorials.blogspot.ca/2012/08/nexus7-android-development.html

4) You'll need to download and unzip the Android SDK for Windows.
http://developer.android.com/sdk/index.html

5) Launch the "SDK Manager" in the zip you just downloaded and install the "Google USB Driver". (It'll probably ask to install the SDK and Android 4.3 while you're at it.)

6) Modify the USB driver to add the device ID of the nexus 7 when in recovery mode.
http://blog.dantup.com/2012/10/fixing-adb-device-not-found-with-nexus-7-in-recovery-mode

7) Plug in your tablet via USB (it will attempt to install drivers if it's the first time or it has failed before).

8) Install the newly modified device driver.
- Go to the Windows Device Manager, select your tablet from the "Other devices" category, right click and select "Update Driver Software".
- Opt to browse your computer for driver software and point it to "\extras\google\usb_driver".
- Note that the modified driver won't pass checksum and thus wont pass signature validation. So you'll have to approve it when it warns you.

9) Run adb to request device debug authorization.
- Open the command prompt (cmd in the start menu).
- Navigate to \platform-tools
- Run "adb devices"
This should print out one device as unauthorized.

10) On your tablet, authorize your computer. Select "always allow from this computer".

11) Run "adb devices" again to make sure your device says "device" and not "unauthorized".

12) Download the "JWR66N->JSS15Q OTA" or "JSS15J->JSS15Q OTA" depending on which version you have on your tablet (Settings > About Tablet > Build Number).
http://forum.xda-developers.com/showthread.php?t=2415497

13) Use adb to reboot your tablet into recovery mode and side load the update.
- Follow Step 11 onward from http://www.droid-life.com/2013/02/12/guide-how-to-use-adb-sideload-to-update-a-nexus-without-root-or-custom-recovery/

14) Do a happy dance!

For the record, I found the responses on this stack overflow question helpful when trying to figure this all out:
http://stackoverflow.com/questions/11974700/nexus-7-not-visible-over-usb-via-adb-devices-from-windows-7-x64#14106931

Apparently this process is easier on the Mac, because the device drivers don't have to whitelist device IDs and "just work".

Friday, December 19, 2008

Lua Deep Equals

I was surprised when I couldn't easily google for a Lua deep compare function. It's main purpose is to compare tables and check if they have the same values, but of course it's recursive so it just uses ~= to check for difference in non-tables.

Anyway, so I wrote my own and figured I'd post it here for posterity. Maybe you can come up with a shorter version?

-- Deep Equals
local function equals(t1, t2)
   if t1 == t2 then
       return true
   end
   if type(t1) ~= "table" or type(t2) ~= "table" then
       return false
   end
   local v2
   for k,v1 in pairs(t1) do
       v2 = t2[k]
       if v1 ~= v2 and not equals(v1, t2[k]) then
           return false
       end
   end
   for k in pairs(t2) do
       if t1[k] == nil then
           return false
       end
   end
   return true
end