Custom Software Development | Nearshoring | Evolvice https://www.evolvice.de/en/ German software engineering. Microsoft .NET experts. Agile software development. Leading platforms software - Manage your digital transformation with us! Wed, 13 Jan 2021 12:06:55 +0000 en-CA hourly 1 https://wordpress.org/?v=5.5.3 https://www.evolvice.de/wp-content/uploads/2019/08/cropped-evoFav-32x32.png Custom Software Development | Nearshoring | Evolvice https://www.evolvice.de/en/ 32 32 163241681 Egypt’s thriving IT Industry   https://www.evolvice.de/en/egypts-thriving-it-industry/ https://www.evolvice.de/en/egypts-thriving-it-industry/#respond Thu, 07 Jan 2021 09:58:52 +0000 https://www.evolvice.de/?p=8847 When you think of Egypt, a thriving IT industry is not the first thing that comes to mind. You think about the great pyramids of Giza and a wide desert with Bedouin tents and camels. It is true that most territory of Egypt is covered...

The post Egypt’s thriving IT Industry   appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
When you think of Egypt, a thriving IT industry is not the first thing that comes to mind. You think about the great pyramids of Giza and a wide desert with Bedouin tents and camels. It is true that most territory of Egypt is covered with desert (95%), still around 100 million Egyptians make the most of the remaining 5%.[1] Egypt, as a developing country, has heavily invested in its technology  and information infrastructure since 1985 to become the platform  for  the  economy’s  development  and growth. In this article you will learn about Egypt’s IT outsourcing Industry and why you should outsource in Egypt with Evolvice.

 

Big cities like Cairo and Alexandria accumulated Smart cities and areas that become working hubs for international tech companies. The Ministry is also working on developing six technology parks in the cities of Minya, Menoufiya, Mansoura, Sohag, Qena and Aswan. These parks are aimed at supporting entrepreneurship and innovation and will consist of hardware design labs, startup incubators and training institutions and integrated systems for AI training, data science, and cybersecurity.[2] By now many major tech companies have moved their headquarters to Egypt or at least operate outsourcing destinations there. The IT Industry has become the working force of the Egyptian economy and is still constantly growing. IT exports are expected to rise up to 4,5 Million US$ until 2021.[3]

 

Evolving into one of the fastest growing offshore destinations

 

Within the last two decades the country has built up its IT industry and IT economy, it has taken steady steps to establish itself as a service provider partner for the US and EMEA markets. According to the Information Technology Industry Development Agency (ITIDA) Egypt’s global BPO market share is at almost 17% and it is now considered one of the fastest-growing offshore destinations in the world. The country has evolved into a high-quality service hub.[4] Egyptian IT sector is very robust with a growth rate higher than Egypt’s level of GDP growth, it contributes 4% to country’s GDP.

 

Why choose Egypt as an outsourcing destination

 

Low wages and many options

 

One of the reasons of this IT success and why so many companies outsource to Egypt are the low costs, especially the low labor costs, which are lower than in most outsourcing countries. For an outsourcing company, the average cost for a software developer ranges between $2.000 and $4.500 saving an outsourcing company up to 60% in labor costs compared to other destinations.

 

Nevertheless, the salaries in IT-related jobs are relatively higher than in other jobs in Egypt. Which is why many young people consider a degree in technology, science or engineering. Each year up to 50.000 students graduate in IT-related fields.[5] Most of those graduates speak English, French or German. The multilingual talent pool is serving over 20 languages across more than 100 countries. The government also invests in the development of a new generation of IT professionals by launching programs such as the Next Technology Leaders (NTL), Technology Learning Initiative and other programs it started with major Tech companies like Microsoft or Cisco.[6] Another example is the initiative “Our Future is Digital”  from the Ministry of Communication and Information Technology (MCIT) that aims at training 100,000 young Egyptians and develop their IT skills in areas of high market demand, including website design, data analysis, and digital marketing.[7]

 

Strong workforce and low taxes

 

Another reason for Egypt’s IT success is its workforce of around 240.000 IT specialists who provide outsourcing services to about 100 countries all around the world. It is also due to an increasing government support that the IT Industry has grown this much. Especially in Egypt the government has built several business parks like Smart villages, where the focus is on simplifying the working process for companies, by providing infrastructure and technical requirements.[8] This way it’s easier for companies to establish outsourcing locations. In addition to that Egypt offers corporate tax releases for companies. [9]

Not only low costs and a constantly growing talent pool speak for outsourcing in Egypt, but also the geographic proximity and small time zone difference. Egypt is only 2 hours apart from most European countries, so the work process won’t be delayed by time difference and it provides business continuity with US and Asia.

 

Start your outsourcing process with us now

 

If you’re interested in outsourcing to Egypt, Evolvice can become your perfect partner. As a service provider, we are active in Cairo since 2018, by developing custom software solutions that are tailored to our customers´ needs. Since 2019 we have been offering outstaffing services by providing IT specialists and tech talents who work remotely for our clients (distributed and remote teams). We’ve also successfully established and run Ukrainian development centers and IT hubs Kiev and Uzhhorod. Read our Blog article about the Ukrainian IT Industry if you want to find out more.

 

Contact us now if you would like to find out more about Egypt and outsourcing opportunities. Many of our customers have been working with us for years. We would be happy to tell you more!

 

[1] https://www.lwf.bayern.de/wissenstransfer/forstliche-informationsarbeit/016491/index.php

https://www.imf.org/en/Publications/WEO/weo-database/2020/October

[2] https://www.trade.gov/country-commercial-guides/egypt-information-and-communications-technology-and-digital-economy

[3] https://www.gtai.de/gtai-de/trade/branchen/branchenbericht/aegypten/ikt-dienstleistungen-in-aegypten-deutlich-im-aufwind-115458

[4] https://itida.gov.eg/English/Reports/Documents/WP-Egypts-Role-in-the-Evolution-of-Global-BPO-October-2-2020.pdf

[5] https://outsourcing-verband.org/wp-content/uploads/2020/01/Egypt_2019_Guide_WEB_FINAL_Aug28_3.pdf

[6] https://outsourcing-verband.org/wp-content/uploads/2020/01/Egypt_2019_Guide_WEB_FINAL_Aug28_3.pdf

[7] https://www.trade.gov/country-commercial-guides/egypt-information-and-communications-technology-and-digital-economy

[8] https://www.researchgate.net/publication/277056963_Beyond_BRIC_offshoring_in_non-BRIC_countries_Egypt_-_a_new_growth_market_an_LSE_Outsourcing_Unit_report_January_2009

[9] https://www.researchgate.net/publication/277056963_Beyond_BRIC_offshoring_in_non-BRIC_countries_Egypt_-_a_new_growth_market_an_LSE_Outsourcing_Unit_report_January_2009

The post Egypt’s thriving IT Industry   appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/egypts-thriving-it-industry/feed/ 0 8847
The Ukrainian IT outsourcing industry on the rise https://www.evolvice.de/en/the-ukrainian-it-outsourcing-industry-on-the-rise/ https://www.evolvice.de/en/the-ukrainian-it-outsourcing-industry-on-the-rise/#respond Tue, 08 Dec 2020 08:35:30 +0000 https://www.evolvice.de/?p=8754 Since 2012, Evolvice has being operating development centers in Ukraine. In our daily working progress, we constantly benefit from the advantages of working with Ukrainian developers. As one of the Eastern European countries Ukraine is becoming increasingly popular among those looking for IT outsourcing possibilities....

