Skip to content

Software Development Blogs: Programming, Software Testing, Agile Project Management

Methods & Tools

Subscribe to Methods & Tools
if you are not afraid to read more than one page to be a smarter software developer, software tester or project manager!

Architecture

Try, Option or Either?

Xebia Blog - Wed, 02/18/2015 - 09:45

Scala has a lot of different options for handling and reporting errors, which can make it hard to decide which one is best suited for your situation. In Scala and functional programming languages it is common to make the errors that can occur explicit in the functions signature (i.e. return type), in contrast with the common practice in other programming languages where either special values are used (-1 for a failed lookup anyone?) or an exception is thrown.

Let's go through the main options you have as a Scala developer and see when to use what!

Option
A special type of error that can occur is the absence of some value. For example when looking up a value in a database or a List you can use the find method. When implementing this in Java the common solution (at least until Java 7) would be to return null when a value cannot be found or to throw some version of the NotFound exception. In Scala you will typically use the Option[T] type, returning Some(value) when the value is found and None when the value is absent.

So instead of having to look at the Javadoc or Scaladoc you only need to look at the type of the function to know how a missing value is represented. Moreover you don't need to litter your code with null checks or try/catch blocks.

Another use case is in parsing input data: user input, JSON, XML etc.. Instead of throwing an exception for invalid input you simply return a None to indicate parsing failed. The disadvantage of using Option for this situation is that you hide the type of error from the user of your function which, depending on the use-case, may or may not be a problem. If that information is important keep on reading the next sections.

An example that ensures that a name is non-empty:

def validateName(name: String): Option[String] = {
  if (name.isEmpty) None
  else Some(name)
}

You can use the validateName method in several ways in your code:

// Use a default value

 validateName(inputName).getOrElse("Default name")

// Apply some other function to the result
 validateName(inputName).map(_.toUpperCase)

// Combine with other validations, short-circuiting on the first error
// returning a new Option[Person]
 for {
   name <- validateName(inputName)
   age <- validateAge(inputAge)
 } yield Person(name, age)

Either
Option is nice to indicate failure, but if you need to provide some more information about the failure Option is not powerful enough. In that case Either[L,R] can be used. It has 2 implementations, Left and Right. Both can wrap a custom type, respectively type L and type R. By convention Right is right, so it contains the successful result and Left contains the error. Rewriting the validateName method to return an error message would give:

def validateName(name: String): Either[String, String] = {
 if (name.isEmpty) Left("Name cannot be empty")
 else Right(name)
 }

Similar to Option Either can be used in several ways. It differs from option because you always have to specify the so-called projection you want to work with via the left or right method:

// Apply some function to the successful result
validateName(inputName).right.map(_.toUpperCase)

// Combine with other validations, short-circuiting on the first error
// returning a new Either[Person]
for {
 name <- validateName(inputName).right
 age <- validateAge(inputAge).right
} yield Person(name, age)

// Handle both the Left and Right case
validateName(inputName).fold {
  error => s"Validation failed: $error",
  result => s"Validation succeeded: $result"
}

// And of course pattern matching also works
validateName(inputName) match {
  case Left(error) => s"Validation failed: $error",
  case Right(result) => s"Validation succeeded: $result"
}

// Convert to an option:
validateName(inputName).right.toOption

This projection is kind of clumsy and can lead to several convoluted compiler error messages in for expressions. See for example the excellent and in detail discussion of the Either type in the The Neophyte's Guide to Scala Part 7. Due to these issues several alternative implementations for a kind of Either have been created, most well known are the \/  type in Scalaz and the Or type in Scalactic. Both avoid the projection issues of the Scala Either and, at the same time, add additional functionality for aggregating multiple validation errors into a single result type.

Try

Try[T] is similar to Either. It also has 2 cases, Success[T] for the successful case and Failure[Throwable] for the failure case. The main difference thus is that the failure can only be of type Throwable. You can use it instead of a try/catch block to postpone exception handling. Another way to look at it is to consider it as Scala's version of checked exceptions. Success[T] wraps the result value of type T, while the Failure case can only contain an exception.

Compare these 2 methods that parse an integer:

// Throws a NumberFormatException when the integer cannot be parsed
def parseIntException(value: String): Int = value.toInt

// Catches the NumberFormatException and returns a Failure containing that exception
// OR returns a Success with the parsed integer value
def parseInt(value: String): Try[Int] = Try(value.toInt)

The first function needs documentation describing that an exception can be thrown. The second function describes in its signature what can be expected and requires the user of the function to take the failure case into account. Try is typically used when exceptions need to be propagated, if the exception is not needed prefer any of the other options discussed.

Try offers similar combinators as Option[T] and Either[L,R]:

// Apply some function to the successful result
parseInt(input).map(_ * 2)

// Combine with other validations, short-circuiting on the first Failure
// returning a new Try[Stats]
for {
  age <- parseInt(inputAge)
  height <- parseDouble(inputHeight)
} yield Stats(age, height)

// Use a default value
parseAge(inputAge).getOrElse(0)

// Convert to an option
parseAge(inputAge).toOption

// And of course pattern matching also works
parseAge(inputAge) match {
  case Failure(exception) => s"Validation failed: ${exception.message}",
  case Success(result) => s"Validation succeeded: $result"
}

Note that Try is not needed when working with Futures! Futures combine asynchronous processing with the Exception handling capabilities of Try! See also Try is free in the Future.

Exceptions
Since Scala runs on the JVM all low-level error handling is still based on exceptions. In Scala you rarely see usage of exceptions and they are typically only used as a last resort. More common is to convert them to any of the types mentioned above. Also note that, contrary to Java, all exceptions in Scala are unchecked. Throwing an exception will break your functional composition and probably result in unexpected behaviour for the caller of your function. So it should be reserved as a method of last resort, for when the other options don’t make sense.
If you are on the receiving end of the exceptions you need to catch them. In Scala syntax:

try {
  dangerousCode()
} catch {
  case e: Exception => println("Oops")
} finally {
  cleanup
}

What is often done wrong in Scala is that all Throwables are caught, including the Java system errors. You should never catch Errors because they indicate a critical system error like the OutOfMemoryError. So never do this:

try {
  dangerousCode()
} catch {
  case _ => println("Oops. Also caught OutOfMemoryError here!")
}

But instead do this:

import scala.util.control.NonFatal

try {
  dangerousCode()
} catch {
  case NonFatal(_) => println("Ooops. Much better, only the non fatal exceptions end up here.")
}

