My Pluralsight course Introducing the Office UI Fabric went live yesterday. It’s a quick hit (clocking in at just over an hour) intro to all of the goodness Fabric has to offer. Here’s the Table of Contents:
- Introducing Office UI Fabric
- UI Elements
- Fabric Futures
If you’re new to Fabric, this is the place to start as it gives a great overview of the what and why of Fabric.
My next course (on track to be out in March or early April) – Developing with the Office UI Fabric – goes further into the how of Fabric, covering details on the components, working with Fabric in Angular, Building and Contributing to the project and much more. Most of the Developing course is demos, just a handful of slides.
To coincide with the publication of my new Pluralsight course on Office UI Fabric, I’ve updated the Fabric Explorer Chrome extension I published a while back to version 1.3. This is a minor update, but it fixes a few bugs:
- Added support for pages loaded into the browser via a file:// URL
- Fixed bugs that prevented the “Reset” button from correctly returning an element back to it’s original state when the page was loaded
In addition, I added the remainder of the Fabric Responsive Grid classes (hidden, offset, push, pull), did some minor code cleanup and published the source code to GitHub.
The update was published on the Chrome Web Store this morning and should be automatically updated if you already have it installed. If you haven’t installed it already, now is the perfect time to do so! You’ll get the latest and greatest bits right away.
Please log any bugs here: https://github.com/Sector43/FabricExplorer/issues
The extension is available here: https://chrome.google.com/webstore/detail/fabric-explorer/iealmcjmkenoicmjpcebflbpcendnjnm
Update for Release 1.2: http://blog.mannsoftware.com/?p=2491
Update for Release 1.0: http://blog.mannsoftware.com/?p=2371
Release Date: Feb 26, 2016
Provided By: Sector 43 Software (David Mann)
Based on: Fabric release 2.01 (Feb 5, 2016)
These snippets are a first go at making the Office UI Fabric easier to use. In general, the HTML is taken directly from the Office UI Fabric GitHub repository, with some tweaking.
Snippets generally fall into one of two flavors:
All of the snippets have a trigger that starts with uif- so you can see what’s available by simply typing uif- and looking at the Intellisense popup shown by VS Code.
For the time being, installation is manual. Once I’ve ironed out any bugs, I’ll make a true VS Code extension and deploy it to the Extension Gallery. At that point, I’ll also create a Visual Studio Extension and deploy that to the Visual Studio Gallery as well. If there is interest, I’ll convert the snippets to other editors – Sublime is one I’m considering, but am open to other suggestions as well.
- Open the file VSCodeFabricSnippets.txt from the GitHub repo (direct link: https://raw.githubusercontent.com/Sector43/FabricSnippets/master/VSCodeFabricSnippets.txt)
- Select all of the contents and copy it to the clipboard
- In VS Code, click File | Preferences | User Snippets and select HTML from the Language dropdown
- Paste the contents from the GitHub file into the html.json file that is now open in VS Code
- Save the html.json file and close it
The snippets are now available when you are editing an HTML file in VS Code. (NOTE: Snippets in VS Code only seem to work if the HTML file is open as part of a folder, not if you just open a standalone file. I’m looking into whether this is really true, and if so whether it is by design or a bug)
Installation and usage is shown in the short video here: https://youtu.be/VsfUTwgNdgg
The following components are not currently supported by the snippets:
- People Picker
- Persona Card
They’ll be coming in the next release.
Please report other issues here: https://github.com/Sector43/FabricSnippets/issues
Update March 3, 2016: http://blog.mannsoftware.com/?p=2171
Microsoft released the Office UI Fabric in August of 2015. It is essentially “Bootstrap for Office, Office 365 and SharePoint” plus more. It allows you to quickly and easily build a user interface for your add-in or app that looks and feels like Office, SharePoint, or Office 365.
Fabric Explorer is a Chrome Extension I wrote which allows you to explore the UI Elements of Fabric within a live web page right inside Chrome. The extension is featured heavily in my upcoming Pluralsight course Introducing Office UI Fabric (coming out in the next week or so) and will also be used in part two – Developing with the Office UI Fabric (due out in March).
Here is a screenshot of Fabric:
You can see a demo of it in action here: https://youtu.be/e8v-Zw1iRZs. The extension itself is available in the Chrome Web Store: https://chrome.google.com/webstore/detail/fabric-explorer/iealmcjmkenoicmjpcebflbpcendnjnm .
I’ll probably update it with some additional functionality in the next few weeks, so feel free to provide suggestions in the Comments. See updates at top of post.
Basically, it works like this:
- Make your REST call to get search results from SharePoint
- Create an instance of the S43.SearchResultParser object:
- Take the parameter returned from SharePoint (In the image its oneSample ) and pass it to the parseResults method in the SPRESTSearchParser object, as shown in the second line in the above image
- The return value from that method call is a JSON object which contains an array of SearchResult objects. Each SearchResult object is simply a representation of a single result from SharePoint that is easier to work with than the raw results. It looks like this in the Chrome dev tools:
Each property from the result set is available directly on the SearchResult object within the array by name – much easier than remembering the position of each property in the result set.
- Right now the following properties are available from the PrimaryQueryResult.RelevantResults collection:
Accessing the results now looks like this:
In the future, I’d like to clean this up and expand it to make use of additional result sets and other search capabilities. Feel free to fork the code and adapt to meet your needs. If you do something interesting, please submit a pull request to allow others to take advantage of it as well.
We all agree that SharePoint is a great application right out of the box, but is it more than that? Can SharePoint be used as a platform upon which we build web applications? The answer is most assuredly, YES. However, it’s not as cut and dried as we might like it to be. SharePoint has strengths and weaknesses that we must keep in mind. At times we may need to tweak our architecture a little to be able to take advantage of all that SharePoint offers. When does it make sense to do so, and when should we look elsewhere for a leg-up in our application building endeavors.
This post will begin to explore this scenario. It will not fully address every aspect, but it is a start. Future posts will continue to explore this thread, based on my own experience as well as comments left here and discussions I have with other developers.
One important point to make before going any further is that almost everything I cover in this post is available in SharePoint Foundation (SPF) – the free SKU (there are no server or client license costs for SPF). In some cases, I’ll talk about a capability of one of the SharePoint Server SKUs, but I’ll explicitly call those out. This means that you can use SPF and everything it gives you for no more than what it costs to buy ASP.Net – nothing.
To begin with, what are the common threads of most (if not all) web applications? What must any respectable web app include in order to be considered complete? A nice beginning list, in no particular order, would have to include:
- Security – who are you and what are you allowed to do? AuthN and AuthZ
- Data storage – a place for the stuff the app is responsible for managing
- Content presentation – showing that stuff in a usable manner
- Administration – Configuring the application
- User Interface – Outside of Content Presentation, above, this is the chrome of the app – navigation, graphics, interaction points, etc
- Performance enhancements/management – caching, etc.
- User management – adding, removing, editing users
I’m sure there are more but those represent a nice general-purpose list of what web applications do. Let’s take a look at these one at a time from a SharePoint perspective.
From an Authorization (AuthZ) perspective, SharePoint gives us a lot. It provides a whole collection of securable objects – from individual pages, to items to sites. In addition, it provides a collection of pages for managing security, assigning/revoking permissions, defining permission levels, managing group membership, etc), the concepts of roles and groups and a whole slew of other items. From an AuthN (authentication) perspective, SharePoint supports NTLM, Username/password and/or Claims based federated identity management out of the box. With little to no work, you can authenticate your users in whatever way makes the most sense for your application.
SharePoint provides a mechanism for storing data. Natively, it is not how most web applications store data, and perhaps not how most application architects “think” but it does store data. Instead of highly configurable relational tables, SharePoint stores rows and columns of data in lists. True, the structure of the database under the covers would make a DBA cringe, but we don’t deal with SharePoint data at that level. We remain higher up where the rows and columns analogy works pretty well.
With SharePoint 2010 you can get what I like to term “lightweight relations” between data points, but SharePoint is NOT a relational data store. I cannot emphasize that enough – SharePoint is not a relational data store. Don’t try to make it one. If you need relational data capabilities SharePoint is not the right place to store your data. That doesn’t mean, though, that SharePoint can’t present that data and allow users to interact with it. See the next section on Content Presentation for additional details on presenting external data.
From a purely “storing of data” point of view, SharePoint does it. You may need to rethink your data storage design and plans, but we’ll address that later.
SharePoint can present data to end users like any other web application. Similar to just about any web application, the actual storage location of that data is irrelevant – which is why I broke this out into two sections. SharePoint can present data and whether that data is stored inside SharePoint or elsewhere doesn’t matter. Presenting data stored in SharePoint is easy and there are a number of out of the box ways to do that – Views, Web Parts, etc. Presenting data stored externally to SharePoint is still no harder than in any other web application (just write the database access code like you would in ASP.Net, PHP, whatever) and could be much easier if you can use Business Connectivity Services (BCS), which is now mostly available in SPF.
Much of this is possible out-of-the-box with no custom code. If the out-of-the-box content presentation capabilities don’t suit your needs, then you need to write some code – but if you’re not using SharePoint and instead developing the application in ASP.NET, you’re writing code anyway, so you’re no worse off.
Any non-trivial application requires administration to one degree or another. SharePoint provides a framework for delivering that administration in the model that it utilizes itself – application pages (which are really just standard ASPX pages). In addition, SharePoint provides an easy mechanism for securing those pages to allow only administrators to access them (RequireSiteAdministrator).
Historically, SharePoint has been tarred with a reputation of delivering only “boxy” unfriendly user interfaces. All of that is over (beginning with 2007, but really coming into it’s own with 2010). Any UI you can deliver in ASP.NET, you can deliver in SharePoint. Period. End of story.
For anything but the most trivial of applications, performance is a concern. SharePoint provides some capability for cache management. For the most part, the actual caching is the same as what’s delivered in ASP.NET. SharePoint just adds a UI to allow you to administer the caching.
User management in SharePoint is primarily based around one of two areas – security and user information. Security is discussed above, and user information is handled via the User Profile Service (Server SKUs) or User Information List (SPF) of SharePoint. In either case, you have the means of managing information about your users that can be used as-is or enhanced (with or without code)
Additional Benefits of SharePoint
In addition to the above list of typical web applications elements, SharePoint provides a number of additional capabilities that can come in handy for some applications:
A fully baked Windows Workflow Foundation host to automate a business process
A built in process timer manager that can execute tasks on a defined schedule
A deployment management paradigm via Solution packages and Features
SharePoint Architectural Considerations
With all of that said, I don’t think there’s any doubt that SharePoint is a viable candidate for giving you a leg-up in your application building endeavors. However, like anything else, choosing SharePoint does require some trade-offs. Primarily I find that this comes into play in terms of interconnectedness. In other words SharePoint ties some things together that might not ordinarily be tied together. For example, when you define a Content Type, it has ramifications for the form used to present items of that Content Type. Sometimes this is a strength, sometimes it’s not. In addition, I try at all costs to avoid using some of the out-of-the-box columns that ship with SharePoint (like the ubiquitous Title column) as they just carry too much baggage. I find I’m far better off not using the default Title column and just creating my own.
SharePoint also has a tendency to force architectures down a certain path, that being a paradigm of multiple sites whereas a more traditional web application might be delivered in a single site. I reality, that’s just a semantic distinction. Sites in SharePoint are really just an organizational boundary and you don’t have to use multiple; you can often deliver everything within one site. In any case, your users never really need to know that they are visiting multiple sites. You can often hide it from all but the most observant of them (those that pay attention to URL strings).
Drawbacks of SharePoint as an App Platform
All is not perfect when using SharePoint as an app-platform, however. It does force you to rethink your applications somewhat and likely approach them in a new and different manner. In addition, SharePoint is a HUGE application and honestly some parts of it are better than others. In time, you get to know what parts to stay away from. Under the covers, there are some real head-scratchers and inconsistencies in the SharePoint object model. Again, you get to know SharePoint’s quirks as you work with it more. SharePoint also tends to lag about one release behind ASP.Net in access to the new things in the .NET Framework so if you find yourself constantly chasing those shiny objects, you’ll be forever tilting at the SharePoint windmill.
There are more drawbacks, and I’m sure each of you would come up with your own list. Honestly, I’ve been approaching SharePoint this way for so long that I forget what I use to rant and rave about. I look at what some of my ASP.Net friends have to do to build their applications and I just shake my head and say to myself – thank god I don’t have to deal with that anymore…
So that’s it. My take on SharePoint as an app-platform. Obviously I’m biased as I’ve already (mostly) made it over the hump and am comfortable with this model. I won’t say it was always an easy battle, but the end result has been well worth it.
What do you think?
Every so often you come across a discussion amongst developers that talk about eking every last drop of performance out of your code. I understand this mindset. It’s natural to want your code to perform as quickly and efficiently as possible. People don’t like to wait, and if we make them wait, they won’t like our application. If they don’t like our application, it’s kind of like we failed. No one likes to fail. Too, wait time is one of the easiest low-hanging fruit by which our code can be measured – “that must be bad code, look how long it takes to load a page.”
It’s time to call bullsh*t.
Performance is important, sure, but it’s not as important as many other things we, as developers, need to be concerned with. Once you reach a threshold of “acceptable” performance (more on this later), any time spent optimizing your code for faster load times is likely wasted effort. There are far more important things to spend that time on.
What else do we need to be concerned with? Lots of stuff:
- Application maintainability
- Overall end user experience (of which acceptable performance is just one piece)
This list isn’t in any particular order, and I’m sure you can come up with a few more things to add to it, but it gives you an idea of the types of things that you should be thinking about once your performance is “good enough.”
Where I’d rather spend my time
Of all the items in the list above, one area where I think people don’t spend enough time by a wide margin is application maintainability. Hopefully your application has a long life. Hopefully people use it for a long time and ask for new functionality or enhancements. In that time, they’ll likely come across a couple of bugs as well.
When this lifetime is measured in years, the hygiene and developer-friendliness of the original codebase are critically important. Too often, in the rush to hit a deadline, we cut corners in our development. Unfortunately, this makes our applications harder to maintain. How often have you inherited code from another developer, or had to revisit your own code 6 months after you wrote it, only to realize what a steaming pile of doo-doo you’ve got on your hands? I find myself in this situation fairly often and it’s rarely fun. How often have you had to spend an exorbitant amount of time debugging the codebase to find out exactly what is going on and the exact conditions that cause a bug to surface before you can even begin fixing it?
Wouldn’t it be better if instead of being dense and hard to follow, our code opened up before us like a road map and we could easily discern exactly what was going on? Wouldn’t it be better if, instead of spending hours tracking down exactly where in 20,000 lines of code we had to make a change to fix a bug, we could simply examine the logs and have them lead us exactly where we need to go?
That’s code that was written with an eye towards maintainability.
Here’s an example of what I’m talking about (click the image to enlarge):
This is an excerpt from the ULS logs of a sample application I wrote to demonstrate application maintainability. I added some color highlighting to the image to help you understand what is being written to the log:
Green is simple messages written into the logs to help a troubleshooter know what is going on and where in the code base this code came from
Blue is variable and parameter values. How nice is it to see actual values that can help you understand that a bug only shows up when a variable is greater than 100 and less than 200, for example. Seeing actual runtime values in the log can be invaluable.
Yellow is process trace message – one for each method I enter and again when I leave the method. Notice, too, that I get input and return parameter values for each method entry/exit (highlighted in blue).
What does all of this logging cost me in terms of performance? Roughly a tenth of a millisecond or so for each message. In other words, the 13 messages written for each iteration of my code (one iteration is shown above) cost me about 1.4 thousandths of a second:
In exchange for this miniscule amount of time, I get the rich details about the processing of my application. I’ll make that trade any day of the week and twice on Sundays.
I’ve been using this approach for projects lately and my current client is impressed with the speed with which I am able to resolve bugs. They almost don’t care that the bugs are showing up because I can get them resolved so quickly.
I’m not saying that this is perfect and I’m still tweaking the code that manages all of this for me (to be released as part of the CKS:API project I started last year) but I wanted to present it as an example of what is possible to give you an idea of what I’m talking about when I talk about maintainability as being more important than performance.
One final note on logging. To avoid filling up my log and slowing things down just a little more during routine production run time, I make use of the secret-squirrel VerboseEx logging level on the TraceSeverity enumeration. This level cannot be set through the UI so you need to do it in code. If a bug surfaces, I crank up the logging level and have the user repeat the steps that produced the bug. From my code’s point of view, nothing is different so we don’t have any issues with Heisenbugs.
More than Just Logging
The example above is simply logging and that is an important part of code maintainability, but it is not all there is. There is also:
Code comments – the oft-maligned part of a developers job. Code comments are important to help understand a codebase. I’m finding that, while I still comment my code, I do so less because the extra logging messages I’m adding can stand in for code comments. One benefit of this is that as my codebase evolves, I’m far more likely to update the inline process trace messages than I ever updated my comments. My comments tend to stay focused on big-picture elements of describing what a method does overall rather than the details of how it does it.
Defensive Coding – making sure that my code can continue running before attempting to do so and that the environment hasn’t changed in such a way that assumptions made by my code are no longer valid. Some of this is hinted at in the image above – the last green highlighted line says Contract satisfied – continuing with update. In my code, I’m checking both pre-conditions and post-conditions for my methods on entry/exit, as well as in the midst of processing to make sure that, for example, the list I need to work with hasn’t been deleted, or that my SPQuery has, in fact, returned items:
Don’t worry about the syntax there (the TrueIf object is another part of CKS:API that will be released publicly as soon as I can finish it). Just understand that I’m making sure I have a valid list item collection that contains items before I attempt to do anything with it. Does this cost me a few processor cycles? Sure, but it makes my code far more bulletproof and maintainable. While I don’t have numbers for this, I’d guess that all of this checking costs me no more than a handful of milliseconds.
Standards – I don’t particularly care what standards you code to, and honestly, no one outside your team should, either. The only thing that matters is that you as a team have standards and you adhere to them as closely as possible. BY standards, I’m talking about things like variable and method naming, approach to testing, commenting, etc. Within a project, I would recommend that you support the same standards. Cross project, it doesn’t so much matter. But it sure would be nice if all of your variables were named following the same pattern within a project. It just makes maintenance SO much easier.
So what is “acceptable” performance? The answer is invariably “it depends.” Mostly it depends on the content you’re serving up. If you are the only source for that information, which is often the case with intranets – SharePoint’s most typical use, then you’ve got some leeway. This doesn’t mean you have license to abuse your users, you still need to stay within the realm of reasonable response times, but you’ve got more time than, say, a public facing website.
Your thoughts on this matter will almost certainly be different, but here are the metrics I shoot for:
- Site home page: 2-3 seconds
- Interior landing pages: 3-4 seconds
- View pages: 3-4 seconds
- Item pages: 2-3 seconds
- Documents: depends on the size of the document
Again, let me repeat myself on a few points:
- These are general guidelines I use, not hard-and-fast rules.
- These are for internally facing sites. Public facing websites are a whole different ballgame
I use these guidelines to help determine how to architect my solutions; how I know that I can have my code spend a little more time making the applications easier to maintain; how I know that I should optimize things a little bit more because I’m not hitting them. Everything related to performance is a trade-off with something else. Knowing when I have some leeway is important.
Fixing Performance Problems
So far, everything I’ve mentioned so far falls into the bucket of slowing down your site (if only by a few hundred milliseconds). If you already have a performance problem, what options do you have?
Performance problems are fixable
But not always via code fixes. Sometimes that means adding more hardware – servers, RAM, CPU, faster disks, etc. Think about it this way – if you pay a developer $150/hour to fix performance problems and you estimate it requiring 80 hours, that will cost you $12,000. Depending on the nature of the problem, that money may be better spent simply increasing the RAM in your web servers or database servers.
Not all problems can be fixed simply by throwing more hardware at the problem. The trick is figuring out whether your particular performance problem is one that can. In general, more hardware will help if your servers (web or database) are heavily utilized and it is legitimate utilization. More hardware probably isn’t the right answer if your performance problems are the result of simply shoddy coding practices – not disposing of objects, poor use of collections, extra database hits, etc.
Perception vs. Reality
In few other places in our line of work is the distinction between perception and reality more important than a discussion about performance. The perception of speed is far more important than actual speed. If your users think your site is fast, then it’s fast; even if a stopwatch says differently.
Am I saying that you shouldn’t make your code run efficiently and as quickly as possible? No. Absolutely not. I’m saying that you shouldn’t be a slave to performance. There are more important things to worry about.
Call to Action
The next time you need to write some code, think about performance in light of everything else. Think about how adding some code that will reap huge benefits during maintenance or bug fixing are well worth the 100 or 200 milliseconds of processing time they take on page load. Actively work to make your code more maintainable and don’t worry quite so much whether a page take 2 or 2.5 seconds to load. No one will notice, except the developer who has to figure out what’s going on in the code 6 months later – the developer that may be you.
Welcome to OnSharePointDevelopment. I’m going to assume that you’re here for one of two reasons:
- You’re a SharePoint developer who is interested in improving his/her craft
- You’re an insomniac and this inane drivel helps you to finally fall asleep.
If the latter, feel free to keep reading until you nod off.
If the former, then let’s get down to business.
Why Are We Here?
I conceived of this site in the Fall of 2011 and started preparing presentations for the SharePoint user group I help to run. At the time, I was seeing a couple of trends develop in the SharePoint space, some of them encouraging, some of them discouraging. In either case, it was something that interested me and I felt like it was an area in which I could help. In no particular order, here’s what I noticed:
- We were at a watershed moment in SP Dev – a cusp or turning point. SharePoint is an extremely powerful product and a game changer in many ways. It brought about significant changes in the way IT operates and developers weren’t keeping pace
- Too much SharePoint development work was really, really horrible. Bad code is bad code, period. Unfortunately, the complexity and popularity of SharePoint have combined to produce an onslaught of really shoddy code and coding practices.
- SharePoint was not slowing down. I really thought that SharePoint would have peaked and begun slowing down by 2011. It hasn’t, and isn’t showing and signs of it, either.
- The Rise of the End User – SharePoint allows non- or less-technical end users to perform a dizzying array of customizations. While this is undeniably a good thing overall, it is not without its problems at the edges. The mantra of “just because you can doesn’t mean you should” applies, and is often the cause of friction.
- Extreme polarization – The dividing line between end user, developer and administrator is, oddly enough, simultaneously blurring and becoming more pronounced. SharePoint allows a significant amount of customization without requiring a single line of managed code. This allows non-developers to do things which historically required a developer. Instead of causing an amalgamation of professionals into a more homogenous “SharePoint Pro”, this has, for some reason, caused the stratification of SharePoint professionals and users into distinct “camps”, and anyone in a different camp is generally wrong. It’s remarkably similar to the dividing line drawn between Republicans and Democrats in the political arena.
A Journey of a Thousand Miles…
Paraphrasing Lao-tzu, the Chinese philosopher from the 6th century BC, a journey of a thousand miles begins with a single step. This is our collective first step… On SharePoint Development is a discussion on the what and why of SP Dev. It is my small attempt to help make us all better at our craft. There are dozens of decent sites/blogs/articles/books that can help you to figure out how to do anything you need to do in SharePoint. A simple Bing/Google search will return hundreds of results for any SharePoint-related query – some of them garbage, some of them gospel; most of them somewhere in between. What has been sorely missing, however, is an understanding of other aspects of getting the most out of this product, how to approach a problem, how to control process, how to get everyone on board and get the job done.
Rather than approach this in a scattershot manner, I’ve broken the journey down into sections:
- Development Process – a large portion of the beginning of this journey is going to be focused on this section. I’m doing this for two reasons – it’s currently the area that interests me the most, and it’s also, I believe, the area most sorely lacking. Writing code is easy. It’s all the other stuff of making that code good, efficient, reusable, repeatable, testable, manageable, fixable, etc that is hard.
- The SharePoint toolbox – SharePoint is the Prego of business software. (Just about) whatever you need…It’s In There. Understanding how best to use this tool and all that it gives you, however, is often where the problems come in. Too often, the immediate answer to the question “with SharePoint, how do I…” is it depends, followed be a litany of questions. Unfortunately, too often those questions are never asked and the developer runs off in the direction with which they are most comfortable, whether it is the right direction or not, only to find out later that their initial direction was flawed and they need to go back and start again. We need to fix this…
We’re all Padawan
I intentionally sub-titled this blog “Insights from a Journeyman Coder” as it’s important to acknowledge that we’re all still learning. I expect to learn as much in the process of writing the content on this site as you will from reading it.
What To Expect
The posts on this site are, for the most part, prose versions of the lectures I’m giving at my user group and other venues; not word-for-word transcripts as they’re augmented with additional detail, but close enough. All of the main concepts come across intact. As appropriate, I link to existing content elsewhere on the web to help drive home points.
I’ll warn you right up front that you’re not going to get a whole lot of “tips & tricks” on this site – there are FAR too many of those types of sites elsewhere and that’s part of the problem
What I’m hoping to Achieve
My goal for the content on this site is to make you think differently about what you’re doing. No longer is “make it work” an acceptable end-goal. I want us all to think about where we’re trying to get to and figure out the best route to get there.