The post The Ukrainian IT outsourcing industry on the rise appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
Since 2012, Evolvice has being operating development centers in Ukraine. In our daily working progress, we constantly benefit from the advantages of working with Ukrainian developers. As one of the Eastern European countries Ukraine is becoming increasingly popular among those looking for IT outsourcing possibilities. But why is it so attractive as an outsourcing destination? In this article you’ll learn more about Ukraine’s IT industry.

 

Over the last fifteen years Ukrainian IT industry has grown by nearly 40 times, in 2018 the IT sectors’ share in country’s GDP was around 4% and is expected to be rising.[1] Due to strong tech education, today there is a large talent pool of around 185.000 IT-specialists, and the country is becoming a leading IT outsourcing destination in Europe and the fourth-largest supplier of tech talent to the world (after the US, Russia, and India). This corresponds with a constant growth in the amount of outsourcing. About 60% of the Ukrainian IT-Specialists work for IT outsourcing companies.[2]

 

What is so advantageous about outsourcing in Ukraine?

 

According to Ukraine Invest, an independent advisory body installed by the Cabinet of Ministers of Ukraine, about one hundred Fortune 500 companies have chosen Ukrainian IT services that previously outsourced in India or Israel. More than 4.000 tech companies and more than 1.500 Software Development Centers are based in Ukraine. The country emerges into a global R&D Hub since over 110 global players have located R&D facilities in Ukraine, further driving the high-tech sector.

 

The reason that so many IT companies have chosen the country as an IT outsourcing location is that the tax conditions are beneficial for the start-ups and establishing branches.  Most of these companies are located in tech areas, such as Kyiv, Lviv or Dnirpo. In Kyiv alone there are over 300 IT companies and more than 40.000 IT specialists.[3]

 

Why choose Ukraine as an outsourcing destination

 

 

Another point in favor of Ukraine is its geographical location – just one hour time difference and close proximity to middle eastern European countries, like Germany.

 

In contrast to other EU countries, there is no sign of a shortage of skilled workers. One of the main reasons is probably the high salary for IT specialists, which is considerably higher than in other jobs. The average salary for a software developer is 1.900 US Dollar, compared to the average salary in other industries of around 800 US Dollar.[4] For mainstream technologies developers with practical experience, the salary is more like 4.000 EUR from our experience. The high salary attracts the young generation. Many graduates are looking for a job in the IT sector because of the good earning potential.

 

Constant stream of new IT talents

 

A further advantage is that Ukraine with about 130.000 graduates in engineering per year is one of the top 10 countries for engineering, manufacturing, and construction graduates.[5] The majority of them are fluent in English, so over 80% of developers speak English. Many of those attend regularly tech events and are active in the tech community.

 

Your first step

 

If after reading you are convinced that it is a good idea to outsource your software development to Ukraine or integrate Ukrainian IT specialists into the existing team, you might need a partner to realize it.

 

Evolvice is as a German service provider active in Ukraine since 2012. We offer custom software solutions. Since 2019 we have been offering outstaffing services by providing IT specialists, tech talents and engineers who work remotely for our customers. We’ve successfully established and run Ukrainian development centers and IT hubs in Kiev and Uzhhorod.

 

Why should you choose Evolvice as your outsourcing partner?

 

We are the right partner for you to start outsourcing in Ukraine. We’ve been active there for a long time. We understand how to operate the business with all its specifics there. Furthermore, we have gained a lot of experience in software development, especially with distributed and remote teams. So, we know what we are talking about!

 

When you’re outsourcing you want it to be fast and efficient, secure and flexible. We provide you with everything you need like an infrastructure, business premises and efficient administration. When building up dedicated remote teams, our very well connected recruiters find the right people, and we integrate them into your in-house team.

 

If you would like to know more about Ukraine and outsourcing opportunities, please contact us. Many of our customers have been working with us for years. We would be happy to tell you more.

[1] https://ukraineinvest.gov.ua/wp-content/uploads/2020/05/IT-presentation_17.02.20-1.pdf

[2] https://hi-tech.org.ua/wp-content/uploads/2012/08/Exploring-Ukraine-IT-Outsourcing-Industry-20121.pdf

[3] https://ukraineinvest.gov.ua/wp-content/uploads/2020/05/IT-presentation_17.02.20-1.pdf

[4] https://ukraineinvest.gov.ua/wp-content/uploads/2020/05/IT-presentation_17.02.20-1.pdf

[5] https://hi-tech.org.ua/wp-content/uploads/2012/08/Exploring-Ukraine-IT-Outsourcing-Industry-20121.pdf

 

The post The Ukrainian IT outsourcing industry on the rise appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/the-ukrainian-it-outsourcing-industry-on-the-rise/feed/ 0 8754
Apple Combine Intro PART II https://www.evolvice.de/en/apple-combine-intro-part-2/ https://www.evolvice.de/en/apple-combine-intro-part-2/#respond Fri, 07 Aug 2020 11:40:48 +0000 https://www.evolvice.de/?p=7838 Let’s put together everything we learned in Part I of this article by developing an app for loading random cat images from a web service. We want to focus only on Combine features and avoid much UI work. Therefore, we will write the code in...

The post Apple Combine Intro PART II appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
Let’s put together everything we learned in Part I of this article by developing an app for loading random cat images from a web service. We want to focus only on Combine features and avoid much UI work. Therefore, we will write the code in Playground, with a very basic UI, just for demonstrating that the Combine pipe works.

 

The app will use this service for loading random cat images.

To obtain an image we should follow a couple simple steps:

  1. Request the image URL from https://api.thecatapi.com
  2. Download the image.

At the time of writing this article, the TheCatAPI is under development. So, some of the API details may change by the time you are reading this article.

You can download the full playground implementation from our repository.

 

It’s time to code!

 

First, create a Playground. Select “iOS” template and “Single View” playground.

 

 

 

Xcode will generate a playground file with a simple ViewController and some support code for rendering the view controller.

Lets make some changes to the ViewController. We need a UIImageView (for showing the loaded image) and a label (for showing status messages, like network errors, etc.).

 

class MyViewController : UIViewController {
    
    var imageView: UIImageView!
    var label: UILabel!
    
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        imageView = UIImageView()
        imageView.contentMode = .scaleAspectFit
        imageView.frame = CGRect(x: 50, y: 200, width: 200, height: 200)
        
        label = UILabel()
        label.frame = CGRect(x: 50, y: imageView.frame.maxY + 15, width: 200, height: 45)
        label.textAlignment = .center

        view.addSubview(imageView)
        view.addSubview(label)
        
        self.view = view
    }
}

 

Also we want them to be centered horizontally

 

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        imageView.center = CGPoint(x: view.bounds.midX,
                                                       y: imageView.frame.minY + imageView.frame.height / 2)
        label.center = CGPoint(x: view.bounds.midX,
                                             y: label.frame.minY + label.frame.height / 2)
        
        view.layoutIfNeeded()
    }

 

 

Now we need to build a pipe that takes care of loading an image with cats ^_^ As it was mentioned, the whole process will take 2 steps, so we need two pipes for each: one for requesting the image URL and one for loading an image from that URL. Let’s make separate functions which will return a pipe for each step: loadImageUrl and loadImageData. Later, we want to chain those two pipes, so the pipe returned by loadImageData will use the output of the pipe returned by loadImageUrl. And of course, at some place in our app we want to use the output of the pipe returned by loadImageData to show the image on UI.

One important concussion: we want our pipes to be able to emit values (image URL for the first, and Image Data from the second). Such pipes are also Publishers, because they emit values.

 

Image URL request pipe

 