To convert exceptions to Option or Either types you can use the methods provided in scala.util.control.Exception (scaladoc):

import scala.util.control.Exception._

val i = 0
val result: Option[Int] = catching(classOf[ArithmeticException]) opt { 1 / i }
val result: Either[Throwable, Int] = catching(classOf[ArithmeticException]) either { 1 / i }

Finally remember you can always convert an exception into a Try as discussed in the previous section.

TDLR;

  • Option[T], use it when a value can be absent or some validation can fail and you don't care about the exact cause. Typically in data retrieval and validation logic.
  • Either[L,R], similar use case as Option but when you do need to provide some information about the error.
  • Try[T], use when something Exceptional can happen that you cannot handle in the function. This, in general, excludes validation logic and data retrieval failures but can be used to report unexpected failures.
  • Exceptions, use only as a last resort. When catching exceptions use the facility methods Scala provides and never catch { _ => }, instead use catch { NonFatal(_) => }

One final advice is to read through the Scaladoc for all the types discussed here. There are plenty of useful combinators available that are worth using.

Hadoop and the OpenDataPlatform

hadoop-logo-square

Pivotal, IBM and Hortonworks announced today the “Open Data Platform” (ODP) – an attempt to standardize Hadoop. This move seems to be backed up by IBM, Teradata and others that appear as sponsors on the initiative site.

This move has a lot of potential and a few possible downsides.

ODP promises standardization – Cloudera’s Mike Olson downplays the importance of this “Every vendor shipping a Hadoop distribution builds off the Hadoop trunk. The APIs, data formats and semantics of trunk are stable. The project is a decade old, now, and the global Hadoop community exercises its governance obligations responsibly. There’s simply no fundamental incompatibility among the core Hadoop components shipped by the various vendors.”

I disagree. While it is true that there are no “fundamental incompatibility” there is a lot of non-fundamental ones. Each release by each vendor includes backport of features that are somewhere on the main trunk but far from the stable release. This means, that as a vendor, we have to both test our solutions on multiple distributions and work around the  subtle incompatibilities. We also have to limit ourselves to the lowest common denominator of the different platforms (or not support a distro) – for instance, until today, IBM did not support Yarn or Spark on their distribution

Hopefully standardization around common core will also mean that the involved vendors will deliver their value-add on that core unlike today where the offerings are based on proprietary extensions (this is true for Pivotal, IBM etc. not so much for Hortonworks). Today, we can’t take Impala and run it on Pivotal can we take Hawk and run it on HDP . With ODP we would, hopefully,  be able  mix-and-match and have installations where we can, say,  use IBM’s BigSQL with GemFire HD running on HDP and other such mixes. This can be good news for these vendors by enlarging their addressable market and for us a users by increasing our choice and reducing lock-in.

So what are the downsides/possible problems?

Well, for one we need to see that the scenarios I described above will actually happen and this isn’t just a marketing ploy. Another problem, the elephant in the room if you will,  is that the move is not complete –  Cloudera, a major Hadoop player, is not part of this move and as can be seen in the post referenced above, are against it. This is also true for MapR. With these two vendors out we still have multiple vendors to deal with and the problems ODP sets to solve will not disappear. I guess if ODP was led by the ASF or some other more “impartial” party it would have been easier to digest but as it is now all I can do is hope that both ODP will live to its expectations and that in the long run Cloudera and MapR will also join this initiative .

 

 

Categories: Architecture

JetBrains webinar recording: Software architecture as code

Coding the Architecture - Simon Brown - Tue, 02/17/2015 - 18:32

The lovely people at JetBrains have published the recording of the live webinar I did with them last week about software architecture as code. I've embedded the YouTube video below, but you should also go and take a look at their website because there are answers to a bunch of questions that I didn't get time to answer during the webinar itself.

If you've already seen one of my Software architecture vs code presentations, you should probably jump straight to the demo section where I show how to create a software architecture model with code and Structurizr. You can also get the slides and the code that I used.

Thanks again to JetBrains (especially Hadi Hariri, Trisha Gee and Robert Demmer) and to everybody who listened in.

Categories: Architecture

Sponsored Post: Apple, Sentient, Couchbase, Farmerswife, VividCortex, Internap, SocialRadar, Campanja, Transversal, MemSQL, Scalyr, FoundationDB, AiScaler, Aerospike, AppDynamics, ManageEngine, Site24x7

Who's Hiring?
  • Apple is hiring a Application Security Engineer. Apple’s Gift Card Engineering group is looking for a software engineer passionate about application security for web applications and REST services. Be part of a team working on challenging and fast paced projects supporting Apple's business by delivering high volume, high performance, and high availability distributed transaction processing systems. Please apply here.

  • Apple is hiring a Software Engineer for Maps Services. The Maps Team is looking for a developer to support and grow some of the core backend services that support Apple Map's Front End Services. Ideal candidate would have experience with system architecture, as well as the design, implementation, and testing of individual components but also be comfortable with multiple scripting languages. Please apply here.

  • Sentient Technologies is hiring several Senior Distributed Systems Engineers and a Senior Distributed Systems QA Engineer. Sentient Technologies, is a privately held company seeking to solve the world’s most complex problems through massively scaled artificial intelligence running on one of the largest distributed compute resources in the world. Help us expand our existing million+ distributed cores to many, many more. Please apply here.

  • Want to be the leader and manager of a cutting-edge cloud deployment? Take charge of an innovative 24x7 web service infrastructure on the AWS Cloud? Join farmerswife on the beautiful island of Mallorca and help create the next generation on project management tools. Please apply here.

  • Senior DevOps EngineerSocialRadar. We are a VC funded startup based in Washington, D.C. operated like our West Coast brethren. We specialize in location-based technology. Since we are rapidly consuming large amounts of location data and monitoring all social networks for location events, we have systems that consume vast amounts of data that need to scale. As our Senior DevOps Engineer you’ll take ownership over that infrastructure and, with your expertise, help us grow and scale both our systems and our team as our adoption continues its rapid growth. Full description and application here.

  • Linux Web Server Systems EngineerTransversal. We are seeking an experienced and motivated Linux System Engineer to join our Engineering team. This new role is to design, test, install, and provide ongoing daily support of our information technology systems infrastructure. As an experienced Engineer you will have comprehensive capabilities for understanding hardware/software configurations that comprise system, security, and library management, backup/recovery, operating computer systems in different operating environments, sizing, performance tuning, hardware/software troubleshooting and resource allocation. Apply here.

  • Campanja is an Internet advertising optimization company born in the cloud and today we are one of the nordics bigger AWS consumers, the time has come for us to the embrace the next generation of cloud infrastructure. We believe in immutable infrastructure, container technology and micro services, we hope to use PaaS when we can get away with it but consume at the IaaS layer when we have to. Please apply here.

  • UI EngineerAppDynamics, founded in 2008 and lead by proven innovators, is looking for a passionate UI Engineer to design, architect, and develop our their user interface using the latest web and mobile technologies. Make the impossible possible and the hard easy. Apply here.

  • Software Engineer - Infrastructure & Big DataAppDynamics, leader in next generation solutions for managing modern, distributed, and extremely complex applications residing in both the cloud and the data center, is looking for a Software Engineers (All-Levels) to design and develop scalable software written in Java and MySQL for backend component of software that manages application architectures. Apply here.
