Higher Ed Tech Tools: Better Assignments, Better Learning

https://pixabay.com/en/apple-education-school-knowledge-256261/THE NEED: Not too long ago, I conducted a workshop entitled Cool Tools: Better Assignments, Better Learning for the Association for Talent Development . When I worked as an instructional designer in higher education, I found that professors developing online courses would often get stuck in a rut with their assignments, which predictably looked like, “Read Chapter 7 and answer the questions at the end.” Perhaps you remember completing those in your undergraduate days. Some profs would go the extra mile, and suggest the student select a topic covered in that material and write a two-page research paper about it, and if they were being REALLY creative, have them do a PowerPoint presentation around some of the content. I don’t know about you, when I taught, I’ve graded some really dreadful papers where students regurgitated content, or took a stab at developing a PowerPoint with no design skills, embodying the concept of Death by PowerPoint. It always made me wonder how much they were actually learning as they did so. As an instructional designer, it’s my job to work with content to make it sticky. Philosophically, I believe that learning should be interactive, and where possible, fun. These mundane assignments were certainly not accomplishing that. Learning online had some restrictions, but it certainly did not limit assignments to text driven pieces. My workshop was birthed to help teachers create better assignments for better student learning, and I wanted to teach them to use some of the fabulous tools readily available to them to do so.

THE TOOL: Enter SmartDraw. As one of this blog’s readers, I don’t need to sell you on how fabulous the tool is. You’re already a fan. You cannot imagine the excitement of the professors in my workshop when they were exposed to SmartDraw for the first time and they began to see possibilities. Here’s a sampling of the suggestions I gave them.

blueberry map1MIND MAPS I started with planning. I always use the mindmapping feature of SmartDraw to lay out any course that I teach. Beginning with the goal, I add the outcomes and enabling objectives, then assessments, followed by content and activities linked to each. This allows me ensure everything is aligned with the goal I’m trying to achieve. For students, this is a great way to plan out a report or a project, because ideas move around easily at this level, and function globally, rather than in a linear fashion. It helps students understand organization in ways that an outline never seems to accomplish.

 

 

 

 

Project PlanBPROJECT PLANNING Next, I moved to SmartDraw’s project management capabilities, which are especially helpful for students doing group work. Identifying tasks, deadlines and resources is an important skill for them, but key in the process is recognizing the interdependencies of the tasks and the impact of one missed deadline on the entire project. Using a project plan keeps students accountable to one another, and equips them with a critical tool for the business world. With SmartDraw in the cloud, everyone has access to the same diagram, and updates occur in real time, as individuals update their individual tasks. Students can even hop on a tablet or smartphone to make updates.

 

 

 

 

Player Journey1FLOWCHARTS After mindmapping and project planning, we talked about flow charts. I’ve used flowcharts in business to diagram processes, but in the classroom they can be effective tools to document the player journey in planning of a game, the hero’s journey in literature, adding in all of the influences impacting his or her decisions. Students can illustrate the step by step process of a lab, or create a how-to job aid for performing a task they just learned about.

 

 

 

Journey Map1TIMELINES Students can use the timeline features of SmartDraw to create a journey map of user interactions as part of design thinking, but could also build timelines from history, or the plot of a story when reading a novel.

 

 

 

 


lifecycleCYCLE DIAGRAM
The diagramming tools are some of my favorites in SmartDraw. This one comes from the Infographics section, but there are similar ones in the Marketing and Science & Education sections, and can be used to illustrate any kind of cycle. In the science classroom, this could illustrate biological lifecycles or ecological concepts.

 

 

 

 

 

 

Cluster Word Web templateCLUSTER WORD WEB In the Science and Education section there are pre-built templates like this word web which would work well for ESL learners as well as foreign language learners discovering relationships between words and concepts. Mapping them out allows the student to visualize connections. Adding the student’s simple sketches in each bubble can aid in recall.

 

 

 

 

 

Story Map TemplateSTORY MAP SmartDraw has many built in templates specifically for education. This one can be used to summarize a book, play or movie, but could also be used to plan out a story overview, similar to the beat sheets used in screenplay writing. Having a big picture overview keeps the students focused on where things are going and reduces writers block.

 

 

 

 

 

 

 

 

THE DISCOVERY: A key point in all this is recognizing that we are teaching students to manipulate information. As teachers, we can give them these kinds of pre-filled diagrams to study, which aids in analysis, but when the student generates the diagram, they must think through the information at a different level. This is a critical differentiator.

bloomstaxonomyWhen we have students create their own diagram, it brings them to a deeper understanding of the content we are trying to teach. If we look at Bloom’s Taxonomy, these activities force them into higher order thinking, which brings about deeper learning. Creating a Venn Diagram about a concept requires the students to understand the it, apply, analyze and evaluate words and ideas related to it to determine where they belong on the chart, and ultimately create a representation of it all to be shared with others, which brings us to the pinnacle of Bloom’s pyramid.  It sure beats fill in the blank worksheets or answering questions at the end of a chapter…. which may or may not even aid in recall.

We want our students to be invested in their learning, and I’ve found using activities like the ones that leverage SmartDraw makes students proud of what they have accomplished when they are finished. That pride loops in all the positive emotions that enables even stronger ties to the learning.

Cool tools like SmartDraw enable better assignments, and better learning, which, after all, is the point of higher education, right? What can you use for your students? I’d love to hear your ideas for assignments using the tool.

About the Author Jean Marrapodi, PhD, CPLP is a learning architect based in Providence, RI, and a SmartDraw user since 2007. Read more about her at www.applestar.org, or on Twitter at @jmarrapodi.

TechCrunch Article – Is HTML5 the New Windows?

Paul, SmartDraw’s founder and CEO, wrote a compelling and thought provoking article on the rise of HTML5 for TechCrunch this week.

“Might the arrival of new cloud-based apps that run in a web browser and store their data in the cloud create enough of an advantage over the common desktop environment to cause a similar shift? Interestingly, there are quite a few parallels between the arrival of cloud-based apps and the arrival of Windows 30 years ago.”Paul Stannard

You can read the full article over at TechCrunch. What do you think? Is HTML5 the new Windows, and cloud-based apps the way forward?

Eating My Own Dog food

Why it took me ten years to use my own product to draw a flowchart

I wrote the first version of SmartDraw in 1994 and I’ve been the sole author, or one of the small team of authors, on every version since. Yet I only began to use my own product to help me think through designs by drawing flowcharts since 2007. Why? There were three obstacles to overcome, but first let me explain why I use flowcharts at all.

How I use flowcharts in software design

If I have to design a solution to a reasonably complex problem, I use a flowchart to help me think through all of the cases my code is going to have to deal with. For example, when I designed the multiple page feature of SmartDraw Cloud, I had to think through how the usual mechanism for loading and saving a one page document would be modified to handle a document with multiple “one-page” documents stored in it: How navigating between pages would work, when changes had been made to the page (or not) and so on.

Creating a flowchart of the steps and cases helps me understand the issues before I start coding and this is the main reason I use it, but it also creates documentation that can be used later to understand what the code I wrote is trying to do (often by me).  You can look at my flowchart by clicking on the preview below.

flowchart_1

This is the real one I did at the time. No cosmetic or grammatical clean up has been applied. [We try for authenticity here at SmartDraw].