Start with loadImageUrl() -> AnyPublisher<URL, MeowError>.  It will take care of requesting the image URL. The return type is a Publisher with Output as URL and Failure as MeowError. Yes, we want our custom error type, so let’s create one.

 

enum MeowError: Error {
    case networkError(error: URLError) /* like timeouts, unreachable,etc) */
    case badServerResponse(response: URLResponse) /* if the HTTP response is not 200 */
    case badServerResponseData(coderError: Error) /* if we can’t serialize the response */
}

 

Combine ads to URLSession a special publisher dataTaskPublisher which will actually make the request. DataTaskPublisher defined as

 

public struct DataTaskPublisher : Publisher {
        public typealias Output = (data: Data, response: URLResponse)
        public typealias Failure = URLError

 

So lets create a urlSession instance of URLSession and start the request with the publisher.

 

urlSession.dataTaskPublisher(for: apiUrl)
.print()

 

The print() Operator prints debug messages to the console.

apiUrl is defined as

 

let apiUrl = URL(string: "https://api.thecatapi.com/v1/images/search")!

 

dataTaskPulisher fires when the request is done and we want to check if there are no URL errors and the response status code is 200. Otherwise we want to convert URL error to MeowError, or generate a MeowError if the response status code is not 200.

 

.mapError { (urlError: URLError) -> CatRepositoryError in
     CatRepositoryError.networkError(error: urlError)
}
 .tryMap {
     if ($0.response as! HTTPURLResponse).statusCode != 200 {
           throw CatRepositoryError.badServerResponse(response: $0.response)
     }
     return $0.data
}

 

 

Please note:

  • in case a publisher emits an error, only error operators will be called, till the emitted error reaches the Subscriber (e.g. end of the pipe), or some error operator convert the error value to an Input value of the next operator/receiver. In the example above, if dataTaskPublisher emits an error, the mapError operator will be called, but tryMap will not.
  • Every Combine Operator with “try” prefix can emit an Error, with Swifts “throw” keyword.

 

Next step would be to decode the returned JSON data, and handle any JSON decoding errors by converting it to MeowError.

Here is one example of the returned JSON struct in the get URL response:

 

[{"breeds":[],"id":"acc","url":"https://cdn2.thecatapi.com/images/acc.jpg","width":500,"height":522}]

 

We define a Swift structure for representing the json list item, and decode only the interested fields, which is the “url” in our case:

 

struct MeowResponse: Codable {
    let url: String
    