Fun and Informative Events
  • Rise of the Multi-Model Database. FoundationDB Webinar: March 10th at 1pm EST. Do you want a SQL, JSON, Graph, Time Series, or Key Value database? Or maybe it’s all of them? Not all NoSQL Databases are not created equal. The latest development in this space is the Multi Model Database. Please join FoundationDB for an interactive webinar as we discuss the Rise of the Multi Model Database and what to consider when choosing the right tool for the job.

  • Sign Up for New Aerospike Training Courses.  Aerospike now offers two certified training courses; Aerospike for Developers and Aerospike for Administrators & Operators, to help you get the most out of your deployment.  Find a training course near you. http://www.aerospike.com/aerospike-training/
Cool Products and Services
  • See how LinkedIn uses Couchbase to help power its “Follow” service for 300M+ global users, 24x7. http://info.couchbase.com/14Q4-MKTG-Website-LinkedIn-Scale-LP.html

  • VividCortex Developer edition delivers a groundbreaking performance management solution to startups, open-source projects, nonprofits, and other organizations free of charge. It integrates high-resolution metrics on queries, metrics, processes, databases, and the OS and hardware to deliver an unprecedented level of visibility into production database activity.

  • SQL for Big Data: Price-performance Advantages of Bare Metal. When building your big data infrastructure, price-performance is a critical factor to evaluate. Data-intensive workloads with the capacity to rapidly scale to hundreds of servers can escalate costs beyond your expectations. The inevitable growth of the Internet of Things (IoT) and fast big data will only lead to larger datasets, and a high-performance infrastructure and database platform will be essential to extracting business value while keeping costs under control. Read more.

  • MemSQL provides a distributed in-memory database for high value data. It's designed to handle extreme data ingest and store the data for real-time, streaming and historical analysis using SQL. MemSQL also cost effectively supports both application and ad-hoc queries concurrently across all data. Start a free 30 day trial here: http://www.memsql.com/

  • Aerospike demonstrates RAM-like performance with Google Compute Engine Local SSDs. After scaling to 1 M Writes/Second with 6x fewer servers than Cassandra on Google Compute Engine, we certified Google’s new Local SSDs using the Aerospike Certification Tool for SSDs (ACT) and found RAM-like performance and 15x storage cost savings. Read more.

  • Diagnose server issues from a single tab. The Scalyr log management tool replaces all your monitoring and analysis services with one, so you can pinpoint and resolve issues without juggling multiple tools and tabs. It's a universal tool for visibility into your production systems. Log aggregation, server metrics, monitoring, alerting, dashboards, and more. Not just “hosted grep” or “hosted graphs,” but enterprise-grade functionality with sane pricing and insane performance. Trusted by in-the-know companies like Codecademy – try it free! (See how Scalyr is different if you're looking for a Splunk alternative.)

  • aiScaler, aiProtect, aiMobile Application Delivery Controller with integrated Dynamic Site Acceleration, Denial of Service Protection and Mobile Content Management. Cloud deployable. Free instant trial, no sign-up required.  http://aiscaler.com/

  • ManageEngine Applications Manager : Monitor physical, virtual and Cloud Applications.

  • www.site24x7.com : Monitor End User Experience from a global monitoring network.

If any of these items interest you there's a full description of each sponsor below. Please click to read more...

Categories: Architecture

Cancelling $http requests for fun and profit

Xebia Blog - Tue, 02/17/2015 - 09:11

At my current client, we have a large AngularJS application that is configured to show a full-page error whenever one of the $http requests ends up in error. This is implemented with an error interceptor as you would expect it to be. However, we’re also using some calculation-intense resources that happen to timeout once in a while. This combination is tricky: a user triggers a resource request when navigating to a certain page, navigates to a second page and suddenly ends up with an error message, as the request from the first page triggered a timeout error. This is a particular unpleasant side effect that I’m going to address in a generic way in this post.

There are of course multiple solutions to this problem. We could create a more resilient implementation in the backend that will not time out, but accepts retries. We could change the full-page error in something less ‘in your face’ (but you still would get some out-of-place error notification). For this post I’m going to fix it using a different approach: cancel any running requests when a user switches to a different location (the route part of the URL). This makes sense; your browser does the same when navigating from one page to another, so why not mimic this behaviour in your Angular app?

I’ve created a pretty verbose implementation to explain how to do this. At the end of this post, you’ll find a link to the code as a packaged bower component that can be dropped in any Angular 1.2+ app.

To cancel a running request, Angular does not offer that many options. Under the hood, there are some places where you can hook into, but that won’t be necessary. If we look at the $http usage documentation, the timeout property is mentioned and it accepts a promise to abort the underlying call. Perfect! If we set a promise on all created requests, and abort these at once when the user navigates to another page, we’re (probably) all set.

Let’s write an interceptor to plug in the promise in each request:

angular.module('angularCancelOnNavigateModule')
  .factory('HttpRequestTimeoutInterceptor', function ($q, HttpPendingRequestsService) {
    return {
      request: function (config) {
        config = config || {};
        if (config.timeout === undefined && !config.noCancelOnRouteChange) {
          config.timeout = HttpPendingRequestsService.newTimeout();
        }
        return config;
      }
    };
  });

The interceptor will not overwrite the timeout property when it is explicitly set. Also, if the noCancelOnRouteChange option is set to true, the request won’t be cancelled. For better separation of concerns, I’ve created a new service (the HttpPendingRequestsService) that hands out new timeout promises and stores references to them.