However this only works if I can create the flowchart at the speed of thought. If I have to futz around trying to get my ideas into a diagram, it slows me down and it’s not worth the effort.  This brings us back to the three obstacles that I had to overcome to make this workable.

Obstacle 1: Drawing Flowcharts is a Pain!

Before 2007 drawing a flowchart with SmartDraw was pretty much the same process as drawing one with MacDraw, Visio or any of the other programs used to draw diagrams: You drag shapes onto the page and join them up with lines. Rearranging the shapes and the flow as your mental model evolved was tedious and slow. Trying to use a diagram to help you think made it harder not easier.

What changed this was SmartDraw’s introduction of automatic formatting. With automatic formatting I could drag shapes around to new locations, add new ones and delete them and SmartDraw did all the work of reformatting the flowchart. I could finally draw and think at the same speed.

Obstacle 2: Flowcharts are incomprehensible.

Flowcharts are often literally a joke. Take a look at this one:

bad_flowchart

The culprit is this innocent looking symbol:

decision_symbol

The decision symbol is a diamond and is used to direct the flow from a decision in perpendicular directions. This is how flowcharts quickly end up as spaghetti messes. Imagine if you wrote text this way: I’m reading the instruction and then suddenly I have to turn the page on its side!

The way to fix this and make your flowcharts useful to you and your audience is to:

  1. draw them from left to right like you do when you write text, and
  2. use a fork in the road to indicate a decision

split_path

A fork in the road (or a split path) lets you see results of the decision, without looking in perpendicular directions. Later decisions make additional forks.

good_flowchart

This is much more readable, so why is the perpendicular flow of the traditional decision symbol so popular? Because of obstacle number three.

Obstacle 3: The tyranny of the printed page.

The reason why flowcharts use perpendicular flow is so that they will more easily fit on a printed page. Flowcharts date from 1921 when they were used to document processes. They were drawn by hand onto a piece of paper using a stencil.

We are way beyond this now. (Although I think it’s telling that Visio still calls its shape libraries “stencils”). There is no need to print my design flowcharts. Ever! This gives me the freedom to draw them for readability and clarity without worrying how they will fit onto a page.

Until recently, when I wanted to share my diagram with my co-authors, I’d store it in a common location and send them a link. They’d view in it in SmartDraw.  Now I use SmartDraw Cloud and just send them a link.

In 2016 there is no need to even consider sacrificing clarity to make your diagram easy to print. Just don’t print them! Share them.

Flowcharts can help you think and communicate

Once you can draw as fast as you can think, and you can create easy to follow flowcharts by abandoning the decision symbol, flowcharts can be a great tool for helping you design algorithms. Sharing them with a link also makes them an effective vehicle for communicating with your co-workers.

 

The Paperless Meeting

night-office-shirt-mailWe’ve all read about “The Paperless Office” first coined in 1964 by IBM to sell their video display terminals. Over time this term has become understood as the replacement of paper documents with electronic ones, using scanners and document storage software. We still have a long way to go before we reach this goal, but the tide has definitely turned. There is less paper used in business today than 10 years ago. Why the decline? Perhaps the biggest influence is the increasing ease with which electronic documents can be shared. Just generating a document with a PC doesn’t reduce the amount of paper you use if the only way to share it is to print it!

Sharing Documents

At SmartDraw we began sharing documents many years ago by attaching them to emails. This works but it’s quite difficult to manage the resultant multiple versions of the same document. About 10 years ago we installed a central document storage system (Microsoft’s SharePoint) and we began emailing links to one copy of a document in SharePoint instead of emailing the actual file.

These days we increasingly use cloud-based software to create documents. This makes sharing even easier, since the person with whom we are sharing doesn’t need to own and install the app that created the document.

While this solved our problems sharing documents while working alone at a desk, it didn’t make it easier to present and capture information in our meetings.

The Meeting Problem

In a meeting you typically print copies of minutes, plans, reports and other documents that present the information needed, and distribute a copy to everyone there.  Decisions and new action items are recorded in notes taken at the meeting. Perhaps someone assembles the notes and distributes them to the attendees later.

This is the same process we’ve used for the past 50 years or longer, and it was the process we used until about ten years ago. Now our meetings involve no paper at all: No printed minutes, no reports. No handwritten notes. I began this change by using the paperless method with one regular meeting, and it quickly spread throughout the company, because it worked so well.

Meeting Without Paper

Our product, SmartDraw, is software that people use to create diagrams. In 2007 we added automatic formatting to a number of diagram types, including mind maps. For the first time it became possible to create and edit a mind map as quickly as you can type. So instead of showing up to our weekly management meeting with a printed list of action items from last week, I decided to make a mind map of tasks assigned to each member of the team and display it using the projector we had in the conference room.Operating_Committee_MindMap

In real time, I deleted tasks that were completed and added new ones that we decided on. Everyone could see what they, and the rest of the team, were tasked with and how much progress had been made since last week. Communication was 100%. Capturing information and assigning new tasks happened instantly.

The SmartDraw file we used was stored in SharePoint and everyone had access to it, so they each had a copy of the action plan for the week. Next week we would open this file and update it at meeting.

Today we follow the same process but we use SmartDraw Cloud to create mind maps and share them. It’s just more convenient and we can more easily access the file from anywhere, even our phones.

Why a Mind Map?

So why not just project a Word document showing tasks in outline format? Like this:

Text Outline_Operating_Committee

We could have done this, but text outline is much more difficult to work with and view. Trying to drag items around from one person to another is tricky. A mind map is a more visual representation of an outline that is easier to edit and view than a text-based version.

We also display other document types in meetings: Excel tables and graphs, other SmartDraw diagrams like flowcharts and Gantt charts, but rarely Word documents.

What you need to make the paperless meeting work

  1. A high quality display in every conference room

You need either a large high resolution TV monitor or a good projector in your conference room so everyone can see the detail on the screen. You need a display resolution of at least 1600 x 1200.

  1. A permanent computer in every conference room.

Each conference room should have a good quality PC permanently installed and hooked up to the display. You don’t want to futz with someone’s laptop at the beginning of the meeting. Just log in and get started. It should also have a fast connection to the Internet.

  1. A wireless keyboard and mouse

Attach a wireless keyboard and mouse to the computer in the room. Have a set of each in each room. Change the batteries every month. Don’t wait until they are dead.

  1. Central storage for documents

Any document shown at the meeting should be accessible and shareable from the conference room PC. Store these documents in the cloud or in a behind-the-firewall common location like SharePoint.

  1. Mind Map software than can edit in real time

There are now other programs beside SmartDraw that can do this. Use the one that best fits your needs.

  1. A designated driver

We have found that this format works best when one of the meeting attendees operates the keyboard and edits the mind map. Sometimes this is the same person for the whole meeting and sometimes it works best to pass control among the participants if they will have the floor for a while. If someone else wants to say, add an item, they ask the driver to do it. “Let’s add an item for the PR campaign…” for example.

Paperless Mtg Floor Plan

The physical requirements, 1-3 are key. When we want to use this format for a meeting at a customer’s facility we are often amazed that many conference rooms don’t have an adequate computer setup.

The Benefits of a Paperless Meeting