    private enum CodingKeys: String, CodingKey {
        case url
    }
}

 

CodingKeys enum will tell the Coder which fields we want to decode (for more details see apple.com)

 

.decode(type: [MeowResponse].self, decoder: JSONDecoder())
.mapError { (error) -> MeowError in
                if let meowError = error as? MeowError {
                    return meowError
                }
                return MeowError.badServerResponseData(coderError: error)
            }

 

We need to be aware that mapError will be also called when some Operator above throwed or mapped an error. So, if the operator input is not a MeowError, it should be an error from the JSON Decoder.

Now we can extract the url from the serialized JSON response. Remember, we are getting a list of MeowReqponse structures from the REST API. We expect that the list will contain at least one structure, so:

 

.map { (response: [MeowResponse]) -> URL in
     URL(string:response.first!.url)!
}

 

And finally put the code snippets together into the loadImageUrl function:

 

func loadImageUrl() -> AnyPublisher<Data, MeowError> {
        if urlSession == nil {
            urlSession = URLSession(configuration: .default)
        }
        
        return urlSession!
            .dataTaskPublisher(for: apiUrl)
            .print()
            .mapError { (urlError: URLError) -> MeowError in
                MeowError.networkError(error: urlError)
            }
            .tryMap {
                if ($0.response as! HTTPURLResponse).statusCode != 200 {
                    throw MeowError.badServerResponse(response: $0.response)
                }
                return $0.data
            }
            .decode(type: [MeowResponse].self, decoder: JSONDecoder())
            .mapError { (error) -> MeowError in
                if let meowError = error as? MeowError {
                    return meowError
                }
                return MeowError.badServerResponseData(coderError: error)
            }
            .map { (response: [MeowResponse]) -> URL in
                URL(string:response.first!.url)!
            }
.eraseToAnyPublisher()
  }

 

 

To make this method work, we need to create a urlSession variable of type URLSession in the ViewController.

 

Probably you noticed the use of eraseToAnyPublisher() at the end of the pipe. This operator is needed to simplify the resulting Publisher type. To understand what we are talking about, just delete the eraseToAnyPublisher() operator and study the error message.

 

Finally, the pipe for requesting the image URL is ready!

 

 

Load image data pipe

 

The load image data pipe is similar to the request image URL pipe, except that we are not serializing the response data.

 

func loadImageData(url: URL) -> AnyPublisher<Data, MeowError> {
        urlSession!
            .dataTaskPublisher(for: url)
            .mapError { (urlError: URLError) -> MeowError in
                return MeowError.networkError(error: urlError)
            }
            .tryMap { comp -> Data in
                if (comp.response as! HTTPURLResponse).statusCode != 200 {
                    throw MeowError.badServerResponse(response: comp.response)
                }
                return comp.data
            }
            .mapError{
                $0 as! MeowError
            }
            .eraseToAnyPublisher()
    }

 

One point which needs to be discussed is

 

.mapError{
     $0 as! MeowError
}

 

Why do we need this operator at the end? Didn’t we map any possible error types to MeowError? Yes we did, but…  Even we emit a MeowError In the tryMap operator, the tryMap.Failure defined as Error. So, the next Operator/Receiver in the chain will automatically expect a general Error Failure type in its input.

 

.tryMap { comp -> Data in
     if (comp.response as! HTTPURLResponse).statusCode != 200 {
          throw MeowError.badServerResponse(response: comp.response)
….

 

But we are 100% sure that after tryMap operator we will deal with MeowError (because we already converted any possible errors to MeowError and in tryMap Operator we also emit  MeowError). So, it is safe to downcast the error type to MeowError in the mapError Operator.

 

 

Connect pipes

 

Now we want to connect the two pipes together, to make One complex pipe which is able to emit values, so, it is a Publisher in fact. In Combine, we can connect two publishers together by the flatMap Operator.

Let’s connect loadImageData to loadImageUrl

 

func loadAll() -> AnyPublisher<Data, MeowError> {
        loadImageUrl().flatMap {
            self.loadImageData(url: $0)
        }.eraseToAnyPublisher()
    }

 

To complete our example, add the following code snippet to the end of the viewDidLoad() method (which we would not do in production, but remember, this is just a study example).

 

cancellable = loadAll()
            .receive(on: RunLoop.main)
            .sink(receiveCompletion: { (completion: Subscribers.Completion) in
                switch completion {
                case .finished:
                    self.label.text = "Success"
                case .failure(let error):
                    switch error {
                    case .badServerResponse:
                        self.label.text = "Bad response"
                    case .badServerResponseData:
                        self.label.text = "Bad response data"
                    case .networkError:
                        self.label.text = "Network error"
                    }
                }
            
            }) { (imageData) in
                self.imageView?.image = UIImage(data: imageData)
            }

 

Cancelable declared in ViewController as

 

var cancelable: AnyCancellable!

 

We need to store cancelable for 2 reasons:

  • To be able to cancel the pipe.
  • To retain it. Otherwise the pipe will be destroyed as soon as the viewDidLoad() method is finished.

 

You should have already noticed that we used a new operator, receive(on:). In Combine, the next operator called in the caller’s thread. And because URLSessions dataTaskPublisher emit event values on a non main thread, all the next operators are called in that thread. But at the end of the pipe we want to modify some UI components, which should happen on main thread only. Therefore we tell Combine to continue the pipe execution on a specific thread by receive(on:) Operator.

 

Execute the playground and wait a few seconds. We are expecting to see the loaded image. Or an error message in case of network issues, bad server response status code or wrong JSON format in the response.

 

You can play with the code, for example, create a load button (to start the pipe manually) and a cancel button (just to be sure we are able to cancel the pipe, and with the cancelled pipe – any network request).

 

 

Conclusion

 

Using Combine, we’ve managed to develop a pipe which interacts with a rest API in few steps. We learned some new operators: eraseToAnyPublisher and receive(on:). We learned that a pipe which emits values is actually a Publisher. Also we clarified that the operators execution order in the pipe in case an error value emitted.

As you see we wrote a nice, declarative and extremely small code for such an API interaction. And  thanks to Combine, it also has a comprehensive, and still simple error handling.

As a bonus, for using Combine, you get all the cancel functionality for free! (just imagine how much more code it would take to write such an app without reactive programming).

 

 

The post Apple Combine Intro PART II appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/apple-combine-intro-part-2/feed/ 0 7838
Apple Combine Basics PART I https://www.evolvice.de/en/apple-combine-basics-part-1/ https://www.evolvice.de/en/apple-combine-basics-part-1/#respond Thu, 30 Jul 2020 08:21:19 +0000 https://www.evolvice.de/?p=7780 Reactive programming is not something new but recently it gained much higher interest. The reason is simple: traditional imperative programming has some limitations when it comes to coping with the demands of today, where applications need to have high availability and provide low response times...

The post Apple Combine Basics PART I appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
Reactive programming is not something new but recently it gained much higher interest. The reason is simple: traditional imperative programming has some limitations when it comes to coping with the demands of today, where applications need to have high availability and provide low response times also during high load, that’s why we decided to take a look at Combine, apples new Reactive Programming framework.

And if you feel like this is the exact solution for your problems, contact us at Evolvice  and we will gladly explore the possibilities together with you.

 

Excited? Let’s dive deep into the world of reactive programming!

 

 

Imperative vs. Reactive programming

 

Reactive programming is a declarative programming paradigm. It is based on data streams and change propagation. In other words, you have some source of events (a stream), you observe that source and react when it emits a value or event. The source of events (e.g. event stream) can be any variable that change over time, any external events, like mouse clicks events, I/O events, http requests, etc.

Let’s take a look at an example:

a = b + c

In imperative programming (like Object Oriented programming) a depend on b and c in the moment of calculation of the expression. So, the machine will calculate b + c, assign the result to a. If afterwords b or c change, a will be not affected anymore. In reactive programming a depend on b and c until you break that dependency intentionally. It means, whenever b or c changes, a will react and change also (in our example it means a will be recalculated).

 

A bit of history…

 

The first ideas of reactive programming appeared in 1970s, but the first big splash was made with Microsoft’s introduction of Reactive Extension (Rx) for .NET. Rx tried to solve the problem of asynchronous data access from event based UI. The standard iterator pattern, where the client asks for data, is not applicable for asynchronous data access. To solve this problem, Rx changed the control flow using Observer pattern. So, the client, instead of requesting the data following the Iterator pattern simply waits for the data to be sent to the client, using the Observer pattern.

After Rx was introduced and successfully used for some domain problems solving as well as for binding the ViewModel to UI, reactive frameworks appeared for other programming language. For Objective-C there are some frameworks, like Bond and ReaciveCocoa, ReactiveObjc. For Swift probably SwiftRx is the leader of all reactive frameworks.

In 2019 Apple presented its own reactive framework – Combine. “Combine is a unified declarative framework for processing values over time.” – Apple sais. Even though they don’t define Combine as an RX framework, it still is.

 

 

Introduction to Combine

 

The heart of the Combine framework is the Observer pattern. Let’s recall how it works. The subject (also called Observable) can change its state and notify Observers about the change.

The Observable analog in Combine is called the Publisher, and the Observer – Subscriber. So, the subscriber subscribes to the Publisher. The publisher can emit some events/values, and the receiver receives those events/values and react to it.

Publishers are represented by a generic protocol Publisher

 

public protocol Publisher {
    associatedtype Output
    associatedtype Failure : Error

    func receive(subscriber: S) where S : Subscriber, Self.Failure == S.Failure, Self.Output == S.Input
}

 

 

A subscriber is represented by a generic protocol Subscriber

 

public protocol Subscriber : CustomCombineIdentifierConvertible {
   associatedtype Input
   associatedtype Failure : Error

   func receive(subscription: Subscription)
   func receive(_ input: Self.Input) -> Subscribers.Demand
   func receive(completion: Subscribers.Completion)
}

 

A publisher has only an Output (because it can only emit values), and a subscriber has only an Input (it can just receive events / values). Publisher also can emit a Failure value, as well as the subscriber, can receive it and react to it. We will talk about it a little bit more in the error handling section.

In order to connect a subscriber to a publisher they should have the same Input and Output interface, e.g. Publisher.Output and Publisher.Failure should be the same type as Subscriber.Input and Subscriber.Failure. This is described in the publisher protocol. There are some publishers and subscribers already implemented in Combine (you can also implement your own using the two protocols).

Let’s play with them in the Playground (do not forget to import Combine). We will make a very simple system made of a subscriber connected to a publisher. Call such a system “pipeline”.

 

import Cocoa
import Combine

let publisher = PassthroughSubject<Int, Never>()
publisher.sink { (value: Int) in
    print("received value \(value)")
}

publisher.send(1)
publisher.send(5)

 

The output is:

received value 1

received value 5

 

PassthroughtSubject is a special kind of publishers, called the Subject.

PassthroughSubject<Int, Never>  means we created a publisher which can publish Int data, and no error (with the Never keyword).

sink – is one of the already implemented subscribers.

 

But what if we also want to handle errors? Lets first define some error enum

 

enum PublisherError: String, Error
 {
    case error1 = "error type 1"
    case error2 = "error type 2"
}

 

and change our publisher and subscriber.

 

let publisher = PassthroughSubject<Int, PublisherError>()
publisher.sink(receiveCompletion: { (completion: Subscribers.Completion) in
    
    switch completion {
    case .failure(let error):
        print("error: \(error)")
    case .finished:
        print("Finished")
    }
    
}, receiveValue: { (value: Int) -> Void in
    print("received value \(value)")
})

 

 

Because now the publisher is able to send errors, we need to define the receiveCompletion closure in the receiver. The completion argument is just an enum with 2 possible values: failure and success

 

When we run the playground, the output is

received value 1
received value 5
error: error2

 

 

Closing a Pipeline

 

As we see from the example above, after we created a pipeline we are able to send multiply events over it. So, the pipeline is not closed/destroyed after the first event arrived.

We can close the pipeline by sending Completion.finished or Completion.failure from the publisher. Study the next examples:

 

publisher.send(1)
publisher.send(5)
publisher.send(completion: .finished)
publisher.send(8)

 

Output

received value 1
received value 5
Finished

or with .failure

publisher.send(1)
publisher.send(5)
publisher.send(completion: .failure(.error1))
publisher.send(8)

 

Output

received value 1
received value 5
error: error1

After we send a completion, the pipe is closed, so, publisher.send(8) has no effect. Even if we try to subscribe to the closed publisher, it will not work again.

But what if we just want to cancel a subscription, and probably subscribe the publisher again some time later?

When we subscribe a publisher with sink, we get an instance of AnyCancellable which has a cancel() method for canceling a subscription.

 

let cancel = publisher.sink(receiveCompletion: { (completion: Subscribers.Completion) in
    
    switch completion {
    case .failure(let error):
        print("error: \(error)")
    case .finished:
        print("Finished")
    }
    
}, receiveValue: { (value: Int) -> Void in
    print("received value \(value)")
})

publisher.send(1)
publisher.send(5)
cancel.cancel()
publisher.send(8)

publisher.sink(receiveCompletion: {
    print($0)
}) {
    print("value \($0)")
}

publisher.send(10)

 

Output

received value 1
received value 5
value 10

 

 

 

Operators

 

Sometimes the emitted value from the Publisher needs to be processed before it gets to the receiver. We can accomplish it by Operators. An operator is a Publisher (because it has an Output) and a Subscriber (because it has an Input).

Let’s convert the Int value from our previous example to String before it gets to the receiver

 

let publisher = PassthroughSubject<Int, PublisherError>()
publisher
    .map{ (inputValue: Int) -> String in
        "\(inputValue)"
    }
    .sink(receiveCompletion: { (completion: Subscribers.Completion) in
    
    switch completion {
    case .failure(let error):
        print("error: \(error)")
    case .finished:
        print("Finished")
    }
    
}, receiveValue: { (value: String) -> Void in
    print("received value \(value)")
})

publisher.send(1)
publisher.send(5)

 

Output

received value 1
received value 5

 

We can chain different operators. For example, let’s filter out odd numbers with filter Operator

 

let publisher = PassthroughSubject<Int, PublisherError>()
publisher
    .filter { (input: Int) -> Bool in
        input % 2 == 0
    }
    .map { (inputValue: Int) -> String in
        "\(inputValue)"
    }
    .sink(receiveCompletion: { (completion: Subscribers.Completion) in
    
    switch completion {
    case .failure(let error):
        print("error: \(error)")
    case .finished:
        print("Finished")
    }
    
}, receiveValue: { (value: String) -> Void in
    print("received value \(value)")
})

publisher.send(1)
publisher.send(5)
publisher.send(6)

 

Output

received value 6

 

Combine has many operators, which can be categorized into:

  • map
  • filtering
  • reducing
  • mathematical operations on elements
  • applying matching criteria to elements
  • applying sequence operations to elements
  • selecting specific elements
  • combining elements from multiply publishers
  • handling errors
  • adapting publisher types
  • controlling timing
  • encoding and decoding
  • debugging

 

For more, refer to the official documentation

 

 

Error handling

 

Apple engineers made error handling in Combine explicit and type-safe (unlike other third party RX frameworks).

If an error can never happen, we can use Never to make it explicit (as we did in our first example).

 

 

Convert error types

 

Sometimes we need to connect a subscriber to a publisher, but they have different error types. For example, we have a search engine, which provides a publisher. Search engine publisher defines its own error type SearchError.  Every time the search engine gets a search request, it proceeds with it and sends the result via a publisher. Lets say, our UI code is the subscriber, which will show the search results somewhere in the window. It defines its own error type ServiceError.

 


import Cocoa
import Combine

enum SearchError: Error {
    case notFound
    case timeExpired
}

enum ServiceError: Error {
    case emptyResponse
    case buisy
}

let searchEnginePublisher = PassthroughSubject<Int, SearchError>()
let subscriber = Subscribers.Sink<Int, ServiceError>(receiveCompletion: { _ in }) { print("\($0)") }

searchEnginePublisher.subscribe(subscriber)

 

If we run this code, we will get an error:

“Instance method ‘subscribe’ requires the types ‘SearchError’ and ‘ServiceError’ be equivalent”. To fix this, we need convert SearchError to ServiceError. In Combine we can do so with mapError operator, just like we used earlier the map operator to convert the publishers output type to the subscribers input type.

 

searchEnginePublisher
    .mapError { (error: SearchError) -> ServiceError in
        switch error {
        case .notFound:
            return .emptyResponse
        case .timeExpired:
            return .buisy
        }
    }
    .receive(subscriber: subscriber)

 

Lets try it:

 

searchEnginePublisher.send("hello")
searchEnginePublisher.send(completion: .failure(.notFound))
searchEnginePublisher.send("world")

 

Output

hello

 

As we see, after we sent the error, the pipe terminated. So, the string “word” is not sent to the receiver.

 

 

replaceError()

 

In our search engine example, the error handling strategy could be to use some placeholder value instead of propagating the error. So, we need to replace an error with a placeholder value. In our case we could show some “empty result” string. Combine provides us with replaceError(with: T) operator.

 

searchEnginePublisher
    .replaceError(with: "empty result")
    .receive(subscriber: subscriber)

searchEnginePublisher.send("hello")
searchEnginePublisher.send(completion: .failure(.notFound))
searchEnginePublisher.send("world")

 

Output

hello
empty result

 

Please note the next:

  • we replace ANY error value with a placeholder value (e.g. we can’t distinguish between different error types).
  • because any error values will be replaced, it means that the subscriber will never receive any error. So, we changed its interface from Subscribers.Sink<String, ServiceError> to Subscribers.Sink<String, Never>.
  • Please note, an error was emitted from the Publisher, so, the pipe will be closed.

 

 

Catch

 

In case we want to have some individual “placeholder” values for each error, we can use the Catch(error: Error) operator.

 

searchEnginePublisher
    .catch{ (error: SearchError) -> Just in
        switch error {
        case .notFound:
            return Just("Not found")
        case .timeExpired:
            return Just("Engine is busy. Try again")
        }
     }
    .receive(subscriber: subscriber)

searchEnginePublisher.send("hello")
searchEnginePublisher.send(completion: .failure(.timeExpired))
searchEnginePublisher.send("world")

 

Output

hello
Engine is busy. Try again

 

Please note the next:

  • Catch has an error argument, so we can replace a specific error value with some “placeholder” object (unlike replaceError, which doesn’t take any error argument).
  • because error values will be replaced, the receiver should have input error type Never.
  • the error was emitted from the Publisher, so, the pipe will be closed.

 

 

Producing errors

 

Sometimes it is needed to produce an error from an Operator in the pipeline. Here we go back to the initial version of our search engine example (without error replacing). If the publisher emits an empty string, it means no search result. So, instead of the empty string we expect the SearchError.notFound error. We can fix this by throwing the error in such a case. There are some operators with the “try” prefix in their names. All of those can produce an error by throwing it. We will use the tryMap operator.

 

searchEnginePublisher
    .tryMap { (value: String) throws -> String in
        guard !value.isEmpty else {
            throw SearchError.notFound
        }
        return value
    }
    .mapError { (error) -> SearchError in
        return error as! SearchError
    }
    .catch{ (error: SearchError) -> Just in
        switch error {
        case .notFound:
            return Just("Not found")
        case .timeExpired:
            return Just("Engine is busy. Try again")
        }
     }
    .receive(subscriber: subscriber)

searchEnginePublisher.send("hello")
searchEnginePublisher.send("")
searchEnginePublisher.send("world")

 

Output

hello
Not found

 

In the output we see only the first word “hello” and “Not found” – because we sent an empty string, which was converted to an error in the tryMap operator, and then converted to a “placeholder” string in cath operator.

Please note:

  • tryMap can throw only Error generic type. But our next operator in the pipe expect a SearchError.
  • We convert the Error (produced by the tryMap operator) to SearchError with the mapError operator.
  • When we throw an error – the pipe is terminated (despite the fact that the error was send by an Operator, not a Publisher).

 

 

Conclusion:

 

Congratulations! If you are still reading this article you’ve studied the basics of Combine, and now you are ready to write your amazing apps using this nice technology. We’ve covered all the components which compose the Combine framework: publishers, receivers, operators. And we’ve studied some error handling and the basic life cycle of the pipe. Also, we’ve seen how easy it is to set up a pipe.

In the next part, we will use our knowledge to create a complex pipe for interacting with a REST API. The interaction will be done in a few steps. Also, we will implement some error handling strategy.

Are you excited? Go to Apple Combine Intro Part II.

The post Apple Combine Basics PART I appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/apple-combine-basics-part-1/feed/ 0 7780
Evolvice Adapts to Meet Small Businesses Needs https://www.evolvice.de/en/evolvice-adapts-to-meet-small-businesses-needs/ https://www.evolvice.de/en/evolvice-adapts-to-meet-small-businesses-needs/#respond Wed, 17 Jun 2020 12:56:44 +0000 https://www.evolvice.de/?p=7444 Small and medium-sized businesses in Germany are getting creative during the COVID-19 pandemic to generate revenue. All anyone can do right now is make the best of the situation and offer support to one another.   Since 2012, we have been servicing companies’ information technology...

The post Evolvice Adapts to Meet Small Businesses Needs appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
Small and medium-sized businesses in Germany are getting creative during the COVID-19 pandemic to generate revenue. All anyone can do right now is make the best of the situation and offer support to one another.

 

Since 2012, we have been servicing companies’ information technology requirements. Adapting, we continue to offer our services and spread our support to small businesses.

 

Evolvice provides custom software development, mobile app development, QA services and application support, as well as staff augmentation services. We’ve completed over 350 projects for satisfied customers all over the world.

 

 

We form long-term partnerships with our customers rather than just complete a project and move on because the success of your business is just as important to us. Working in a family atmosphere, we hope to extend that to our clients.

 

While small businesses make up about 35% of our clientele, it is important to us that we extend our support to our clients throughout these uncertain times. A great way for customers to show support for their favorite business is to leave a glowing review on their platform of choice.

 

We use Clutch, a B2B ratings and reviews platform, to collect feedback from our clients to make their experiences even better. One of our clients just left us this awesome 5-star review on our profile!

 

“They’re a young, intelligent team that works efficiently.” – Managing Director, Ex-Trade

 

 

Evolvice received a positive review from ExTrade on clutch.

 

 

For Ex-Trade, we built a new IT system. Along the way, we also developed a mobile application for iOS and Android platforms.

 

Clutch also connects buyers and vendors so businesses can find the right vendor that best suits their needs. You can find a list of the top Stuttgart custom software development companies along with reviews from real customers to help make your search a bit easier.

 

Evolvice brings German quality and values into software development abroad. Learn how your business can benefit from enhanced software and the right people to accelerate your work progress.

 

Want to start your digital evolution with us? Our experts are looking forward to contact you.

The post Evolvice Adapts to Meet Small Businesses Needs appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/evolvice-adapts-to-meet-small-businesses-needs/feed/ 0 7444
The price of loyalty: things Evolvice GmbH has copied from Apple https://www.evolvice.de/en/the-price-of-loyalty-things-evolvice-gmbh-has-copied-from-apple/ https://www.evolvice.de/en/the-price-of-loyalty-things-evolvice-gmbh-has-copied-from-apple/#respond Mon, 02 Mar 2020 12:16:32 +0000 https://www.evolvice.de/?p=7081 There is a myth that acquiring best professionals, skill-wise, will create the best results for the project. What many forget is that projects are run by people. IT specialist work with technology which makes interesting deformation in psyche making them more likely to acquire semi-machine-like...

The post The price of loyalty: things Evolvice GmbH has copied from Apple appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
There is a myth that acquiring best professionals, skill-wise, will create the best results for the project. What many forget is that projects are run by people. IT specialist work with technology which makes interesting deformation in psyche making them more likely to acquire semi-machine-like traits on the surface. However, on a deeper level these traits are much more in connection with miscommunication. One can have the best skill set, efforts and work ethic and still fail the project miserably.

 

Basic look into human psyche gives us the understanding that while money provides us with basic stability in life, it doesn’t give us much else. People have needs and good company provides more than just stable money flow into one’s pocket.

 

To understand how to motivated your company employees are one needs to understand what needs people can have. Tony Robbins, being probably the best motivational speaker in the world, divided human needs into 6 categories:

 

1) Certainty

2) Uncertainty/Variety

3) Significance