Let’s have a look at that pending requests service:

angular.module('angularCancelOnNavigateModule')
  .service('HttpPendingRequestsService', function ($q) {
    var cancelPromises = [];

    function newTimeout() {
      var cancelPromise = $q.defer();
      cancelPromises.push(cancelPromise);
      return cancelPromise.promise;
    }

    function cancelAll() {
      angular.forEach(cancelPromises, function (cancelPromise) {
        cancelPromise.promise.isGloballyCancelled = true;
        cancelPromise.resolve();
      });
      cancelPromises.length = 0;
    }

    return {
      newTimeout: newTimeout,
      cancelAll: cancelAll
    };
  });

So, this service creates new timeout promises that are stored in an array. When the cancelAll function is called, all timeout promises are resolved (thus aborting all requests that were configured with the promise) and the array is cleared. By setting the isGloballyCancelled property on the promise object, a response promise method can check whether it was cancelled or another exception has occurred. I’ll come back to that one in a minute.

Now we hook up the interceptor and call the cancelAll function at a sensible moment. There are several events triggered on the root scope that are good hook candidates. Eventually I settled for $locationChangeSuccess. It is only fired when the location change is a success (hence the name) and not cancelled by any other event listener.

angular
  .module('angularCancelOnNavigateModule', [])
  .config(function($httpProvider) {
    $httpProvider.interceptors.push('HttpRequestTimeoutInterceptor');
  })
  .run(function ($rootScope, HttpPendingRequestsService) {
    $rootScope.$on('$locationChangeSuccess', function (event, newUrl, oldUrl) {
      if (newUrl !== oldUrl) {
        HttpPendingRequestsService.cancelAll();
      }
    })
  });

When writing tests for this setup, I found that the $locationChangeSuccess event is triggered at the start of each test, even though the location did not change yet. To circumvent this situation, the function does a simple difference check.

Another problem popped up during testing. When the request is cancelled, Angular creates an empty error response, which in our case still triggers the full-page error. We need to catch and handle those error responses. We can simply add a responseError function in our existing interceptor. And remember the special isGloballyCancelled property we set on the promise? That’s the way to distinguish between cancelled and other responses.

We add the following function to the interceptor:

      responseError: function (response) {
        if (response.config.timeout.isGloballyCancelled) {
          return $q.defer().promise;
        }
        return $q.reject(response);
      }

The responseError function must return a promise that normally re-throws the response as rejected. However, that’s not what we want: neither a success nor a failure callback should be called. We simply return a never-resolving promise for all cancelled requests to get the behaviour we want.

That’s all there is to it! To make it easy to reuse this functionality in your Angular application, I’ve packaged this module as a bower component that is fully tested. You can check the module out on this GitHub repo.

When development resembles the ageing of wine

Xebia Blog - Mon, 02/16/2015 - 20:29

Once upon a time I was asked to help out a software product company.  The management briefing went something like this: "We need you to increase productivity, the guys in development seem to be unable to ship anything! and if they do ship something it's only a fraction of what we expected".

And so the story begins. Now there are many ways how we can improve the teams outcome and its output (the first matters more), but it always starts with observing what they do today and trying to figure out why.

It turns out that requests from the business were treated like a good wine, and were allowed to "age", in the oak barrel that was called Jira. Not so much to add flavour in the form of details, requirements, designs, non functional requirements or acceptance criteria, but mainly to see if the priority of this request would remain stable over a period of time.

In the days that followed I participated in the "Change Control Board" and saw what he meant. Management would change priorities on the fly and make swift decisions on requirements that would take weeks to implement. To stay in vinotology terms, wine was poured in and out the barrels at such a rate that it bore more resemblance to a blender than to the art of wine making.

Though management was happy to learn I had unearthed to root cause to their problem, they were less pleased to learn that they themselves were responsible.  The Agile world created the Product Owner role for this, and it turned out that this is hat, that can only be worn by a single person.

Once we funnelled all the requests through a single person, both responsible for the success of the product and for the development, we saw a big change. Not only did the business got a reliable sparring partner, but the development team had a single voice when it came to setting the priorities. Once the team starting finishing what they started we started shipping at regular intervals, with features that we all had committed to.

Of course it did not take away the dynamics of the business, but it allowed us to deliver, and become reliable in how and when we responded to change. Perhaps not the most aged wine, but enough to delight our customers and learn what we should put in our barrel for the next round.

 

ScottGu Azure event in London on March 2nd

ScottGu's Blog - Scott Guthrie - Mon, 02/16/2015 - 19:16

On March 2nd I'm doing an Azure event in London that you can attend for free.  I'll be speaking for about 2.5 hours and will do an end-to-end walkthrough of Microsoft Azure, show off a bunch of demos of great new features/capabilities, and talk about some of the improvements coming out over the next few months.

logo[1]

You can sign-up and attend the event for free (while tickets last - they are going fast).  If you are interested sign-up now.  The event is being held at the Mermaid Conference & Events Centre in Blackfriars, London:

mermaidspic3[1]

Hope to see some of you there!

Scott

omni
Categories: Architecture, Programming

Scaling Kim Kardashian to 100 Million Page Views

The team at PAPER estimated their article (NSFW) containing pictures of a very naked Kim Kardashian would quickly receive over 100 million page views. The very definition of bursty viral driven traffic.

As a comparison in 2013 it was estimated Google processed over 500 million searches a day. So a nude Kim Kardashian is worth one-fifth of a Google. Strangely, I can believe it.

How did they handle this traffic gold mine? A complete recounting of the unusual behind the scenes story is told by Paul Ford in How PAPER Magazine’s web engineers scaled their back-end for Kim Kardashian (SFW).  (BTW, only one butt pun was made intentionally in this story, all others are serendipity).

What can we learn from the experience? I know what you are thinking. This is just a single static page with a few static pictures. It’s not a complex problem like search or a social network. Shouldn’t any decent CDN be enough to handle that? And you would be correct, but that’s not the whole of the story:

Categories: Architecture

The Great Love Quotes Collection Revamped

A while back I put together a comprehensive collection of love quotes.   It’s a combination of the wisdom of the ages + modern sages.   In the spirit of Valentine’s Day, I gave it a good revamp.  Here it is:

The Great Love Quotes Collection

It's a serious collection of love quotes and includes lessons from the likes of Lucille Ball, Shakespeare, Socrates, and even The Princess Bride.

How I Organized the Categories for Love Quotes