While paperless meetings save paper and trees, the greatest benefit is in communication. Every participant can see exactly what is expected of the whole team, what has been accomplished and what decisions have been made in real time, and has a permanent record to review later. It’s made a significant contribution to the agility and success of our company and can do the same for yours.

5 Reasons Why You Should Determine Your Business’ Customer Satisfaction Rate

According to Michael Gerber, author of The E-Myth, “ . . . the customer you’ve got is a lot less expensive to sell to than the one you don’t have yet.”  It’s a no brainer – satisfied customers lead to loyal customers which means more business. Boom. End of article. But businesses and the people that run them are all inherently different. Therefore, customer satisfaction is important to each business differently.

iStock_000009612926Small

Have you determined the customer satisfaction rate for your business and how it has impacted it? If not, here are reasons why you should.

REASON #1 Customer satisfaction maximizes your marketing budget, by optimizing it

All businesses spend tons of money marketing their products and services to win new customers every day. From small “Mom and Pop” restaurants to large technology corporations. But if your customer satisfaction level is low, those customers may not return. However, as mentioned in the opening of this article the more satisfied your customers are with your products and services the more likely they will return again and refer others as well. When that happens, your marketing dollar is now stretched and optimized producing incremental business. Determining how satisfied your customers are may potentially lead to more business without actually spending more on marketing but rather making a concerted effort to keep the customers you have already originated because of it.

REASON #2 Customer satisfaction is your point of differentiation

Free market enterprise exists to produce competition in a variety of ways. So in essence, there are always options for customers to select which business they purchase from for their needs. Customer satisfaction, like anything else, quite often is the reason people select one business over another.

Take Apple for example. Apple, especially under the direction of Steve Jobs and his successor Tim Cook, has always aimed to create high-quality products and experiences with them. And as such they have a large fan base of product champions that continually grows each year. For years, Apple placed a premium on meeting and exceeding expectations of their customers that has led them to surpass technology giants like Microsoft and become the largest technology company in the world.

REASON #3 Customer satisfaction shores up operational issues and inefficiencies

Let me ask you a question – if you discovered that your customer satisfaction rate with your business was lower than expected, what would you do? Wouldn’t you look at doing business differently?

Change can often be a frightening word to people and especially those in business. But in this case, change can be a tremendous benefit. Your discovery leads to an opportunity to change operationally the things that are inefficient. New processes. New projects. And a tremendous chance to improve the overall quality of your products, services, and the rate of satisfaction your customers have for them.

REASON #4 Customer satisfaction spurs new ideas

Similar to the above bullet, knowing your customer satisfaction rate and its impact can lead to ideas that are with the customer in mind first and foremost. Apple is tremendous at this. They are quite keyed into making their products appealing, hip, fun, user friendly and simple. Customer satisfaction is at the core of what they do, and they’re notorious for not inventing new gadgets but reinventing ones already adopted and making them exponentially better. MP3 players existed before the iPod, but the iPod transformed the digital music industry. The iPhone? Same story. Apple makes the most popular personal technology products because their products are so engaging, and so customer-centric that their fans have no reason to buy such items from the competition.

REASON #5 Customer satisfaction and employee satisfaction are interwoven

When you work for a company that puts people at the center of its purpose, inevitably satisfaction levels remain high. Customers ultimately buy the feelings the products and services provide them. And employees perform with passion when they feel validated, challenged and involved. It’s a natural yin and yang.

Employees treated fairly and with a stakeholder mindset build better products and services. The customers that buy those products ultimately feel happy and satisfied about their decision to buy. And those same customers are more likely to do it again and share their experience with others. The positive mojo transfers from employees to customers and back again.

Our Mac and iOS Dilemma

http://streetwill.co/posts/351-craft-fig
During the planning and development of SmartDraw Cloud we were faced with a pair of dilemmas that many developers have faced lately. Should we build a native Mac app, and if we do, should we put it in the Mac App Store? Over the last 12 months both these questions have been hotly debated. I’ve been using Macs since the early 90’s, and an iPhone and iPad owner since their first incarnations. The Apple fanboy in me wanted to ignore the growing chatter about issues with the App Stores, but the product manager in me couldn’t ignore them. At the same, JavaScript has taken over the world and at the same time the browser wars have produced an incredible platform to develop on.

After much analysis the answer was obvious, building an amazing desktop-class app was the best way to serve the Mac community, and our users as a whole.

App store policies

In the crowded world of software, differentiation is difficult, and often comes down to one or two unique experiences. This has been true for SmartDraw. Our two most popular features (content and automation) really needed to be experienced in a trial. Words and screenshots don’t do it justice. This meant the lack of a trial in App Stores was a major hurdle.
We could have hosted the trial on our website, then when the user decided to buy send them to the app store to purchase there and reinstall. Having personally been through this experience for several apps, it was not an option. Too much user confusion and technical overhead that didn’t make sense.

Software purchases via the App Stores provided very little customer information, and returns happened in somewhat of a black box. Observing others experiencing the results of these policies didn’t leave a great impression. More often than not, issues were pushed public, where users were desperate for answers, and developers and support personal were left scrambling for better ways to communicate with their users.

While the App Stores certainly has its positives, some of these policies are downright hostile toward businesses trying to sell software.

App Store pricing dynamics

Widely discussed in Apple developer circles, the App Stores also had (and continue to have) pricing issues. Customers expected App Store apps to be cheap, low-risk, and perpetual. None of those expectations make it easy to build a sustainable business from, and all were directly related to the policies that made the app store troublesome.

Because users couldn’t give apps a test-drive, they were less likely to impulse buy pricier apps with sane prices. This, coupled with the flood of apps available created a race to the bottom for prices. There were very few examples of professional, infrequent user apps that had seen success. Even charging $19.99 places you in the expensive category. An examination of the App Stores top charts indicated a very obvious pattern of free-to-play apps which derived revenue from consumables available via in-app purchase.

Public outrage over excessive in-app purchases, and the complete lack of upgrade pricing policies in the App Stores further reduced options. We concluded the App Stores pricing dynamic was a poor fit for the kind of software we produced.

Reliability and the customer experience

Apple provides many frameworks to help build great apps. In many cases they truly help developer productivity. CloudKit, is a great platform for a startup. But, its pricing is unclear and Apple has not had the best track record with its cloud services. We never wanted to be in a position of not being able to answer our users’ questions because of unknown issues in CloudKit or other frameworks.

We also had many customers not using Mac and iOS, with a legacy Windows business and growing Android market. Many of the technologies available in Apple’s ecosystem are iOS & Mac only, rendering them nearly useless for us. As attractive as they were, they were again a poor fit for our product.

The tech was ready

At this point using any of Apple’s tools (iCloud, CloudKit, App Store distribution, etc.) was not an option. The only question left was whether we should build a native app, but that question almost answered itself. On the one hand it was clear Apple’s development platform showed little benefit for us. On the other hand our experiments with web technologies like Angular, React, and jQuery showed a robust, desktop-class app was possible in the browser now.

Facebook & LinkedIn had both struggled with wrapped apps on iOS early. But, their learnings and an active and open JavaScript community had pushed browsers forward. HTML5, CSS3, JavaScript, and SVG gave us everything we needed, and allowed us to serve all our customers with one solution.

In the end we went cloud