4) Love/Connection

5) Growth

6) Contribution

 

Looking at these, you think how does that help me in any form or manner? Be patient with me, cuz this can transform your company just as Tony Robbins transforms people’s lives.

 

The difference between company that succeeds and the one that fails is in the way it treats people. Happy loyal people work better. The company that fulfills all the needs of a person is a treasure. So how does one do that?

 

  1. People need to be certain about a bunch of stuff. Money being one of them. They also need to be certain that they are not going to be fired or cut tomorrow.

 

  1. Routine kills everything. While any job has a fair share of routine, if it is all you can give, nobody is going to be excited about Monday mornings.  Do you have new exciting technologies and projects for the team? Is your company exploring new ideas and markets?

 

  1. Nobody likes to feel like a piece of machine, just another tool replaced at any moment. Can you make people feel like their effort, skills and amount of overtime on the project matters for the company and there is a measurable value to it?

 

  1. What does your HR do? Do they mediate your employees’ conflicts? Do your Leads work as leaders or as bosses?

 

  1. Can your company in all honesty say that its employees become better, as a result of working in the company? Do they learn new stuff and improve as professionals or do they need some time off getting back into college just to repair the damage your company has done?

 

  1. People need to give back. That is never an option, it is a need. Can your employees make real changes to the company that will improve its policies and work?

 

