TDD and the Power of Habit

“Champions don’t do extraordinary things. They do ordinary things, but they do them without thinking, too fast for the other team to react. They follow the habits they’ve learned.” –Tony Dungyimage

The quote above comes from The Power of Habit: Why We Do What We Do in Life and Business by Charles Duhigg. This book is a fascinating look at habits—what they are, how they form, how they affect us, and how can we choose our habits.

The Habit Loop

Most of us are barely aware of the habits that make up so much of what we do, but psychology and neuroscience researchers have made great progress in understanding how habits form.

image

At the core of this research is what Duhigg calls the habit loop. We usually have no trouble identifying the routine, which is what we think of as the habit itself. The value comes from identification of the two other elements of the habit loop.

The first insight comes in realizing that habits are driven by some kind of reward. The reward could be virtually anything–relief from boredom, sense of completion, etc.image As our behaviors result in the reward we seek repeatedly, our brains literally restructure themselves. Our brains move the instructions for performing the actions needed to invoke the reward to areas that can operate without our conscience thought. Our habits become become so deeply encoded that they become almost impossible to separate from who we are.

The second insight comes in recognizing that there are particular cues that trigger the routine in pursuit of the reward. Cues could be just about anything as well–a feeling of boredom, the sight of a particular object, the presence of a particular person, etc.  Identifying these cues are key to understanding and changing our habits, but you’ll have to read the book for that.

Keystone Habits

Studies have documented that families who habitually eat dinner together seem to raise children with better homework skills, higher grades, greater emotional control, and more confidence. Making your bed every morning is correlated with better productivity, a greater sense of well-being, and stronger skills at sticking with a budget. It’s not that a family meal or a tidy bed causes better grades or less frivolous spending. But somehow those initial shifts start chain reactions that help other good habits take hold. If you focus on changing or cultivating keystone habits, you can cause widespread shifts. However, identifying keystone habits is tricky. To find them, you have to know where to look. Detecting keystone habits means searching out certain characteristics. Keystone habits offer what is known within academic literature as “small wins.” They help other habits to flourish by creating new structures, and they establish cultures where change becomes contagious.

Keystone habits are the drivers that lead to other habits. For example, studies have shown that people who adopt the habit of regular exercise find that seemingly unrelated areas of their lives change for the better (being more productive at work, smoking less, being more patient with their kids, etc.).

Small Wins

Small wins are exactly what they sound like, and are part of how keystone habits create widespread changes. A huge body of research has shown that small wins have enormous power, an influence disproportionate to the accomplishments of the victories themselves. “Small wins are a steady application of a small advantage,” one Cornell professor wrote in 1984. “Once a small win has been accomplished, forces are set in motion that favor another small win.” Small wins fuel transformative changes by leveraging tiny advantages into patterns that convince people that bigger achievements are within reach.

Small wins are those sure steps in the right direction that separate high performers from everyone else.

TDD: Keystone Habit of Great Developers

image

The agile software movement centers around incremental and iterative steps with feedback mechanisms that allow for lots of small adjustments to bring the project to success. So, when I hear Duhigg talk about small wins, it resonates with what we’ve found in building software.

Test-Driven Development (TDD) is the most central of agile practices. It fits Duhigg’s definition of a keystone habit.

TDD and Small Wins

The demands on software developers get bigger and more more ambitious all the time. We presented with complex problems that we generally don’t know how to solve. It is easy to become overwhelmed by the magnitude and get bogged down trying to boil the ocean with code.

The discipline of TDD forces us to methodically break problems down into small chunks. Each passing test is a win and one small step closer to the system the customer needs.

The Cue is obvious: a customer needs a new feature.

The Routine is the well documented (but seldom practiced) red-green-refactor loop.

The Reward is the passing test and a thoroughly executed unit of responsibility completed.

The cycle continues, with small wins coming one after another until the feature is complete.

TDD as Keystone Habit

The TDD habit has many follow-on benefits beyond completed, tested software. Every time we write a test before we write the code, we remind ourselves of several truths:

  • If the software is worth creating, it is worth ensuring that it works.
  • Each unit of functionality must have a single responsibility and its dependencies must be loosely coupled.
  • Keeping the code clean is vital. Keeping it clean is made possible by the protection provided by a comprehensive suite of tests.
  • Writing only enough to make the test pass keeps our focus on the customer’s requirement and not a speculative future feature.