Choosing to go cloud first was a difficult choice. But, in the end it was the path that allowed us to best serve all our current and prospective users. The benefits of the App Store look so good on paper, and would have been great for us as a business. But, there were too many asterisks, too many black boxes. As we iterate on SmartDraw Cloud we will continue to ask ourselves if the market has changed. We will be watching what Apple does at WWDC closely this year.

Why We Ditched Angular.js and Wrote Our Own UI Library

https://pixabay.com/en/technology-computer-black-code-1283624/We recently announced SmartDraw Cloud, a browser-based version of our native Windows diagramming application SmartDraw 2016. SmartDraw Cloud, built entirely in JavaScript using the HTML 5 stack, was more than three years in the making and has the full feature set of our Windows Business Edition.

Ask most people how they feel about browser-based apps and they’ll tell you that there’s a trade-off between the convenience the cloud offers, and the power they get from the desktop versions of the same programs. Even the browser versions of Microsoft Office applications do not have the full feature sets of Microsoft’s desktop versions of the same. When we designed SmartDraw Cloud our goal was to eliminate this tradeoff and we’ve succeeded.

An earlier post summarizes the techniques we used to achieve this goal. This article focuses in depth on our unique approach to handling the complex UI of an app like SmartDraw, and why we initially adopted and then rejected Angular.js.

Framework Hell

The most common approach to developing a JavaScript app is to decide on a “framework” that isolates you from the common tasks of developing a UI, getting user input from it and showing the user the state of their document.

This is the sort of thing a framework is supposed to do for you: create and handle a simple control like this for the text font. The control shows the font of the currently selected shape or text, and allows you to change it.

sdcloud_text_ui

We looked at a wide range of such frameworks, including Dojo and React before setting on Angular.js. As we began development we quickly realized three things:

  1. Angular wouldn’t scale to the extent our sophisticated app required, and it obfuscated what was going on.
  2. The whole approach of wrapping the UI in a code-based framework made it impossible to separate the UI from the code. This is an important principle to us. The UI in SmartDraw is very rich and it needs to be coded by experts in HTML and CSS. The calls made to the app from the UI need to be specified in the UI HTML in manner easy enough for a non-JavaScript programmer to handle. We needed to be able to add commands by merely updating the HTML. Angular (and the other frameworks) just don’t work this way.
  3. Once you pick a framework, you become dependent on it. It becomes integral to your code. If support for it wanes, or your want to move to the latest “cool” framework, you have to pull your app apart. Our code base for Windows has been around for 20 years. We expect our JavaScript code base to last for many years too. We wanted no part of this “framework hell.”

How Angular.js failed us

Originally, when we set out to write SmartDraw Cloud we followed the typical pattern for app building: find an existing framework or libraries / modules and stitch them together into an app. After doing some research we decided on Angular.js because it looked like it offered us the power needed to make a snappy, responsive UI to what would necessarily become a very complicated drawing program. In particular it was the two way data-binding that looked cool. Hook up the UI element with your data model, and presto: Changes to the UI updates your model and changes to the model updates the UI. Nice.

However, once we got into the weeds of actually making the UI respond to changes in the drawing area, the performance of the app began to suffer.

The big challenge was UI idling, where we make the commands in the command bars at the top of the app (called ribbons) react to the user’s current shape selection, just like the text font  we used as an example earlier.

idle_text_ribbon

It seemed like precisely the task two-way data binding was designed to do. The problem was that as we added controls, this sort of idling began taking a noticeable amount of time – hundreds of milliseconds – and was causing the app to stutter and feel clunky.

And it’s not just the command buttons themselves that are idled: it’s also the rich menus that they call. For example:

fill_menu

These were all idled by two-way data binding.

Two-way Data Binding in Angular.js is Inefficient

We did additional research into the guts of how Angular.js does its two-way data binding, and the results were disturbing. Angular is based around the concept of “watches.” Watches bind a variable from a controller to a part of the DOM by making a copy of the value from the controller, “watching” for any change from either the controller or the DOM, and updating the in-memory value with whichever value was out of sync.

angular_digest_ex

These watches work well enough by themselves, but the real problem is in the way Angular solved the problem of when to have the watches sync themselves.

Because getters and setters are (currently) rarely used in JavaScript, there often isn’t a good way to tell when a value has been updated in either the DOM (excluding the DOM’s native eventing) or the in-memory object model of the app. So, Angular uses a blanket approach: re-evaluate every single watch every time any Angular event (ng-click, ng-mouseover, ng-keydown, ng-mousemove, etc) is raised. For example, if you have 100 data bound elements in your application, any time any event is raised (such as clicking on something) all 100 get re-evaluated and synced.  The result is a seriously inefficient – and ultimately un-scalable – application framework.

No wonder the app was having problems, we had hundreds of data bound values in our complex UI and every time a key was pressed each and every one of them were re-evaluated, and there is no good way in Angular to filter out watches that do not need to be re-evaluated (like watches whose elements have “display: none” on them).

We Tried to Make it More Efficient

In an effort to improve performance and tame the beast by controlling the flow of watch re-evaluations, we manually took control of what is called the $digest()/$apply() loop. $digest()sends a message down from a parent controller recursively to its child controllers telling them all to re-evaluate their watches, while $apply() sends a message recursively up the controller inheritance chain and ultimately causes every single watch in the entire application to be re-evaluated. We set it up so that $apply() was never called (except in a few instances where it made sense to do so) and only relevant parts of the UI would be digested in response to user events.  While this strategy dramatically improved performance, it was still noticeably slow and not satisfactory for our requirements and usability standards.

Finally – We Just Gave Up

We decided to put the final nail in the coffin when we called $digest() and $apply() at the same time, and the two commands “collided” in the Angular framework and caused a crash that effectively broke the app. We debugged the Angular code to see if we could find a quick fix to the problem, and discovered it was choking on a massive if statement that had at least a dozen separate clauses cobbled together, including a variable assignment INSIDE the if statement:

if ((x > y && hackyCode = true) === true)

This statement which is syntactically valid is nonetheless an awful corruption of what is supposed to be a vessel of pure Boolean logic and simply not the place for variable assignments.

Combined with the overall slow performance of the Angular framework, this kind of sloppy coding was enough for us to decide to ditch Angular completely and re-start our development effort using a different system.

Removing Angular.js had other benefits too:

  1. We were no longer dependent on a framework we had no control over that seriously affected the design of our app.
  2. We could develop a system that had much cleaner separation of UI and code.
  3. We could make a much lighter weight system that could perform well in a large complex app

The SmartDraw UI Library: Bantm.js

The problem we were trying to solve was not that hard. We needed a library that would:

  1. Organize the application codebase so that it was easy to write and maintain
  2. Get events from the UI in a way that allowed UI coders to assign functionality and values to user interface elements in HTML without touching the JavaScript.
  3. Idle the UI elements based on the state of the model (the drawing in our case) in an efficient and fast way.
  4. Make the model respond to changes in the UI in a clean and simple way.

So we decided to bite the bullet and just manually write the JavaScript required to power our app without a third-party framework. We call this library bantm.js (because its lightweight).

As we thought more about how to replace the two-way data binding provided by Angular.js it became clear that we didn’t need some bloated catch-all solution to try and alleviate ourselves the terrible and arduous task of writing actual code. Since the DOM gives us an event every time something in the UI has changed, we as the programmer always know when an in-memory value is changing – because we’re the one changing it!