It all starts with the leads and project managers. What makes a good leader and manager is not pure skill but the standards they have. To be a leader is to have the highest standards in the group. Boss manages and leader inspires. There is one reason Apple succeeds – they all together decided to have higher standards than anybody else. They created a level of quality nobody had before. That is why they had product which blew up.

 

 

How does one feel when making something truly special – they feel special. Apple decided to go with something new, so they had plenty of variety in what they did. Apple has offices nobody wants to leave and spends a ton on HR department and retention specialist. What I am saying is that at Apple people feel like they have stable interesting work where they do something that matters, where they matter and can grow and give back. When a company fulfills all the 6 needs employees become raging fans of the company. Raging fan will protect, shield and work for the sake of the company’s success.

 

How does Evolvice strive to recreate this Raging Fan team – by creating our own standards higher than what our customer expects. We suggest a new technology and insist on it being the best for the project.

 

There is a reason for it, because we are looking for your project to succeed and not fail on some old junk everybody knows is outdated and plain boring. We have learning sessions with our employees to improve their growth rate and connection to the project.

 

Evolvice GmbH lets the employees assume more responsibilities and trust them to deliver the standard that exceed our expectations. We are not ashamed to copy and learn from other companies.

 

What we want to maintain is company for which every coming project is something to have the highest passion for. So please, do contact us only when you value success of the project over stereotypes about what IT team is supposed to be. Evolvice knows all of that!

 

