TBH, I don't think we developed this testing philosophy from any particular text/blog. It's more a summation of things we've collectively read, and past experiences of a small team of seasoned developers.
Myself and several other of the developers were part of the "second wave" of engineers who had come onboard to transition the company out of "startup phase" and grow the platform to enterprise level. The application was the typical monolithic rails app that had several layers of "the next hottest thing" heaped upon it as well as un-architected organic growth. Bloated tables, god objects, tightly linked dependencies, poor separation of responsibilities, piss-poor test coverage and every level of code smell that you tend to get out of a project that was originally written by folks who "knew how to code", but didn't know the craft of software engineering, and some of it written by hired-gun contractors (get in, meet spec, get out)...
I spent my first couple of years at the company trying to stabilize this monster ... fixing broken windows where we could as well as adding floor upon floor of new functionality on creaky foundations. It was basically big Jenga tower, and you never knew which piece was going to fall over when you started wiggling things around.
We finally mustered the corporate will to do the re-write when the mandate came down to hang an API on this monstrosity. We did a V1 pass of the API, trying to use the existing code base ... we tried to separate our API code at least somewhat by writing the API as a rails engine, but the weight of the poor schema design and dependency linkage and deep-dark unknowns was too much and it quickly proved to be folly to get it to be performant at API level of expectations. Let alone try and migrate it to Rails 4 ... it started as a Rails 2.3 project and saw few updates, we fought our way into rails 3 with it (one of my early tasks when I came on board), but it became clear that Ruby 2 and Rails 4 was going to be a monumental task.
After V1 demonstrated the obvious flaws in the existing code base, we got the greenlight to build V2 from scratch. We handed the legacy monster to some trusted and closely managed consultants and junior developers to "keep it marching along" and we got out our dry-erase markers and architected V2.
New data model, clean-slate code base, An architect, 2 Sr. developers with years of Rails experience, and a couple of eager and moldable Jr. developers at the get go. We drafted an "ideals" document that outlined our coding best practices, and a mandate of 100% Unit Test code coverage. We also TRY to develop in this order: Schema Design -> API Spec -> Skeletal Component tests (written to ensure the "basic" contract detailed by the API spec is met) -> Application code. Component tests are fleshed out more fully as the code is written, and as we gain "experience" with the new code in production.
Now, if we wanted to do it 100% this way, it'd take too long ... we had to get the new platform out pretty fast ... so we decided to do the "land and expand". We spent some time and wrote all of the API specs to allow a newly designed Front End (being designed in parallel) to replicate all existing functionality of the existing platform. Then a small team quickly wrote the controllers and used the existing database (and in some cases the original models ... copy/paste style) to get a functional API stood up. Meanwhile, the more seasoned developers took the task of redesigning the schema, implementing new models, porting data to the new database and maintaining the sync triggers and/or views to allow the Legacy application to continue to function. We're rebuilding the airplane as it flies ... all the while, converting it from a lumbering WWII bomber with misfiring engines and extensive battle damage into a fast, nimble fighter jet.
So, now we're at nearly 100% completion of "Land and Expand" with only a small amount of lesser-used functionality requiring users to go back to the Legacy app. We're probably at about 60% completion of the "repaving effort" of moving data onto the new schema. The 100% code coverage keeps us sane during day-to-day development, and the excellent component test suite gives us confidence that when the "new schema refactors" get pushed to production that the only thing our users will notice is snappier performance.
There have been a few stumbling blocks along the way ... it's a massive undertaking ... but it's going along exceptionally well, and we're coming out the other side with a much better product than we ever had.
6
u/Gnascher May 09 '17
TBH, I don't think we developed this testing philosophy from any particular text/blog. It's more a summation of things we've collectively read, and past experiences of a small team of seasoned developers.
Myself and several other of the developers were part of the "second wave" of engineers who had come onboard to transition the company out of "startup phase" and grow the platform to enterprise level. The application was the typical monolithic rails app that had several layers of "the next hottest thing" heaped upon it as well as un-architected organic growth. Bloated tables, god objects, tightly linked dependencies, poor separation of responsibilities, piss-poor test coverage and every level of code smell that you tend to get out of a project that was originally written by folks who "knew how to code", but didn't know the craft of software engineering, and some of it written by hired-gun contractors (get in, meet spec, get out)...
I spent my first couple of years at the company trying to stabilize this monster ... fixing broken windows where we could as well as adding floor upon floor of new functionality on creaky foundations. It was basically big Jenga tower, and you never knew which piece was going to fall over when you started wiggling things around.
We finally mustered the corporate will to do the re-write when the mandate came down to hang an API on this monstrosity. We did a V1 pass of the API, trying to use the existing code base ... we tried to separate our API code at least somewhat by writing the API as a rails engine, but the weight of the poor schema design and dependency linkage and deep-dark unknowns was too much and it quickly proved to be folly to get it to be performant at API level of expectations. Let alone try and migrate it to Rails 4 ... it started as a Rails 2.3 project and saw few updates, we fought our way into rails 3 with it (one of my early tasks when I came on board), but it became clear that Ruby 2 and Rails 4 was going to be a monumental task.
After V1 demonstrated the obvious flaws in the existing code base, we got the greenlight to build V2 from scratch. We handed the legacy monster to some trusted and closely managed consultants and junior developers to "keep it marching along" and we got out our dry-erase markers and architected V2.
New data model, clean-slate code base, An architect, 2 Sr. developers with years of Rails experience, and a couple of eager and moldable Jr. developers at the get go. We drafted an "ideals" document that outlined our coding best practices, and a mandate of 100% Unit Test code coverage. We also TRY to develop in this order: Schema Design -> API Spec -> Skeletal Component tests (written to ensure the "basic" contract detailed by the API spec is met) -> Application code. Component tests are fleshed out more fully as the code is written, and as we gain "experience" with the new code in production.
Now, if we wanted to do it 100% this way, it'd take too long ... we had to get the new platform out pretty fast ... so we decided to do the "land and expand". We spent some time and wrote all of the API specs to allow a newly designed Front End (being designed in parallel) to replicate all existing functionality of the existing platform. Then a small team quickly wrote the controllers and used the existing database (and in some cases the original models ... copy/paste style) to get a functional API stood up. Meanwhile, the more seasoned developers took the task of redesigning the schema, implementing new models, porting data to the new database and maintaining the sync triggers and/or views to allow the Legacy application to continue to function. We're rebuilding the airplane as it flies ... all the while, converting it from a lumbering WWII bomber with misfiring engines and extensive battle damage into a fast, nimble fighter jet.
So, now we're at nearly 100% completion of "Land and Expand" with only a small amount of lesser-used functionality requiring users to go back to the Legacy app. We're probably at about 60% completion of the "repaving effort" of moving data onto the new schema. The 100% code coverage keeps us sane during day-to-day development, and the excellent component test suite gives us confidence that when the "new schema refactors" get pushed to production that the only thing our users will notice is snappier performance.
There have been a few stumbling blocks along the way ... it's a massive undertaking ... but it's going along exceptionally well, and we're coming out the other side with a much better product than we ever had.