Organizing the Application

One of the major problems we experienced with Angular is that applications written using the framework tended to become very messy very quickly which made it difficult to determine where things were happening, even for experienced developers. Perhaps there’s a way to write an Angular app that is organized and intuitive, but in following the examples found in various books, documentation, and samples we found online all led to very messy, convoluted code that was difficult to follow and debug. We clearly needed a cleaner solution.

The first part of the solution was to use object literals (i.e. myObject = {}) as namespaces and constants tables. We decided to make a root namespace by creating the single global variable that the entire SmartDraw UI application would live under, called “SDUI”, and then made sub-namespaces for different logical areas of the application. We made the constants tables for application settings or values that wouldn’t be changed between runs, for example:

SDUI.Constants =
{
    ConstantA: "apple",
    ConstantB: "banana"
};

Below is the basic structure of SmartDraw Cloud’s UI namespace/constants table hierarchy:

sdui_structure

The next part of organizing the app was setting up a few simple rules that, if followed, would keep the app from becoming the incomprehensible tangled mess that is all too common with JavaScript apps.

Define Constructors for Objects

The first rule is that every object used anywhere in the application has a defining constructor in the Resources namespace for reference. Every time that object needs to be used, it is instantiated using the fully namespaced constructor so any other programmer reading the code can tell exactly what object is being used and how to find out what the properties of that object are.

Define a Hierarchy of Controllers

A controller is a JavaScript object that responds to UI commands. Each grouping of UI has its own controller. For example, each Dialog has a controller, the Ribbons have a controller, the SmartPanel has a controller and so on. All commands are routed to these controllers via the MainController.

The second rule is that, in almost all cases, one controller cannot directly reference another controller, they must instead talk to each other somewhere outside themselves (in our case, this was the main controller).  This rule prevents dependency nightmares where controllers get tangled together into an unworkable mess. While this does present its own challenge of how to elegantly coordinate the controllers when they need to work together, this is solvable through careful planning. An awesome side benefit of having controllers effectively be silos is that they are reusable and can usually be ported from application to application without issue.

All of our controllers are first defined as functions (in the root namespace) with their own properties and methods, and each exists as single instance of the function in the MainController. For example:

/** Controller for the symbol browser dialog. */
SDUI.SymbolLibraryBrowser = function ()
{
    /*jQuery reference to the root gallery node of symbol icons.*/
    this.Gallery = null;
    /*HTML template of a symbol icon.*/
    this.GalleryItemTemplate = null;
    /*HTML template for an item in the tree view.*/
    this.TreeViewItemTemplate = null;
    /*jQuery reference to the root node of the tree view.*/
    this.TreeRoot = null;
    /*The TreeView on the left hand side of the browser.*/
    this.TreeView = new SDUI.TreeView2();
    /*Array of AppendedItems representing all the symbol icons currently displayed.*/
    this.GalleryItems = [];
    /*The PreviewList representing the symbol library that is currently being viewed.*/
    this.CurrentLibrary = null;
    /*Whether or not the library browser has been initialized.*/
    this.Initialized = false;
    /*The current 'file path' to the current library for the windows client to use.*/
    this.CurrentLibraryPath = null;
    /*The 'file path' of the library to open the symbol browser up to on first start up.*/
    this.LibraryPathTarget = null;

    /**Initializes the symbol library browser.
    @method Initialize
    @param {Object} galleryRoot: jQuery reference to the root gallery node for symbol icons.
    @param {String} galleryTemplate: The HTML string to serve as the template for symbol gallery items.
    @param {Object} treeViewRoot: jQuery reference to the root node for the tree view.
    @param {String} treeViewItemTemplate: The HTML string to serve as the template for items in the tree view.
    @param {String} treeViewListTemplate: The HTML string to serve as the template for a list of items in the tree view.*/
    this.Initialize = function (galleryRoot, galleryTemplate, treeViewRoot, treeViewItemTemplate, treeViewListTemplate) {…};

    /**Gets a library from the internal content hierarchy of the symbol browser.
    @method GetLibrary
    @param {String} libraryId: The ID of the library to find.*/
    this.GetLibrary = function (libraryId) {…};

    /**Loads a library from the server.
    @method LoadLibrary
    @param {String} libraryId: The ID of the library to load the contents of.
    @param {Function} callback: A callback function that takes the result JSON as a parameter to call asynchronously when the request ends. If left null the operation is synchronous.*/
    this.LoadLibrary = function (libraryId, callback) {…};

    …
};

Getting Events from the UI

The next problem to solve was how to get events from the DOM into the core of the application. As an added challenge, the system of event routing also had to be useable by someone who doesn’t know JavaScript. The system we decided on was simple: have a registry of command names that would be written into the markup of the application’s HTML and use attributes to hold values that would be parameters to pass into the functions that would be called.

One of the most important parts of this scheme was constructing a wall to separate the direct UI event handling from the business logic. For each command there was a UI handing method that would be directly called by the DOM which would take the calling element, extract whatever parameters had been added to it as attributes, and then pass those attributes as parameters into the business logic method.  The benefit of this strategy is that you can write simple, parameterized methods that can be called either as a response to an event, or invoked manually when you want to call the functionality outside of an eventing context.

For example, this is the Arrowhead menu.

arrowhead_menu_ex

This is the HTML for the Arrowhead Menu:

<ul id="dd-arrowheads" class="dropdown-menu">
	<li id="dd-arrowheads-none" onclick="SD_Click(event, 'SD_Line_SetArrowhead')" arrowheadLocation="none" arrowheadId="0">
		<button><i class="icon-arrowhead-none"></i> None</button>
	</li>

	<li id="dd-arrowheads-right" onclick="SD_Click(event, 'SD_Line_SetArrowhead')" arrowheadLocation="end" arrowheadId="1">
		<button><i class="icon-long-arrow-right"></i> Right</button>
	</li>

	<li id="dd-arrowheads-left" onclick="SD_Click(event, 'SD_Line_SetArrowhead')" arrowheadLocation="start" arrowheadId="1">
		<button><i class="icon-long-arrow-left"></i> Left</button>
	</li>

	<li id="dd-arrowheads-both" onclick="SD_Click(event, 'SD_Line_SetArrowhead')" arrowheadLocation="both" arrowheadId="1">
		<button><i class="icon-resize-horizontal"></i> Both</button>
	</li>

	<li><hr></li>
	<li id="dd-arrowheads-custom"  class="dropdown-submenu" onclick="SD_Click(event, 'SD_ShowModal')" modalId="m-arrowheads">
		<button>Custom<i class="icon-external-link icon-1x pull-right"></i></button>
	</li>
</ul>

Note each item in the menu has an onclick method that specifies a method in EventCommands.js. The first four are the same command (SD_Line_SetArrowhead()) but with different arrowheadLocation and  arrowheadId values. The final item calls ShowModal with a modalId of “m_arrowheads”. This shows the custom arrowhead dialog:

code_example_2

Again, the first thing that happens is our global event handler (SD_Click) is invoked, and SD_Click looks in the “SDUI.Commands” lookup table for a function with the same name as the second argument passed into SD_Click (the first argument is always the browser’s event arguments), which in this case is “SD_ShowModal”. SD_Click then invokes SDUI.Commands.SD_ShowModal function and passes in the browser’s event augments.