I organized the quotes into a set of buckets:
Beauty
Broken Hearts and Loss
Falling in Love
Fear and Love
Fun and Love
Kissing
Love and Life
Significance and Meaning
The Power of Love
True Love

I think there’s a little something for everyone among the various buckets.   If you walk away with three new quotes that make you feel a little lighter, put a little skip in your step, or help you see love in a new light, then mission accomplished.

Think of Love as Warmth and Connection

If you think of love like warmth and connection, you can create more micro-moments of love in your life.

This might not seem like a big deal, but if you knew all the benefits for your heart, brain, bodily processes, and even your life span, you might think twice.

You might be surprised by how much your career can be limited if you don’t balance connection with conviction.  It’s not uncommon to hear a lot of turning points in the careers of developers, program managers, IT leaders, and business leaders that changed their game, when they changed their heart.

In fact, on one of the teams I was on, the original mantra was “business before technology”, but people in the halls started to say, “people before business, business before technology” to remind people of what makes business go round.

When people treat each other better, work and life get better.

Love Quotes Help with Insights and Actions

Here are a few of my favorite love quotes from the collection …

“Love is like heaven, but it can hurt like hell.” – Unknown

“Love is not a feeling, it’s an ability.” — Dan in Real Life

“There is a place you can touch a woman that will drive her crazy. Her heart.” — Milk Money

“Hearts will be practical only when they are made unbreakable.”  – The Wizard of Oz

“Things are beautiful if you love them.” – Jean Anouilh

“Life is messy. Love is messier.” – Catch and Release

“To the world you may be just one person, but to one person you may be the world.” – Unknown

For many more quotes, explore The Great Love Quotes Collection.

You Might Also Like

Happiness Quotes Revamped

My Story of Personal Transformation

The Great Leadership Quotes Collection Revamped

The Great Personal Development Quotes Collection Revamped

The Great Productivity Quotes Collection

Categories: Architecture, Programming

Stuff The Internet Says On Scalability For February 13th, 2015

Hey, it's HighScalability time:


Stunning depiction of every space mission over the past 50 years. (Max Roser)
  • 700 billion: Apple's valuation; 1: Number of lines of code it takes to bring down UK air traffic control; 20: how old that line of code was in years; 2: the problem was of course a never been seen before double failure; 1: atom-thin silicon transistors may mean super-fast computing; a few: how many data points it takes to identify you
  • Quotable Quotes:
    • @EpicureanDeal: The Uber model is everywhere: using the internet to connect infrequent, consumers of ad hoc, spot market services with fragmented suppliers.
    • @awendt: “I’m sorry you learned about transactions and joins in college, but you’ll have to de-normalize for #microservices” – @adrianco #microxchg
    • @samnewman: @adrianco "JSON was 10x faster than XML. Protobufs 10x faster than JSON. Avro same speed as Protobufs, but half the size"
    • @RichardWarburto: Premature Optimization isn't the root of all evil: misunderstood domain models are.
    • @MichaelPisula: Says @ewolff at #microxchg: start big with your microservices, splitting is easier than joining and your architecture will be wrong anyway
    • @MJFKlewitz: "With vertical scaling the problem is you end up giving a lot of money to Larry Ellison" #greatquote @crichardson #microxchg
    • Jenny Rood: Species of ants which differ in size can coexist peacefully, but the insects will chase away similarly sized competing species.
    • Steven Levy: The nonlinear gains that Moore predicted are so mind-bending that it is no wonder that very few were able to bend their minds around it.
    • ntoshev: There seems to be a fundamental trade-off between latency and throughput, with stream processors optimizing for latency and batch processors optimizing for throughput.
    • Sam Altman: Nobody cares if you’re using an Intel Edison or a 555 to blink the LED in the prototype you show them: people care about whether you’ve made something that they want.
    • @swardley: 30-50 years from genesis to industrialisation is about the average these days
    • Alex Clemmer: 84% of a single-threaded 1KB write in Redis is spent in the kernel
    • @allspaw: Psst: while lots of folks hope for fully "autonomous" tech to solve all the world's ills, I'll just be over here getting some work done.
    • @alejandrocrosa: “The database you read from is just a cached view of the event log”
    • @viktorklang: Optimizing for latency (as in "time to serve") will also yield higher throughput. Thank you, Mr Little.
    • rakoo: using GOMAXPROCS doesn't automagically turn your program into a parallel one
    • fluidcruft: Data science manifesto: The purpose of computing is numbers.

  • Is the golden age of the cheap startup over? The Rising Costs Of Scaling A Startup. In San Francisco it is. Twice as expensive in 2014 than it was in 2009. Wages have doubled. Op-ex has doubled. And thus startup round sizes have increased. People and place costs dwarf compute infrastructure cost savings.

  • Just in case you are of the fashionable opinion Perl code must look like line noise, take a gander: Real measurement is hard. Nice, eh?

  • Magic tricks for algorithms. This may prove helpful in your new job as Algorithm Profiler...Deep Neural Networks are Easily Fooled: High Confidence Predictions for Unrecognizable Images:  It is possible to produce images totally unrecognizable to human eyes that DNNs believe with near certainty are familiar objects. 

  • Here's the rare Docker nocker. Many reasons why you should stop using Docker. One side: Idea good, implementation leaves something to be desired. Other side: it tastes great and is less filling. Interesting from dacjames: In general, I agree 100%. With the case of Docker, the concept of containerization is more important than the current project. Decoupling the application environment from the infrastructure environment is an immensely valuable paradigm.

  • Bounty Hunter. A job title that conjures up romantic images and dreams of the never was. You can still be one in the digital age. And make some money too. 11 Essential Bug Bounty Programs of 2015. Hundreds of thousands of dollars are available. Good hunting.

  • When algorithms rule the world you are just one weighting factor away from insignificance. Apple,Apps and Algorithmic Glitches. Divination used to be how we attempted to contol the future. Now we attempt to penetrate to the unknowable heart of opaque algorithms with something different...data.

Don't miss all that the Internet has to say on Scalability, click below and become eventually consistent with all scalability knowledge (which means this post has many more items to read so please keep on reading)...

Categories: Architecture

Rescuing an Outsourced Project from Collapse: 8 Problems Found and 8 Lessons Learned

If you are one of those people that think most of the products featured on HighScalability use way too many servers then you'll love this story: 130 VMs serving less than 10,000 users daily were chopped down to just one machine.