I’ve found a common idea emerging among the colleagues that I respect most: we would rather hire a developer that practices TDD and does not have experience in the primary programming language our shop uses than hire a developer with that programming language experience that does not practice TDD.

Language syntax and style is relatively easy to learn. TDD is a keystone habit of great software developers.

Getting Started with the RavenDB Index Replication Bundle

imageBeing able to push Raven data out to a SQL-based data repository for reporting will be a huge boost to RavenDB adoption. The Index Replication Bundle does a great job of solving that problem, but I found the documentation to be a little weak.

I created a minimal program that implemented it for myself and decided to post it to GitHub so someone else looking to experiment with the Index Replication Bundle can get started more smoothly. This Stack Overflow question was helpful along the way.

This sample has a simple Raven store with a collection of trivial documents. Those documents are directly reflected out to SQL Server for reporting purposes. Once you have all of the necessary plumbing worked out, making the mapping between Raven and SQL Server more sophisticated is just a matter of making the indices more complicated.

Install The Plugin

Create a “Plugins” directory under the directory where Raven.Server.exe resides. Copy Raven.Bundles.IndexReplication.dll there…

image

Configure the Connection String

Add a connection string to Raven.Server.exe.config…

<connectionStrings>
     <add
       name="Reports"
       providerName="System.Data.SqlClient"
       connectionString="Data Source=(local);Initial Catalog=Sample;Integrated Security=SSPI;"/>
</connectionStrings>

Create a database in SQL Server called “Sample”. The rest of the steps are implemented in the sample program.

Create Table

A bit of code to create the table in SQL Server…

using (SqlConnection connection = new SqlConnection(_sqlConnectionStringTextBox.Text))
{
    connection.Open();
    SqlCommand createTable = new SqlCommand(@" CREATE TABLE [dbo].[Dogs]( [Id] nvarchar(64) NULL, [Name] nchar(255) NULL, [Breed] nchar(255) NULL) ON [PRIMARY]", connection);
    createTable.ExecuteNonQuery();
    connection.Close();
}

 

 

Create Index

Next, we create a Raven index…

public class Dogs_List : AbstractIndexCreationTask<Dog>
{
    public Dogs_List()
    {
        Map = dogs => from d in dogs select new { Breed = d.Breed, Name = d.Name };
    }
}

 

 

Configure Replication

Applying the replication configuration described in the docs was not clear to me. It is simple once you see it, but not necessarily obvious…

var replicationDocument = new Raven.Bundles.IndexReplication.Data.IndexReplicationDestination
    {
        Id = "Raven/IndexReplication/Dogs/List",
        ColumnsMapping =
            {
                { "Name", "Name" },
                { "Breed", "Breed" }
            },
        ConnectionStringName = "Reports",
        PrimaryKeyColumnName = "Id",
        TableName = "Dogs"
    };

using (var store = new DocumentStore { Url = _ravenUrlTextBox.Text })
{
    store.Initialize();
    store.DatabaseCommands.EnsureDatabaseExists(RavenDatabaseName);
    using (var session = store.OpenSession(RavenDatabaseName))
    {
        session.Store(replicationDocument);
        session.SaveChanges();
    }
}

 

 

Add Items to Raven

Now, once you add items to Raven, they should appear in the Dogs table in SQL Server.

If you don’t see them, try turning debug logging on.

On Summer Internships

SummerInternship

I had my first experience with hiring a summer intern this summer. It turned out to be a great experience, but I credit this to the fact that I work with a great team and our intern was a stellar young guy. I realized that I need to have a plan for future internships. First though, I need to clarify my philosophy of internships. In other words, I have to answer the question… Why have summer internships?

Future Hires

Summer interns make great hires. What better or more thorough interview process than working with someone for three months? Finding and eventually hiring great developers is reason enough to have an internship program.

Networking

At the end of the summer, those interns will go back to school. That is where many of tomorrow’s great developers are hanging out. What better way to reach those future developers than to send students back to school having had a fantastic experience at your company?

Giving Back

A summer internship gives your developers an opportunity to have a positive influence on future developers. Even your most junior developers get to become mentors to an intern. Giving back in this way reinforces the value that software development is a profession and we are professionals. Taking the time to invest in the career of a young software developer is one way to separate professional developers from hackers.