SD_ShowModal then takes the element that raised the event and looks for a modalid and contextId attribute on that element and extracts whatever values were present. Note that the names of the attributes we are looking for both live in SDUI.Constants and every time we need to reference either of those constants we refer to the constants table (SDUI.Constants.Whatever) rather than writing out the raw value (so if we change it, we only have to change it in one place).

Once the attribute values have been extracted from the target element, we pass them into the MainController’s ShowModal function that actually does the work of loading, building, and displaying the modal dialog. ShowModal can be called from anywhere and isn’t hard-wired to a browser event, so we get the flexibility of being able to call it in response to an event or in the middle of our business/display logic as needed.

Making the UI Respond to User Actions

The final challenge was to efficiently solve the problem of making all the buttons on the ribbons, menus and SmartPanels light up or grey out based on user actions. Angular.js had struggled with accomplishing this due to its lack of scalability, but using the namespace hierarchy with constants tables made this much easier.

One of the most important constants tables we used was the SDUI.Resources.Controls table, which contained a special object reference for every piece of UI we programmatically manipulated in the application (each control we manipulate is given a unique three-part ID based on its name and location in the UI, so “r-home-save” would be the save button on the home ribbon).

This special object was called “SDUI.Resources.ControlInfo” (below) and it served three purposes:

  1. Serve as the official lookup location of the element’s ID.
  2. Query the DOM once to get a jQuery reference to a DOM element and then keep it around forever so we don’t impact performance by re-querying the same few dozen elements every time the user clicked on a shape or dropped a dropdown.
  3. Hold custom metadata about each control so that making them respond to user actions could be parameterized and handled generically.
SDUI.Resources.ControlInfo = function (controlElementId, minItems, minShapes, minLines, notesEditEnable,HasTextOnly, noPolyLineContainer)
{
    /*The HTML Element ID of this control.*/
    this.Id = (controlElementId == null) ? null : controlElementId;
    /*The JQuery results for the HTML Element that corresponds to the Id.*/
    this.Control = null;
    /*The minimum number of items that must be selected in order for this control to become active.*/
    this.MinSelectedItems = (minItems == null) ? 0 : minItems;
    /*The minimum number of shapes that must be selected in order for this control to become active.*/
    this.MinSelectedShapes = (minShapes == null) ? 0 : minShapes;
    /*The minimum number of lines that must be selected in order for this control to become active.*/
    this.MinSelectedLines = (minLines == null) ? 0 : minLines;
    /*If this control should always be enable during notes editing. */
    this.NotesEditEnable = (notesEditEnable == null) ? false : notesEditEnable;
    /*Hilite this control only when an item with text is selected.*/
    this.HasTextOnly = (HasTextOnly == null) ? false : HasTextOnly;
    /*Do not hilite control if a polylinecontainer is selected.*/
    this.NoPolyLineContainer = (noPolyLineContainer == null) ? false : noPolyLineContainer;

    /*Runs a jQuery query based on the Id property.*/
    this.GetControl = function (forceReQuery)
    {
        if (this.Control != null && forceReQuery !== true) //if we have it and are not re-querying the control.
        {
            return this.Control;
        }

        var control = $("#" + this.Id);

        if (control != null && control.length > 0) //found the control
        {
            this.Control = control;
        }
        else
        {
            return null;
        }

        return this.Control;
    };
};

In addition to creating a ControlInfo for every control in the app, we categorized them based on where they appeared in the UI so that if, for example, we wanted to grab the controls for every button on the home ribbon, we had a function (SDUI.Resources.Controls.GetRibbonControls(ribbonID)) that would return an array of every ControlInfo contained by that ribbon.

Our organized approach also allowed us to easily keep track of what UI elements were visible (such as which ribbon the user was looking at), so when the time came to make the UI reflect the current selection state, we just looked up what was visible, used that data to grab all the ControlInfo objects belonging to the visible portion of the UI and tossed them into the generic UI idling function which would enable/disable them based on their metadata.

Here’s the definition of the controls for ribbons and then the design ribbon:

Ribbons:
{
    Design: new SDUI.Resources.ControlInfo("r-design"),
    Help: new SDUI.Resources.ControlInfo("r-help"),
    Home: new SDUI.Resources.ControlInfo("r-home"),
    Insert: new SDUI.Resources.ControlInfo("r-insert"),
    Page: new SDUI.Resources.ControlInfo("r-page"),
    Table: new SDUI.Resources.ControlInfo("r-table"),
    Review: new SDUI.Resources.ControlInfo("r-review"),
    File: new SDUI.Resources.ControlInfo("r-file"),
    Options: new SDUI.Resources.ControlInfo("r-options")
},
Ribbon_Home:
{
    Paste: new SDUI.Resources.ControlInfo("r-home-paste"),
    Copy: new SDUI.Resources.ControlInfo("r-home-copy"),
    Cut: new SDUI.Resources.ControlInfo("r-home-cut", 1),
    FormatPainter: new SDUI.Resources.ControlInfo("r-home-formatPainter", 1),
    Undo: new SDUI.Resources.ControlInfo("r-home-undo"),
    ReDo: new SDUI.Resources.ControlInfo("r-home-redo"),
    Select: new SDUI.Resources.ControlInfo("r-home-select"),
    LineTool: new SDUI.Resources.ControlInfo("r-home-lineTool"),
    LineToolDD: new SDUI.Resources.ControlInfo("r-home-lineToolDD"),
    ShapeTool: new SDUI.Resources.ControlInfo("r-home-shapeTool"),
    ShapeToolDD: new SDUI.Resources.ControlInfo("r-home-shapeToolDD"),
    Text: new SDUI.Resources.ControlInfo("r-home-text"),
    AddLink: new SDUI.Resources.ControlInfo("r-home-addLink", 1),
    AddNote: new SDUI.Resources.ControlInfo("r-home-addNote", 1),
    Theme: new SDUI.Resources.ControlInfo("r-home-theme"),
    QuickStyle: new SDUI.Resources.ControlInfo("r-home-quickStyle"),
    Fill: new SDUI.Resources.ControlInfo("r-home-fill"),
    Lines: new SDUI.Resources.ControlInfo("r-home-lines"),
    Effects: new SDUI.Resources.ControlInfo("r-home-effects"),
    Font: new SDUI.Resources.ControlInfo("r-home-font"),
    CurrentFontLabel: new SDUI.Resources.ControlInfo("r-home-currentFont"),
    TextSize: new SDUI.Resources.ControlInfo("r-home-textSize"),
    CurrentTextSizeLabel: new SDUI.Resources.ControlInfo("r-home-currentTextSize"),
    Bold: new SDUI.Resources.ControlInfo("r-home-bold", 0, 0, 0, true),
    Italic: new SDUI.Resources.ControlInfo("r-home-italic", 0, 0, 0, true),
    Underline: new SDUI.Resources.ControlInfo("r-home-underline", 0, 0, 0, true),
    Subscript:new SDUI.Resources.ControlInfo("r-home-subscript", 1, 0, 0, true),
    Superscript:new SDUI.Resources.ControlInfo("r-home-superscript", 1, 0, 0, true),
    TextColor:new SDUI.Resources.ControlInfo("r-home-textColor", 0, 0, 0, true),
    Align: new SDUI.Resources.ControlInfo("r-home-align",1),
    Bullets: new SDUI.Resources.ControlInfo("r-home-bullets", 1, 0, 0, true,true),
    Spacing: new SDUI.Resources.ControlInfo("r-home-spacing", 1, 0, 0, true,true),
    Direction: new SDUI.Resources.ControlInfo("r-home-direction",0,0,1),
    InsertSymbol: new SDUI.Resources.ControlInfo("r-home-insertSymbol",0,0,0,true)
},       