Here's the setup. A smallish website was having problems. Users were unhappy. In the balance was not only the product, but the company. The site was built using Angular, Symfony2, Postgres, Redis, Centos, 8 HP blades with 128 G RAM each, two racks, a very large HP 3par storage array, a 1Gbps uplink, and VMWare.

More than enough power for the task at hand. Yet the system couldn't handle the load. What would you do?

That's the story Jacques Mattheij tells in his very entertaining and educational Saving a Project and a Company article.

Jacques says much was right about the website, but time pressure and mismanagement created big problems at the system level. "A single clueless person in a position of trust with non technical management, an outsourced project and a huge budget, what could possibly go wrong?" Sound familiar? 

Problem 1: Virtualization Gone Crazy
Categories: Architecture

Random thoughts on big data

4367409632_a58b2798ca_m

I began blogging in 2005, back then I managed to post something new almost everyday. Now, 10 years after, I hardly post anything. I was beginning to think I don’t have anything left to say but I recently noticed I have quite a few posts in various states of “draft”. I guess that  I am spending too much thinking about how to get a polished idea out there, rather than just go on and write what’s on my mind. This post is an attempt to change that by putting some thought I have (on big data in this case) without worrying too much on how complete and polished they are.

Anyway, here we go:

  1. All data is time-series – When data is added to the big data store (Hadoop or otherwise) it is already historical i.e. it is being imported from a transactional system, even if it is being streamed into the platform. If you treat the data as historical and somehow version it (most simplistic is  adding timestamp) before you store it it would enable you to see how this data changes over time  – and when you relate it to other data you’d be able to see both the way the system was at the time of that data particular data (e.g. event) was created as well as getting the latest version and see its state now. Essentially  treating all data as slow changing dimensions gives you enhanced capabilities when you’d want to analyse the data later.
  2. Enrich data with “foreign keys” before persisting it (or close to it). Usually a data source is not stand alone and it can be related to other data – either form the same source or otherwise. Solving some of these correlations when the data is fresh and context is known can save a lot of time doing them later both because you’d probably do these correlations multiple times instead of once as well as because when the data is ingested the context and relations are more obvious than when, say, a year later you try to make sense of the data and recall its relations to other data.
  3. Land data in a queue – This ties nicely to the previous two points as the type of enrichments mentioned above are suited well for handling in streaming. if you lend all data in a queue you can gain a unified ingestion pipeline for both batch and streaming data. Naturally not all the computations can be handled in streaming, but you’d be able to share at least some of the pipeline.
  4. Lineage is important (and doesn’t get enough attention) – raw data is just that but to get insights you need to process it , enrich and aggregate it – a lot of times this creates a disconnect between the end result and the original data. Understanding how insights were generated is important both for debugging problems as well as ensuring compliance (for actions that demand that).
  5. Not everything is big data – Big data is all the rage today but a lot of problems don’t require that. Not only that when you make the move to a distributed system you both complicate the solution and more importantly slow the processing (until, of course, you hit the threshold where the data can’t be handled by a single machine). This is even truer for big data systems where you have a lot of distributed nodes so the management (coordination etc.) is more costly (back at Nice we referred to  the initialization time for Hadoop jobs as “waking the elephant”  and we wanted to make sure we need to wait it).
  6. Don’t underestimate scale-up – A related point to the above. Machines today are quite powerful and when the problem is only “bigish” it might be that a scale-up solution would solve it better and cheaper. Read for example “Scalability! But at what COST?” by Frank McSherry and “Command-line tools can be 235x faster than your Hadoop cluster” by Adam Drake as two examples for points 5 & 6

This concludes this batch of thoughts. Comments and questions are welcomed

image by Nilay Gandhi

Categories: Architecture

Vinted Architecture: Keeping a busy portal stable by deploying several hundred times per day

This is guest post by Nerijus Bendžiūnas and Tomas Varaneckas of Vinted.

Vinted is a peer-to-peer marketplace to sell, buy and swap clothes. It allows members to communicate directly and has the features of a social networking service.

Started in 2008 as a small community for Lithuanian girls, it developed into a worldwide project that serves over 7 million users in 8 different countries, and is growing non-stop, handling over 200 M requests per day.

Stats
Categories: Architecture

The Great Productivity Quotes Collection Revamped

A while back I put together a comprehensive collection of personal productivity quotes.   It’s a combination of the wisdom of the ages + modern sages.   It was time for a revamp.  Here it is:

The Great Productivity Quotes Collection

It's a serious collection of personal productivity quotes and includes lessons from the likes of Benjamin Franklin, Bruce Lee, Peter Drucker, Tony Robbins Voltaire, and more.

Productivity is Value Divided by Time

My favorite definition is a simple formula from Steve Pavlina:

Productivity = Value / Time

I like the formula because of it’s simplicity and because of the insight it provides.  If you want to increase your productivity, then you can increase the value or reduce the time it takes, or both.

One of the things I remind my colleagues in the halls of Microsoft is that value is the ultimate short-cut.  If you know what’s valued, you can eliminate or reduce all the waste in between.

Productivity Hot Spots

To organize the productivity quotes, I use a simple frame of productivity Hot Spots:

Action, Approach, Efficiency / Effectiveness, Energy Management, Failure, Focus, Goals, Improvement, Motivation and Mindset, Planning, Opportunity, Self-Awareness, and Time Management.

I find these buckets are useful for organizing principles, patterns, practices, and even quotes.   There are a lot of productivity quotes, so using this frame helps group the quotes into more manageable themes.

The Ultimate Formula for Personal Productivity

It sounds so simple when I say it now, but it took me a while to figure out the ultimate formula for personal productivity.   Here’s the formula:

Work on the right things, at the right time, the right way, with the right energy.

In other words, start with the right things.  Trim your tree of opportunity and focus on the right branches and leaves that will bear the most fruit.   Work on these things at the right time.  It’s easy to miss windows of opportunity and time changes what’s valued.   We also have better times in the day to work on things than others.   Work on things the right way.  This is really about using better techniques.  If have the wrong technique, then throwing hours and effort at something will just waste your time.  Lastly, work on things with the right energy.  Your energy is your force multiplier since you won’t get more time in the day.

A simple way to think of the way to optimize your productivity is to use your best energy for your best results.

I share a simple system and a comprehensive set of proven practices for personal productivity in my book, Getting Results the Agile Way. (It’s been a best seller in time management, and it helps you master productivity, time management, and work-life balance.)

Productivity Strategies