Getting Work Done

I put this last because I think it is the least important of the list, but you just might find that that your interns do some really great work. My team was fortunate enough to have such a great young developer this summer that the work he contributed to was outstanding. Fresh perspective and ideas can be very valuable to a team.

Copy and Paste From Any Kindle

I have always wished I could copy and paste text from a Kindle book for quoting in a blog post or email. I could understand that this might not be possible from a Kindle device, but certainly it should be easy from my iPad or the Kindle cloud reader, right? Wrong!

A friend of mine wrote a great article on how to remember more of what you read on Kindle. He showed how kindle.amazon.com will display a page with all of your highlights. This gave me a great idea… simply highlight the passage of interest, allow the reader to sync, and viola… you have the highlighted text on a Web page that you can copy and paste from. This even works with Kindle devices. Nice!

Audio Book Recommendations

I make use of my commute time to listen to podcasts and audio books from audible.com. A coworker recently asked me about my favorite titles. Here are some of my favorites that would be of interest to software professionals.

Developing Software

The Lean Startup by Eric Ries: This is a fantastic book about how to develop a product in a lean/agile manner. Ries’s description of the build-test-learn loop is worth the price of the book.

 

Rework by Jason Fried and David Heinemeier Hansson: I found some interesting stuff here from the 37signals guys. My biggest complaint about this book is that the authors are way to quick to assume that all of their success is due to the choices they made. Just because they did something and had some success with it does not mean that the success was caused by the particular behavior in question.

Product Management

The Innovator’s Dilemma by Nathan Christensen: Christensen describes how disruptive technologies overthrow established technology when those incumbents believe they are least vulnerable to such a disruption.

The Innovator’s Solution by Nathan Christensen: Christensen continues where he left off. Another must-read for anyone who manages a technology product or company.

 

The Design of Everyday Things by Donald Norman: Norman wrote this back in 1988 (and you can tell), but it is an enduring classic and a product management must-read for good reason. A surprisingly fun listen.

General/Management

Good to Great by Jim Collins: This is one of my favorite books of all time in any category. Collins describes the common attributes his research team found behind successful company leaders. I found the book to be quite inspiring and have made the attributes of leadership Collins describes personal goals for my own leadership.

Leading Change by John Kotter: Kotter describes eight steps to successful organizational change. I’ve seen these principles play out in commercial and social settings—sometimes where the leaders follow these steps and create effective change, but more often where they did not and the change efforts failed.

The Goal by Eli Goldratt: I first read The Goal in the late 1980s as an Industrial Engineering student. It is a good read and helps to clarify the folly of local optimization–in manufacturing or any complex system. This has become a favorite of proponents of Lean Software Development.

There are many more audio books that have really enjoyed, but I’ll save those for another day.

Help Turn the “Jersey Shore” into “Silicone Shore”

SiliconeShoreWant to work with the latest technology on a self-directed team? Think you need to be in Silicone Valley to be part of a company setting the standard in cloud and mobile computing? Read on.

Marathon Data Systems, on the beautiful Jersey Shore, through our various vertical-focused brands, serves the people who provide the services that we all count on: HVAC, plumbing, lawn care, pest control, maid services, carpet cleaning, and more. We are in the process of building a mobility solution that will set the industry standard for field service worker and salesperson productivity.

Cross-Platform Mobile

Our new cross-platform mobile client is HTML5-powered and will initially run on iOS and Android devices. The technician or salesperson is continually operating on the latest information (no more periodic synchronization) and yet can be fully functional while out of network coverage.

SenchaPlusCoffee

The new mobile client is built in CoffeeScript on the Sencha Touch 2 platform. The combination of Sencha Touch and CoffeeScript making building off-line capable, singe-page applications actually pretty fun. Sencha takes care of the tedium of rendering just the right HTML to the screen for each device, while we focus  on building great user experiences.

Since WebSockets are not yet a reality (and pull-based applications are lame), we’re using SignalR to simulate server push from ASP.NET MVC (think Node.js scalability in ASP.NET MVC).

Message-Driven CQRS Back-End

DomainDrivenDesignOn the back-end we are are building out a scalable, event-driven CQRS system built around NServiceBus, following the principles of Domain-Driven Design (DDD).