We are able to get all of the controls in the home ribbon because the Home member of the ribbon array tells us that all the home ribbon controls begin with “r-home”. In the same way we can get all of the controls for any ribbon, so if we know that the current ribbon displayed is “Home”, we need only idle the controls defined by Ribbon_Home.

Setting Values for UI Based on User Interaction

The controls in the UI change their state based on the selection of shapes in the drawing. The action of selecting (or unselecting) a shape is easily detected by the JavaScript code that does this, and it calls a function to aggregate the properties of every shape selected into a “current properties” object.

As the particular shapes selected in the drawing change, in response we need to set the states of only the controls that are visible at all times. After updating the “current properties” object we call the method to adjust the state of the visible controls. This is very fast because it is restricted to a small subset of the total number of controls, and we don’t have to traverse the DOM to get their references each time we do this. We get them once and store them.

The controls in dialogs and menus are not visible until they are displayed, and so we need set their states only as they are about to be displayed. This too is very fast because we are handling only a small subset of all of the controls and we get their references only once.

Conclusion

Off-the shelf frameworks and components can save time and effort if you want to develop a quick in-house line of business app, but they are absolutely not the way to go if your goal is to develop a reliable, scalable, maintainable commercial application. With a few person weeks of coding we developed the the bantm UI Library. It allowed us to build an app with a very rich UI that is easy to maintain, responsive and scales with no noticeable performance hit.

Editors Note: This is part 2 of a technical series about the making of SmartDraw Cloud. You can read part 1 here.

How We Wrote a Desktop Quality App in JavaScript That Avoids Framework Hell

http://negativespace.co/photos/computer-stock-photo-3/We recently announced SmartDraw Cloud, a browser-based version of our native Windows diagramming application SmartDraw 2016. SmartDraw Cloud, built entirely in JavaScript using the HTML 5 stack, was more than three years in the making and has the full feature set of our Windows Business Edition.

Ask most people how they feel about browser-based apps and they’ll tell you that there’s a tradeoff between the convenience the cloud offers, and the power they get from the desktop versions of the same programs. Even the browser versions of Microsoft Office applications do not have the full feature sets of Microsoft’s desktop versions of the same. When we designed SmartDraw Cloud our goal was to eliminate this tradeoff and we’ve succeeded.

We’ve shown that it’s entirely possible to create a desktop-quality experience with app written in JavaScript and running in a web browser. You just have to go about it in the right way.

How Did We Do It?

We started with three design goals:

  1. SmartDraw Cloud had to have the full feature set and be file compatible withSmartDraw for Windows.
  2. It had to be fast enough to be fun to use.
  3. It had to be written in JavaScript in a manner which was easy to understand, maintainable, robust and fast.

Frankly we didn’t know if it was even possible. Our team consists of very senior and experienced application developers – but with little to no experience in JavaScript or browser-based apps.

Our initial approach was to do what everyone else seemed to be doing – research existing JavaScript frameworks and libraries, choose the right ones, piece them together, write some glue, and then build an app. After a few months, and a few false starts, we realized that this approach was not going to work for us.

Off-the shelf frameworks and components can save time and effort if you want to develop a quick in-house line of business app, but they are absolutely not the way to go if your goal is to develop a reliable, scalable, maintainable commercial application. In fact, this may be the reason why so many cloud apps have a “lightweight” reputation.

So we wrote some code! In fact, a lot of code. We built our own object libraries which are:

  • lightweight,
  • easy to maintain,
  • under our control, and
  • quick and scalable.

It took more time but SmartDraw is our bread and butter. Quick and dirty was not going to cut it.

This post is the first in a series that explains our approach, reviews some of the problems we encountered, and discusses why we made decisions we made. Later posts in this series will cover:

  1. Why we ditched Angular.js and wrote our own lightweight UI Library
  2. Why we used SVG for the graphics engine and not Canvas, and why we wrote own graphics library instead of using Raphael.
  3. How we used a combination of sockets and our memory manager to save incremental changes.
  4. And why, even with something as seemingly ubiquitous as hosting, we decided to create our own solution and avoid the pitfalls of AWS and similar services.

Writing a commercial app is the same in any language

No matter what language or platform you choose in writing a commercial application, the basic steps are the same.

  1. Decide what your app will do and what interface you want.This was easy for us since we had our Windows desktop application as a template.
  2. Propose an internal design to achieve this. Break it down into functional components that will become the building blocks of the app.This was also pretty easy because we had the Windows product as a guide. We would need a memory block manager to handle undo and redo effortlessly, a graphics interface, a way of presenting and interacting with a user interface, a file format, a text editor, a graphic editor, a business logic manager and so on.
  3. Propose the software architectureThis is where we specify the object design, object hierarchy and data that are maintained.
  4. Look to see if there are existing libraries that can be used for one or more of these building blocks. If so, carefully evaluate them and if they do the job by all means use them. Otherwise write your own.
  5. Write code in a disciplined and maintainable way.Code has to be readable and understandable by everyone on the team – including anyone that might join the team in the future. Code must also follow standards that the team agrees to.

The SmartDraw Cloud Architecture

The diagram below shows a simplified view of the SmartDraw Cloud architecture.

We made the some important design decisions early on:

  1. We would use SVG as our graphics engine because of its performance and superior quality when compared to Canvas. SVG is also quite scalable for printing and export.
  2. We would design a memory block manager that manages all of the objects that make up the composition of a document as discrete blocks, and also manages undo and the writing of the file to the server in a very efficient way.
  3. We would use Web Sockets to save the data and to communicate with the server.
  4. Our file format would be the very compact binary (but xml-like) format we use for our Windows product.

The List Manager manages the shapes on a page. The Business Manager applies the business logic that controls the behavior of specific diagrams like flowcharts or floor plans.

We also made some decisions after we got started and learned some of the pitfalls of traditional JavaScript development for this complex of a project. Those decisions included deciding to build many of our own components and frameworks.

Rolling Our Own Components

The user interface

The most common approach to developing a JavaScript app is to decide on a “framework” that isolates you from the common tasks of developing a UI, getting user input from it and showing the user the state of their document.

This is the sort of thing a framework is supposed to do for you: create and handle a simple control like this for the text font. The control shows the font of the currently selected shape or text, and allows you to change it.

sdcloud_ui_ex1

We looked at a wide range of such frameworks, including Dojo and React before setting on Angular.js. As we began development we quickly realized three things:

  1. Angular wouldn’t scale to the extent our sophisticated app required, and it obfuscated what was going on.
  2. The whole approach of wrapping the UI in a code-based framework made it impossible to separate the UI from the code. This is an important principle to us. The UI in SmartDraw is very rich and it needs to be coded by experts in HTML and CSS. The calls made to the app from the UI need to be specified in the UI HTML in manner easy enough for a non-JavaScript programmer to handle. We needed to be able to add commands by merely updating the HTML. Angular (and the other frameworks) just don’t work this way.
  3. Once you pick a framework, you become dependent on it. It becomes integral to your code. If support for it wanes, or your want to move to the latest “cool” framework, you have to pull your app apart. Our code base for Windows has been around for 20 years. We expect our JavaScript code base to last for many years too. We wanted no part of this “framework hell.”