The post The price of loyalty: things Evolvice GmbH has copied from Apple appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/the-price-of-loyalty-things-evolvice-gmbh-has-copied-from-apple/feed/ 0 7081
Why Egypt becomes IT hub for the software https://www.evolvice.de/en/why-egypt-becomes-it-hub-for-the-software/ https://www.evolvice.de/en/why-egypt-becomes-it-hub-for-the-software/#respond Sat, 01 Feb 2020 15:07:13 +0000 https://www.evolvice.de/?p=7027 Egypt has an excellent opportunity to establish a relatively small but effective software industry. The potential is already there and growing but could be extended way beyond the current levels. The efforts and support enabled by the government, industry, financial institutions and the educational system...

The post Why Egypt becomes IT hub for the software appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
Egypt has an excellent opportunity to establish a relatively small but effective software industry. The potential is already there and growing but could be extended way beyond the current levels. The efforts and support enabled by the government, industry, financial institutions and the educational system will ultimately determine the level of development and success of the industry making it an effective contributor to Egypt’s economic development.

 

The software industry in Egypt is still in its first stage.

However, it is diverse and heterogeneous in nature with the presence of local vendors and multinationals about 28% of its population, who are enrolled in education programs (schools and universities education) and 19 million represent its workforce (www.idsc.gov.eg).

Pro-business government policies and regulations have helped grow the software industry and have encouraged a number of multinationals to invest in Egypt including, but not limited to, the likes of IBM, Intel, Valeo and Oracle that have invested substantially in setting-up facilities and grew their operations.

Since 2005, there has been various efforts and steps taken to position Egypt as an alternative location for investment in intellectual capital as well as offering software development, business process outsourcing and call center services. This has led Egypt to invest in accelerating its high-tech infrastructure by developing technology parks with over 130 multinational company in the areas of ICT, software development, outsourcing and call centers.

 

Following analysis describes Strengths & Opportunities points of Software industry in Egypt:

 

Strengths:

  • Growing generation of well-educated fresh graduates interested in the fields of information technology.
  • Accumulated, though limited, experience, technical skills and capacities in the industry.
    Young, educated and competitive workforce with required knowledge.
  • Low and competitive labor costs.
  • Other languages are also learnt, such as French and Spanish.
  • Same time zone advantage with Europe and possibility of a second shift for the United States.
  • Geographically well located for most African and European cities and some Asian countries.
  • No shortage of entrepreneurs willing to take risks in the development of their businesses.
  • Encouragement of the government by facilitating procedures and logistics related to the software industry.

 

Opportunities:

  • Creation of software business incubators such as the smart villages’ model.
  • More proactive role played by educational institutions and training centers.
  • Internships and scholarships from software vendors both local and multinationals.
  • Promotional role played by software associations to activate the role of software development companies.
  • Government support role needs to be more at the macro and micro levels.
  • Changes in tax treatment, reduction on telephone tariffs and the introduction of new IP laws.

 

Since 2005, there has been various efforts and steps taken to position Egypt as an alternative location for investment in intellectual capital as well as offering software development, business process outsourcing and call center services. This has led Egypt to invest in accelerating its high-tech infrastructure by developing technology parks with over 130 multinational company in the areas of ICT, software development, outsourcing and call centers.

The post Why Egypt becomes IT hub for the software appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/why-egypt-becomes-it-hub-for-the-software/feed/ 0 7027
When automation tests become expensive? https://www.evolvice.de/en/when-automation-tests-become-expensive/ https://www.evolvice.de/en/when-automation-tests-become-expensive/#respond Fri, 24 Jan 2020 12:28:37 +0000 https://www.evolvice.de/?p=7004 If your team is looking for effective ways to optimize testing processes – test automation is an option for you. In the right hands, it can significantly increase product quality, speed up software testing cycles, and therefore improve the efficiency of QA teams. However, despite...

The post When automation tests become expensive? appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
If your team is looking for effective ways to optimize testing processes – test automation is an option for you. In the right hands, it can significantly increase product quality, speed up software testing cycles, and therefore improve the efficiency of QA teams. However, despite everything, test automation is not a magical solution to achieve cheap, lightning-fast, effortless QA results.

 

When the expected benefits and ROI are not delivered test automation always becomes expensive. The main challenge is that 99.9% of automated testing tools require written code. For that a great amount of time and effort must be invested, that’s why the expected benefits must be equally great.

 

Many companies historically relied on manual testing. Automation was expensive due to the following reasons:

 

1.  Technical expertise is required to continuously manage tests and the environments in which they run. Test automation experts are highly sought-after and often demand competitive salaries. As a result, hiring out a team to continuously keep automated tests aligned with the code can be a significant expense.

 

 

2. Time is money. To write scripts, tests, and make them work requires time. We’re talking time and effort here. And time means money. Writing test scripts is slow, painstaking, and hard. At every stage, you have to debug and test your test script. Then you have to update the script for each browser and platform you need to test it on. Finally, even a simple test script takes most skilled engineers several days to get right.

 

3. Automated tests are indirectly influenced by feature application changes, which may lead to a test break. When evaluating the cost of incorporating automation into your QA strategy, consider how frequently automated tests will need updating to stay useful. Every time you make a change to your UI tests tend to break. Even minor changes will affect the selectors that the test script interacts with. The upshot is that most test engineers now spend half their time performing routine test maintenance.

 

4. Hidden Cost of Automation is Delayed Release Timelines. This is especially problematic if you have developers maintaining your automation test suite. A bug can cause automated tests to fail, but also it fails because the test itself is broken.  If your automated tests fail while your team is in the middle of launching a release, you’re not likely to continue with the release until you identify the source of the failure, because there might be problems with software quality.

 

Evolvice GmbH offers you free project analyze and professional consulting to confirm if your project requires automation or not.

The post When automation tests become expensive? appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/when-automation-tests-become-expensive/feed/ 0 7004
Mobile version vs PWA vs Apps: a short guide to test early rather than late https://www.evolvice.de/en/mobile-version-pwa-apps-short-guide-testing/ https://www.evolvice.de/en/mobile-version-pwa-apps-short-guide-testing/#respond Wed, 22 Jan 2020 07:38:41 +0000 https://www.evolvice.de/?p=6994 We live in the new era. The era were mobile devices have flooded our lives, thoughts and markets. In 2019, mobile population accounted to 4 billion unique users. If you ask anyone that is just a huge slice of cliental to miss.  Around 48% of...

The post Mobile version vs PWA vs Apps: a short guide to test early rather than late appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
We live in the new era. The era were mobile devices have flooded our lives, thoughts and markets. In 2019, mobile population accounted to 4 billion unique users. If you ask anyone that is just a huge slice of cliental to miss.  Around 48% of the view of all web pages in the world were conducted using mobile devices. As time passes, the things you can do with your iPhone and iPad only grow.

 

One should divide mobile testing into three categories: mobile version of website, mobile application and Progressive Web Application (PWA) testing. Each of these have their own specific details and uses.  Let us get into crack of how to use it for your needs.

 

Let us say, you already have a full functioning website, which does what it is supposed to do, and does it right. Then in majority of cases, you do not need to create a completely new application for your users. However, you cannot adapt it to mobile devices cause the viewport difference and user experience on desktop and iPhone is different.

 

If you have a website and the functionality is too complex and does not translate to the mobile version at all. Then you need to rethink the whole functionality and it might be good idea to switch to PWA or just plain old application one can download in apple store. The difference in choosing one or the other is in the amount of changes required. If you want to use majority of the functionality and old code of the website (if it can be used) then you had better stick with PWA. To put it simply PWA is a fancy way of saying “the website turned into application”. It has certain features that apps have like standalone functionality. User can download it as an app. It also works as a website in user accessing it via browser.

 

Upon reading this, you might think, that PWA is better solution for any problem. However, while I am slightly biased in me liking it, there are cons to this approach. For example, PWA is not flexible when it comes to using the devices hardware components and this is where apps come in.

 