In Domain-Driven Design, we recognize that the heart of the software is the domain-specific behavior that allows its users to solve their problems. We establish a vocabulary that spans across technical and nontechnical people. We iteratively tweak and adjust our domain model to better map to the problem space. We focus on building an effective model of our domain, while minimizing entanglement with infrastructure concerns.

nServiceBus_LogoNServiceBus (NSB) allows us to focus on the semantic meaning of our commands and events and what the system’s behavior should be. NSB handles interaction with queues, message routing, retries, and other plumbing-level concerns.

ravendb

Data persistence is achieved through the joy that is RavenDB. If you think ORMs like NHibernate are good, just wait until you have built a C# application with RavenDB.

RavenDB is a high-performance, second generation document database, native to C#. Queries are made through LINQ. Joins and transforms are handled through map/reduce functions also written in LINQ. The impedance mismatch between object-oriented code and a relational database is not merely bridged, but is eliminated.

Agile Team

Agile can mean almost anything you want it to mean, but at Marathon, it means…

Agile at Marathon

A belief in the core values of the agile manifesto:

Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan

The Scrum process, where a self-organizing team works together to plan and deliver iteratively and incrementally.

The Extreme Programming (XP) practices of test-driven development, pair-programming, continuous integration, collective code ownership.

A commitment to software craftsmanship. Being a professional means a commitment to quality work and continual improvement. Great software comes less from particular technologies that come and go, but from fundamentals like the SOLID principles and object-oriented design principles and patterns that stand the test of time.

This job may be for you if…

  • You are good, but you expect to keep getting better.
  • You can do it yourself, but you’d much rather work together with a team of dedicated developers.
  • You love cool technologies, but you care about user loving and using your software more.
  • You love coding in C#.
  • If you are not currently test-driven, you want to learn to be.
  • If you are not currently pair-programming, you are willing to give it a try.

If that sounds like you, please send your resume to jobs@marathondata.com. Come join us as we create great software to serve the people who serve the world!

JavaScript and the Seven Stages of Grief

  1. Shock and Denial: “Surely JavaScript is just for designers and for making annoying, gratuitous animations on Web pages.”
  2. Pain and Guilt: “No classes. No namespaces. I didn’t know where else to put the code except in the script tag on the page!”
  3. Anger: “You expect me to write JavaScript!?! I’m a real programmer!”
  4. Bargaining: “Don’t we have an intern that can do this?”
  5. Depression and Sorrow: “I realize JavaScript is dynamic and functional, but every time I have to write or read it, I begin to consider changing careers.”
  6. Testing and Reconstruction: “At least with Jasmine, I can write tests, but look how ugly it is. There has got to be a better way.”
  7. Acceptance: “CoffesScript!”

Review of Advanced Distributed Systems Design using SOA & DDD on Video

As my team was getting ready to embark on a significant new project built around asynchronous messaging and NServiceBus, I would have really liked to send the entire team to Udi Dahan‘s  five-day Advanced Distributed Systems Design using SOA & DDD course. Distributed, service-oriented systems have many advantages over traditional centralized solutions. However, the change in thinking that the development team must go through is daunting. However, sending the entire team offer a week would’ve been a challenge. As an alternative, I purchased the course videos and we work through them together over the course of three weeks. This is my review of that course (on video).

Why should you even care?

Before getting into the review, why would you want to build a distributed, service-oriented system? In a word, scale.

Scaling the software: Asynchronous messaging and eventual consistency allows the system to scale out to redundant, cheap hardware. Brewer’s CAP theorem shows, centralized systems that rely on two-phase commits for all updates sacrifice reliability/availability in favor of an immediate consistency that isn’t always necessary.

Scaling the development team: A well-factored service-oriented system avoids the problem of a single monolithic system that becomes increasingly difficult to enhance and maintain and requires scale up of a single development team and resists scale out to multiple teams.

Review

Advanced_Distributed_Systems_Design_-_Day_1_Session_1The production quality leaves a lot to be desired. There is an annoying amount of background noise through all of the videos. The video is shot with a single camera that pans inconsistently between Udi, the whiteboard, and the projector screen. Honestly, you have to really want the content to make it through all 40 hours. However, you will be well rewarded.