Our solution was to build a lightweight JavaScript library, called “Bantm” to handle this.

The Graphics Interface

Another choice we made was to use SVG to display graphics instead of Canvas. From a performance point of view this was an easy choice. SVG is a vector graphic format that gives you resolution independent output. However it does present some difficulties:

  1. There is no open source rich text editor for SVG. We would have to write one.
  2. We weren’t satisfied with the existing graphics libraries for SVG. Raphael for example was designed to use either Canvas or SVG, and to also work with older browsers. This gave it a “lowest common denominator” feature set. We wanted the advanced effects of a pure SVG library and so we wrote our own.

Memory Management

Our “Block Manager” lies at the core of the SmartDraw Cloud app. It allows us to store JavaScript objects as discrete blocks. We get references to objects by getting their block. When we get a block we can tell the block manager whether we are going to modify it or not. If we modify it, the block manager makes a backup of just that block. When a user operation is complete, we commit the changed blocks to become the new state of the document. This is a lot like a commit operation in a database.

If an error occurs during an operation, the previous good state is restored, maintaining the integrity of the model.

An undo operation exchanges only the modified blocks from the previous state with the current state. Redo does the reverse. Undo states maintain only the changes to the document model. This is very efficient both in speed and memory usage.

The Block Manager also makes it possible to write only the modified objects to the server after each operation. A change will often only write a few bytes back to the server. This combined with the use of web sockets to send the data makes saving the document after each change very fast.

Libraries we did use.

After much prototyping and research we used just a handful of third party components. These include:

  • jQuery – to get references to UI elements,
  • Fileparser.js – to read and write the binary file format,
  • Hammer.js – to handle both mouse and touch events, and
  • Svg.js – to provide the lowest level interface to SVG markup.

We used these sparingly, often with our own modifications to make them more robust. We load them all from our own site so that our app is not dependent someone else’s site being available, or on updates which we don’t control. (Relying on external loading of components can lead to serious problems, such as the recent NPM Kik module debacle.)

It took us a year or more to write these libraries. With these in place we set about writing the app.

Writing JavaScript like C++

We all have long resumes using C, C++ and C# to write apps. So it was natural for us to treat JavaScript the same way – with well-defined objects and disciplined coding techniques.

A lot of the JavaScript we saw looked indescribably sloppy to us. We noted practices such as:

  • Adding members to an object on the fly,
  • Never actually formally defining an object, and
  • Assigning variables as hard coded constants (like align=16 instead of align=SDJS.ListManager.TextFlags.AlignLeft).

These are all recipes for unreliable code that is impossible to maintain three years out when the author has moved on or forgotten what he or she did.

Here are just a few of the constructs we established to write disciplined code:

  1. Created a consistent name space for all objects. For example, all of the ListManager objects began with SDJS.ListManager…. The UI objects began with SDUI. And so on.
  2. Defined constructors for all of the objects we used. For example:
// arrowhead record
SDJS.ListManager.ArrowheadRecord = function ()
{
	"use strict";
	this.StartArrowID = 0; //starting arrowhead
	this.StartArrowDisp = false; //starting arrowhead displacement
	this.EndArrowID = 0; //ending arrowhead
	this.EndArrowDisp = false; //ending arrowhead displacement
	this.ArrowSizeIndex = 1; //arrowhead size
};

If we needed to add a new member to the object, we added it to the definition, never to an instance on the fly. We also froze objects so this wasn’t possible. Constants were also formally defined:

SDJS.ListManager.ActionArrow = {
	"UP": 1,
	"LEFT": 2,
	"DOWN": 3,
	"RIGHT": 4,
	"SLOP": 5
};
Object.freeze(SDJS.ListManager.ActionArrow);
  1. Created an inherited object model for shapes.The list manager manages a list of shapes that together make up the drawing. Shapes are all inherited versions of a basic drawing object. For example:
SDJS.ListManager.BaseDrawingObject = function (attributes) {
	"use strict";

	// Set the stored object type
	this.Type = SDJS.Globals.StoredObjectType.BASE_LM_DRAWING_OBJECT;

	// Positional attributes
	this.Frame = attributes.Frame || {
		x: 0,
		y: 0,
		width: 0,
		height: 0
	};
};

Etc….
The base object has prototypes for ALL methods used by the derived shapes, but implements very few of them. There are derived objects for shape, simple line, and polygon line and so on. For example:

SDJS.ListManager.BaseLine.prototype = new SDJS.ListManager.BaseDrawingObject();
SDJS.ListManager.BaseLine.prototype.constructor = SDJS.ListManager.BaseLine;

/**
List Manager SmartDraw Base Line Object

Base line object class

@class BaseLine
@namespace ListManager
@constructor
@static
**/
SDJS.ListManager.BaseLine = function (attributes) {
	attributes.DrawingObjectBaseClass = SDJS.ListManager.DrawingObjectBaseClass.LINE;

These objects either implement their own methods, or inherit them from their base class. Again all methods appear in the

BaseDrawingObject 

class, even if they do nothing, so that it represents the union of all methods for all objects.

The emergence of TypeScript and Ecmascript 6 make it easier to write this kind of code. Writing a serious application requires disciplined coding.

Performance

We made many optimizations to ensure snappy performance including simple things like:
Pre-calculating array lengths so we never write:

For (i=0; i < array.length; i++)
{
 …
}

Instead we write :

len= array.length;
for (i=0; i < len; i++)
{
 …
}

Getting the length of a long array inside a loop takes time.

Looking up constants:

If a comparison is made in a loop with SDJS.ListManager.TextFlags.AlignLeft, it takes time within each loop to find this value. Instead we assign:

var AlignLeft= SDJS.ListManager.TextFlags.AlignLeft;

before the loop so this is done just once.

Adding Visio Compatibility

One of our design goals was to import Visio files in an editable form. To do this we had to extend the model of SmartDraw for Cloud and Windows to accommodate the Visio file format. These included multiple pages per document and support for new types of curves including NURBs, Splines and more.

The inherited object structure we implemented for the list manager objects we described earlier made this much simpler to implement. We just added or overrode the methods we already had for other polygon lines, and so on. This applied to our 20-year-old windows model too.

Conclusions

The HTML 5 stack can support desktop quality apps. What’s important is applying the same techniques that make desktop apps work well to the web platform. The language in which the app is written is much less important than applying the design and discipline a large app requires.

It’s also important to use well-designed components that you control and understand, even if it means writing them yourself. Slapping together a grab bag of open source code will make your app as reliable as the worst component you use. It can also make it much larger and significantly slower than it need be. And if you do use a third party library – load a stable version from our own site!

I am confident that as more JavaScript developers acquire the skills to develop commercial-quality applications, and more traditional app developers try their hand at JavaScript, the universe of truly powerful cloud apps will increase dramatically and the trade-off between desktop and cloud will fade away.

Editors Note: This is part 1 of a technical series about the making of SmartDraw Cloud. You can read part 2 here.