Now that we know what we have basic understanding of what is what and decided what we need to develop. How do we test it?

 

The main difference with mobile versions and PWA is that testing will not be from empty slate. The code and functionality will be based on the old website. Which will require from QA expertise and ability to analyze documentation that already exists, as well as exploratory testing. Exploratory testing will be the main research tool. Many projects try to involve QA in the development stage only, which is a huge pitfall.  QA has experience and expertise over multiple projects adapted for mobiles devices and can assess issues before they are created which is just plain cheaper than correcting them when developer were already involved.  While project manager can do similar things, the expertise of the two differs and QA should work as a tool to review the documentation created by PM. There is a reason why Quality Assurance engineer are called that, the sole idea of the position is to review and assess each details and prevent as much issues as it is even possible for a human being.

 

The tools use to work with PWA, apps and mobile versions will differ as well. One cannot really expect to treat all these the same way.

 

PWA and mobile version being similar in certain aspects will have more common ground. However, there are certain tools that help to solve this issue like Appium, which can be applied for certain projects to save on costs. However, using iOS SDK, Anroid SDK for apps is a more sound decision due to better flexibility test wise and a wider range of back end test one can perform, PWA being closer to web than that of an app is fine with using Appium as a tool.

 

So no matter what you project you create you should consider what you have and have early investigation of test tools and testing expertise you need. This investigation will determine the end quality product and its success in the market. The issue can be solved by early introduction of quality assurance experts to help you match your needs to testing tools and methods.

 

We will gladly help you. Find out more about our QA testing services on our website.

The post Mobile version vs PWA vs Apps: a short guide to test early rather than late appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/mobile-version-pwa-apps-short-guide-testing/feed/ 0 6994
Guide to Flutter implicit animations https://www.evolvice.de/en/guide-to-flutter-implicit-animations/ https://www.evolvice.de/en/guide-to-flutter-implicit-animations/#respond Tue, 17 Dec 2019 12:55:58 +0000 https://www.evolvice.de/?p=6863 Looking for an effective way to upgrade your app? Consider using a cool animation. Flutter renders everything on the screen relying on Skia graphics library, instead of using those pesky native views. Therefore, you can animate literally anything. In this tutorial, you will learn how...

The post Guide to Flutter implicit animations appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
Looking for an effective way to upgrade your app? Consider using a cool animation. Flutter renders everything on the screen relying on Skia graphics library, instead of using those pesky native views. Therefore, you can animate literally anything. In this tutorial, you will learn how to implement basic animations in Flutter.

 

Implicit animations

 

Flutter includes a series of widgets that are animated versions of existing widgets that you’ve probably already used in your app. For instance, Container -> AnimatedContainer, Positioned -> AnimatedPositioned,  Opacity -> AnimatedOpacity are widgets you will see in this tutorial. These widgets automatically animate changes to their properties. They extend ImplicitlyAnimatedWidget that’s why these animations, in general, are called Implicit animations.

 

 

AnimatedContainer in action (using hot reload)

 

Although implicit animated widgets are easy to use, they have some disadvantages. Most important – you don’t have full control of these animations, so it is not possible to implement repeating animation or listen to the animation state and react to the changes.

 

Practice

 

Let’s look a little closer at how you can use one of those widgets to implement animations in your app.

In this app, we have a typical structure: AppBar, home page and a drawer (side menu). For this sample we will implement drawer by ourselves, instead of using drawer property in Scaffold widget.

Here we create a basic app with MainPage and Container which is our own implementation of drawer.

 

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State {
  var isShownMenu = false;

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width * 0.65;
    final height = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blue,
        title: Text("Home"),
        leading: IconButton(
            icon: Icon(Icons.menu),
            onPressed: () {
              setState(() {
                isShownMenu = !isShownMenu;
              });
            }),
      ),
      body: Stack(
        children: [
          MainPage(),
          Positioned(
            width: width,
            height: height,
            left: isShownMenu ? 0 : -width,
            top: 0,
            child: Container(
              width: width,
              color: Colors.redAccent,
              height: double.infinity,
              child: ListView(
                  children: [
                    ListTile(title: Text("Home"),),
                    ListTile(title: Text("Settings")),
                    ListTile(title: Text("Logout"),)
                  ],
                ),
              ),
          ),
        ],
      ),
    );
  }
}

 

 

Drawer without animation

 

You can see AppBar here with IconButton for opening menu. Body of the Scaffold consist of Stack with MainPage and our drawer. Its visibility is controlled by setting negative left when hidden and zero left when visible. MainPage is a simple Container with Text widget, it is omitted for brevity. There are no animations for now and drawer opening looks a little clunky.

We can add a simple animation by replacing Positioned with AnimatedPositioned. Let’s check the code.

 

  @override
  Widget build(BuildContext context) {
    ………
      body: Stack(
        children: [
          MainPage(),
          _buildAnimatedMenu(width, height),
        ],
      ),
    );
  }

  Widget _buildAnimatedMenu(double width, double height) {
    return AnimatedPositioned(
        duration: Duration(milliseconds: 300),
        width: width,
        height: height,
        left: isShownMenu ? 0 : -width,
        top: 0,
        child: MainMenu(
          width: width,
        ));
  }

 

Same as AnimatedContainer, AnimatedPositioned widget will animate any changes to its properties and this is exactly what we need. By setting only one additional property – duration, which defines how long animation will run, we added animation to the drawer opening.

Usually, drawer menu should dim what is behind it. You can implement such behavior in many ways, but we will use AnimatedOpacity in this case.

 

  @override
  Widget build(BuildContext context) {
    ………
      body: Stack(
        children: [
          MainPage(),
          _buildBackgroundSkim(), // new code
          _buildAnimatedMenu(width, height),
        ],
      ),
    );
  }

  Widget _buildBackgroundSkim() {
    return AnimatedOpacity(
      duration: Duration(milliseconds: 300),
      opacity: isShownMenu ? 1 : 0,
      child: Container(
        color: Color.fromARGB(42, 0, 0, 0),
      ),
    );
  }

 

New function returns AnimatedOpacity widget with the same duration as our previous animation. Property opacity is set to 1 if menu is visible and to 0 if no. Child of this widget is a simple Container with transparent grey background.

 

 

Result of using AnimatedPositioned and

 AnimatedOpacity (background dimming)

 

Adding Curves

 

Animations in all animated widgets are constant by default, they are changing their values in a linear way. Changing the curves is as easy as setting another property in the constructor. Look at the code below.

 

Widget _buildAnimatedMenu(double width, double height) {
    return AnimatedPositioned(
        duration: Duration(milliseconds: 300),
        width: width,
        height: height,
        left: isShownMenu ? 0 : -width,
        top: 0,
        curve: isShownMenu ? Curves.bounceOut : Curves.linear, // new code
        child: MainMenu(
          width: width,
        ));
  }
}

 

Linear curve is set if the menu is shown, so next animation (dismissing the menu) will be linear, otherwise bounceOut is set. All possible predefined curves can be found here.

 

 

Conclusion

Using Implicit Animated Widgets is the most straightforward way to implement basic animations in Flutter. But keep in mind, that basic animation is the one which doesn’t repeat forever and it is only for one widget. If you want to implement custom animations check AnimatedWidget and AnimatedBuilder.

The post Guide to Flutter implicit animations appeared first on Custom Software Development | Nearshoring | Evolvice.

]]>
https://www.evolvice.de/en/guide-to-flutter-implicit-animations/feed/ 0 6863