The best way to describe the course is to think of it as a five day walk through all of the factors that led Udi to develop NServiceBus. I’ve followed Udi since way before NServiceBus. I listened to the Ask Udi podcast and attempted to grasp the essence of SOA. No matter how hard I tried, I was never able to implement the tenants of SOA with the traditional Microsoft tools and WCF. It wasn’t until I built a system with NServiceBus that I started to make the mental transition. Every time something I was trying to do was difficult and I was feeling that NServiceBus was overly constraining, I eventually realized it’s not you, it’s me. When you are doing it right, NServiceBus feels natural. When you violate good design for distributed, service-oriented systems, NServiceBus nudges you back by becoming difficult, causing you to go looking for a work-around, and eventually finding a post by Udi that gently explains why what you are trying to do would eventually bite you in the rear end and what you should be doing instead. This course lays the groundwork that will help you avoid the wrong turns and false starts you are bound to make otherwise if you are moving from the familiar world of centralized, monolithic systems.

He spends a significant portion of the course methodically and deliberately dislodging ideas that most of us have held for so long that we no longer question. He also works to temper and ground some of the techniques that have caught on with a small but vocal minority of.net developers, such as CQRS and event sourcing.

I recommend this course if any of these apply to you:

  • I don’t know how to model autonomous services. Everything is related to everything else. My domain is too hard to tease apart into independent components. (Hint: this is hard at first, but Udi will take you through enough examples to get you headed in the right direction. Oh… and your domain is not too hard to do this.)
  • I love Domain-Driven Design, but I don’t know how to model the domain and application layers. I recognize that I have fallen into the anemic domain model and all of my logic is in procedural application layer functions. (Hint: There is a place for simple CRUD and the rest cannot be modeled without sagas.)
  • I like the idea of CQRS, but I don’t know how to approach it, or I tried and it didn’t work out as well as I expected. (Hint: Event sourcing is not the silver bullet of CQRS.)
  • I am using NServiceBus, but I don’t understand sagas; so, I’m not using them. (Hint: you’re doing it wrong.)

All of these were true for me at some level. Getting these issues addressed made the course extremely valuable to me.

Conclusion

The entire team feels the course was a great investment and is entering this new project with anticipation and confidence that we will avoid many mistakes that we would have otherwise made if we had not taken the virtual course. I believe we will save the money we spent on the course and the time away from coding many times over on this project and beyond. If you are building a moderately complex collaborative system, you owe it to yourself to check out this course. If you can attend a live offering, I recommend that. But if you cannot, then the videos are well worth the investment as the next best thing.

Lightweight Context/Specification BDD in C#

Behavior-Driven Development (BDD) provides all of the engineering benefits of traditional Test-Driven Development (TDD) while additionally resulting in a specification that non-developers can read and validate. At its heart, BDD transforms the tests of TDD into specifications. Those specifications are expressed in English sentences that are expressed in business value as opposed to coding or engineering terms.

The most popular structure for BDD today is called the Gherkin format and follows a Given/When/Then format, like…

Given a new bowling game
When all frames are strikes
Then the score should be 300

There are frameworks like SpecFlow to help you arrange your specifications (test) into this format. However, I find this format awkward and forced. I prefer the simpler format known as Context/Specification (aka When/Should)…

When all frames are strikes
Should have a score of 300

There are frameworks, like MSpec, that attempt to make the specifications read more like English sentences. However, I find that these frameworks get in the way as much as they help. It is also nice to be able to write readable tests with just PONU (plain old NUnit). Over time, I’ve developed a convention that I find easy to write and easy to read. I’ve also developed a tool  that turns the tests into a markdown file that can be turned into a pretty HTML report.

To show the approach at work, I present some snippets from a hypothetical order pricing system I created as a “developer test” provided by a prospective employer last summer. Here is what I was given:

Instructions: Build a system that will meet the following requirements. You may make assumptions if any requirements are ambiguous or vague but you must state the assumptions in your submission.

Overview: You will be building an order calculator that will provide tax and totals. The calculator will need to account for promotions, coupons, various tax rule, etc… You may assume that the database and data-access is already developed and may mock the data-access system. No UI elements will be built for this test.

Main Business Entities:

  • Order: A set of products purchased by a customer.
  • Product: A specific item a customer may purchase.
  • Coupon: A discount for a specific product valid for a specified date range.
  • Promotion: A business wide discount on all products valid for a specified date range.