Believe it or not, quotes are not just neat and fun little sayings.   The right quotes are actually pithy ways to share strategies and insights.  They can completely change your game.

Here are a handful of some of the strategies that I’ve learned for improving productivity and many of these strategies are echoed in The Great Productivity Quotes Collection:

Less is more.

Focus on quality.

Quotas and quantity can help you achieve quality.  (If you learn from your process and apply it.)

Value is in the eye of the beholder and the stakeholder.

Find better techniques to multiply your results.

Enjoy the process.

Spend more time in your strengths, and less time in your weaknesses.

Pair up to amplify your talents and capabilities.

Focus on continuous improvement.

Manage your energy, not time.

Reduce the time you spend and you’ll innovate in your process.

Use timeboxing to invest time more intelligently. (Set limits and boundaries so you don’t over-spend in the wrong areas of your life.)

Work smarter, not harder.

Change your approach when it’s not working.

Test your results.

Productivity is Power

There are many ways to think about productivity.   I like to think of productivity as power.  I think of power as the ability to take action.   When you exercise your ability to take action and concentrate your effort and your focus, you can make amazing things happen in work and life.

Productivity is a powerful tool in your toolbox for personal empowerment.

As with anything, make sure you use the right tool for the job.  And that’s why I continue to fill my toolbox with several tools.  Otherwise, if all you have is a hammer, then everything looks like a nail.

You Might Also Like

The Great Personal Development Quotes Collection Revamped

The Great Leadership Quotes Collection Revamped

Happiness Quotes Revamped

Categories: Architecture, Programming

The Great Personal Development Quotes Collection Revamped

“Knowing others is intelligence.  Knowing yourself is true wisdom.  Mastering others is strength.  Mastering yourself is true power.” -- Lao Tzu

A while back I put together a comprehensive collection of personal development quotes.   It’s a combination of the wisdom of the ages + modern sages.   It was time for a revamp.  Here it is:

The Great Personal Development Quotes Collection

It's a serious collection of personal development quotes and includes lessons from the likes of Buddha, Covey, Emerson,  Gandhi, Robbins, Ziglar, and more.

Personal Development is a Way to Realize Your Potential

Personal development is a process for life where you improve your awareness, your skills, your abilities, and your potential.  Personal development shapes your growth by developing your strengths, reducing your liabilities, and expanding what you’re capable of.

You improve your potential through self-awareness, habits, practice, and feedback.

Awareness is Half the Battle

A big part of personal development is simply awareness.  For example, when you know your Myers & Briggs Personality Type, you gain insight into whether you outwardly or inwardly focused, how you prefer to take in information, how you prefer to make decisions, and how you prefer to live your outer life.

Aside from better understanding your own patterns, you can also use it to understand other people’s behavior preferences, and you can adapt your style.  If you see somebody staring blankly at you during your presentation, it doesn’t mean they aren’t engaged.  They might just be an introvert processing the information in their own quiet way.

If you know your Conflict Style, you can tailor and adapt it to the situation, as well as better understand the mode that others are operating in.

There are many models and tools for self-awareness, but the goal is the same:  learn how to be more effective in more situations based on your individual strengths, abilities, and experience.

Action is the Other Half

Personal development is a verb.   You need to take action.  All the knowledge in the world doesn’t matter if you don’t apply it.  Even thoughts are habits that we haven’t learned how to measure.  When you apply what you learn, you can adjust what you learn based on feedback and results.

If you keep in mind that personal development is about continuously improving your thinking, feeling, and doing, then it’s easier to stay focused and to evaluate your results.

You can also approach personal development in a number of ways.  Just like martial arts, there are hard-styles and there are soft-styles.  In my experience, it helps to balance and blend hard-core skill building along with building the soft skills, especially interpersonal skills and your emotional intelligence.

Personal Development Requires a Growth Mindset

If you want to grow, you have to believe you can.

If you adopt a Growth Mindset, you can create a love of learning and a resilience that is the basis of great accomplishment in every area of work and life.

In the book, Mindset: The New Psychology of Success, author Carol Dweck shares a lot of science and stories around how our mindset limits or enables our growth.  If we believe that our abilities are fixed traits, and that we are either good or bad at something, then we have a Fixed Mindset.

If, on the other hand, you believe that you can get better through skills development, then you have a Growth Mindset.

If you’ve ever been in any sort of elite training, or specialized skills development or had a great mentor that provides deep feedback, it should be more than obvious to you how much growth and greatness is possible.

Adapting is the Key to Personal Development Success

So if you have a Growth Mindset, and you practice personal development, and you develop your self-awareness, then what will hold you back?

Simple.   The inability or lack of willingness for you to change your approach.

Darwin taught us that nature favors the flexible and Einstein said that doing the same thing over and over again and expecting different results is the definition of insanity.

And yet, how many people get stuck in a rut or hold themselves back through limiting thought patterns or behaviors?

One of the greatest things you can possible do for your future success is to learn how to change your approach with skill.

I could say so much more about personal development but at this point, I’d rather share what some of the greatest giants in personal development have had to say.  

Use The Great Personal Development Quotes Collection to stand on the shoulders of giants, and see further, as you look inward and upward.

And if you want a jumpstart in agile personal development, check out my best-selling book on productivity:  Getting Results the Agile Way.   It’s a simple system for meaningful results, and  it’s a way to use personal development to think better, feel better, and do better in all areas of your life.

Categories: Architecture, Programming

Stuff The Internet Says On Scalability For February 6th, 2015

Hey, it's HighScalability time:


What a beautiful example of Moore's law visualized through the evolution of Lara Croft! (from @silenok)
  • $1 million: per day gross of Clash of Clans
  • Quotable Quotes:
    • @dancow: In 45 minutes, the largest trader in U.S. equities went bankrupt because of bad devops
    • @bmdhacks: How to be a 10x engineer: Incur technical debt fast enough to appear 10x as productive as the ten engineers tasked with cleaning it up.
    • @CompSciFact: Scaling poorly: Performance degrades with problem size Poorly scaled: Things change far more rapidly in one direction than others
    • @mikiobraun: Before scaling out, a machine learning person would always try some approximation shortcut to achieve speed up. #cheating #orisit
    • @cshirky: 3/4 If your organization has ever made a significant and unpleasant change based on something you measured, you can probably use more data.
    • @PatrickMcFadin: Service Discovery Overview: ZooKeeper vs. Consul vs. Etcd vs. Eureka 
    • @jaykreps: TIL: Dequeuing a single item in RabbitMQ requires traversing every single item in the queue. Oh my.
    • @Carnage4Life: No single recipe 4 success. Great companies had bad habits; Apple micromanagement, Google random side projects & Facebook used fricking PHP
    • Stubbornly Persistent: although life would persist in the absence of microbes, both the quantity and quality of life would be reduced drastically.

  • At inflection points change the world must. Netflix: In the early days of Netflix streaming, circa 2008, we manually tracked hundreds of metrics, relying on humans to detect problems.  Our approach worked for tens of servers and thousands of devices, but not for the thousands of servers and millions of devices that were in our future.  Complexity and human-reliant approaches don’t scale; simplicity and algorithm-driven approaches do.

  • IBM is turning Watson into a platform, offering 5 new services: Speech to Text, Text to Speech, Visual Recognition, Concept Insights, Tradeoff Analytics. GA probable next month. Good discussion on Hacker News. Most of the services allow for training through feedback. Some question the quality of the services, but it's early days. Pricing is not set. Hopefully it won't suffer from what these next gen deep learning services tend to suffer from: expensivitis. Who can afford $1.00 per 1000 API calls for a mobile app that needs to acquire users? IBM, make it cheap, try for ubiquity. Cool stuff will happen.

  • Looking for that next step in distributed reliability? Look at TLA+. Murat has several articles on TLA+ and is using it his teaching distributed systems class. Oh, TLA stands for Temporal Logic of Actions. Leslie Lamport has many papers on TLA. James Hamilton wrote up their experiences at Amazon using TLA+: Challenges in Designing at Scale: Formal Methods in Building Robust Distributed Systems: TLA+, a formal specification language invented by ACM Turing award winner, Leslie Lamport. TLA+ is based on simple discrete math, basic set theory and predicates with which all engineers are quite familiar. A TLA+ specification simply describes the set of all possible legal behaviors (execution traces) of a system. 

Don't miss all that the Internet has to say on Scalability, click below and become eventually consistent with all scalability knowledge (which means this post has many more items to read so please keep on reading)...

Categories: Architecture

《程序员必读之软件架构》作者Simon Brown:架构师与程序员的区别(图灵访谈)

Coding the Architecture - Simon Brown - Thu, 02/05/2015 - 07:52

Simon Brown 是全球知名软件架构独立咨询师、讲师,创办了专门讨论软件架构问题的网站“编码架构”(CodingTheArchitecture.com)。他自称是写代码的软件架构师和明白架构的软件开发者。自2008年以来的7年时间里,Simon在全球28个国家做过有关软件架构、技术领导力及其与敏捷的平衡等主题的百余场演讲,并于2012年8月在中国举办的ArchSummit全球架构师峰会上以“郁闷的架构师”和“如何设计安全的架构”为主题发表演讲,深受与会者好评。Simon已为全球20多个国家的软件团队提供咨询和培训,他的客户既有小型技术初创企业,也不乏全球家喻户晓的品牌公司。Simon著有《程序员必读之软件架构》一书,他在这本书中打破传统的认知,模糊软件开发和架构在流程中的界限,进而为软件架构正名。

问:开发者和架构师之间最大的区别是什么?

架构师和开发者一样,也经常写代码,简单的说,开发者和架构师之间最大的区别就是技术领导力。软件架构师的角色需要理解最重要的架构驱动力是什么,他提供的设计需要考虑这些因素。架构师还要控制技术风险,在需要的时候积极演化架构,并且负责技术质量保证。从根本上讲,架构师是一个技术领导者的角色,这就是最大的区别。

Read more...

Categories: Architecture

I'm speaking at the O'Reilly Software Architecture Conference

Coding the Architecture - Simon Brown - Mon, 02/02/2015 - 13:19

I'm thrilled to say that I'll be speaking at the inaugural O'Reilly Software Architecture Conference in Boston during March. The title of my session is Software architecture vs code and I'll be speaking about the conflict between software architecture and code. This is a 90-minute session, so I look forward to also discussing how can we solve this issue. Here's the abstract...

Software architecture and coding are often seen as mutually exclusive disciplines, despite us referring to higher level abstractions when we talk about our software. You've probably heard others on your team talking about components, services and layers rather than objects when they're having discussions. Take a look at the codebase though. Can you clearly see these abstractions or does the code reflect some other structure? If so, why is there no clear mapping between the architecture and the code? Why do those architecture diagrams that you have on the wall say one thing whereas your code says another? In fact, why is it so hard to automatically generate a decent architecture diagram from an existing codebase? Join us to explore this topic further.

Software Architecture Conference 2015

You can register with code FRIEND20 for a discount. See you there!

Categories: Architecture

Another elasticsearch blog post, now about Shield

Gridshore - Thu, 01/29/2015 - 21:13

<p>I just wrote another piece of text on my other blog. This time I wrote about the recently release elasticsearch plugin called Shield. If you want to learn more about securing your elasticsearch cluster, please head over to my other blog and start reading</p>

http://amsterdam.luminis.eu/2015/01/29/elasticsearch-shield-first-steps-using-java/

The post Another elasticsearch blog post, now about Shield appeared first on Gridshore.

Categories: Architecture, Programming

Live Webinar with JetBrains: Software Architecture as Code

Coding the Architecture - Simon Brown - Thu, 01/29/2015 - 14:17

I'm doing a live and free webinar with Trisha Gee and the other fine people over at JetBrains on February 12th at 15:00 GMT. The topic is "software architecture as code" and I'll be talking about/showing how you can create a software architecture model in code, rather than drawing static diagrams in tools such as Microsoft Visio.

Over the past few years, I've been distilling software architecture down to its essence, helping organisations adopt a lightweight style of software architecture that complements agile approaches. This includes doing "just enough" up front design to understand the significant structural elements of the software, some lightweight sketches to communicate that vision to the team, identifying the highest priority risks and mitigating them with concrete experiments. Software architecture is inherently about technical leadership, stacking the odds of success in your favour and ensuring that everybody is heading in the same direction.

But it's 2015 and, with so much technology at our disposal, we're still manually drawing software architecture diagrams in tools like Microsoft Visio. Furthermore, these diagrams often don't reflect the implementation in code, and vice versa. This session will look at why this happens and how to resolve the conflict between software architecture and code through the use of architecturally-evident coding styles and the representation of software architecture models as code.

Please sign-up here if you'd like to join us.

Categories: Architecture