*Not all entities are listed – you may need to create additional models to complete the system.

Business Rules:

  • Tax is calculated per state as one of the following:
    • A simple percentage of the order total.
    • A flat amount per sale.
  • Products categorized as ‘Luxury Items’ are taxed at twice the normal rate in the following states
    • FL
    • NC
    • CA
  • Tax is normally calculated after applying coupons and promotional discounts. However, in the following states, the tax must be calculated prior to applying the discount:
    • FL
    • NM
    • NV
  • In CA, military members do not pay tax.

Requirements:

Adhering to the business rules stated previously:

  • The system shall calculate the total cost of an order.
  • The system shall calculate the pre-tax cost of an order.
  • The system shall calculate the tax amount of an order.

Deliverables:

  • A .NET solution (you may choose either C# or VB) containing the source code implementing the business rules.
  • Unit tests (you may choose the unit testing framework).
  • A list of assumptions made during the implementation and a relative assessment of risk associated with those assumptions.

You can see that there are quite a few specifications here. It’s a perfect scenario for a BDD approach. Lets take a look at the specification that most states charge taxes on the discounted price, while a few states require taxes to be calculated on the original price.

Here is a specification that a standard tax state calculates taxes on the discounted price…

namespace Acme.Tests.ConcerningCoupons
{
    [TestFixture]
    public class When_coupon_is_applied_to_item_on_order_in_standard_tax_state
    {
        private Order _order;
        [TestFixtureSetUp] public void Context()
        {
            Product product = new Product(10);
            Coupon coupon = CreateCoupon.For(product).WithDiscountOf(.5m);
            _order = CreateOrder.Of(product).Apply(coupon).In(StateOf.NC);
        }

        [Test] public void Should_calculate_tax_on_discounted_price()
        {
            _order.Tax.ShouldEqual(.25m);
        }
    }
}

You can see that the test fixture class name defines the context (the when) The test method name specifies the specification (the should). The Context method sets us the context in the class name. Also note the ConcerningCoupons in the namespace. This allows us to categorize the specification.

Here is the code that specifies the prediscount tax states…

namespace Acme.Tests.ConcerningCoupons
{
    [TestFixture]
    public class When_coupon_is_applied_to_item_on_order_in_prediscount_tax_state
    {
        private Order _order;
        [TestFixtureSetUp] public void Context()
        {
            Product product = new Product(10);
            Coupon coupon = CreateCoupon.For(product).WithDiscountOf(.5m);
            _order = CreateOrder.Of(product).Apply(coupon).In(StateOf.FL);
        }

        [Test] public void Should_calculate_tax_on_full_price()
        {
            _order.Tax.ShouldEqual(.50m);
        }
    }
}

Now take a look at a section of the report generated from the tests…

orders

Anyone can now compare the generated report to the original specification to verify we hit the mark. It’s a little more work to structure your tests this way, but the benefits are worth it.

The full source for the sample and the report generator are available here.

Lunch with Uncle Bob

unclebob

Ever since I stumbled across the original C++ Report articles that have become known as the SOLID principles, I have been a disciple of Robert Martin (aka Uncle Bob). He is a leader within the agile and software craftsmanship movements. He has as good a sense of what makes good software as anyone currently writing and teaching. If he thinks it’s worth writing, then it’s worth reading.

I’m not usually a fan of video for learning. I like the random access referenceability of books and I like the on-the-go accessibility of audio recordings. I find video to be the worst of both worlds: I cannot flip to the a particular page or go at my own pace, nor can I consume it while driving or mowing the lawn. Further, there are so many good conference videos available for free that I find it difficult to justify paying for video content.

clean_codeHowever, when Uncle Bob began releasing the Clean Code video series, I thought I’d at least check them out. I found them to be so good, that I’m now having my development team watch them together over lunch hours. Uncle Bob does a great job teaching (and preaching) the techniques that lead to clean, maintainable software. As we watch the sessions together, we are creating a common baseline of understanding that we can all refer to as we work together.

I highly recommend them for any software development team that is looking to get better (and if your team is not working to get better, it is on it’s way to obsolescence).  If you have trouble justifying the cost ($12 per viewer per video) to management, have them take a look at this excellent explanation of the value of software craftsmanship and professionalism.